Skip to content

Commit

Permalink
Save backup in chrome storage (#41)
Browse files Browse the repository at this point in the history
* Save backup in chrome storage

* Update descriptions for backup
  • Loading branch information
MichaelKim authored and fg123 committed Nov 28, 2018
1 parent a42f2a7 commit b6617ef
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 56 deletions.
50 changes: 30 additions & 20 deletions flow-typed/mercurywm.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,39 @@
// type of the variable instead (number, string, etc.)

declare var Constants: {|
NAME: 'Mercury WM',
VERSION: string,
STATE_KEY: 'state',
DIR_TYPE: 'dir',
FILE_TYPE: 'file',
EXE_TYPE: 'exe',
MERCURYWM_URL: string,
MERCURYWM_ORIGIN: string,
MERCURYWM_CONTENT_URL: string,
NAME: 'Mercury WM',
VERSION: string,
STATE_KEY: 'state',
DIR_TYPE: 'dir',
FILE_TYPE: 'file',
EXE_TYPE: 'exe',
MERCURYWM_URL: string,
MERCURYWM_ORIGIN: string,
MERCURYWM_CONTENT_URL: string,

// KEY CODES
KEY_LEFT_ARROW: 37,
KEY_UP_ARROW: 38,
KEY_RIGHT_ARROW: 39,
KEY_DOWN_ARROW: 40,
KEY_ENTER: 13,
KEY_BACKSPACE: 8,
KEY_DELETE: 46,
KEY_TAB: 9
// KEY CODES
KEY_LEFT_ARROW: 37,
KEY_UP_ARROW: 38,
KEY_RIGHT_ARROW: 39,
KEY_DOWN_ARROW: 40,
KEY_ENTER: 13,
KEY_BACKSPACE: 8,
KEY_DELETE: 46,
KEY_TAB: 9
|};

declare var PRODUCTION: boolean;

declare module "updeep" {
declare module.exports: <T>(update: Object, object: T) => T;
// Updeep
declare module 'updeep' {
declare module.exports: <T>(update: Object, object: T) => T;
}

// lz-string string compression
declare module 'lz-string' {
declare module.exports: {
// TODO: technically, decompress can return null if given empty string
compressToBase64(uncompressed: string): string,
decompressFromBase64(compressed: string): string
};
}
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"flow-bin": "^0.85.0",
"flow-interfaces-chrome": "^0.4.0",
"flow-typed": "^2.5.1",
"lz-string": "^1.4.4",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"react-redux": "^5.0.6",
Expand Down
32 changes: 0 additions & 32 deletions src/background/commands/backup.js

This file was deleted.

1 change: 0 additions & 1 deletion src/background/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ function Command(state, command, params) {

export function isCommand(name: string) {
const names = [
'backup',
'cat',
'cd',
'clear',
Expand Down
144 changes: 144 additions & 0 deletions src/background/scripts/backup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/* @flow strict */

import LZString from 'lz-string';

import type { Script, StoreState } from 'types';

/*
Backups are stored in chrome.storage.sync, and are organized in storage as such:
- backupDate: time the backup was saved
- backupSize: number of blocks that the backup is split into
- block + "i": i'th block of the backup (0 indexed)
*/

function isError(script: Script, message: string): boolean {
const error = chrome.runtime.lastError;
if (error != null) {
script.output(message);
if (error.message != null) {
script.output('Error: ' + error.message);
}

return true;
}
return false;
}

function compressState(state: StoreState): string[] {
const comp = LZString.compressToBase64(JSON.stringify(state));

const len = 2000;
const size = Math.ceil(comp.length / len),
blocks = new Array(size);

for (let i = 0; i < size; i++) {
blocks[i] = comp.substr(i * len, len);
}

return blocks;
}

function saveBackup(script: Script, resolve: Function): void {
const blocks = compressState(script.getState());

script.output('Saving backup to your Google account...');

const backup = blocks.reduce(
(obj, block, i) => {
return {
...obj,
['block' + i]: block
};
},
{ backupSize: blocks.length, backupDate: Date.now() }
);

chrome.storage.sync.set(backup, () => {
if (!isError(script, 'Backup failed!')) {
script.output('Backup successful!');
}

resolve();
});
}

function restoreBackup(script: Script, resolve: Function): void {
chrome.storage.sync.get(['backupDate', 'backupSize'], data => {
if (isError(script, 'Backup restore failed!')) {
resolve();
return;
}

const backupDate: number = data.backupDate;
if (backupDate == null) {
script.output("No backup saved");
resolve();
return;
}

const backupSize: number = data.backupSize;
if (backupSize == null) {
script.output("Missing backup data");
resolve();
return;
}

const keys = [...Array(backupSize).keys()].map(i => 'block' + i);
chrome.storage.sync.get(keys, items => {
if (isError(script, 'Backup restore failed!')) {
resolve();
return;
}

const data = keys.reduce((acc, key) => {
return acc + items[key];
}, '');
const decomp = LZString.decompressFromBase64(data);

try {
const state = JSON.parse(decomp);
script.updateStore(state);
} catch (e) {
script.output('Backup restore failed!');
script.output('Error parsing backup');
}

resolve();
});
});
}

export default function backup(
script: Script,
params: Array<string>,
resolve: Function
) {
if (params.length === 0) {
chrome.storage.sync.get('backupDate', data => {
if (!isError(script, 'Backup list failed!')) {
const date: number = data.backupDate;
if (date == null) {
script.output('No backup saved');
} else {
script.output('Last backup saved ' + new Date(date).toString());
}
}

resolve();
});
return true;
} else if (params.length === 1) {
if (params[0] === 'save') {
saveBackup(script, resolve);
return true;
} else if (params[0] === 'restore') {
restoreBackup(script, resolve);
return true;
} else {
script.output('Unknown parameter: ' + params[0]);
}
} else {
script.output('Invalid number of parameters');
}
}
5 changes: 3 additions & 2 deletions src/background/scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import store from 'background/store';
import { createFile, createTerminal, createWindow } from 'creators';
import { findWindow, getDirectory, getFile, getPath } from 'utils';

import type { Directory, File, Script as ScriptType, Window } from 'types';
import type { Directory, File, Script as ScriptType, StoreState, Window } from 'types';

// Parse input into command and parameters
function parseInput(text): Array<string> {
Expand All @@ -16,7 +16,7 @@ function parseInput(text): Array<string> {

// List of built-in scripts (doesn't include .bin)
function isScript(name: string) {
const names = ['async', 'edit', 'yum'];
const names = ['async', 'backup', 'edit', 'yum'];
return names.find(n => n === name);
}

Expand Down Expand Up @@ -69,6 +69,7 @@ function Script(command): ScriptType {
// workspace: workspaceID,
// window: windowID
// }),
updateStore: (newState: StoreState) => store.dispatch({ type: 'LOAD_STORAGE', data: newState}),
createFile: (name: string, data: string) => createFile(name, data),
createTerminal: () => createTerminal(),
createWindow: (x: number, y: number, w: number, h: number, id: number) => createWindow(x, y, w, h, id),
Expand Down
3 changes: 2 additions & 1 deletion src/background/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ function setupFile(script, args, resolve) {
'rm -d [file] - Removes directory'
]);
createMan('backup', '', [
'backup save - Writes a backup of the current state of Mercury into the console',
'backup - Shows when the last backup was made',
'backup save - Writes a backup of the current state of Mercury into synced storage',
'backup restore - Restores Mercury from a backup created by "backup save"'
]);
createMan('render', '', [
Expand Down
1 change: 1 addition & 0 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export type Script = {|
+output: (text: string, showPrompt?: boolean, showCommand?: boolean) => void,
+exec: (input: string, callback?: (any) => void) => void,
// Action creators
+updateStore: (newState: StoreState) => void,
// +resetStore: () => void,
// +clearHistory: () => void,
// +addCommand: (text: string, showPrompt: boolean) => void,
Expand Down

0 comments on commit b6617ef

Please sign in to comment.