2013年8月1日木曜日

[Chrome]SyncFileSystemAPIでGoogleDriveと同期

Chromeが提供する SyncFileSystem API は大切なデータ(ファイル)を扱うのにとても便利です。SyncFileSystem APIを使えば、一つの処理でローカルとクラウド(Google Drive)上の両方にデータを保存することができ、しかも適当なタイミングでローカルとクラウドのファイルが自動的に同期されます。

ただし、SyncFileSystem APIが chrome.*なパッケージ配下にあることからもわかるように、このAPIはHTML5の仕様ではありません。Chrome独自のAPIです。Chromeアプリ限定(Extensions や PackagedApps)で利用できるAPIだということは忘れないでください。つまりWebサイトやHosted Appsでは使えないということですね。

というわけで早速サンプルを見てみましょう。

ファイル構成

  • manifest.json
  • background.js
  • index.html
  • app.js
  • 128.png
Chrome Extensions や Packaged Apps の典型的なファイル構成です。

manifest.json
{
  "name": "syncFilesystem sample App",
  "description": "Sample app using the Chrome SyncFilesystem API.",
  "version": "0.1",
  "app": {
    "background": {
      "scripts": ["background.js"]
    }
  },
  "icons": { "128": "128.png" },
  "permissions": [
    "syncFileSystem"
  ]
}

background.js
chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('index.html', {
    'bounds': {
      'width': 600,
      'height': 500
    }
  });
});

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
contents:<br/>
<textarea id="write_ta" placeholders="write text."></textarea><br/>
<button id="write_btn">create and write</button><br/>
<hr>
<button id="read_btn">read</button><br/>
contents:<br/>
<pre id="read_result"></pre>
<hr>
<button id="remove_btn">remove a file</button><br/>
<script src="app.js"></script>
</body>
</html>

app.js
// ボタンとかのDOM取得
var write_ta = document.querySelector('#write_ta');
var write_btn = document.querySelector('#write_btn');
var read_btn = document.querySelector('#read_btn');
var read_result = document.querySelector('#read_result');
var remove_btn = document.querySelector('#remove_btn');

/*
 * onclick 'create and write' button
 */
write_btn.onclick = function(e){
  chrome.syncFileSystem.requestFileSystem(function(fs){
    fs.root.getFile('hoge.txt', { create : true }, function(fileEntry){
      fileEntry.createWriter(function(fileWriter) {
        // onwriteend
        fileWriter.onwriteend = function(e) {
          console.log('Write completed.');
        };
        // onerror
        fileWriter.onerror = function(e) {
          console.log('Write failed: ' + e.toString());
        };
        // create blob data
        var data = new Blob([ write_ta.value ]);
        // write data into the file.
        fileWriter.write(data);
      }, onErr);
    }, onErr);
  });
}

/*
 * onclick 'read' button 
 */
read_btn.onclick = function(e){
  chrome.syncFileSystem.requestFileSystem(function(fs){
    fs.root.getFile('hoge.txt', { create : false }, function(fileEntry){
      fileEntry.file(function(file){
        var reader = new FileReader();
        reader.onload = function(e){
          console.log('result: ' + this.result);
          read_result.textContent = this.result;
        };
        reader.readAsText(file);
      });
    }, onErr);
  });
}

/**
 * onclick 'remove' button
 */
remove_btn.onclick = function(e) {
  chrome.syncFileSystem.requestFileSystem(function(fs) {
    fs.root.getFile('hoge.txt', {}, function(fileEntry) {
      fileEntry.remove(function() {
        console.log('removed: ' + fileEntry.fullPath);
      }, onErr);
    }, onErr);
  });
}

/**
 * func for onerror
 */
function onErr(err) {
  var msg = '';
  switch (err.code) {
    case FileError.QUOTA_EXCEEDED_ERR:
      msg = 'QUOTA_EXCEEDED_ERR';
      break;
    case FileError.NOT_FOUND_ERR:
      msg = 'NOT_FOUND_ERR';
      break;
    case FileError.SECURITY_ERR:
      msg = 'SECURITY_ERR';
      break;
    case FileError.INVALID_MODIFICATION_ERR:
      msg = 'INVALID_MODIFICATION_ERR';
      break;
    case FileError.INVALID_STATE_ERR:
      msg = 'INVALID_STATE_ERR';
      break;
    default:
      msg = 'Unknown Error';
      break;
  }
  console.log('Error: ' + msg);
}

さて、これを実行してみましょう。
まずtextareaに "あいうえお" と入力し、"create and write"ボタンを押してみましょう。すると下のようにログ出力されます。
Write completed. app.js:18
Googleアカウントでログイン状態であれば、この時点でクラウド(Google Drive)上にファイルが作成されていると思います。クラウド上のパスは以下のとおりです。
/Chrome Syncable FileSystem/APP_ID/hoge.txt
このファイルには、先ほど書き込んだ文字列 "あいうえお" が入力されているはずです。

もちろんローカルにも保存されています。Windows7の場合、ファイルの在り処はここらへんだと思います。余り自信はありませんが、、、。
C:\Users\USER_NAME\AppData\Local\Google\Chrome\User Data\Default\Sync FileSystem\*
C:\Users\USER_NAME\AppData\Local\Google\Chrome\User Data\Default\File System\*

さて次に"read"ボタンを押してみましょう。すると下のようにログ出力されます。
result: あいうえお app.js:42
ここでインターネットを切断して、もう一度 "read"ボタンを押しても、同じようにログ出力されます。つまりローカルにもファイルが保存されているということです。

最後にオフライン状態のまま"remove"ボタンを押してみましょう。すると下のようにログ出力されます。
removed: /hoge.txt app.js:58
ここで"read"ボタンを押せば、NOT_FOUND_ERR がログ表示されますので、ローカルのhoge.txtファイルが正しく削除されたことがわかります。
この時点ではクラウド上のhoge.txtファイルは未だ残っていますが、ここで再びインターネットに接続するとローカルの状態と自動的に同期され、クラウド上のファイルも削除されます。


Sync: authentication failed.

chromeログインしていない状態でこのサンプルを実行したとき、稀に下のようなエラーメッセージが表示されて動作しないときがあります。
syncFileSystem.requestFileSystem: Sync: authentication failed. at chrome-extension://APP_ID/app.js:8:23
そんな時はchromeログインしてから実行すればエラー無く動きます。が、原因はいまだ不明です、、、。

追記(2014/11/9)
ひさしぶりに上のサンプルを動かそうとしてもSync: authentication failed.が発生して動きませんでした。もしかして SyncFileSystem API っていまだにCanaryビルドから抜け出してなかったのかな・・・?

参考にしたサイト

chrome.syncFileSystem - Google Chrome
【Packaged Apps】SyncFileSystemを使ってローカルファイルとリモートファイルを別け隔てなく扱う【Chrome】 - 俺の砂箱

0 件のコメント:

コメントを投稿