ContactRawSupport.scala
package wechaty.padplus.support
import java.util
import com.google.protobuf.ByteString
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.{BinaryBitmap, DecodeHintType, MultiFormatReader}
import com.typesafe.scalalogging.LazyLogging
import javax.imageio.ImageIO
import wechaty.padplus.PuppetPadplus
import wechaty.padplus.grpc.PadPlusServerOuterClass.{ApiType, ResponseType, StreamResponse}
import wechaty.padplus.schemas.GrpcSchemas.GrpcQrCodeLogin
import wechaty.padplus.schemas.ModelContact.{GrpcContactPayload, PadplusContactPayload}
import wechaty.padplus.schemas.ModelRoom.GrpcRoomPayload
import wechaty.padplus.schemas.ModelUser.ScanData
import wechaty.padplus.schemas.PadplusEnums.QrcodeStatus
import wechaty.puppet.ResourceBox
import wechaty.puppet.schemas.Contact.{ContactGender, ContactPayload, ContactType}
import wechaty.puppet.schemas.Event.{EventLoginPayload, EventScanPayload}
import wechaty.puppet.schemas.Puppet._
import wechaty.puppet.schemas.{Contact, Puppet}
import scala.concurrent.{Future, Promise}
import scala.language.implicitConversions
import scala.util.Try
/**
*
* @author <a href="mailto:jcai@ganshane.com">Jun Tsai</a>
* @since 2020-06-21
*/
trait ContactRawSupport extends LazyLogging{
self: PuppetPadplus =>
override def contactAlias(contactId: String): Future[String] = ???
override def contactAlias(contactId: String, alias: String): Future[Nothing] = ???
override def contactAvatar(contactId: String): Future[ResourceBox] = ???
override def contactAvatar(contactId: String, file: ResourceBox): Future[ResourceBox] = ???
override def contactList(): Future[Array[String]] = ???
/**
* contact
*/
override protected def contactRawPayload(contactId: String): Future[Contact.ContactPayload] = {
this.getContact(contactId).map(convertPadplusContactToContactPayload)
}
protected def getContact(contactId: String): Future[PadplusContactPayload] = {
getPadplusContactPayload(contactId) match{
case Some(padplusContactPayload) => Future.successful(padplusContactPayload)
case _ =>
val promise = Promise[PadplusContactPayload]
CallbackHelper.pushContactCallback(contactId,promise)
val json = objectMapper.createObjectNode()
json.put("userName", contactId)
asyncRequestNothing(ApiType.GET_CONTACT,Some(json.toString)).flatMap(_=>promise.future)
}
}
protected def loginPartialFunction(response: StreamResponse): PartialFunction[ResponseType, Unit] = {
case ResponseType.QRCODE_SCAN =>
onQrcodeScan(response)
case ResponseType.LOGIN_QRCODE =>
val qrcodeData = objectMapper.readTree(response.getData)
logger.debug("qrcode:",response.getData)
val base64 = qrcodeData.get("qrcode").asText().replaceAll("\r|\n", "")
val fileBox = ResourceBox.fromBase64(s"qrcode${(Math.random() * 10000).intValue()}.png", base64)
//解析二维码的类
val multiFormatReader = new MultiFormatReader();
//要解析的二维码的图片
val bufferedImage = ImageIO.read(fileBox.toStream);
val binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
//二维码的参数设置
val hints = new util.HashMap[DecodeHintType, String]();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); //设置二维码的编码
//得到解析结果,
val result = multiFormatReader.decode(binaryBitmap, hints);
val payload = new EventScanPayload
payload.qrcode = result.getText
logger.debug("Scan QR Code to login: %s\nhttps://wechaty.github.io/qrcode/%s\n".format(payload.status, payload.qrcode))
emit(PuppetEventName.SCAN, payload)
case ResponseType.QRCODE_LOGIN =>
val loginData = objectMapper.readValue(response.getData, classOf[GrpcQrCodeLogin])
this.selfId = Some(loginData.userName)
this.saveUin(ByteString.copyFromUtf8(loginData.uin))
val padplusContactPayload = new PadplusContactPayload
padplusContactPayload.alias = loginData.alias
padplusContactPayload.bigHeadUrl = loginData.headImgUrl
padplusContactPayload.nickName = loginData.nickName
padplusContactPayload.sex = ContactGender.Unknown
padplusContactPayload.userName = loginData.userName
padplusContactPayload.verifyFlag = 0
savePadplusContactPayload( padplusContactPayload)
val eventLoginPayload = new EventLoginPayload
eventLoginPayload.contactId = padplusContactPayload.userName
emit(PuppetEventName.LOGIN, eventLoginPayload)
getContact(padplusContactPayload.userName).foreach(payload=>{
this.savePadplusContactPayload(payload)
})
case ResponseType.AUTO_LOGIN =>
logger.debug("response data:{}", response.getData)
val autoLoginData = objectMapper.readTree(response.getData)
if (autoLoginData.get("online").asBoolean()) {
val wechatUser = autoLoginData.get("wechatUser")
if (wechatUser != null) {
val rawContactPayload = new PadplusContactPayload
if (wechatUser.has("alias"))
rawContactPayload.alias = wechatUser.get("alias").asText("")
rawContactPayload.bigHeadUrl = wechatUser.get("headImgUrl").asText()
rawContactPayload.nickName = wechatUser.get("nickName").asText()
rawContactPayload.sex = ContactGender.Unknown
rawContactPayload.userName = wechatUser.get("userName").asText()
savePadplusContactPayload(rawContactPayload)
// "{\"uin\":1213374243,\"online\":true,\"wechatUser\":{\"headImgUrl\":\"http://wx.qlogo.cn/mmhead/ver_1/iag5D2R2U9ibgTW2eh7XUbPTHqpEMP2DhSpXSBeQYzEPWgEmLIx5IDibwicGh4fTh4IibkL4hNianoiaTzXmVORnm1O4ZjhxfPosKzkMPSwic8Iicylk/0\",\"nickName\":\"\351\230\277\350\224\241\",\"uin\":1213374243,\"userName\":\"wxid_gbk03zsepqny22\",\"alias\":\"\",\"verifyFlag\":0}}"
selfId = Some(rawContactPayload.userName)
}
contactSelfInfo().foreach(payload=>{
savePadplusContactPayload(payload)
})
} else {
deleteUin()
asyncRequest(ApiType.GET_QRCODE)
}
case ResponseType.CONTACT_LIST | ResponseType.CONTACT_MODIFY =>
val data = response.getData
if(!isBlank(data)){
val root = objectMapper.readTree(data)
val userName = root.get("UserName").asText()
logger.trace("response data:{}",data)
if(isRoomId(userName)){
val roomTry=Try {
val grpcRoomPayload = objectMapper.readValue(data, classOf[GrpcRoomPayload])
val roomPayload = convertRoomFromGrpc(grpcRoomPayload)
/* //TODO process room members
const roomMembers = briefRoomMemberParser(roomPayload.members)
const _roomMembers = await this.cacheManager.getRoomMember(roomPayload.chatroomId)
if (!_roomMembers) {
await this.cacheManager.setRoomMember(roomPayload.chatroomId, roomMembers)
}
await this.cacheManager.setRoom(roomPayload.chatroomId, roomPayload)
} else {
throw new PadplusError(PadplusErrorType.NO_CACHE, `CONTACT_MODIFY`)
}
*/
savePadplusRoomPayload(roomPayload)
roomPayload
}
CallbackHelper.resolveRoomCallBack(userName,roomTry)
}else{
val result:Try[PadplusContactPayload] = Try {
val contact = objectMapper.readValue(data, classOf[GrpcContactPayload])
val padplusContactPayload = convertFromGrpcContact(contact)
savePadplusContactPayload(padplusContactPayload)
padplusContactPayload
}
CallbackHelper.resolveContactCallBack(userName,result)
}
}
}
private def onQrcodeScan(response: StreamResponse): Unit = {
val scanRawData = response.getData()
val scanData = objectMapper.readValue(scanRawData, classOf[ScanData])
QrcodeStatus(scanData.status.intValue()) match {
case QrcodeStatus.Scanned =>
case QrcodeStatus.Confirmed =>
case QrcodeStatus.Canceled | QrcodeStatus.Expired =>
}
}
implicit def convertFromGrpcContact (contactPayload: GrpcContactPayload): PadplusContactPayload = {
val payload = new PadplusContactPayload
payload.alias = contactPayload.Alias
payload.bigHeadUrl = contactPayload.BigHeadImgUrl
payload.city = contactPayload.City
payload.contactFlag = contactPayload.ContactFlag
payload.contactType = if(Puppet.isBlank(contactPayload.ContactType)) 0 else contactPayload.ContactType.toInt
payload.country = ""
payload.nickName = contactPayload.NickName
payload.province = contactPayload.Province
payload.remark = contactPayload.RemarkName
payload.sex = Contact.ContactGender(contactPayload.Sex.intValue())
payload.signature = contactPayload.Signature
payload.smallHeadUrl = contactPayload.SmallHeadImgUrl
payload.stranger = contactPayload.EncryptUsername
payload.tagList = contactPayload.LabelLists
payload.ticket = ""
payload.userName = contactPayload.UserName
payload.verifyFlag = contactPayload.VerifyFlag
payload
}
implicit def convertPadplusContactToContactPayload(rawPayload:PadplusContactPayload): ContactPayload ={
if (isRoomId(rawPayload.userName)) {
throw new Error("Room Object instead of Contact!")
}
var contactType = ContactType.Unknown
if (isContactOfficialId(rawPayload.userName) || rawPayload.verifyFlag != 0) {
contactType = ContactType.Official
} else {
contactType = ContactType.Personal
}
var friend = false
if (rawPayload.contactFlag > 0 && rawPayload.contactFlag != 0 && rawPayload.verifyFlag == 0) {
friend = true
}
val payload = new ContactPayload
payload.alias = rawPayload.remark
payload.avatar = rawPayload.bigHeadUrl
payload.city = rawPayload.city
payload.friend = friend
payload.gender = rawPayload.sex
payload.id = rawPayload.userName
payload.name = rawPayload.nickName
payload.province = rawPayload.province
payload.signature = (rawPayload.signature).replace("+", "") // Stay+Foolis
payload.`type` = contactType
payload.weixin = rawPayload.alias
payload
}
}