大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

消息通讯

概念、原理、接口

docutils document without title

实时应用涉及到多人和服务端实时通讯。聊天室是一个典型的实时应用,实时白板也是的。

平台规范一套极简的实时应用开发模式

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,群组将会被删除。

3.4   删除群组频道

使用如下方式删除一个群组:

group_manager.remove(group_id=12345)

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.4   from

包含用户id和名字:

{
    'id': 'users.zhang3',
    'name': '张三',
}

4.2.5   to

收信人的id:

['users.admin']

4.2.11   context

{  # 消息关联
    'uid': 123,
    'url': 'http://xxxx.com/++intid++123',
    'title': '某个表单',
    'object_types': ['DataItem'],
}