作者:webb
审阅:outprog
来源:内容公会 - 新闻
什么是 module
module 可以看做 ao 中运行的操作系统的核心代码,就是一个编译好的 wasm 文件,包含了 process 运行时的环境和我们可以引用的所有基础库。
module 的代码是 aos 的一部分,在 aos/process 下。
每个 process 在启动时会加载一个 module,并且不能更换,使用 Eval 消息可以进行更新。module 编译出的 wasm 文件需要上传到 arweave 上,进程通过 txid 进行加载(module id 就是上传 module 的 ar txid)。aolink 中可以查看进程对应的 module 信息。
每个 module 的 tag 中会定义一些关键信息,比如是 wasm32 还是 wasm64、进程内存限制等,可以从 aolink 中查看。
为什么要自定义 module
我们在 ao 中使用的标准库,如 ”chance“、”bint”、”handlers” 等都是 aos 中自带的包,我们在代码中可以通过 require('.xxx') 引用。
自定义 module 相当于把自己的包写进了标准库里,进程只要加载了我们的 module 就可以直接使用自定义库,不用再使用 eval 消息加载代码了。
当我们的 ao app 需要多进程交互,并且需要动态创建 process 的时候,会很有用。或者我们的 module 功能希望被其他 app 使用的时候,也可以用这种方法。比如 Permaswap 发布了一个带有 swap 功能的 module,其他开发者需要使用其功能的时候可以直接使用 module 创建进程,进行二次开发。
具体步骤
1. 准备工作
编译和部署需要准备一些代码和工具:
-
module 的 lua 代码
-
docker 环境
安装docker环境,编译是通过 docker 镜像进行的。
-
docker 镜像源码
docker 镜像分为带 sqlite 和不带 sqlite 两个版本,我们以带 sqlite 的版本编译为例。代码在 https://github.com/permaweb/aos-sqlite
-
一个可以上传文件到 arweave 的工具
可以使用的工具很多,比如 irys、ardrive、weweave 等,我使用的是 goar 自己编写的一个上传程序。
2. 编译
2.1 编译 docker 镜像
下载 https://github.com/permaweb/aos-sqlite 的代码,进入 container 目录执行编译脚本。具体细节见dockerfile:
编译完成后可以看到 Tag 为 latest 的 docker image。ao 也提供了很多版本的 image,但都是不带 sqlite 的,如果使用 sqlite 需要自行编译。
ao 也发布了 dev-cli 工具,但都是没有 sqlite 版本的编译和发布。带 sqlite 版本的稍有区别,本文以带 sqlite 版本为准。
容器 wasm 模块使用 emcc 编译,格式是 wasm64位,查看 dockerfile:
2.2 编译 wasm
下面使用 docker 镜像编译 wasm 文件。需要下载 aos 最新源码:https://github.com/permaweb/aos
进入 process 目录,然后执行编译命令:
编译好后会出现 process.wasm 文件。同样是使用 emcc 编译 wasm64 格式,命令如下:
3. 部署
部署即上传 process.lua 文件到 arweave,并记录 txid,txid 在创建进程的时候需要指定。需要自己准备一个钱包文件,并且保证钱包里有一定的 AR Token 作为费用。
- 可以使用 aos-sqlite 的工具,在 https://github.com/permaweb/aos-sqlite 目录下执行:
- 使用 goar 库制作的上传工具,代码如下:
其中 keyfile 是钱包文件路径,filename 是要上传的 process.wasm 文件的路径,需要自行设置。tag 中的 name 也需要自行设置。
运行代码,等待文件上传,获取 txid。显示成功后需要等待上链确认,过程大约需要5分钟。
成功后可以在 viewblock 中通过 txid 查看:
在 aolink 中输入 txid 也可以显示为 Module:
4. 自定义 module
编译部署自定义代码
在 module 的核心代码库中加入自定义的 lua 包即可,把 .lua 文件放到核心代码文件夹,也就是 aos/process 文件夹。
我的例子中放了 test.lua 和 handle.lua 两个包。
然后进行编译和部署,参考2、3章的内容,最终获取 module 的 txid。
5. 使用自定义 module
5.1 创建进程
使用刚才生成的 txid 创建一个进程,进程会加载我们自己编译的 module。
有两种方式创建进行:
- 在 aos 启动命令中加入 module 参数:aos --module
- 在 lua 代码中使用 spawn 函数:ao.spawn(txid, spawnMessage)
5.2 显示引用自定义 lua 库
使用 module 的 txid 创建进程:
可以进行在进程中引用 test.lua 的内容进行测试。test.lua 是一个测试包,下面是代码。
用 .editor 模式行测试,输入require(’.test’) 并进行调用,可以看到输出 “Hello my module!”
这样自定义库的引用和调用就完成了。
5.2 创建无需引用的 lua 库
上述步骤还需要手动 require,就像使用 bint、chance 等库一样。
还有一种情况,比如的 ao 包、 Handlers 包、Utils 包都不需要引用可以直接调用。我们需要在编译前将自定义包引入 process.lua 文件。process.lua 在进程启动时被自动加载,是进程的核心代码,里面加载的包也会自动引入。
以 handle.lua 包为例:
在 handle.lua 中我们自定义了一些消息:
在 proces.lua 中引入 handle 包。
进行编译和部署。
使用 aos --module 命令创建一个进程。
然后直接查看进程的 Handlers。输入 Handlers:
可以看到我们自定义的消息已经被自动加载到进程,可以直接进行调用。
5.3 使用本 docker 容器进行本地代码调试
我们在使用 ao 的时候都是在链上部署代码,很难调试,使用 docker 镜像可以在本地调试代码。
将自定义代码放到 process 目录中,在 docker 容器中即可本地运行代码,但是没有交互,需要写一些测试用例进行测试。
使用 lua <待测试代码文件> 命令进行测试,示例如下:
其中 test2.lua 就是测试用例的代码。
PS
通过上述方法可以将自定义的 lua 代码部署到 module 中,使用 module的进程就可以无需 load 使用自定义库了。更多细节请看参考 aos 源码和 docker 镜像的构建过程。
ao 也提供了 dev-cli 工具(https://hackmd.io/@ao-docs/H16LENGcA)进行 module 的编译、测试、部署,但只提供了没有 sqlite 版本的镜像和命令,如果编译部署 sqlite 版本的镜像可以参考本文。并等待后续 dev-cli 工具的更新。