サーバAPI仕様  Rev1.0

ライブラリプロトタイプ

typedef struct _SSTConn SSTConn;

sentinelサーバとの接続を維持する構造体。


typedef struct _SSTStream SSTStream;

sentinelサーバからのデータを受信するストリーム構造体。



SST_PORT_API int SST_Connect(SSTConn **conn, char *addr, int port, char *app, char *user, char *pass);
sentinelサーバとの接続を行う。
conn:接続子を受け取るポインタへのポインタ。
addr:sentinelサーバのホスト名
port:sentinelサーバのポート番号
app:接続するアプリケーション領域名
user:ユーザ名
pass:パスワード
正常にセッションが開始されると、戻り値にSST_E_OKが返され、connに接続子が戻されます。
戻り値にSST_E_OK以外が戻された場合、セッションは開始されずconnにはNULLが戻されます。
アプリケーション名、ユーザ名、パスワードはあらかじめsentinelサーバに登録されている必要があります。



SST_PORT_API int SST_Send(SSTConn *conn, char *cmd, int len, SSTStream **ans);

sentinelサーバへコマンドを送る。
conn:接続子
cmd:コマンド文字列をutf-8で指定。詳細はコマンドの章を参照のこと。
len:コマンド文字列のバイト数を指定。文字列終端の\0は含まない。
ans:応答を受け取るストリームポインタへのポインタ。応答が不要の場合NULLを指定できます。
正常にコマンドが送信された場合、戻り値にSST_E_OKが戻されます。即時応答がある場合にはansに読み込み用ストリームのポインタが戻されます。即時応答がない場合、ansにはNULLが戻されます。
戻り値にSST_E_OK以外が戻された場合、コマンド送信は失敗し処理は行われず、ansにはNULLが戻されます。



SST_PORT_API int SST_ReadStream(SSTStream *st, char *buffer, unsigned int size, unsigned int *readed);
入力ストリームからデータを受信します。
st:入力ストリームポインタを指定します。
buffer:データを格納するバッファを指定します。
size:bufferで指定したバッファの容量をバイト数で指定します。
readed:実際に読み込まれたバイト数が返されます。
正常に読み込みが完了した場合、戻り値にSST_E_OKが戻され、bufferに読み込まれたデータ、readedにそのバイト数が戻されます。
戻り値にSST_E_OKが戻され、readedに0が戻された場合、ストリームの終端を意味します。
戻り値にSST_E_OK以外が戻された場合、入力でエラーが発生したことを示し、bufferにエラー発生までに読み込まれたデータ、ansにはエラー発生までに読み込まれたデータのバイト数が戻されます。



SST_PORT_API int SST_CloseStream(SSTStream *st);

入力ストリームを閉じ、SSTStreamを開放します。
正常終了した場合、戻り値にSST_E_OKが戻されます。



SST_PORT_API int SST_Disconnect(SSTConn *conn);

セッションを終了し、SSTConnを開放します。
正常終了した場合、戻り値にSST_E_OKが戻されます。

---------------------------------------------------------------------
概要

sentinelサーバとの通信は以下のシーケンスにより行います。


SSTConn *conn;
SSTStream *st;
char cmd[xxx];
/* セッション開始 */
if( SST_Connect(&conn, "server", 1119, "SharePDF", "user-a", "pass-a") != SST_E_OK ) {
	(error)
}

/* コマンドの用意 */
strcpy(cmd,"hello");

/* コマンドの送信 */
if( SST_Send(conn, cmd, strlen(cmd), &st) != SST_E_OK ) {
	(error)
}

/* 応答の受信 */
if( st != NULL ) {
	char buff[256];
	unsigned int len;
	if( SST_ReadStream(st, buff, sizeof(buff), &len) != SST_E_OK ) {
		(error)
	}
	printf("ret = %s", buff);
	SST_CloseStream(st);
}

/* セッション終了 */
SST_Disconnect(conn);

1回のセッション接続で複数のコマンドの送信が可能です。
また、すべてのAPIはスレッドセーフですのでマルチスレッドアプリケーションからも同一のセッションを使用して通信が可能です。
ただし、先行するスレッドの通信処理が完了するまでの間、後続のスレッドの処理はブロックされることがあります。

---------------------------------------------------------------------
コマンド

一般規則
コマンドはテキストベースでjson形式のメッセージ交換で処理されます。文字コードはutf-8のみに対応しています。また、文字コードの16進数表記(\x07feなど)には対応しません。

リクエストメッセージの一般書式は以下の通りです。

パラメータを伴わないコマンド
"コマンド名"

パラメータを伴うコマンド
{
	"コマンド名":{
		"パラメータ名1":"パラメータ値1", ... option
		"パラメータ名2":"パラメータ値2",
			:
		"パラメータ名n":"パラメータ値n"
	}
}

レスポンスメッセージの一般書式は以下の通りです。

正常終了
{
	"result":0,
	"取得データ名1":"取得データ1",
	"取得データ名2":"取得データ2",
		:
	"取得データ名n":"取得データn"
}

エラー終了
{
	"result":10
}

resultは終了コードを示し、0で正常、それ以外はエラーを示します。
取得データはコマンドの返値です。複数の項目や階層構造を持つデータが返される事あり、それぞれの項目の値はjson規則に従った型（null値、文字列、数値、ブール値、オブジェクト値、配列）です。
SST_Send関数はresultを戻り値として戻し、result、取得データを含む応答メッセージ全体をSSTStreamにより戻します。ただし、応答メッセージがresultのみの場合、SSTStreamにはNULLを戻します。
optionの記載があるパラメータは、省略可能です。

=====================================================================
ユーザ管理関係
---------------------------------------------------------------------
regaccount コマンド
新しくユーザアカウントを登録します。

{
	"regaccount":{
		"uid":"tanaka@core-corp.co.jp",
		"name1":"user name1", ... option
		"name2":"user name2", ... option
		"locale":"ja", ... option
		"lang":"jp", ... option
		"device":"device id", ... option
		"authType":"password|none|extern",
		"authData":"password"
	}
}

uid:ユーザID。sentinelサーバ内でユニークなIDを指定してください。
name1,2:ユーザ名。
lang:ユーザの利用する言語。
locale:ユーザの利用する地域。
device:ユーザのデバイス。固定する場合のみ
authType:認証の種類
authData:認証に使用するデータ。authType=none:無効,authType=password:パスワード,authType=extern:URL

レスポンス
{
	"result":0,
	"aid":"A00000001",
}

正常終了の場合にはaidでアカウントIDが返されます。

---------------------------------------------------------------------
setaccountコマンド
ユーザ情報を更新します。

{
	"setaccount":{
		"aid":"A00000001"
		または
		"aid":"self"
		または
		"uid":"tanaka@core-corp.co.jp"

		"set":{
			"uid":"tanaka@core-corp.co.jp", ... option
			"name1":"name1", ... option
			"name2":"name2", ... option
			"locale":"ja", ... option
			"lang":"jp", ... option
			"device":"device id", ... option
			"authType":type, ... option
			"authData":"password" ... option
		}
	}
}

aidまたはuidで指定したユーザの登録情報を更新します。更新しない項目はメッセージ中に含める必要はありません。

レスポンス
リザルトコードが返されます。
{
	"result":0
}

---------------------------------------------------------------------
rmaccountコマンド

既存のユーザを抹消します
{
	"rmaccount":{
		"aid":"A00008372"
		または
		"uid":"tanaka@core-corp.co.jp"
	}
}

aidまたはuidで指定したユーザを抹消する処理を開始します。
即座に抹消されるわけではない点に注意してください。


レスポンス
リザルトコードが返されます。
{
	"status":0,
}
---------------------------------------------------------------------
lsaccountコマンド
指定したアカウントのリスト。

{
	"lsaccount":{
		"from":0,  ... option
		"count":30   ... option
	}
}

レスポンス
{
	"result": 0,
	"from":0,
	"accounts": [
		"S0000001",
		"S0000021",
		"S0000234"
		:
	]
}

from:リストの先頭位置を示します。
accounts:アカウントIDを配列で返します。
※ システム管理者権限が必要
---------------------------------------------------------------------
showaccountコマンド
指定したアカウントのユーザ情報を返します。

{
	"showaccount":{
		"aid":"00000001"
		または
		"aid":"self"
		または
		"uid":"tanaka@core-corp.co.jp"
	}
}

aidで指定したアカウントID、またはuidで指定したユーザIDのユーザ情報を返します。
uidに"self"を指定した場合、及びaid,uidを指定しない場合は接続ユーザの情報を返します。

レスポンス
{
	"result":0,
	"aid":"00000001",
	"uid":"tanaka@core-corp.co.jp",
	"authType":n,
	"authData":"pass",
	"name1":"田中 康興",
	"name2":"Yasuoki Tanaka",
	"createTime":"2012/07/12-03:36:55"
	"updateTime":"2012/07/12-03:36:55"
	"lastTime":"2012/07/12-03:36:55"
	"devices":3,
	"resources":500
}

aid:アカウントID
uid:ユーザID
authType:認証の種類 "password|none|extern"
authData:認証に使用するデータ。
name1,2:ユーザ名
createTime:登録日時
updateTime:更新日時
lastTime:最終接続日時
devices:所有端末数
resources:同期対象リソース数

※ ログインセッションのアカウント以外はシステム管理者権限が必要

=====================================================================
アプリケーション管理関係
---------------------------------------------------------------------
lsserviceコマンド
利用可能なアプリケーションをリストします

{
	"lsservice":{
		"from":0,
		"count":30
	}
}

fromでリストする最初の位置を指定します。countでリストする最大件数を指定します。
fromを省略すると先頭から、countを省略するとすべてとなります。

レスポンス
{
	"result": 0,
	"from":0,
	"services": [
		"S0000001",
		"S0000021",
		"S0000234"
		:
	]
}

from:リストの先頭位置を示します。
services:アプリケーションIDを配列で返します。

※ システム管理者権限が必要

---------------------------------------------------------------------
showserviceコマンド
指定したアプリケーションの詳細を返します

{
	"showservice":{
		"sid":"アプリケーションID"
		または
		"sname":"アプリケーション名"
		または、省略し接続先アプリケーションを選択。
	}
}


レスポンス
{
	"result": 0,
	"sid":"S0000001",
	"sname":"アプリケーション名",
	"title":"アプリケーション掲題",
	"description":"説明",
	"owner":"owner account",
	"status":"service status"
	"authType":"password|none|extern"
	"authData":"https://app-server/user_validate"
}

owner:このアプリケーションの管理ユーザを示す。
status:アプリケーションのステータス。
authType: passwordの場合、ユーザ情報に設定されるパスワードで認証
	  noneの場合、パスワード不要
	  externの場合、externで指定したURLで認証
authData: ユーザ認証を外部サーバで行う場合にURLを指定します。この場合、ユーザ認証が必要になるとsentinelサーバは指定のURLに接続を試み、接続が成功すると認証されたものとみなします。ユーザ情報はHTTPにおけるダイジェスト認証またはベーシック認証により確認するようにしてください。

※ ログインセッションで接続中のアプリケーション以外はシステム管理者権限が必要

=====================================================================
ユーザグループ管理関係
---------------------------------------------------------------------
addgroupコマンド
ユーザグループを作成します

{
	"addgroup":{
		"sid":"アプリケーションID"
		または
		"sname":"アプリケーション名"
		または、省略し接続先アプリケーションを選択。

		"gname":"グループ名",
	}
}

group.gname:グループ名を指定します。アプリケーション内でユニークな名前を指定してください。


レスポンス
{
	"result": 0,
	"gid":"G0000001"
}

gid:グループIDを返します。

※ システム管理者権限が必要

---------------------------------------------------------------------
setgroupコマンド
ユーザグループを変更します

{
	"setgroup":{
		"gid":"G0000001",
		または
		"gname":"グループ名"
		"set":{
			"gname":"新しいグループ名"
		}
	}
}

gidまたはgnameで変更するグループを指定します。


レスポンス
{
	"result": 0,
}

※ アプリケーション管理者権限または、システム管理者権限が必要

---------------------------------------------------------------------
rmgroupコマンド
ユーザグループを削除します

{
	"rmgroup":{
		"gid":"G0000001"
	}
	または以下の指定
	"rmgroup":{
		"gname":"グループ名"
	}
}

gidでグループを指定するか、sidまたはsnameでアプリケーションを指定しgnameでグループを指定します。


レスポンス
{
	"result": 0,
}

※ アプリケーション管理者権限または、システム管理者権限が必要

---------------------------------------------------------------------
lsgroupコマンド
ユーザグループ一覧を返します

{
	"lsgroup":{
		"from":0,  ... option
		"count":30   ... option
	}
}

count:指定した場合、リストの件数を指定件数に制限します。指定しない場合は全件数をリストします。

レスポンス
{
	"result": 0,
	"from":0,
	"groups": [
		"G0000001",
		"G0000021",
		"G0000234"
		:
	]
}

groups:グループIDを配列で返します。

※ アプリケーションに接続または、システム管理者権限が必要

---------------------------------------------------------------------
showgroupコマンド
ユーザグループの詳細を返します

{
	"showgroup":{
		"gid":"G0000001"
	}
	または以下の指定
	"group":{
		"gname":"グループ名"
	}
}

gidまたはgnameでグループを指定します。

レスポンス
{
	"result": 0,
	"gid":"G0000001",
	"gname":"グループ名"
}

gid:グループIDを返します。
gname:グループ名を返します。

※ アプリケーションに接続または、システム管理者権限が必要

---------------------------------------------------------------------
addgroupuserコマンド
ユーザグループにユーザを追加します

{
	"addgroupuser":{
		"gid":"G0000001",
		または
		"sid":"アプリケーションID",
		"sname":"アプリケーション名",
		"name":"グループ名"

		"users":{
			"0000001",
			"0000021",
			"0000234"
		}
		または
		"user"="0000001"
	}
}

gidまたはnameでグループを指定します。
users:複数のユーザを一度に指定する場合、配列形式でアカウントIDを指定します。
user:１つのユーザを追加する場合に指定します。

レスポンス
{
	"result": 0,
}

※ アプリケーション管理者権限または、システム管理者権限が必要

---------------------------------------------------------------------
rmgroupuserコマンド
ユーザグループからユーザを削除します

{
	"rmgroupuser":{
		"gid":"G0000001",
		または
		"gname":"グループ名"

		"users":{
			"0000001",
			"0000021",
			"0000234"
		}
		または
		"user"="0000001"
		または
		"user"="*"
	}
}

gidまたはgnameでグループを指定します。
users:複数のユーザを一度に指定する場合、配列形式でアカウントIDを指定します。
user:１つのユーザを削除する場合に指定します。*を指定すると全ユーザを削除します。

レスポンス
{
	"result": 0,
}

※ アプリケーション管理者権限または、システム管理者権限が必要

---------------------------------------------------------------------
lsgroupuserコマンド
ユーザグループに参加するユーザのリストを返します

{
	"lsgroupuser":{
		"gid":"G0000001"
		または
		"gname":"グループ名"
		"from":0,  ... option
		"count":30   ... option
	}
}

gidまたはgnameでグループを指定します。
from:指定した場合、その位置からリストします。指定しない場合は先頭からリストします。
count:指定した場合、リストの件数を指定件数に制限します。指定しない場合は全件数をリストします。

レスポンス
{
	"result": 0,
	"gid":"G0000001"
	"from":0,
	"users": [
		"0000001",
		"0000021",
		"0000234"
		:
	]
}

from:リストの先頭位置をグループの属するアプリケーションのIDを返します。
users:ユーザのアカウントIDを配列で返します。

※ アプリケーションへ接続または、システム管理者権限が必要

=====================================================================
リソース管理関係
---------------------------------------------------------------------
lsresourceコマンド
リソースの一覧を取得します

{
	"lsresource":{
		"gid":"グループID" ... option
	}
}

gidを指定した場合、そのグループに公開されているリソースをリストします。

レスポンス
{
	"result":0,
	"gid":"G00000001",
	"resources": [
		{
			"rid":"R0000001",
			"rname":"リソース名",
			"rev":"00999382",
			"date":"2012/12/05 20:58:59",
			"size":9382781
		},
		{
			"rid":"R0000231",
			"rname":"リソース名",
			"rev":"03837337",
			"date":"2012/12/05 22:58:39",
			"size":93827
		},
		:
	]
}

rid:リソースID
rev:リビジョン

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
showresourceコマンド
指定リソースの情報を取得します
{
	"showresource":{
		"rid":"R0000001",
	}
}
ridで指定したリソース情報を返します。

レスポンス
{
	"result":0,
	"rid":"R0000001",
	"rname":"リソース名",
	"rev":"038373837",
	"date":"2012/12/05 20:58:59",
	"size":9382781,
	"ref":"https://server/target/bodyget?rid=R0000001",
	"tag":"tag1,tag2,tag3",
	"gadget":[
		{
			"rid":"gadgetId",
			"rname":"gadget名",
			"rev":"038373837",
			"date":"2012/12/05 20:58:59",
			"size":9382781,
			"tag":"tag1,tag2,tag3"
		},
		{
			"rid":"gadgetId",
			"rname":"gadget名",
			"rev":"038373837",
			"date":"2012/12/05 20:58:59",
			"size":9382781,
		},
	]
}

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
rmresourceコマンド
リソースを削除します

{
	"rmresource":{
		"rid":"S0000001",
		または
		"rname":"リソース名",
	}
}

ridまたはsnameとrnameで削除するリソースを指定します。

レスポンス
{
	"result":0,
}

※ アプリケーション管理者権限または、システム管理者権限が必要

=====================================================================
リソース共有設定関係
---------------------------------------------------------------------
shareコマンド
ユーザグループにリソースを共有します。

{
	"share":{
		"rid":"S0000001",
		または
		"rname":"リソース名"

		"mode":"index|full", ... option
		"groups":[	... option
			"G000001",
			"G000231",
			"G000441",
			"G000743",
		]
	}
}

ridまたはrnameで共有するリソースを指定します。
modeにindexを指定するとインデックス情報のみ共有され、実態はクライアントの要求によって転送します。
fullでは実態を直接転送します。省略時はfullです。
groupsに共有するグループを指定します。groupsを指定しない場合、既存のすべてのグループに共有します。

レスポンス
{
	"result":0,
}

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
unshareコマンド
ユーザグループからリソース共有を取り消します

{
	"unshare":{
		"rid":"S0000001",
		または
		"rname":"リソース名"
		"groups":[	... option
			"G000001",
			"G000231",
			"G000441",
			"G000743",
		]
	}
}

ridまたはrnameで共有解除するリソースを指定します。
groupsに共有解除するグループを指定します。groupsを指定しない場合、すべてのグループから解除します。

レスポンス
{
	"result":0,
}

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
showshareコマンド
リソースが共有されているユーザグループをリストします

{
	"showshare":{
		"rid":"S0000001",
		または
		"rname":"リソース名"
	}
}

ridまたはrnameで共有解除するリソースを指定します。
groupsに共有解除するグループを指定します。groupsを指定しない場合、すべてのグループから解除します。

レスポンス
{
	"result":0,
	"groups":[
		"G000001",
		"G000231",
		"G000441",
		"G000743",
	]
}

※ アプリケーションへ接続または、システム管理者権限が必要

=====================================================================
同期管理関係
---------------------------------------------------------------------
updateコマンド
リソースの更新を通知します

{
	"update":[
		追加、更新
		{
		"rname":"リソース名",
		"ref":"https://server/target/bodyget?data=R0000001"
		},
		{
		"rname":"リソース名",
		"ref":"https://server/target/bodyget?data=R0000001"
		}

		削除
		{
		"rname":"リソース名",
		"ref":"remove"
		}
	]
}

rnameでリソースを指定します。
refで変更内容を交換するURLを指定します。refにremoveとするとrmresourceと同様にリソースは削除されます

レスポンス
{
	"result":0,
}

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
syncstatコマンド
共有リソースの同期情報の状態を取得します

{
	"syncstat":{
		"rid":"R0000001"
		または
		"rname":"リソース名"
	}
}

ridまたはrnameで同期情報を取得するリソースを指定します。

レスポンス
{
	"result":0,
	"sid":"S0000001",
	"rid":"R0000001",
	"rev":"038373837",
	"date":"2012/12/05 20:58:59",
	"size":9382781,
	"devices":[
		{
			"aid":"939382938",
			"dev":"jshue283738",
			"model":"Google Nexus 7",
			"rev":"038373837",
			"date":"2012/12/05 20:58:59",
			"size":9382781
		},
		{
			"aid":"643623423",
			"dev":"348x9383",
			"model":"Samsun GalaxyTab10",
			"rev":"038373837",
			"date":"2012/12/05 20:58:59",
			"size":9382781
		},
		:
	}
}


sid:アプリケーションID
rid:リソースID
rev:サーバ内のリビジョン
date:サーバ内の更新日時
size:サーバ内のサイズ

device.aid:ユーザアカウントID
device.dev:デバイスID
device.model:デバイスモデル名
device.rev:デバイス内のリビジョン
device.date:デバイス内の更新日時
device.size:デバイス内のサイズ

※ アプリケーションへ接続または、システム管理者権限が必要

---------------------------------------------------------------------
syncコマンド
共有リソースの同期を実行します。

※ アプリケーションへ接続または、システム管理者権限が必要

=====================================================================
update処理概要
---------------------------------------------------------------------

処理シーケンス

１ アプリケーションサーバ(以下AP)からupdateコマンドを実行します。

AP → updateコマンド → S3
AP ← result ← S3

	"update":[
		追加、更新
		{
		"rname":"res-a",
		"ref":"https://server/sync?data=XXX"
		}
	}

２ S3はupdateコマンドをパースし、リソース情報をAPに要求します

AP ← http://server/sync?data=XXX&sync=info&rname=res-a ← S3

この時のURLはupdateコマンドのrefに指定したURLにパラメータsync=infoとrname=リソース名を付与したものです。


３ APは要求に従いリソース情報を返します。

AP → リソース情報 → S3

リソース情報は以下の形式です。

{
    "resource": {
        "date": "2012/12/05 20:58:59",
        "tag": "tag1,tag2,tag3",
        "gadget": [
            {
                "gname": "gadget1",
                "date": "2012/12/05 20:58:59",
                "tag": "tag1,tag2,tag3"
            },
            {
                "gname": "gadget2",
                "date": "2012/12/05 20:58:59",
                "tag": "tag1,tag2,tag3"
            }
        ],
        "share": {
            "groups": [
                "共有グループ名1",
                "共有グループ名2",
                {
                    "gname": "共有グループ名3",
                    "permission": {
                        "access": "write,gadget,tag",
                        "geo-location": ""
                    }
                }
            ],
            "permission": {
                "access": "write,gadget,tag",
                "expire": "2012/12/05 19:00:00",
                "geo-location": [
                    {"dis": 200, "lat": 35.684629,"lon": 139.627888},
                    {"dis": 200, "lat": 35.455677,"lon": 140.467893},
                ],
                "gps-grace": 3000,
                "offline-grace": 3000,
                "time": {
                    "from": "2012/12/05 00:00:00",
                    "to": "2012/12/05 19:00:00"
                }
            }
        }
    }
}


４ S3は受け取ったリソース情報(RI)と自身がデバイス別に管理するインデックス(IX)を比較し、更新の要否を判断します。

・RI.date > IX.date ⇒ データ更新
・RI.tag != IX.tag ⇒ tag更新
・RI.gadget[].date > IX.gadget[].date ⇒ gadget更新
・RI.gadget[].tag != IX.gadget[].tag ⇒ gadget.tag更新
・shareで指定されていないgroupに既に共有設定がある場合、それを削除。
・shareで指定されてるgroupに共有設定がない場合、それを追加。
・permission情報の適用。

resource[date:2012/12/05 20:58:59]
   --> group[共有グループ1]
	--> user[ユーザA]
	     --> device[デバイス-a]
                  --> ix[date:2012/12/04 10:28:50] *** 要更新
	     --> device[デバイス-b]
                  --> ix[date:2012/12/05 20:58:59] --- 更新不要
	--> user[ユーザB]
	     --> device[デバイス-c]
                  --> ix[date:2012/12/04 10:28:50] *** 要更新
	     --> device[デバイス-d]
                  --> ix[date:2012/12/05 20:58:59] --- 更新不要
   --> group[共有グループ2]
	--> user[ユーザB]
	     --> device[デバイス-c]
                  --> ix[date:2012/12/04 10:28:50] *** 要更新
	     --> device[デバイス-d]
                  --> ix[date:2012/12/05 20:58:59] --- 更新不要
	--> user[ユーザC]
	     --> device[デバイス-e]
                  --> ix[]  *** 要更新
	     --> device[デバイス-f]
                  --> ix[]  *** 要更新
	--> user[ユーザD]
	     --> device[デバイス-g]
                  --> ix[date:2012/12/05 20:58:59] --- 更新不要
	     --> device[デバイスh]
                  --> ix[date:2012/12/05 20:58:59] --- 更新不要
   --> group[共有グループ3]

この例の場合、ユーザAの所有するデバイス-a、ユーザBの所有するデバイス-cへ同期処理が必要と判断されます。
ユーザBはグループ１、グループ２の両方に属しますが、一つのデバイスに対して同一リソースの同期が重複して行われることはありません。
共有グループ3にはユーザが割り当てられていないため、更新は起こりません。

以上より、デバイス-a、デバイス-cへのデータ転送が起こります。
データは以下の５以降の手順によりAPへ要求しますが、sentinelサーバは転送データの一部をキャッシュするため、必ずしも更新が必要なデバイスの数だけ要求が発生しないこともあります。

５ 端末側のデータ更新が必要と判断された場合、S3は端末に同期要求（sync要求）を送付します。
端末がオフラインの場合、この動作はオンラインに回復するまで延期されます。


=====================================================================
sync処理概要
---------------------------------------------------------------------

sync処理は端末内のデータを最新状態に更新し、端末内で更新されたデータをサーバにアップロードする処理です。
この処理は、updateコマンドまたは、端末内のデータ更新操作によって暗黙的に開始されます。

処理シーケンス

１ 端末からS3へ最新のインデックス情報を要求します。

２ S3は端末内にあるべきリソースすべて、または特定のリソースについてリビジョンNOを返します。

{
    "resources": [
	{
		"rid":"09392789337",
		"rev":"00000093938",
	        "gadget": [
			{ "rid":"09392789337", "rev":"00000093938" },
			{ "rid":"09392789336", "rev":"00000093938" },
			{ "rid":"09392789335", "rev":"00000093938" }
		]
	},{
		"rid":"09938388938",
		"rev":"remove",
	}
    ]
}

３ 端末側で内部に保有するリビジョンと比較し、必要な処理を判定します。

・サーバ側＝未更新 端末側＝未更新
実行すべき処理はありません

・サーバ側＝更新有 端末側＝未更新
サーバからダウンロードを行います → ４へ

・サーバ側＝未更新 端末側＝更新有
サーバへアップロードを行います → ５へ

・サーバ側＝更新有 端末側＝更新有
コンフリクト発生を端末アプリへ通知します → ６へ

・サーバ側＝remove 端末側＝データ有
端末内のデータを削除します


４ ダウンローが必要となると、端末はS3へデータを要求します。

S3 ← download rid=09392789337 ← 端末

4-1 S3はデータ要求を受けるとAPへその要求を伝達します。

AP ← http://server/sync?data=XXX&sync=getdata&rname=res-a ← S3

この時のURLはupdateコマンドのrefに指定したURLに以下のパラメータを付与したものです。
・データ本体のダウンロード
	sync=getdataとrname=リソース名を付与
・gadget本体のダウンロード
	sync=getdataとrname=リソース名、gname=gadget名を付与
※ tagだけあるいはpermissionだけを独立してダウンロードすることはありません。

4－2 APは要求に従いデータを返します。

AP → データ本体 → S3

返されたデータは、基本的にそのまま端末に届けられます。
・APからHTTP 200以外の応答が返った場合
  ⇒ 一定時間同期動作は遅延し、後でリトライが行われます。
・S3から端末への転送が失敗した場合
  ⇒ 一定時間同期動作は遅延し、後でリトライが行われます。

S3 → データ本体 → 端末

５ アップロードが必要となると、端末はS3へデータを送信します。

5-1 S3はアップロード要求を受けるとAPへその要求を伝達します。

AP ← http://server/sync?data=XXX&sync=putbody&rname=res-a ← S3

この時のURLはupdateコマンドのrefに指定したURLに以下のパラメータを付与したものです。
・データ本体のアップロード
	sync=putdataとrname=リソース名を付与
・データに付属するtagのアップロード
	sync=puttagとrname=リソース名を付与
・gadget本体のアップロード
	sync=putdataとrname=リソース名、gname=gadget名を付与
・gadgetに付属するtagのアップロード
	sync=puttagとrname=リソース名、gname=gadget名を付与
※ permissionは端末内で更新できないため、permissionをアップロードすることはありません。

5－2 APは処理結果を返します。

AP → 処理結果 → S3

・APからHTTP 200以外の応答が返った場合
  ⇒ 一定時間同期動作は遅延し、後でリトライが行われます。
・S3から端末への転送が失敗した場合
  ⇒ 一定時間同期動作は遅延し、後でリトライが行われます。

S3 → リザルト → 端末

６ コンフリクトが起こると、端末アプリに通知し判断を仰ぎます。
その間、コンフリクトしたリソースに関する同期処理は停止し、端末アプリから「サーバデータの採用」または「端末データの採用」の指示によって４または５の処理を行います。



=====================================================================
コンフリクトについて

コンフリクトは、ひとつのデータを共有するデバイスで、同時に異なる更新操作を行った場合に発生します。

コンフリクトはS3サーバ内で検出され、先に更新操作に入った方のデータが採用となり、後続の更新操作は端末側へコンフリクトとして戻されます。







