Skip to content

meshV2 integration guide

Kouji Takao edited this page Jan 3, 2026 · 2 revisions

Mesh v2 統合ガイド

概要

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認証情報の確認

# 認証情報の確認
aws sts get-caller-identity

# 未設定の場合は設定
aws configure

抽出するファイル一覧

1. infra/mesh-v2 (インフラストラクチャ)

フォーク元リポジトリ: 元の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/

2. gui/scratch-vm (拡張機能実装)

必要なファイル:

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"
  }
}

3. gui/smalruby3-gui (UI・アセット)

必要なファイル:

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/

infra/mesh-v2のデプロイ手順

1. 環境変数の設定

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 グループの最大接続時間(分)

2. 依存関係のインストール

# Node.js依存関係
npm install

# Ruby依存関係(テスト実行に必要)
bundle install

# TypeScriptのビルド
npm run build

3. CDK Bootstrap(初回のみ)

# AWS環境でCDKを初めて使用する場合
cdk bootstrap

# Bootstrap済みか確認
aws cloudformation describe-stacks --stack-name CDKToolkit

4. デプロイ実行

ステージング環境へのデプロイ

# ステージング環境(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

5. デプロイ確認

デプロイが完了すると、以下のような出力が表示されます:

✅  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

重要: GraphQLApiEndpointGraphQLApiKey の値を控えてください。クライアント統合で使用します。

6. 統合テストの実行

# 環境変数の設定
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/

scratch-vmの統合手順

1. 拡張機能の登録

ファイル: your-scratch-vm/src/extension-support/extension-manager.js

// 拡張機能リストに追加
const builtinExtensions = {
    // ... 既存の拡張機能 ...
    meshV2: () => require('../extensions/scratch3_mesh_v2'),
};

2. GraphQLエンドポイント設定の追加

ファイル: 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-xxxxxxxxxxxxxxxxxxxxxxxxxx

3. 依存関係のインストール

cd your-scratch-vm
npm install uuid graphql aws-amplify

4. ビルドとテスト

# ビルド
npm run build

# テスト(あれば)
npm test

scratch-guiの統合手順

1. 拡張機能メタデータの登録

ファイル: 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'
    },
];

2. 多言語対応(オプション)

ファイル: 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に接続中"
}

3. ビルドと動作確認

cd your-scratch-gui

# 依存関係のインストール(必要に応じて)
npm install

# 開発サーバーの起動
npm start

# 本番ビルド
npm run build

動作確認

1. 拡張機能の読み込み

  1. Scratch/Smalrubyを開く
  2. 拡張機能ボタンをクリック
  3. "Mesh V2" を選択
  4. 拡張機能が読み込まれることを確認

2. グループの作成とデータ共有

ホスト側(グループを作成):

1. "グループを作る" ブロックを使用
2. グループ名を入力
3. グループIDが表示される

メンバー側(グループに参加):

1. "グループに参加する" ブロックを使用
2. ホスト側のグループIDを入力
3. 接続成功を確認

データの送受信:

1. ホスト/メンバーが "データを報告する" ブロックでkey-valueを送信
2. 他のノードが "データを受信したとき" イベントで受信
3. "センサーデータを取得" ブロックで値を確認

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拡張機能が表示されない

チェック項目:

  1. extension-manager.js に拡張機能が登録されているか
  2. index.jsx に拡張機能メタデータが追加されているか
  3. ビルドが正常に完了しているか
  4. ブラウザのキャッシュをクリアしたか

問題: GraphQLエンドポイント接続エラー

チェック項目:

  1. APPSYNC_ENDPOINTAPPSYNC_API_KEY が正しく設定されているか
  2. API Keyの有効期限が切れていないか
  3. CORSが正しく設定されているか(AppSyncは自動設定)

問題: Subscriptionが動作しない

チェック項目:

  1. WebSocket接続が確立されているか(開発者ツールのNetworkタブで確認)
  2. グループIDとドメインが正しいか
  3. ハートビートが正常に送信されているか(CloudWatch Logsで確認)

パフォーマンス問題

問題: データ更新が遅い

解決策:

  • ハートビート間隔を調整(環境変数 MESH_HOST_HEARTBEAT_INTERVAL_SECONDS 等)
  • レート制限の設定を確認(rate-limiter.js
  • CloudWatch Metricsでスロットリングをチェック

問題: コストが予想以上に高い

解決策:

  • 本番環境用の環境変数を使用(ハートビート間隔を長くする)
  • イベントバッチング機能を活用(fireEventsByNode Mutation)
  • 不要なグループは削除(leaveGroup Mutation)

追加リソース

ドキュメント

  • 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 を参照してください
  • infra/mesh-v2/docs/architecture.md: システムアーキテクチャ詳細
  • infra/mesh-v2/examples/javascript-client/: JavaScriptクライアント実装例

AWS関連リソース

GitHub Issue

まとめ

このガイドに従うことで、以下を実現できます:

  1. infra/mesh-v2をfork: 独自のAWS環境にデプロイ
  2. scratch-vmから抽出: Mesh V2拡張機能を自身のscratch-vmに統合
  3. scratch-guiから抽出: UIアセットと拡張機能メタデータを統合
  4. 動作確認: グループ作成・データ共有・イベント通知が正常に機能

質問や問題が発生した場合は、GitHub Issueまたはドキュメントを参照してください。


作成日: 2026-01-02 対象バージョン: Mesh v2 (GitHub Issue #444完了時点) ライセンス: MIT