madoi-client
Version:
A Client library of Madoi Server for Distributed Sharing
115 lines (87 loc) • 6.11 kB
Markdown
# madoi-client-ts-js
A TypeScript/JavaScript Client library for <a href="https://github.com/kcg-edu-future-lab/madoi">Distributed Information Sharing Platform: Madoi</a>.
<a href="https://github.com/kcg-edu-future-lab/madoi">分散情報共有基盤Madoi</a>のTypeScript/JavaScript用クライアントライブラリ。
Reactと組み合わせて使う場合は <a href="https://github.com/kcg-edu-future-lab/madoi-client-react">madoi-react</a> も参照してください。
[](https://www.npmjs.com/package/madoi-client)
[](https://github.com/kcg-edu-future-lab/madoi-client-ts-js/blob/master/LICENSE)
## Install
```bash
npm i madoi-client
```
## Getting started
### Prepare HTML
```html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf8" />
</head>
<body>
<div>
<button id="counter1" type="button">count is 0</button>
<button id="counter2" type="button">count is 0</button>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
```
### Sharing a function execution (Madoi.registerFunction)
関数の実行をウェブアプリケーション間で共有する例を以下に示します。
```ts
import { Madoi } from 'madoi-client'
window.addEventListener("load", ()=>{
const madoi = new Madoi("wss://host/madoi-server/rooms/room001", "MADOI_API_KEY");
const element1 = document.querySelector('#counter1')!;
let counter1 = 0;
const incrementCounter = madoi.registerFunction(() => {
counter1++;
element1.innerHTML = `count is ${counter1}`
});
element1.addEventListener('click', () => incrementCount()); // incrementCounter is executed at all applications joined to same room.
});
```
`Madoi`クラスの`registerFunction`メソッドに関数を渡すと、新たな関数を返します。
返された関数を実行すると、Madoiサーバに関数の登録番号と引数が送信され、自身も含め同じルームに参加しているアプリケーション全てにそれが送信され、それを受信すると、`registerFunction`に渡された関数が実行されます。このように、`registerFunction`を使うと、簡単に関数の実行を共有できます。複数のアプリケーションで同時に実行された場合でも、サーバから各アプリケーションへは同じ順番でメッセージが届くので、アプリケーション間での振る舞いを統一できます。
ここで、新しいアプリケーションが参加してきた時の状態共有を考えてみます。上記の例では、`incrementCounter`関数でcounterを+1しているため、最新時の状態に追いつくには、それまでの全ての実行を再現する必要があります。そのためMadoiは、関数の実行履歴を全て保存しており、新しくアプリケーションが参加するとその履歴を渡しています。しかし実行回数が増えてくると、このやり方は非効率です。この問題を解決する方法を次に紹介します。
### Sharing a model (Madoi.register)
まず、同期したい状態と、その状態を変更・取得・設定するメソッドを持つクラスを作成します。
```ts
class Counter{
private element: HTMLElement
private count = 0; // 同期したい状態
constructor(element: HTMLElement){
this.element = element;
}
// 状態を変更するメソッド
increment(){
this.count++;
this.element.innerHTML = `count is ${this.count}`;
}
// 状態を取得するメソッド
getCount(){
return this.count;
}
// 状態を変更するメソッド
setCount(count: number){
this.count = count;
this.element.innerHTML = `count is ${this.count}`;
}
}
```
`Counter`クラスは、状態の変更を行う`increment`、状態を取得する`getCount`、状態を設定する`setCount`メソッドを持つシンプルなクラスです。状態を取得するメソッドには``デコレータを、状態を設定するメソッドには``デコレータを、状態を変更するメソッドには、``デコレータを付けます。Madoiクライアントは、状態共有を行うために、これらのメソッドを適切に呼び出します。
次に、`Counter`クラスのインスタンスを作成し、Madoiクライアントに登録します。
```ts
import { Madoi } from 'madoi-client'
window.addEventListener("load", ()=>{
const madoi = new Madoi("wss://host/madoi-server/rooms/room001", "MADOI_API_KEY");
const element2 = document.querySelector<HTMLDivElement>('#counter2')!;
let counter2 = new Counter(element2);
madoi.register(counter2);
element2.addEventListener('click', () => counter2.increment()); // counter2.increment() is executed at all applications joining same room.
});
```
Madoiクライアントにオブジェクトを登録すると、デコレータがつけられたメソッドを介して、状態が管理されます。この例では、`increment`メソッドが実行されると、同じMadoiサーバのルームに参加している他のアプリケーションの`increment`メソッドも実行されます。また、定期的に`getCount`メソッドが呼び出され、状態が取得され、Madoiサーバに送信されます。新しくアプリケーションが参加してくると、最新の状態と、それ以降のメソッド実行履歴が送信され、アプリケーション内で状態の設定(`setCount`)とメソッドの実行が行われ、最新の状態に追いつきます。
このように、Madoiクライアントを利用すると、コラボレーションツールなどの実装に必要な状態同期を、クライアントアプリケーション側の宣言的な記述のみで(サーバ実装やクライアントのネットワーク関連処理、状態管理処理無しで)実現できます。