-
-
Notifications
You must be signed in to change notification settings - Fork 3
meshV2 integration guide
Mesh v2は、Smalruby 3.0のMesh拡張機能をAWS AppSync (GraphQL) バックエンドで実装した新しいシステムです。従来のSkyWayベースのP2Pアーキテクチャを置き換え、スケーラブルかつ信頼性の高いリアルタイム通信を実現します。
- GitHub Issue: smalruby/smalruby3-gui#444
-
主な成果:
- SkyWayへの依存を完全に削除
- AWS AppSyncによる新しいバックエンドの実装
- 既存のMesh拡張機能と同じブロック・イベント処理を提供
- リアルタイムデータ共有・イベント通知機能
- バックエンド: AWS AppSync GraphQL API
- データベース: Amazon DynamoDB (Single Table Design)
- リアルタイム通信: AppSync Subscriptions (WebSocket)
- 認証: API Key
- インフラストラクチャ: AWS CDK (TypeScript)
┌──────────────────┐
│ Scratch/Smalruby │
│ ブラウザタブ │
└────────┬─────────┘
│ WebSocket/HTTPS
↓
┌──────────────────┐
│ AWS AppSync │ ← GraphQL API + Subscriptions
│ GraphQL API │
└────────┬─────────┘
│
┌────┴────┐
↓ ↓
┌─────────┐ ┌──────────┐
│DynamoDB │ │ Lambda │
│ Table │ │ (Ruby) │
└─────────┘ └──────────┘
| エンティティ | 説明 |
|---|---|
| Group | データ共有とイベント通知のスコープ。ホスト(作成者)が退出すると解散 |
| Node | 抽象的なクライアント(ブラウザタブ、センサー等) |
| NodeStatus | Nodeが報告した最新のデータ集合 |
| SensorData | key-valueペアの単一データ項目 |
| Event | Nodeが発火する通知ペイロード |
| MeshMessage | すべてのメッセージタイプ(NodeStatus、BatchEvent、GroupDissolve)を包括する統合型 |
- 最大クライアント数: 40ノード/グループ
- 同時稼働グループ: 10グループ
- データ更新レート: 15回/秒/グループ
- イベント発火レート: 2回/秒/グループ
- 全体書き込み負荷: 170 TPS
- Node.js: 18以上
- npm: Node.jsに含まれる
- AWS CLI: インストール済み・設定済み
-
AWS CDK CLI:
npm install -g aws-cdk - AWSアカウント: 有効な認証情報が設定済み
# 認証情報の確認
aws sts get-caller-identity
# 未設定の場合は設定
aws configureフォーク元リポジトリ: 元のsmalruby3-developプロジェクトから独立した形でfork
ディレクトリ構造:
infra/mesh-v2/
├── bin/
│ └── mesh-v2.ts # CDK app entry point
├── lib/
│ └── mesh-v2-stack.ts # CDK stack definition
├── graphql/
│ └── schema.graphql # GraphQL schema
├── js/
│ ├── resolvers/ # AppSync JavaScript resolvers
│ │ ├── Query.*.js
│ │ └── Mutation.*.js
│ └── functions/ # AppSync Pipeline functions
│ └── *.js
├── lambda/
│ └── leave_group_logic/ # Lambda functions (Ruby)
│ └── index.rb
├── spec/
│ ├── requests/ # Integration tests
│ └── unit/ # Unit tests
├── docs/
│ ├── DEPLOYMENT.md
│ ├── api-reference.md
│ └── architecture.md
├── examples/
│ └── javascript-client/ # クライアント実装例
├── package.json
├── Gemfile
├── cdk.json
├── .env.example
└── README.md
抽出方法:
# infra/mesh-v2ディレクトリ全体をコピー
cp -r smalruby3-develop/infra/mesh-v2 your-project/infra/必要なファイル:
gui/scratch-vm/src/extensions/scratch3_mesh_v2/
├── index.js # Mesh V2拡張機能のメインファイル
├── mesh-client.js # GraphQLクライアントの実装
├── mesh-service.js # サービス層(グループ管理・通信)
├── gql-operations.js # GraphQL Query/Mutation/Subscription定義
├── rate-limiter.js # レート制限機能
└── utils.js # ユーティリティ関数
抽出方法:
# scratch-vmの拡張機能ディレクトリをコピー
mkdir -p your-scratch-vm/src/extensions/scratch3_mesh_v2
cp -r smalruby3-develop/gui/scratch-vm/src/extensions/scratch3_mesh_v2/* \
your-scratch-vm/src/extensions/scratch3_mesh_v2/package.jsonへの依存関係追加:
{
"dependencies": {
"uuid": "^8.3.2",
"graphql": "^16.6.0",
"aws-amplify": "^5.3.0"
}
}必要なファイル:
gui/smalruby3-gui/src/lib/libraries/extensions/mesh_v2/
├── mesh-illustration.png # 拡張機能の説明用イラスト
├── mesh-small.png # 小アイコン
└── mesh.png # 大アイコン
その他の関連ファイル (オプション):
gui/smalruby3-gui/src/lib/ruby-to-blocks-converter/mesh.js
gui/smalruby3-gui/src/lib/ruby-generator/mesh.js
gui/smalruby3-gui/src/containers/ruby-tab/mesh-snippets.json
抽出方法:
# 拡張機能のアセットをコピー
mkdir -p your-scratch-gui/src/lib/libraries/extensions/mesh_v2
cp -r smalruby3-develop/gui/smalruby3-gui/src/lib/libraries/extensions/mesh_v2/* \
your-scratch-gui/src/lib/libraries/extensions/mesh_v2/cd your-project/infra/mesh-v2
# .env.exampleをコピー
cp .env.example .env
# .envファイルを編集(開発環境用)
cat <<EOF > .env
MESH_SECRET_KEY=dev-secret-key-for-testing
MESH_HOST_HEARTBEAT_INTERVAL_SECONDS=15
MESH_HOST_HEARTBEAT_TTL_SECONDS=60
MESH_MEMBER_HEARTBEAT_INTERVAL_SECONDS=15
MESH_MEMBER_HEARTBEAT_TTL_SECONDS=60
MESH_MAX_CONNECTION_TIME_MINUTES=10
EOF環境変数の説明:
| 変数名 | 開発環境 | 本番環境 | 説明 |
|---|---|---|---|
MESH_SECRET_KEY |
dev-secret-key-for-testing |
(GitHub Secretsで設定) | ドメイン検証用の秘密鍵 |
MESH_HOST_HEARTBEAT_INTERVAL_SECONDS |
15 |
30 |
ホストのハートビート送信間隔(秒) |
MESH_HOST_HEARTBEAT_TTL_SECONDS |
60 |
150 |
ホストグループの有効期限(秒) |
MESH_MEMBER_HEARTBEAT_INTERVAL_SECONDS |
15 |
120 |
メンバーのハートビート送信間隔(秒) |
MESH_MEMBER_HEARTBEAT_TTL_SECONDS |
60 |
600 |
メンバーノードの有効期限(秒) |
MESH_MAX_CONNECTION_TIME_MINUTES |
10 |
50 |
グループの最大接続時間(分) |
# Node.js依存関係
npm install
# Ruby依存関係(テスト実行に必要)
bundle install
# TypeScriptのビルド
npm run build# AWS環境でCDKを初めて使用する場合
cdk bootstrap
# Bootstrap済みか確認
aws cloudformation describe-stacks --stack-name CDKToolkit# ステージング環境(stg)へデプロイ
npx cdk deploy --context stage=stg
# または(cdk.jsonのデフォルト値"stg"が使用される)
npx cdk deploy# 本番環境用の環境変数を指定してデプロイ
MESH_SECRET_KEY="<本番用秘密鍵>" \
MESH_HOST_HEARTBEAT_INTERVAL_SECONDS=30 \
MESH_HOST_HEARTBEAT_TTL_SECONDS=150 \
MESH_MEMBER_HEARTBEAT_INTERVAL_SECONDS=120 \
MESH_MEMBER_HEARTBEAT_TTL_SECONDS=600 \
npx cdk deploy --context stage=prodデプロイが完了すると、以下のような出力が表示されます:
✅ MeshV2Stack-stg
Outputs:
MeshV2Stack-stg.GraphQLApiEndpoint = https://xxxxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql
MeshV2Stack-stg.GraphQLApiKey = da2-xxxxxxxxxxxxxxxxxxxxxxxxxx
MeshV2Stack-stg.TableName = MeshV2Table-stg
重要: GraphQLApiEndpoint と GraphQLApiKey の値を控えてください。クライアント統合で使用します。
# 環境変数の設定
export APPSYNC_ENDPOINT=$(aws cloudformation describe-stacks \
--stack-name MeshV2Stack-stg \
--query 'Stacks[0].Outputs[?OutputKey==`GraphQLApiEndpoint`].OutputValue' \
--output text)
export APPSYNC_API_KEY=$(aws cloudformation describe-stacks \
--stack-name MeshV2Stack-stg \
--query 'Stacks[0].Outputs[?OutputKey==`GraphQLApiKey`].OutputValue' \
--output text)
# 統合テストの実行
bundle exec rspec spec/requests/ファイル: your-scratch-vm/src/extension-support/extension-manager.js
// 拡張機能リストに追加
const builtinExtensions = {
// ... 既存の拡張機能 ...
meshV2: () => require('../extensions/scratch3_mesh_v2'),
};ファイル: your-scratch-vm/src/extensions/scratch3_mesh_v2/mesh-client.js
// mesh-client.js内で設定を読み込む
const APPSYNC_ENDPOINT = process.env.APPSYNC_ENDPOINT || 'https://your-appsync-endpoint.appsync-api.region.amazonaws.com/graphql';
const APPSYNC_API_KEY = process.env.APPSYNC_API_KEY || 'da2-xxxxxxxxxxxxxxxxxxxxxxxx';または環境変数ファイルを使用:
# .env.local
APPSYNC_ENDPOINT=https://xxxxxxxxxx.appsync-api.ap-northeast-1.amazonaws.com/graphql
APPSYNC_API_KEY=da2-xxxxxxxxxxxxxxxxxxxxxxxxxxcd your-scratch-vm
npm install uuid graphql aws-amplify# ビルド
npm run build
# テスト(あれば)
npm testファイル: your-scratch-gui/src/lib/libraries/extensions/index.jsx
import meshV2IconURL from './mesh_v2/mesh.png';
import meshV2InsetIconURL from './mesh_v2/mesh-small.png';
import meshV2IllustrationURL from './mesh_v2/mesh-illustration.png';
export default [
// ... 既存の拡張機能 ...
{
name: (
<FormattedMessage
defaultMessage="Mesh V2"
description="Name for the 'Mesh V2' extension"
id="gui.extension.meshV2.name"
/>
),
extensionId: 'meshV2',
iconURL: meshV2IconURL,
insetIconURL: meshV2InsetIconURL,
description: (
<FormattedMessage
defaultMessage="Connect multiple Scratch instances via AWS AppSync"
description="Description for the 'Mesh V2' extension"
id="gui.extension.meshV2.description"
/>
),
featured: true,
disabled: false,
bluetoothRequired: false,
internetConnectionRequired: true,
launchPeripheralConnectionFlow: true,
useAutoScan: false,
connectionIconURL: meshV2IconURL,
connectionSmallIconURL: meshV2InsetIconURL,
connectingMessage: (
<FormattedMessage
defaultMessage="Connecting to Mesh V2"
description="Message to help people connect to Mesh V2"
id="gui.extension.meshV2.connectingMessage"
/>
),
helpLink: 'https://github.com/smalruby/smalruby3-gui/issues/444'
},
];ファイル: your-scratch-gui/src/lib/libraries/extensions/ja.json(日本語の場合)
{
"gui.extension.meshV2.name": "Mesh V2",
"gui.extension.meshV2.description": "AWS AppSyncを使用して複数のScratchインスタンスを接続",
"gui.extension.meshV2.connectingMessage": "Mesh V2に接続中"
}cd your-scratch-gui
# 依存関係のインストール(必要に応じて)
npm install
# 開発サーバーの起動
npm start
# 本番ビルド
npm run build- Scratch/Smalrubyを開く
- 拡張機能ボタンをクリック
- "Mesh V2" を選択
- 拡張機能が読み込まれることを確認
ホスト側(グループを作成):
1. "グループを作る" ブロックを使用
2. グループ名を入力
3. グループIDが表示される
メンバー側(グループに参加):
1. "グループに参加する" ブロックを使用
2. ホスト側のグループIDを入力
3. 接続成功を確認
データの送受信:
1. ホスト/メンバーが "データを報告する" ブロックでkey-valueを送信
2. 他のノードが "データを受信したとき" イベントで受信
3. "センサーデータを取得" ブロックで値を確認
// コンソールでWebSocket接続を確認
// 以下のようなログが表示されるはず:
// Mesh V2: Initialized with domain xxx.xxx.xxx.xxx and nodeId xxxxxxxx
// Mesh V2: Connected to group xxxxxxxx@xxx.xxx.xxx.xxx問題: Need to perform AWS calls for account XXX, but no credentials found
解決策:
aws configure問題: This stack uses assets, so the toolkit stack must be deployed to the environment
解決策:
cdk bootstrap問題: リソース名の競合 (MeshV2Table already exists)
解決策:
# 既存のスタックを削除
npx cdk destroy --context stage=stg問題: Mesh V2拡張機能が表示されない
チェック項目:
-
extension-manager.jsに拡張機能が登録されているか -
index.jsxに拡張機能メタデータが追加されているか - ビルドが正常に完了しているか
- ブラウザのキャッシュをクリアしたか
問題: GraphQLエンドポイント接続エラー
チェック項目:
-
APPSYNC_ENDPOINTとAPPSYNC_API_KEYが正しく設定されているか - API Keyの有効期限が切れていないか
- CORSが正しく設定されているか(AppSyncは自動設定)
問題: Subscriptionが動作しない
チェック項目:
- WebSocket接続が確立されているか(開発者ツールのNetworkタブで確認)
- グループIDとドメインが正しいか
- ハートビートが正常に送信されているか(CloudWatch Logsで確認)
問題: データ更新が遅い
解決策:
- ハートビート間隔を調整(環境変数
MESH_HOST_HEARTBEAT_INTERVAL_SECONDS等) - レート制限の設定を確認(
rate-limiter.js) - CloudWatch Metricsでスロットリングをチェック
問題: コストが予想以上に高い
解決策:
- 本番環境用の環境変数を使用(ハートビート間隔を長くする)
- イベントバッチング機能を活用(
fireEventsByNodeMutation) - 不要なグループは削除(
leaveGroupMutation)
- infra/mesh-v2/README.md: プロジェクト概要
- infra/mesh-v2/docs/DEPLOYMENT.md: 詳細なデプロイ手順
-
infra/mesh-v2/docs/api-reference.md: GraphQL API完全リファレンス
-
注: Issue #500 の修正により、Subscription が
onMessageInGroupに統合されました。詳細は api-reference.md を参照してください
-
注: Issue #500 の修正により、Subscription が
- infra/mesh-v2/docs/architecture.md: システムアーキテクチャ詳細
- infra/mesh-v2/examples/javascript-client/: JavaScriptクライアント実装例
- EPIC Issue: smalruby/smalruby3-gui#444
このガイドに従うことで、以下を実現できます:
- infra/mesh-v2をfork: 独自のAWS環境にデプロイ
- scratch-vmから抽出: Mesh V2拡張機能を自身のscratch-vmに統合
- scratch-guiから抽出: UIアセットと拡張機能メタデータを統合
- 動作確認: グループ作成・データ共有・イベント通知が正常に機能
質問や問題が発生した場合は、GitHub Issueまたはドキュメントを参照してください。
作成日: 2026-01-02 対象バージョン: Mesh v2 (GitHub Issue #444完了時点) ライセンス: MIT