project,

2022-基于5G平台开发puppet模块接入wechaty

fabian fabian Follow Feb 17, 2022 · 8 mins read
2022-基于5G平台开发puppet模块接入wechaty

基于 5G 平台开发 puppet 模块接入 wechaty

背景介绍

  • Wechaty 社区目前已经支持微信、Whatsapp、企业微信、飞书等常见流行即时通讯工具,并且能够通过多语言 SDK (比如 Python Wechaty) 进行调用。
  • 5G Chatbot (RCS) 是近期中国电信运营商基于 5G 的消息战略落地平台,未来的 5G 手机将会内置 RCS 消息的处理能力。
  • 硬核桃社区电信运营商商5G Chatbot 平台。

目标计划

  • 基于 5G 平台的开放 api 进行封装,实现可以收发消息的机器人 bot。
  • 丰富机器人的扩展性功能,完善对于 Wechaty 的 api 适配。

项目进展

  • 基于 5G 平台的开放 api 进行封装,实现简单的ding-dong-bot
  • 丰富 5G 的消息模式,实现支持富文本、文件、css等多样消息格式的 puppet。

需求分析与设计

1. WechatyPuppet的交互

WechatyPuppetWalnut

  • 开发者通过Wechaty提供的 Api 来进行具体的交互操作。
  • Wechaty只需要具体调用开发者指定的Puppet即此处的Walnut来实现开发者需要的逻辑。
  • 我们的Walnut继承于抽象的Puppet父类,实现其预定义的抽象方法来实现具体的能力。
  • 具体的Walnut会和5G平台进行数据交互从而实现真正的 ChatBot。

2. 抽象方法的实现

在继承了抽象父类之后,我们就可以按照自己需要去实现具体的方法。

  1. messageMixin: 消息相关的抽象方法

    abstract messageContact      (messageId: string)                       : Promise<string>
    abstract messageFile         (messageId: string)                       : Promise<FileBoxInterface>
    abstract messageImage        (messageId: string, imageType: ImageType) : Promise<FileBoxInterface>
    abstract messageMiniProgram  (messageId: string)                       : Promise<MiniProgramPayload>
    abstract messageUrl          (messageId: string)                       : Promise<UrlLinkPayload>
    abstract messageLocation     (messageId: string)                       : Promise<LocationPayload>
       
    abstract messageForward         (conversationId: string, messageId: string,)                     : Promise<void | string>
    abstract messageSendContact     (conversationId: string, contactId: string)                      : Promise<void | string>
    abstract messageSendFile        (conversationId: string, file: FileBoxInterface)                 : Promise<void | string>
    abstract messageSendMiniProgram (conversationId: string, miniProgramPayload: MiniProgramPayload) : Promise<void | string>
    abstract messageSendText        (conversationId: string, text: string, mentionIdList?: string[]) : Promise<void | string>
    abstract messageSendUrl         (conversationId: string, urlLinkPayload: UrlLinkPayload)         : Promise<void | string>
    abstract messageSendLocation    (conversationId: string, locationPayload: LocationPayload)       : Promise<void | string>
       
    abstract messageRecall (messageId: string) : Promise<boolean>
    
  2. contactMixin: 联系人相关的抽象方法

    abstract contactSelfName (name: string)           : Promise<void>
    abstract contactSelfQRCode ()                     : Promise<string /* QR Code Value */>
    abstract contactSelfSignature (signature: string) : Promise<void>
    abstract contactAlias (contactId: string)                       : Promise<string>
    abstract contactAlias (contactId: string, alias: string | null) : Promise<void>
    abstract contactAvatar (contactId: string)                : Promise<FileBoxInterface>
    abstract contactAvatar (contactId: string, file: FileBoxInterface) : Promise<void>
    abstract contactPhone (contactId: string, phoneList: string[]) : Promise<void>
    abstract contactCorporationRemark (contactId: string, corporationRemark: string | null): Promise<void>
    abstract contactDescription (contactId: string, description: string | null): Promise<void>
    abstract contactList (): Promise<string[]>
    abstract contactRawPayload (contactId: string): Promise<any>
    abstract contactRawPayloadParser (rawPayload: any) : Promise<ContactPayload>
    

3. 缓存模块

  1. 当我们的 sever 监听到有用户发送消息,此时我们就需要去对消息的具体内容做一个缓存。

    这里我们需要自己实现一个缓存模块,将 message 的具体内容存储进去,并且返回 id。

    推荐李卓桓老师开发的缓存组件:flash-storehttps://github.com/huan/flash-store

  2. 然后我们用 Puppet 触发一个 message 事件,把我们本地缓存的 id 传出去。

    this.emit('message', { messageId: messageId })
    
  3. 这时候 Wechaty 已经拿到我们消息的 id ,这个时候会根据一个需要我们实现的查询方法来获取本地缓存。

    override async messageRawPayload (messageId: string): Promise<WalnutMessagePayload | undefined> {
      log.verbose('PuppetWalnut', 'messageRawPayload(%s)', messageId)
      // 这里根据 id 去缓存中查出来刚刚存入的消息
    }
    
  4. 当查出具体的消息内容后,其实和我们 Wechaty 中预定义的消息结构可能不太一致,需要我们进行一个转换。

    override async messageRawPayloadParser (rawPayload: WalnutMessagePayload): Promise<PUPPET.payloads.Message> {
      // 这里实现转换规则:WalnutMessagePayload ===> PUPPET.payloads.Message
    }
    
  5. 不过这里要注意,在每次进行收发消息的时候 Wechaty 都会去加载一遍我们的联系人缓存。 所以对应的联系人缓存的模块也需要实现:

    • contactRawPayloa
    • contactRawPayloadParser

项目成果

1. Contact Api 支持

  • Properties

    Name Type Description Support Details
    id string Get Contact id. This function is depending on the Puppet Implementation, see puppet-compatible-table Phone number
  • Instance Methods

    Instance Methods Return type Support Details
    say(text Or Contact Or File) Promise ⚠Contact not Support
    name() String Phone number
    alias(newAlias) Promise  
    friend() Boolean or null True
    type() ContactType.Unknown or ContactType.Personal or ContactType.Official ContactType.Personal
    gender() ContactGender.Unknown or ContactGender.Male or ContactGender.Female ContactGender.Unknown
    province() String or null  
    city() String or null  
    avatar() Promise Default avatar
    sync() Promise  
    self() Boolean  

    Default avatar 👉 https://raw.githubusercontent.com/wechaty/puppet-walnut/main/docs/images/avatar.webp

  • Static Methods

    Static Methods Return Type Support Detail
    find(query) Promise <Contact | null>  
    findAll(Query Arguements) Promise <Contact []>  

2. Message Api 支持

  • Instance Methods

    Instance methods Return type Support Detail
    from() Contact or null  
    to() Contact or null  
    room() Room or null null
    text() string  
    say(text Or Contact Or File) Promise ⚠Contact not Support
    type() MessageType Message.Text
    self() boolean  
    mention() Promise  
    mentionSelf() Promise  
    forward(to) Promise  
    date() Date  
    age() Number  
    toFileBox() Promise  
    toContact() Promise  
    toUrlLink() Promise  
  • Static Method

    Static Methods Return type Support Detail
    find() Promise  
    findAll() Promise  

3. 消息格式支持

消息类型 从属(根据接口返回) 获取方式 接收 发送 群聊
文本 text message.text
图片 image message.toImage()
视频 video message.toFilebox()
音频 audio message.toFilebox()
位置 location message.toLocation()
文件 other message.toFilebox()
联系人 other message.toContact()

视频展示

答辩报告

未来与展望

  • 对 walnut 进行细节的补充和完善。
  • 尽可能增加对其他功能的支持、并且持序维护。

Author: @fabian

Join Newsletter
Get the latest news right in your inbox. We never spam!
Written by fabian
a passionate learner