Complete: Enhanced plugin migration guide v2 with comprehensive implementation details

Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-08-18 12:40:26 +00:00
parent 5d1a140919
commit 901890521c
4 changed files with 392 additions and 60 deletions

View File

@ -1,53 +1,76 @@
# 📦 Nyash ビルトインBox → プラグイン化移行依頼
# 📦 Nyash ビルトインBox → プラグイン化移行ガイド v2
## 🎯 概要
NyashのビルトインBoxをプラグイン化し、コアを軽量化したい
FileBoxプラグインの成功例を参考に、以下のBoxを順次プラグイン化してください
NyashのビルトインBoxをプラグイン化し、コアを軽量化します
FileBoxプラグインの成功例を詳しく解説しながら、移行方法を説明します
## 📋 移行対象Box一覧
## 🔑 重要な概念nyash.tomlの型定義システム
### 🌐 Phase 1: ネットワーク・通信系(最優先)
```
plugins/nyash-http-plugin/
├── HttpClientBox - HTTP通信クライアントGET/POST/PUT/DELETE
├── HTTPServerBox - HTTPサーバー機能
├── HTTPRequestBox - HTTPリクエスト表現
└── HTTPResponseBox - HTTPレスポンス表現
### 型変換の仕組み
nyash.tomlでは、Nyash側とプラグイン側の型変換を明示的に定義します
plugins/nyash-socket-plugin/
└── SocketBox - TCP/UDPソケット通信
```toml
# FileBoxの例
[plugins.FileBox.methods]
# writeメソッドNyashのstringをプラグインではbytesとして扱う
write = { args = [{ from = "string", to = "bytes" }] }
# openメソッド2つのstring引数型変換なし
open = { args = [
{ name = "path", from = "string", to = "string" },
{ name = "mode", from = "string", to = "string" }
] }
```
### 🖼️ Phase 2: GUI・グラフィック系
```
plugins/nyash-egui-plugin/
└── EguiBox - デスクトップGUI既にfeature分離済み
### from/toの意味
- **from**: Nyash側の型ユーザーが渡す型
- **to**: プラグイン側で受け取る型TLVエンコーディング
plugins/nyash-canvas-plugin/
├── CanvasEventBox - Canvas描画イベント
└── CanvasLoopBox - Canvas描画ループ
### TLVタグとの対応
プラグインはTLVType-Length-Value形式でデータを受け取ります
- `to = "i32"` → TLV tag=232ビット整数
- `to = "string"` → TLV tag=6UTF-8文字列
- `to = "bytes"` → TLV tag=7バイト配列
plugins/nyash-web-plugin/WASM専用
├── WebDisplayBox - HTML表示
├── WebConsoleBox - ブラウザコンソール
└── WebCanvasBox - Canvas描画
## 📋 移行対象Box一覧優先順位順
### 🌐 Phase 1: ネットワーク系(最優先・最も簡単)
既にスタブ実装があり、reqwest依存を追加するだけで完成します。
#### HttpClientBox
```toml
[plugins.HttpClientBox.methods]
# シンプルなGETリクエスト
get = {
args = [{ from = "string", to = "string" }], # URL
returns = "string" # レスポンスボディ
}
# POSTリクエストボディ付き
post = {
args = [
{ from = "string", to = "string" }, # URL
{ from = "string", to = "bytes" } # ボディ(バイナリ対応)
],
returns = "string"
}
# 詳細なリクエスト(ヘッダー等を含む)
request = {
args = [
{ from = "string", to = "string" }, # メソッドGET/POST等
{ from = "string", to = "string" }, # URL
{ from = "map", to = "map" } # オプションheaders, timeout等
],
returns = "map" # { status: i32, body: string, headers: map }
}
```
### 🎵 Phase 3: 特殊用途系
```
plugins/nyash-audio-plugin/
├── AudioBox - 音声再生・合成
└── SoundBox - 効果音再生
### 🖼️ Phase 2: GUI系プラットフォーム依存
EguiBoxは既にfeature分離されているので参考になります。
plugins/nyash-qr-plugin/
└── QRBox - QRコード生成
plugins/nyash-stream-plugin/
└── StreamBox - ストリーム処理
plugins/nyash-timer-plugin/
└── TimerBox - タイマー機能
```
### 🎵 Phase 3: 特殊用途系(独立性高い)
TimerBox、QRBox等は単機能で実装しやすいです。
## 🔧 実装ガイドライン
@ -169,30 +192,178 @@ encode_string_result(&contents, result, result_len)
- **プラグインシステム説明**: `docs/説明書/reference/plugin-system/plugin-system.md`
- **BID-FFI型変換** (参考): `src/bid-converter-copilot/tlv.rs`
## 📅 推奨実装順序とロードマップ
## 🔧 実装ガイドFileBoxを例に
### Week 1: HttpBox系最も簡単
- 既にスタブ実装済み
- reqwest依存を追加するだけ
- FileBoxと同じパターンで実装可能
### 1. プラグイン側での型受け取り例
### Week 2: 特殊用途系(独立性高い)
- QRBox: 単機能で簡単
- TimerBox: 非同期処理の練習に最適
- StreamBox: 中程度の複雑さ
```rust
// nyash.toml: write = { args = [{ from = "string", to = "bytes" }] }
METHOD_WRITE => {
// TLVでbytesとして受け取る
let data = tlv_parse_bytes(args)?; // Vec<u8>として取得
// ファイルに書き込み
match file.write(&data) {
Ok(n) => {
file.flush()?; // 重要:フラッシュを忘れずに!
// 書き込んだバイト数を返すTLV i32
write_tlv_i32(n as i32, result, result_len)
}
Err(_) => NYB_E_PLUGIN_ERROR
}
}
```
### Week 3: GUI/グラフィック系(プラットフォーム依存)
- EguiBox: feature分離済みなので参考になる
- Canvas系: Web/Desktop両対応必要
- Audio系: 最も複雑(最後に実装)
### 2. 複数引数の解析例
## 🎯 期待される効果
1. **ビルド時間**: 3分 → 30秒以下
2. **バイナリサイズ**: 最小構成で500KB以下
3. **保守性**: 各プラグイン独立開発可能
4. **拡張性**: ユーザーが独自プラグイン作成可能
```rust
// nyash.toml: open = { args = [{ from = "string", to = "string" }, { from = "string", to = "string" }] }
METHOD_OPEN => {
// 2つのstring引数を解析
let (path, mode) = tlv_parse_two_strings(args)?;
// ファイルを開く
let file = match mode.as_str() {
"r" => File::open(&path)?,
"w" => File::create(&path)?,
"a" => OpenOptions::new().append(true).open(&path)?,
_ => return NYB_E_INVALID_ARGS
};
// 成功時はVoidを返す
write_tlv_void(result, result_len)
}
```
## 📝 質問・相談先
- プラグイン化で不明な点があれば、FileBoxプラグインの実装を参考に
- FFI実装で困ったら、plugin-testerのソースコードも参考になります
- nyash.tomlの型定義で迷ったら、既存のFileBox定義を真似してください
### 3. 引数なしメソッドの例
```rust
// nyash.toml: read = { args = [] }
METHOD_READ => {
// 引数なし - ファイル全体を読む
file.seek(SeekFrom::Start(0))?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
// bytesとして返す
write_tlv_bytes(&buf, result, result_len)
}
```
## 📝 HttpClientBox実装の具体例
```rust
// HttpClientBoxプラグインの実装イメージ
use reqwest::blocking::Client;
METHOD_GET => {
// URLを解析
let url = tlv_parse_string(args)?;
// HTTPリクエスト実行
let client = Client::new();
let response = client.get(&url).send()?;
let body = response.text()?;
// 文字列として返す
write_tlv_string(&body, result, result_len)
}
METHOD_POST => {
// URL と ボディを解析
let (url, body_bytes) = tlv_parse_string_and_bytes(args)?;
// POSTリクエスト
let client = Client::new();
let response = client.post(&url)
.body(body_bytes)
.send()?;
let body = response.text()?;
write_tlv_string(&body, result, result_len)
}
```
## 💡 実装のコツとよくある間違い
### ✅ 正しいnyash.toml
```toml
# 引数の型変換を明示
write = { args = [{ from = "string", to = "bytes" }] }
# 戻り値の型も指定可能
exists = { args = [], returns = "bool" }
```
### ❌ よくある間違い
```toml
# 間違い:型情報がない
write = { args = ["string"] } # ❌ from/toが必要
# 間違い:不要なフィールド
get = { args = [{ type = "string" }] } # ❌ typeではなくfrom/to
```
### メモリ管理の注意点
1. 文字列は必ずCString/CStr経由で変換
2. プラグイン側でallocしたメモリはプラグイン側でfree
3. ホスト側のVtableを使ってログ出力
### エラーハンドリング
```rust
// パニックをFFI境界で止める
let result = std::panic::catch_unwind(|| {
// 実際の処理
});
match result {
Ok(val) => val,
Err(_) => NYB_E_PLUGIN_ERROR
}
```
## 🧪 テスト方法
### 1. プラグインビルド
```bash
cd plugins/nyash-http-plugin
cargo build --release
```
### 2. plugin-testerで診断
```bash
cd ../../tools/plugin-tester
./target/release/plugin-tester ../../plugins/nyash-http-plugin/target/release/libnyash_http_plugin.so
# 期待される出力:
# Plugin Information:
# Box Type: HttpClientBox (ID: 20)
# Methods: 5
# - birth [ID: 0] (constructor)
# - get, post, put, delete
# - fini [ID: 4294967295] (destructor)
```
### 3. Nyashで実行
```nyash
// test_http.nyash
local http = new HttpClientBox()
local response = http.get("https://api.example.com/data")
print(response)
```
## 📚 参考資料
- **FileBoxプラグイン完全実装**: `plugins/nyash-filebox-plugin/src/lib.rs`
- **TLVエンコーディング仕様**: `docs/説明書/reference/plugin-system/ffi-abi-specification.md`
- **nyash.toml設定例**: プロジェクトルートの`nyash.toml`
## 🎯 成功の秘訣
1. **FileBoxを完全に理解してから始める** - コピペベースで改造
2. **nyash.tomlの型定義を正確に** - from/toを明示
3. **TLVの理解** - tag=6(string), tag=7(bytes)の違い
4. **plugin-testerで早期検証** - 問題を早期発見
---
質問があれば、FileBoxの実装を参考にしてください。
すべての答えがそこにあります!