Adapter Node¶
在上一节:hello world(Adapter Extension) 中我们学会了如何自定义一个 extension。
extension 有如下的限制:
- 必须放置在插件目录中(
~/codelab_adapter/extensions
)。 - 只能使用 CodeLab Adapter 已打包的第三方库。
如果你想使用 Python 社区海量的第三方库:诸如 Pygame、PyQt、PyTorch、flask... extension 就办不到了,但 Adapter Node 可以!
ps: 如果你只是想把外部系统接入Adapter,也可以参考更为简单的: 与外部系统通信
提醒
实际上 Adapter Extension 是 AdapterNode 的子类.
我们希望 CodeLab Adapter 专注于连接万物,所以构建了 Adapter Node,允许你在任何地方创建 CodeLab Adapter 的扩展,允许你使用任何 Python 库,无论你准备构建游戏、构建网站、构建深度学习应用还是构建一个机器人!
Adapter Node 是什么¶
Adapter Node 只是普通的 Python 程序,继承自 AdapterNode。
第一个 Adapter Node¶
我们开始写第一个 Adapter Node。
你需要完成这些前置工作:
- 安装了 Python3(
>=3.6
) - pip3 install codelab_adapter_client --upgrade
接着可以随便在什么地方创建一个 Python 文件,随便给它起个名字,诸如my_first_adapter_node.py
:
我们让这个 Node 的功能与 hello world 里我们自定义的插件功能相同:反转字符串
import time from loguru import logger from codelab_adapter_client import AdapterNode class EIMNode(AdapterNode): NODE_ID = "eim" DESCRIPTION = "Everything Is a Message" HELP_URL = "https://adapter.codelab.club/extension_guide/eim/" def __init__(self): super().__init__() def send_message_to_scratch(self, content): message = self.message_template() message["payload"]["content"] = content self.publish(message) def extension_message_handle(self, topic, payload): self.logger.info(f'the message payload from scratch: {payload}') content = payload["content"] if type(content) == str: content_send_to_scratch = content[::-1] # 反转字符串 self.send_message_to_scratch(content_send_to_scratch) def run(self): while self._running: time.sleep(1) if __name__ == "__main__": try: node = EIMNode() node.receive_loop_as_thread() node.run() except KeyboardInterrupt: node.terminate() # Clean up before exiting.
运行¶
打开 CodeLab Adapter(不需要选择插件),将 CodeLab Adapter 作为消息中心。
运行 my_first_adapter_node.py:python3 my_first_adapter_node.py
让我们在 CodeLab Scratch3 中尝试一下反转字符串:
成功!
它只是普通的 Python 程序,使用你本地的 Python 环境,所以你现在可以任何你偏爱的Python库来增强 Scratch3 啦!
GUI¶
有开发者在邮件中提到:
tkinter、PyQt 都有一个主循环,Adapter Node 也有一个主循环,怎么才能共存呢?
Adapter Node 可以与任何 GUI 框架共存
if __name__ == "__main__": try: node = EIMNode() node.receive_loop_as_thread() node.run() except KeyboardInterrupt: node.terminate() # Clean up before exiting.
其中node.run()
不是必要的,只是为了阻塞程序,使其不立刻结束,如果 GUI 框架本身已经有主循环,则可以移除node.run()
, node.receive_loop_as_thread()
是非阻塞的。
以下是示范例子:
from tkinter import * # AdapterNode from loguru import logger from codelab_adapter_client import AdapterNode class EIMNode(AdapterNode): NODE_ID = "eim" def __init__(self): super().__init__() def send_message_to_scratch(self, content): message = self.message_template() message["payload"]["content"] = content self.publish(message) def extension_message_handle(self, topic, payload): self.logger.info(f'the message payload from scratch: {payload}') content = payload["content"] if type(content) == str: content_send_to_scratch = content[::-1] # 反转字符串 self.send_message_to_scratch(content_send_to_scratch) node = EIMNode() node.receive_loop_as_thread() # tkinter window = Tk() window.title("Adapter Node & tkinter") window.geometry('300x100') lbl = Label(window, text="click to send message") lbl.grid(column=0, row=0) i = 1 def clicked(): global i message = node.message_template() message["payload"]["content"] = "click_{}".format(i) node.publish(message) i += 1 btn = Button(window, text="emit", command=clicked) btn.grid(column=1, row=0) window.mainloop()
该 node 接收来自 Scratch EIM 的消息,并逆转字符串;当用户点击按钮时,给 Scratch 发送消息:click_<NUMBER>
想象空间¶
如果你希望构建分布式的应用,诸如构建密室逃脱中的各种机关。只需要做一下配置就行,让 CodeLab Adapter 接受分布式的请求。
你可以将 Adapter Node 跑在任何地方,来增强 CodeLab Adapter 的能力,无论是本地、云端还是分布式节点。
我们也正在构建其他语言的 client,你不会被限制在 Python 中,而是可以在任何编程语言任何平台上构建 Adapter Node。 参考:编程语言支持