class WeChat::Bot::Message

微信消息

Constants

AT_MESSAGE_REGEX
GROUP_MESSAGE_REGEX

Attributes

bot[R]

@return [Core]

events[R]

事件列表 @return [Array<Symbol>]

from[R]

消息发送者

用户或者群组 @return [Contact]

kind[R]

消息类型 @return [Message::Kind]

media_id[R]
message[R]

消息正文 @return [String]

meta_data[R]
raw[R]

原始消息 @return [Hash<Object, Object>]

source[R]

消息来源 @return [Contact::Kind]

time[R]

@return [Time]

Public Class Methods

new(raw, bot) click to toggle source
# File lib/wechat/bot/message.rb, line 61
def initialize(raw, bot)
  @raw = raw
  @bot = bot

  @events  = []
  @time    = Time.now
  @statusmsg_mode = nil

  parse

  @bot.logger.verbose "Message Raw: #{@raw}"
end

Public Instance Methods

at_message(message) click to toggle source

尝试解析群聊中的 @ 消息

群消息格式:

@ToNickNameUserName Message

@param [String] message 原始消息 @return [String] 文本消息,如果不是 @ 消息返回原始消息

# File lib/wechat/bot/message.rb, line 274
def at_message(message)
  if match = AT_MESSAGE_REGEX.match(message)
    return match[2].strip
  end

  message
end
at_message?() click to toggle source
# File lib/wechat/bot/message.rb, line 140
def at_message?
  @at_mesage == true
end
group_message(message) click to toggle source

解析用户的群消息

群消息格式:

@FromUserName:<br>Message

@param [String] message 原始消息 @return [Array<Object>] 返回两个值的数组

- 0 from_username
- 1 message
# File lib/wechat/bot/message.rb, line 259
def group_message(message)
  if match = GROUP_MESSAGE_REGEX.match(message)
    return [match[1], at_message(match[2])]
  end

  false
end
match(regexp, type) click to toggle source

消息匹配

@param [String, Regex, Pattern] regexp 匹配规则 @param [String, Symbol] type 消息类型 @return [MatchData] 匹配结果

# File lib/wechat/bot/message.rb, line 121
def match(regexp, type)
  # text = ""
  # case type
  # when :ctcp
  #   text = ctcp_message
  # when :action
  #   text = action_message
  # else
  #   text = message.to_s
  #   type = :other
  # end

  # if strip_colors
  #   text = Cinch::Formatting.unformat(text)
  # end

  @message.match(regexp)
end
parse() click to toggle source

解析微信消息

@return [void]

# File lib/wechat/bot/message.rb, line 92
def parse
  parse_source
  parse_kind

  message = @raw["Content"].convert_emoji
  message = CGI.unescape_html(message) if @kinde != Message::Kind::Text
  if match = group_message(message)
    # from_username = match[0]
    message = match[1]
  end

  @message = message
  # TODO: 来自于特殊账户无法获取联系人信息,需要单独处理
  @from = @bot.contact_list.find(username: @raw["FromUserName"])
  parse_emoticon if @kind == Message::Kind::Emoticon

  case @kind
  when Message::Kind::ShareCard
    @meta_data = MessageData::ShareCard.parse(@message)
  end

  parse_events
end
parse_emoticon() click to toggle source

解析表情

表情分为两种:

1. 微信商店表情
1. 自定义表情

@return [void]

# File lib/wechat/bot/message.rb, line 234
def parse_emoticon
  if @message.empty?
    @media_id = @raw["MediaId"]
    # TODO: 解决微信商店表情
    # file = @bot.client.download_image(@raw["NewMsgId"])
  else
    data = MultiXml.parse(@message)
    @media_id = data["msg"]["emoji"]["md5"]
  end
end
parse_events() click to toggle source

解析 Handler 的事件

- `:message` 用户消息
  - `:text` 文本消息
  - `:image` 图片消息
  - `:voice` 语音消息
  - `:short_video` 短视频消息
- `:group` 群聊消息
  - `:at_message` @ 消息

@return [void]

# File lib/wechat/bot/message.rb, line 215
def parse_events
  @events << :message
  @events << @kind
  @events << @source

  @at_mesage = false
  if @source == :group && @raw["Content"] =~ /@([^\s]+)\s+(.*)/
    @events << :at_message
    @at_mesage = true
  end
end
parse_kind() click to toggle source

解析消息类型

- 1: Text 文本消息
- 3: Image 图片消息
- 34: Voice 语言消息
- 37: 验证消息
- 42: BusinessCard 名片消息
- 47: Emoticon 微信表情
- 49: ShareCard 分享链接消息
- 62: ShortVideo 短视频消息
- 1000: System 系统消息
- Unkown 未知消息

@return [void]

# File lib/wechat/bot/message.rb, line 179
def parse_kind
  @kind = case @raw["MsgType"]
          when 1
            Message::Kind::Text
          when 3
            Message::Kind::Image
          when 34
            Message::Kind::Voice
          when 37
            Message::Kind::Verify
          when 42
            Message::Kind::BusinessCard
          when 62
            Message::Kind::ShortVideo
          when 47
            Message::Kind::Emoticon
          when 49
            Message::Kind::ShareCard
          when 10000
            Message::Kind::System
          else
            Message::Kind::Unkown
          end
end
parse_share() click to toggle source
# File lib/wechat/bot/message.rb, line 245
def parse_share
  # TODO: 完成解析
  data = MultiXml.parse(@message)
end
parse_source() click to toggle source

解析消息来源

特殊账户/群聊/公众号/用户

@return [void]

# File lib/wechat/bot/message.rb, line 149
def parse_source
  @source = if @bot.config.special_users.include?(@raw["FromUserName"])
              # 特殊账户
              Contact::Kind::Special
            elsif @raw["FromUserName"].include?("@@")
              # 群聊
              Contact::Kind::Group
            elsif (@raw["RecommendInfo"]["VerifyFlag"] & 8) != 0
              # 公众号
              Contact::Kind::MP
            else
              # 普通用户
              Contact::Kind::User
            end
end
reply(text, **args) click to toggle source

回复消息

# File lib/wechat/bot/message.rb, line 75
def reply(text, **args)
  to_user = args[:username] || @from.username
  to_user = @bot.contact_list.find(nickname: args[:nickname]) if args[:nickname]

  message_type = args[:type] || :text

  # if @bot.config.special_users.include?(to_user) && to_user != 'filehelper'
  #   @bot.logger.error "特殊账户无法回复: #{to_user}"
  #   raise NoReplyException, "特殊账户无法回复: #{to_user}"
  # end

  @bot.client.send(message_type, to_user, text)
end