消息通讯
概念、原理、接口
实时应用涉及到多人和服务端实时通讯。聊天室是一个典型的实时应用,实时白板也是的。
平台规范一套极简的实时应用开发模式
1 理解概念
单机的前端开发,通过事件触发和处理,可以做到立刻响应。
而实时应用开发,只是将这些事件,通过通讯频道分发到远端其他的终端而已,实时事件的处理完全相同。
看一下其中的几个概念。
1.1 通讯频道
每个站点存在多个通讯频道,在频道内投放的任何消息,会通知到频道中的所有人群。
频道分类如下几类:
通知频道
这个是系统到个人的通讯频道,用于单向通讯,不需要单独创建
私人频道
场景场景是私聊。任何2个人的专有频道,不需要单独创建。
私人频道的一个特殊用途是,自己对自己的频道,自话自说。通常用于多端同步。
群组频道
常见的场景是群组聊天,或者群组白板。群组频道可以进行创建,成员管理,或者解散频道。
1.2 事件消息
在频道内广播的消息,可能有很多种,比如:
- 与某人聊天
- 系统广播
- 某人上线/离线
- 某人开始打字
- 某人发送红包
这些消息类型不同,处理方法也不同。为了更好的处理消息,我们通过 实时事件 来定义频道里面的消息。
每个实时事件包含如下信息:
- event_name:事件名称
- event_type: 是否存储事件到消息历史,
- persistent 保存
- transient 不保存
- event_data: 事件内容,可以自由定义
2 站点信使服务 root.messenger
每个站点,可以得到消息发送器,这个用来发送消息和触发事件:
messenger = root.messenger
2.1 通知频道
2.1.1 先得到频道 get_notify_channel
channel = messenger.get_notify_channel( 'default', # 消息的 category to=['users.admin'], # 这个通知发送给哪些用户和组 exclude=[] # 需要排除的用户和组 )
2.1.2 发送通知 trigger
发送通知消息:
# 触发一个通知事件 channel.trigger( 'notify', # 事件名称 data=event_data # 事件数据,此处以标准的通知为例 type='persistent', # 默认保存消息历史,不想保存可以使用 transient )
对于 notify 事件,发送标准的通知消息,event_data 为:
{ 'body': 'hey are you there?', # 消息内容 'from': { 'id': 'users.zhang3', 'name': '张三', }, 'context': { # 消息关联 'uid': 123, 'url': 'http://xxxx.com/++intid++123', 'title': '某个表单', 'object_types': ['DataItem'], }, 'attachments': None, # 消息附件,其中每个附件结构与 context 一致 'subject': None, # 消息主题 'action': 'default', # 由哪个动作触发 }
2.2 私人频道
2.2.1 得到私人频道 get_private_channel
私人频道用于2个人之间的消息通讯:
channel = messenger.get_private_channel( 'users.admin', # 用户 ID from_='users.zhang3', # 来自哪个用户 )
2.2.2 触发一个私聊事件 trigger
channel.trigger( 'chat', # 事件名称 data=event_data, type='persistent' # 默认保存消息历史,不想保存可以使用 transient )
对于 chat 事件, event_data 为:
{ # 事件字段参考上面的通知事件 'to': ['users.admin'] # 群聊中 to 字段一般留空,此字段表示这条消息特别提到了这些用户,用于群聊中的 at 某用户功能 'from': { 'id':'bot', 'name':'机器人', }, 'body': 'hello, world' }
2.3 群组频道
2.3.1 得到群聊频道 get_group_channel
channel = messenger.get_group_channel( 123123123 # 群组 ID )
2.3.2 群聊 trigger
群聊事件,得到可以是聊天或者其他自定义事件:
channel.trigger( 'chat', # 事件名称 data=event_data # 事件数据 type='persistent' # 默认保存消息历史,不想保存可以使用 transient )
对于 chat 事件的 event_data ,格式参见群组频道中事件数据的说明。
3 群组频道的管理
首先获得一个管理器:
group_manager = root.get_client(request, 'message').group
3.1 创建和修改群组频道 update_group
使用如下方式创建或更新一个通讯频道:
group_manager.update_group( group_id=12345, # 群组 ID group_title='my test group', # 群组的标题 members=[ # 群组成员 'users.zhang3', # 支持用户 ID 'users.admin', 'groups.tree.123', # 也支持部门 ID ] )
如果群组不存在将会被创建,否则会被更新。
3.2 添加人员 join_group
group_manager.join_group( 12345, # 群组 ID members=['users.li4'] # 要添加的人员清单 )
3.3 移除人员 leave_group
group_manager.leave_group( 12345, # 群组 ID members=['users.admin'] # 要移除的人员清单 )
注意:如果移除之后群组中人员数量为 0,群组将会被删除。
4 消息历史的查询 MessageQuerySet
4.2 索引数据
返回结果:
[{ '_score': 1.0, '_id': u'AWemoHCZ6XTU2HHVOxDo', '_source': { 'body': 'test', 'channel_type': 'notify', 'from': { 'id': 'users.admin', 'name': 'admin' }, 'attachments': [], 'to': ['users.admin', 'users.test'], 'event_name': 'notify', 'timestamp': 1544688791.70516, 'instance_id': 'message.default.zopen', 'channel_name': ['sendme<>users.admin', 'sendme<>users.test'], 'context': { 'url': 'http://192.168.1.116:1810/default/docs', 'title': 'test', 'thumbnail_url': '', 'uid': 1046063752, 'object_types': ['Folder', 'Container'] }, 'action': 'share', 'subject': None } }]
4.2.3 频道名 channel_name
不同类型的频道,频道名命名是不同的:
- notify: 通知频道,格式 CATEGORY,USERID 比如 sendme,users.panjunyong
- private: 私有频道,格式 USER1,USER2 比如 users.panjunyong,users.zhangsan
- group: 群组频道,格式 GROUP_ID 比如 3214333
4.2.11 context
{ # 消息关联 'uid': 123, 'url': 'http://xxxx.com/++intid++123', 'title': '某个表单', 'object_types': ['DataItem'], }