ממשקי API לאחסון

כמעט כל היבט בפיתוח האפליקציה כולל רכיב כלשהו של שליחה או קבלה של נתונים. בבסיס זה, כדאי להשתמש ב-MVC framework כדי לתכנן ולהטמיע את האפליקציה כך שהנתונים יהיו נפרדים לחלוטין מתצוגת האפליקציה לגבי הנתונים האלה (ראו ארכיטקטורת MVC).

צריך לחשוב גם על אופן הטיפול בנתונים כאשר האפליקציה במצב אופליין (עיינו בקטע מצב אופליין תחילה). במסמך הזה נציג בקצרה את אפשרויות האחסון לשליחה, קבלה ושמירה של נתונים באופן מקומי. שאר המסמך מראה איך להשתמש בממשקי ה-API של מערכת הקבצים (File System) ו-Sync File System של Chrome (ראו גם ב-fileSystem API וב-syncFileSystem API).

אפשרויות אחסון

אפליקציות ארוזות משתמשות במנגנונים רבים ושונים לשליחה ולקבלה של נתונים. לגבי נתונים חיצוניים (משאבים, דפי אינטרנט), חשוב שתכירו את Content Security Policy (CSP). בדומה לתוספים ל-Chrome, אפשר להשתמש ב-XMLHttpRequests בין מקורות כדי לתקשר עם שרתים מרוחקים. אתם יכולים גם לבודד דפים חיצוניים כדי לשמור על האבטחה של שאר האפליקציה (מידע נוסף מפורט במאמר הטמעה של דפי אינטרנט חיצוניים).

כששומרים נתונים באופן מקומי, אפשר להשתמש ב-Chrome Storage API כדי לשמור כמויות קטנות של נתוני מחרוזת וב-IndexedDB כדי לשמור נתונים מובְנים. באמצעות IndexedDB אפשר לשמור אובייקטים ב-JavaScript לאחסון אובייקטים ולהשתמש באינדקסים של החנות כדי להריץ שאילתות על נתונים (למידע נוסף, ראו Simple Todo List guide של HTML5 Rock). כדי להשתמש בכל סוגי הנתונים האחרים, כמו נתונים בינאריים, השתמשו בממשקי ה-API של 'מערכת קבצים' ו'סנכרון של מערכת הקבצים'.

ממשקי ה-API של מערכת הקבצים והסנכרון של Chrome מרחיבים את ממשק ה-API של HTML5 FileSystem. באמצעות ממשק ה-API של מערכת הקבצים של Chrome, אפליקציות יכולות ליצור, לקרוא, לנווט ולכתוב בקטע ארגז חול במערכת הקבצים המקומית של המשתמש. לדוגמה, באפליקציית שיתוף תמונות אפשר להשתמש ב-Filesystem API כדי לקרוא ולכתוב תמונות שהמשתמש בוחר.

באמצעות ממשק ה-API של Sync Filesystem של Chrome, אפליקציות יכולות לשמור ולסנכרן נתונים ב-Google Drive של המשתמשים, כדי שאותם נתונים יהיו זמינים ללקוחות שונים. לדוגמה, אפליקציה של עורך טקסט המגובה בענן יכולה לסנכרן באופן אוטומטי קובצי טקסט חדשים עם חשבון Google Drive של המשתמש. כשהמשתמש פותח את עורך הטקסט בלקוח חדש, Google Drive שולח קובצי טקסט חדשים למכונה הזו של עורך הטקסט.

שימוש ב-Chrome Filesystem API

הוספת הרשאה למערכת קבצים

כדי להשתמש ב-File System API של Chrome, עליכם להוסיף את ההרשאה fileSystem למניפסט, כדי שתוכלו לקבל מהמשתמש הרשאה לאחסון נתונים קבועים.

"permissions": [
  "...",
  "fileSystem"
]

אפשרויות משתמש לבחירת קבצים

המשתמשים מצפים לבחור קבצים באותו אופן שבו הם עושים את זה. לכל הפחות, הם מצפים ללחצן 'בחירת קובץ' ולבורר קבצים סטנדרטי. אם האפליקציה שלכם עושה שימוש רב בהעברת קבצים, כדאי גם להטמיע גרירה ושחרור (ראו בהמשך, וכדאי גם לנסות את גרירה ושחרור מקוריים של HTML5).

קבלת הנתיב של fileEntry

כדי לקבל את הנתיב המלא של הקובץ שהמשתמש בחר, fileEntry, יש לבצע קריאה ל-getDisplayPath():

function displayPath(fileEntry) {
  chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
    console.log(path)
  });
}

יישום גרירה ושחרור

אם אתם צריכים להטמיע בחירה של גרירה ושחרור, כדאי להתחיל לעבוד עם בקר הקבצים באמצעות גרירה ושחרור (dnd.js) בדוגמה של גישה למערכת הקבצים. הבקר יוצר רשומת קובץ מ-DataTransferItem באמצעות גרירה ושחרור. בדוגמה הזו, הערך fileEntry מוגדר לפריט הראשון שהורד.

var dnd = new DnDFileController('body', function(data) {
  var fileEntry = data.items[0].webkitGetAsEntry();
  displayPath(fileEntry);
});

קריאת קובץ

הקוד הבא פותח את הקובץ (לקריאה בלבד) וקורא אותו כטקסט באמצעות אובייקט FileReader. אם הקובץ לא קיים, מוצגת הודעת שגיאה.

var chosenFileEntry = null;

chooseFileButton.addEventListener('click', function(e) {
  chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {

    readOnlyEntry.file(function(file) {
      var reader = new FileReader();

      reader.onerror = errorHandler;
      reader.onloadend = function(e) {
        console.log(e.target.result);
      };

      reader.readAsText(file);
    });
    });
});

כתיבת קובץ

שני התרחישים הנפוצים לכתיבת קובץ הם 'שמירה' ו'שמירה בשם'. הקוד הבא יוצר writableEntry מהקובץ chosenFileEntry לקריאה בלבד וכותב אליו את הקובץ שנבחר.

 chrome.fileSystem.getWritableEntry(chosenFileEntry, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = callback;

    chosenFileEntry.file(function(file) {
      writer.write(file);
    });
  }, errorHandler);
});

הקוד הבא יוצר קובץ חדש עם הפונקציונליות 'Save as', וכותב את ה-blob החדש בקובץ באמצעות השיטה writer.write().

chrome.fileSystem.chooseEntry({type: 'saveFile'}, function(writableFileEntry) {
    writableFileEntry.createWriter(function(writer) {
      writer.onerror = errorHandler;
      writer.onwriteend = function(e) {
        console.log('write complete');
      };
      writer.write(new Blob(['1234567890'], {type: 'text/plain'}));
    }, errorHandler);
});

שימוש ב-Chrome Sync Filesystem API

באמצעות אחסון קבצים שניתן לסנכרן, ניתן להפעיל אובייקטים שמוחזרים של נתונים בדיוק כמו מערכות מקומיות של קבצים במצב אופליין ב-FileSystem API, אלא רק באמצעות סנכרון נוסף (ואוטומטי) של הנתונים האלה ל-Google Drive.

הוספת הרשאה למערכת הקבצים לסנכרון

כדי להשתמש בממשק ה-API של Sync Filesystem של Chrome, צריך להוסיף את ההרשאה 'syncFileSystem' למניפסט, כדי לקבל הרשאה מהמשתמש לאחסן ולסנכרן נתונים מתמשכים.

"permissions": [
  "...",
  "syncFileSystem"
]

מפעיל אחסון קבצים שניתן לסנכרן

כדי להפעיל אחסון קבצים שניתן לסנכרן באפליקציה, פשוט קוראים ל-syncFileSystem.requestFileSystem. שיטה זו מחזירה מערכת קבצים שניתן לסנכרן עם Google Drive, לדוגמה:

chrome.syncFileSystem.requestFileSystem(function (fs) {
   // FileSystem API should just work on the returned 'fs'.
   fs.root.getFile('test.txt', {create:true}, getEntryCallback, errorCallback);
});

מידע על סטטוס סנכרון קבצים

משתמשים ב-syncFileSystem.getFileStatus כדי לקבל את סטטוס הסנכרון של קובץ נוכחי:

chrome.syncFileSystem.getFileStatus(entry, function(status) {...});

ערכי הסטטוס של סנכרון הקבצים יכולים להיות אחד מאלה: 'synced', 'pending' או 'conflicting'. המשמעות של "סנכרון" היא שהקובץ מסונכרן במלואו ואין שינויים מקומיים בהמתנה שלא סונכרנו עם Google Drive. עם זאת, יכולים להיות שינויים בהמתנה בצד של Google Drive שעדיין לא אוחזרו.

המשמעות של הסטטוס 'בהמתנה' היא שבקובץ יש שינויים בהמתנה שעדיין לא סונכרנו עם Google Drive. אם האפליקציה פועלת אונליין, השינויים המקומיים מסונכרנים (כמעט) מיד עם Google Drive, והאירוע syncFileSystem.onFileStatusChanged מופעל עם הסטטוס 'synced' (פרטים נוספים מופיעים בהמשך).

הפרמטר syncFileSystem.onFileStatusChanged מופעל כשהסטטוס של הקובץ משתנה ל-'conflicting'. המשמעות של 'התנגשות' היא שיש שינויים מתנגשים באחסון המקומי וב-Google Drive. קובץ יכול להיות במצב הזה רק אם המדיניות בנושא יישוב סכסוכים מוגדרת כ-'manual'. מדיניות ברירת המחדל היא 'last_write_win', והתנגשויות נפתרות באופן אוטומטי באמצעות מדיניות פשוטה של כתיבה אחרונה. אפשר לשנות את המדיניות של המערכת בנושא יישוב סכסוכים באמצעות syncFileSystem.setConflictResolutionPolicy.

אם המדיניות לפתרון סכסוכים מוגדרת כ-'manual' וקובץ מסוים מגיע למצב 'conflicting', האפליקציה עדיין יכולה לקרוא ולכתוב את הקובץ כקובץ מקומי אופליין, אבל השינויים לא מסונכרנים והקובץ לא יסונכרן משינויים מרחוק שבוצעו בלקוחות אחרים עד שהמחלוקת תטופל. הדרך הקלה ביותר לפתור התנגשות היא למחוק את הגרסה המקומית של הקובץ או לשנות את השם שלה. פעולה זו מאלצת סנכרון של הגרסה המרוחקת, את המצב מתנגש והאירוע onFileStatusChanged מופעל עם הסטטוס 'synced'.

המערכת מאזינה לשינויים בסטטוס המסונכרן

האירוע syncFileSystem.onFileStatusChanged מופעל כשסטטוס הסנכרון של קובץ משתנה. לדוגמה, נניח שבקובץ יש שינויים בהמתנה והוא נמצא במצב 'בהמתנה'. ייתכן שהאפליקציה הייתה במצב אופליין, כך שהשינוי עומד להסתנכרן. כששירות הסנכרון מזהה את השינוי המקומי שבהמתנה ומעלה את השינוי ל-Google Drive, השירות מפעיל את האירוע onFileStatusChanged עם הערכים הבאים: { fileEntry:a fileEntry for the file, status: 'synced', action: 'updated', direction: 'local_to_remote' }.

באופן דומה, ללא קשר לפעילויות המקומיות, שירות הסנכרון עשוי לזהות שינויים מרחוק שבוצעו על ידי לקוח אחר ולהוריד את השינויים מ-Google Drive לאחסון המקומי. אם השינוי מרחוק נועד להוספת קובץ חדש, יופעל אירוע עם הערכים הבאים: { fileEntry: a fileEntry for the file, status: 'synced', action: 'added', direction: 'remote_to_local' }.

אם יש שינויים מתנגשים באותו קובץ גם בצד המקומי וגם בצד המרוחק, ואם המדיניות לפתרון התנגשות מוגדרת לערך 'manual', סטטוס הקובץ ישתנה למצב conflicting, הוא מנותק משירות הסנכרון ולא יסונכרן עד שתפתרו את הבעיה. במקרה הזה, מופעל אירוע עם הערכים הבאים: { fileEntry: a fileEntry for the file, status: 'conflicting', action: null, direction: null }.

ניתן להוסיף אוזן לאירוע הזה שיגיב לכל שינוי בסטטוס. לדוגמה, האפליקציה נגן המוזיקה של Chrome מאזינה לכל מוזיקה חדשה שסונכרנה מ-Google Drive, אבל עדיין לא יובאה לאחסון המקומי של המשתמש בלקוח מסוים. כל מוזיקה שנמצאה מסתנכרנת עם אותו לקוח:

chrome.syncFileSystem.onFileStatusChanged.addListener(function(fileInfo) {
  if (fileInfo.status === 'synced') {
    if (fileInfo.direction === 'remote_to_local') {
      if (fileInfo.action === 'added') {
        db.add(fileInfo.fileEntry);
      } else if (fileInfo.action === 'deleted') {
        db.remove(fileInfo.fileEntry);
      }
    }
  }
});

בדיקת השימוש ב-API

כדי לבדוק את כמות הנתונים שמשמשים את ה-API, צריך לבצע שאילתה בספריית ארגז החול (Sandbox) המקומית של האפליקציה או בבייטים של השימוש שהוחזרו על ידי syncFileSystem.getUsageAndQuota.

chrome.syncFileSystem.getUsageAndQuota(fileSystem, function (storageInfo) {
   updateUsageInfo(storageInfo.usageBytes);
   updateQuotaInfo(storageInfo.quotaBytes);
});

תוכל גם לבחון את אחסון השירות לקצה העורפי של הסנכרון של המשתמש (ב-Google Drive). קבצים שמסונכרנים נשמרים בתיקייה מוסתרת ב-Google Drive – Chrome Syncable FileSystem. התיקייה לא תוצג ברשימה 'האחסון שלי', אבל אפשר לחפש אותה על ידי חיפוש שם התיקייה בתיבת החיפוש. (שימו לב שלא בטוח שהפריסה של התיקייה המרוחקת תהיה תואמת לאחור בין הגרסאות).