Skip to content
wwj718 edited this page Jun 28, 2019 · 11 revisions

设计原则

Codelab Adapter的设计追随Smalltalk的设计原则everything is message.

基础结构

消息的基础结构为

{ "topic": "TOPIC", "payload": "MESSAGE" }

注意: 此结构与MQTT消息结构保持一致。

插件消息

插件消息的topic由插件作者自定义,一般而言,由插件名决定。 举几个例子:

extension_eim.py
{"topic": "eim", "payload": "YOUR_MESSAGE"}
extension_python_kernel
{"topic": "eim/python", "payload": "YOUR_MESSAGE"}

以下两种情况,建议 topic直接用eim:

  • 测试阶段
  • 不想构建独立Scratch extension

同步消息插件

基于消息的系统一般都是异步非阻塞的。前头的两个插件都是异步的。

如果你希望基于消息构建同步插件(按顺序、阻塞式地逐个积木执行),可以参考这篇文章,核心思路是在消息结构里加上消息id(Scratch Link也是这么做的)

看几个例子

extension_req_rep.py
{"topic": "eim/reqRep", "payload": "YOUR_MESSAGE"}
extension_cozmo.py
// MESSAGE_ID来自前端
{"topic": "eim/cozmo", "payload": "YOUR_MESSAGE", "messageID": "MESSAGE_ID"}

系统消息

消息是Codelab Adapter的核心机制,Codelab Adapter使用系统消息来构建部分系统功能(有别于插件消息)。

随着功能需求的增长,这类消息会陆续增多。

目前有两个系统消息

  • CONTROL_TOPIC = "__control"
  • WORMHOLE = "__wormhole"

CONTROL_TOPIC用于控制插件的启停, WORMHOLE用于classroom功能(暂未发布,可以忽视)。

CONTROL_TOPIC

CONTROL_TOPIC用于以下几个功能

终止插件

Codelab Adapter 的extension由线程启动。

Python的线程无法像进程和协程一样被管理,目前使用python3-cookbook的建议来管理线程。

但有一个问题,试看extension_eim.py的代码

while self._running:
            read_message = self.read() # 不能有多个read
            topic = read_message.get("topic")
            if topic == self.TOPIC:
                data = read_message.get("payload")
                self.logger.info("eim message:%s", data)

由于self.read()是阻塞的,所以即便在Codelab Adapter里取消勾选停止了插件(self._running变为False),但依然需要scratch里多发一条消息,才能结束self.read()的阻塞,退出while。

所以这种情况下,当用户在Codelab Adapter暂停插件时,会触发一条消息:

{"topic":CONTROL_TOPIC, "payload":"terminate","type":"adapter"}

打破self.read()阻塞。

开启插件

从前端开启插件的消息为:

{
  "topic": CONTROL_TOPIC,
  "type": "web/extension_control",
  "payload": { "action": "turn_on", "extension_name": "extension_eim" }
}

CodeLab Adapter将定时汇报插件状态(这样可以支持多个前端,类似linux GUI与server分离)

{
  "message": {
    "topic": CONTROL_TOPIC,
    "payload": {
      "extension_iot": false,
      "extension_eim": true,
      "extension_vector": false,
      "extension_eim_monitor": false,
      "extension_tello": false,
      "extension_blender": false,
      "extension_mpfshell": false,
      "extension_eim_script": false,
      "extension_python_kernel": false,
      "extension_wechat": false,
      "extension_cozmo": false,
      "extension_usb_microbit": false
    },
    "type": "event/extensions_statu"
  }
}

todo

连接硬件

实现类似Scratch Link的交互:在前端选择硬件。

思路:分析Scratch micro:bit extension与Scratch Link通信的细节,模仿它:Scratch micro:bit extension与Scratch Link通信的细节

发现设备

request from scratch

{
  "messageID": MESSAGE_ID,
  "topic": CONTROL_TOPIC,
  "type": "web/devices_control",
  "payload": { "action": "discover", "extension_name": "extension_usb_microbit" }
}

response from codelab adapter extension(定时扫描回复)

{
    "messageID": MESSAGE_ID,
    "topic": CONTROL_TOPIC,
    "type": "web/devices_control",
    "payload": { "devices_type": "PORT", "names": ["COM2","COM3"] }
}

建立连接

{
    "messageID": MESSAGE_ID,
    "topic": CONTROL_TOPIC,
    "type": "web/devices_control",
    "payload": { "action": "connect", "extension_name": "extension_usb_microbit", "name": "COM2"}
}

response from codelab adapter extension

{
    "messageID": MESSAGE_ID,
    "topic": CONTROL_TOPIC,
    "type": "web/devices_control",
    "payload": { "status":"success"}
}