🐙

【Extism】名状し難いユニバーサル・プラグインシステム

2022/12/04に公開

特徴的なアイコンを持つExtismというプラグインシステムを知ったので紹介します。
https://extism.org/

Extism

タイトルにもある通り、Extismとはユニバーサルなプラグインシステムです。

Extism's goal is to make all software programmable

Extismの目標は、すべてのソフトウェアをプログラマブルにすることです。

プラグインシステムとは

プラグインシステムは、ソフトウェアに拡張性をもたらし、エンドユーザーがソフトウェアに新機能などを自由に追加することができます。

ユニバーサルとは

さらに、ExtismはWebAssemblyを活用しています。これにより、どの言語を使ったソフトウェアでもプラグインシステムを組み込めるようにしているため、ユニバーサル・プラグインシステムと名を打っています。
現在は、13の言語に公式SDKが対応しています。
ここで注意点ですが、プラグインシステムを組み込むSDKに対応しているのが13言語です。
プラグインは、PDK(Plug-in Development Kit)を使って作成し、こちらは対応しているのが5言語です。
GitHubの方では、まだ対応していない言語についてissueが上がっているのでこれから増えそうです。
https://github.com/extism/extism/issues

対応している言語(SDK)

  • C/C++
  • Elixier
  • Erlang
  • Go
  • Haskell
  • Node
  • OCaml
  • PHP
  • Python
  • Ruby
  • Rust

対応している言語(PDK)

  • Rust
  • Go
  • Haskell
  • AssemblyScript
  • C

試してみた

私が最も使い慣れている言語がPythonだったので、PythonでExtismのプラグインシステムを試してみます。
その他の言語についてはここにたくさん載っています。
https://extism.org/docs/category/integrate-into-your-codebase

プラグインは、文字列に含まれる母音の数を数えるというとても単純なものです。

下のエラーについては作者からコメント頂き、次のようにコードを書き換えることで修正できました。

plugin = context.plugin(config, wasi=True)

また、プラグインをRustで作ろうとしたのですが、次のようなエラーでうまくいかなかったので、とりあえずGitHubリポジトリにあるサンプルのwasmファイルをプラグインとして使用しました。

extism.extism.Error: unknown import: `wasi_snapshot_preview1::fd_write` has not been defined

インストール方法

自分のためにここにインストール方法を残しますが、公式ドキュメントにあるのでそちらをお読みください。
https://extism.org/docs/install

pip3 install poetry
pip3 install git+https://github.com/extism/cli
sudo extism install latest

確認

extism CLIをテストランナーとして使用して、ホストプログラムがなくてもプラグインの動作をチェックすることができます。
サンプルのwasmファイル

extism call --input "this is a test" code.wasm count_vowels

ホストのプログラム

こちらも公式ドキュメントにあるPythonのコードをそのまま利用しました。

pip3 install extism
Pythonのコード
import sys
import os
import json
import hashlib

from extism import Plugin, Context

if len(sys.argv) > 1:
    data = sys.argv[1].encode()
else:
    data = b"some data from python!"

# a Context provides a scope for plugins to be managed within. creating multiple contexts
# is expected and groups plugins based on source/tenant/lifetime etc.
with Context() as context:
    wasm = open("code.wasm", 'rb').read()
    hash = hashlib.sha256(wasm).hexdigest()
    config = {"wasm": [{"data": wasm, "hash": hash}], "memory": {"max": 5}}

    plugin = context.plugin(config)
    # Call `count_vowels`
    j = json.loads(plugin.call("count_vowels", data))
    print("Number of vowels:", j["count"])
❯ python3 app.py "Hello, Extism."
Number of vowels: 4

できた。

❯ npm start "aiueo"

> node@1.0.0 start
> node index.js "aiueo"

5

ついでに、nodeもできたが、denoは流石にできなかった。

感想

今回はサンプルプログラムしか触っていないですが、非常に有用そうなので何か簡単なアプリでも作ってみようかと思います。
Extismは、まだv0.1.0ですが非常に面白いプロジェクトだと思うのでこれからが楽しみです。(あわよくば自分もコミットしてみたい)
また、HackeNewsでWasmerの方も興味を示しており、Wasmerのブログでも軽く触れていたのでこれから展開がありそうです。
https://news.ycombinator.com/item?id=33816186

Discussion