diff --git a/omega-locales/en_US/LC_MESSAGES/omega-web.po b/omega-locales/en_US/LC_MESSAGES/omega-web.po index 3143247..a7b3f53 100644 --- a/omega-locales/en_US/LC_MESSAGES/omega-web.po +++ b/omega-locales/en_US/LC_MESSAGES/omega-web.po @@ -452,6 +452,9 @@ msgstr "Syncing (Experimental)" msgid "options_syncEnable" msgstr "Enable Syncing" +msgid "options_useBuiltInSyncEnhance" +msgstr "Enhance your Gist sync experience with built-in browser sync" + msgid "options_syncEnableForce" msgstr "Download from Syncing" diff --git a/omega-locales/zh_CN/LC_MESSAGES/omega-web.po b/omega-locales/zh_CN/LC_MESSAGES/omega-web.po index 3a41e0a..da90cd6 100644 --- a/omega-locales/zh_CN/LC_MESSAGES/omega-web.po +++ b/omega-locales/zh_CN/LC_MESSAGES/omega-web.po @@ -413,6 +413,9 @@ msgstr "选项同步 (测试中)" msgid "options_syncEnable" msgstr "启用同步" +msgid "options_useBuiltInSyncEnhance" +msgstr "使用浏览器内置同步功能增强 Gist 同步使用体验" + msgid "options_syncEnableForce" msgstr "下载云端版本" diff --git a/omega-target-chromium-extension/src/coffee/background.coffee b/omega-target-chromium-extension/src/coffee/background.coffee index 24294d5..58e680d 100644 --- a/omega-target-chromium-extension/src/coffee/background.coffee +++ b/omega-target-chromium-extension/src/coffee/background.coffee @@ -5,6 +5,9 @@ Promise.longStackTraces() OmegaTargetCurrent.Log = Object.create(OmegaTargetCurrent.Log) Log = OmegaTargetCurrent.Log + +BUILTINSYNCKEY = 'zeroOmegaSync' + # TODO 将来可能代码需要重构下,这里写得有点乱. (suziwen1@gmail.com) globalThis.isBrowserRestart = globalThis.startupCheck is undefined globalThis.hasStartupCheck = not globalThis.isBrowserRestart @@ -212,7 +215,10 @@ zeroBackground = (zeroStorage, opts) -> if chrome?.storage?.sync or browser?.storage?.sync syncStorage = new OmegaTargetCurrent.SyncStorage('sync', state) - sync = new OmegaTargetCurrent.OptionsSync(syncStorage) + builtInSyncStorage = new OmegaTargetCurrent.Storage('sync') + sync = new OmegaTargetCurrent.OptionsSync( + syncStorage, builtInSyncStorage, state + ) sync.transformValue = OmegaTargetCurrent.Options.transformValueForSync proxyImpl = OmegaTargetCurrent.proxy.getProxyImpl(Log) @@ -228,7 +234,46 @@ zeroBackground = (zeroStorage, opts) -> if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId and false options.switchySharp = new OmegaTargetCurrent.SwitchySharp() options.switchySharp.monitor() - + if sync and options and builtInSyncStorage + builtInSyncStorage.watch [ + BUILTINSYNCKEY + ], (changes, opts = {}) -> + builtInSyncConfig = changes[BUILTINSYNCKEY] + if builtInSyncConfig + {gistId, gistToken, lastGistCommit} = builtInSyncConfig + state.set({gistId, gistToken}) + if sync.enabled + console.log('check gist change', lastGistCommit) + sync.init({gistId, gistToken}) + state.get({ + 'lastGistCommit': '' + }).then((syncConfig) -> + if syncConfig.lastGistCommit isnt lastGistCommit + console.log( + 'no match last gist commit, will check change', + syncConfig.lastGistCommit + ) + sync.checkChange() + ) + else + # try to enable sync + state.get({ + 'syncOptions': '' + 'lastGistCommit': '' + }).then((syncConfig) -> + return if syncConfig.lastGistCommit is lastGistCommit + if syncConfig.syncOptions in ['pristine', 'conflict'] + state.set({ + syncOptions: 'conflict' + }).then( -> + options.setOptionsSync(true, { + gistId, + gistToken, + useBuiltInSync: true, + force: true + }) + ) + ) tabs = new OmegaTargetCurrent.ChromeTabs(actionForUrl) tabs.watch() diff --git a/omega-target-chromium-extension/src/module/sync_storage.coffee b/omega-target-chromium-extension/src/module/sync_storage.coffee index f8da4b3..173a679 100644 --- a/omega-target-chromium-extension/src/module/sync_storage.coffee +++ b/omega-target-chromium-extension/src/module/sync_storage.coffee @@ -7,6 +7,7 @@ isPulling = false isPushing = false state = null +optionsSync = null mainLetters = ['Z','e', 'r', 'o', 'O', 'm','e', 'g', 'a'] optionFilename = mainLetters.concat(['.json']).join('') @@ -97,7 +98,7 @@ processPush = (syncStore) -> processPush.sequence.push(syncStore) return if isPushing isPushing = true - _processPush() + setTimeout(_processPush, 600) # use timeout to merge push processPush.sequence = [] @@ -155,11 +156,16 @@ updateGist = (gistId, options) -> ).then((data) -> if data.message throw data.message + lastGistCommit = data.history[0]?.version state?.set({ - 'lastGistCommit': data.history[0]?.version + 'lastGistCommit': lastGistCommit 'lastGistState': 'success' 'lastGistSync': Date.now() - }) + }).then( -> + optionsSync?.updateBuiltInSyncConfigIf({ + lastGistCommit + }) + ) return data ).catch((e) -> state?.set({ @@ -262,6 +268,8 @@ class ChromeSyncStorage extends OmegaTarget.Storage # param(withRemoteData) retrive gist file content ## init: (args) -> + optionsSync = args.optionsSync + state = args.state gistId = args.gistId || '' if gistId.indexOf('/') >= 0 # get gistId from url `https://gist.github.com/{username}/{gistId}` diff --git a/omega-target/src/options.coffee b/omega-target/src/options.coffee index c654f9c..2d29945 100644 --- a/omega-target/src/options.coffee +++ b/omega-target/src/options.coffee @@ -101,8 +101,9 @@ class Options 'gistToken': '' }).then(({syncOptions, gistId, gistToken}) => unless gistId - syncOptions = 'pristine' - @_state.set({'syncOptions': 'pristine'}) + unless syncOptions is 'disabled' + syncOptions = 'pristine' + @_state.set({'syncOptions': syncOptions}) @sync.enabled = syncOptions is 'sync' unless @sync.enabled @_storage.get(null) @@ -182,6 +183,8 @@ class Options ### init: (startupCheck = -> true) -> # startupCheck 一定要放在 isBrowserRestart 后面 + # startupProfileName 如果为空,就使用当前的 currentProfileName + # 如果没有 currentProfileName, 就使用默认的 fallbackProfileName # TODO (suziwen1@gmail.com) # 1. 好像有 bug , 一直没法重现,但就是很不经意就能出现,概率很小的样子 # 2. 有全局变量,容易污染代码,需要重构初始化流程 @@ -189,12 +192,17 @@ class Options if globalThis.isBrowserRestart and startupCheck() and @_options['-startupProfileName'] + console.log( + 'apply browser restart startup profile', + @_options['-startupProfileName'] + ) @applyProfile(@_options['-startupProfileName']) else @_state.get({ 'currentProfileName': @fallbackProfileName 'isSystemProfile': false }).then (st) => + console.log('apply init startup profile', st) if st['isSystemProfile'] @applyProfile('system') else @@ -208,7 +216,7 @@ class Options ).then => @getAll() @ready.then => - @sync.requestPush(@_options) if @sync?.enabled + #@sync.requestPush(@_options) if @sync?.enabled @_state.get({'firstRun': ''}).then ({firstRun}) => @onFirstRun(firstRun) if firstRun @@ -296,14 +304,20 @@ class Options reset: (options) -> @log.method('Options#reset', this, arguments) options ?= @getDefaultOptions() - @upgrade(@parseOptions(options)).then ([opt]) => + _options = @parseOptions(options) + @upgrade(_options).then ([opt]) => # Disable syncing when resetting to avoid affecting sync storage. @sync.enabled = false if @sync? @_state.remove(['syncOptions']) + @_watchStop?() + @_watchStop = null @_storage.remove().then(=> @_storage.set(opt) - ).then => + ).then( => @init() + ).then => + if _options['-startupProfileName'] + @applyProfile(_options['-startupProfileName']) ###* # Called on the first initialization of options. @@ -1055,7 +1069,7 @@ class Options }).then ({syncOptions, lastGistCommit}) => if not enabled if syncOptions == 'sync' - @_state.set({'syncOptions': 'pristine'}) + @_state.set({'syncOptions': 'disabled'}) @sync.enabled = false @_syncWatchStop?() @_syncWatchStop = null @@ -1082,9 +1096,26 @@ class Options if syncOptions == 'conflict' # Try to re-init options from sync. @sync.enabled = false - @_storage.remove().then => + @_watchStop?() + @_watchStop = null + @_storage.remove().then( => + if remoteOptions + console.log('flush data') + @sync.flush({data: remoteOptions}) + ).then => @sync.enabled = true - @init() + @init().then( => + if remoteOptions + if remoteOptions['-startupProfileName'] + console.log('apply startup') + @applyProfile(remoteOptions['-startupProfileName']) + if args.useBuiltInSync + @sync.toggleBuiltInSync(true) + else + @sync.toggleBuiltInSync(false) + ).then( => + @updateProfile() + ) else if remoteOptions?.schemaVersion @sync.flush({data: remoteOptions}).then( => @@ -1097,6 +1128,10 @@ class Options @_syncWatchStop?() @sync.requestPush(@_options) @_syncWatchStop = @sync.watchAndPull(@_storage) + if args.useBuiltInSync + @sync.toggleBuiltInSync(true) + else + @sync.toggleBuiltInSync(false) return ) diff --git a/omega-target/src/options_sync.coffee b/omega-target/src/options_sync.coffee index 4e353bc..041604e 100644 --- a/omega-target/src/options_sync.coffee +++ b/omega-target/src/options_sync.coffee @@ -6,6 +6,9 @@ Log = require './log' jsondiffpatch = require 'jsondiffpatch' TokenBucket = require('limiter').TokenBucket + +BUILTINSYNCKEY = 'zeroOmegaSync' + class OptionsSync @TokenBucket: TokenBucket @@ -31,7 +34,15 @@ class OptionsSync ### storage: null - constructor: (@storage, @_bucket) -> + ###* + # Use browser built-in sync to enhance gist sync function + # @type Storage + ### + builtInSyncStorage: null + + state: null + + constructor: (@storage, @builtInSyncStorage, @state, @_bucket) -> @_pending = {} @_bucket ?= new TokenBucket(10, 10, 'minute', null) @_bucket.clear ?= => @@ -207,12 +218,45 @@ class OptionsSync doPull() else pullScheduled = setTimeout(doPull, @pullThrottle) + toggleBuiltInSync: (useBuiltInSync) -> + @getBuiltInSyncConfig().then((builtInSyncConfig) => + @state.get({ + 'gistId': '', + 'gistToken': '', + 'lastGistCommit': '' + }).then((syncConfig) => + if useBuiltInSync is undefined + useBuiltInSync = !builtInSyncConfig + if useBuiltInSync is true + _obj = {} + _obj[BUILTINSYNCKEY] = syncConfig + @builtInSyncStorage.set(_obj) + else + @builtInSyncStorage.remove(BUILTINSYNCKEY) + ) + ) + getBuiltInSyncConfig: -> + @builtInSyncStorage.get(BUILTINSYNCKEY).then((_obj) -> + return _obj[BUILTINSYNCKEY] + ) + updateBuiltInSyncConfigIf: (_builtInSyncConfig) -> + @getBuiltInSyncConfig().then((builtInSyncConfig) => + if !!builtInSyncConfig + newBuiltInSyncConfig = Object.assign( + {}, builtInSyncConfig, _builtInSyncConfig + ) + _obj = {} + _obj[BUILTINSYNCKEY] = newBuiltInSyncConfig + @builtInSyncStorage.set(_obj) + ) checkChange: -> @storage.checkChange({ immediately: true force: true }) init: (args) -> + args.optionsSync = this + args.state = @state @storage.init(args) destroy: -> @storage.destroy() diff --git a/omega-web/src/omega/controllers/io.coffee b/omega-web/src/omega/controllers/io.coffee index a7544fe..6d31c88 100644 --- a/omega-web/src/omega/controllers/io.coffee +++ b/omega-web/src/omega/controllers/io.coffee @@ -2,6 +2,7 @@ angular.module('omega').controller 'IoCtrl', ( $scope, $rootScope, $window, $http, omegaTarget, downloadFile ) -> + $scope.useBuiltInSync = true getGistId = (gistUrl = '') -> # get gistId from url `https://gist.github.com/{username}/{gistId}` # or directly gistId @@ -32,7 +33,7 @@ angular.module('omega').controller 'IoCtrl', ( plainOptions = angular.fromJson(angular.toJson($rootScope.options)) content = JSON.stringify(plainOptions) blob = new Blob [content], {type: "text/plain;charset=utf-8"} - downloadFile(blob, "OmegaOptions.bak") + downloadFile(blob, "Zero" + """OmegaOptions.bak""") $scope.importSuccess = -> $rootScope.showAlert( @@ -89,6 +90,7 @@ angular.module('omega').controller 'IoCtrl', ( return args.gistId = $scope.gistId args.gistToken = $scope.gistToken + args.useBuiltInSync = $scope.useBuiltInSync $scope.enableOptionsSyncing = true omegaTarget.setOptionsSync(true, args).then( -> $window.location.reload() diff --git a/omega-web/src/partials/io.jade b/omega-web/src/partials/io.jade index f9bc5bc..09df454 100644 --- a/omega-web/src/partials/io.jade +++ b/omega-web/src/partials/io.jade @@ -59,6 +59,10 @@ section.settings-group a(href="https://github.com/settings/tokens/new" role="button" target="_blank") | {{ 'Create a token that manages the Gist.(Only gist permission is required.)'}} div(ng-show='syncOptions == "pristine" || syncOptions == "disabled"') + div.checkbox + label + input#use-built-in-sync-enhance(type='checkbox' ng-model='useBuiltInSync') + span {{'options_useBuiltInSyncEnhance' | tr}} p.help-block(omega-html='"options_syncPristineHelp" | tr') p button.btn.btn-default(ng-click='enableOptionsSync()' ladda='enableOptionsSyncing' data-spinner-color="currentColor") @@ -89,6 +93,10 @@ section.settings-group = ' ' | {{'options_syncDisable' | tr}} div(ng-show='syncOptions == "conflict"') + div.checkbox + label + input#use-built-in-sync-enhance(type='checkbox' ng-model='useBuiltInSync') + span {{'options_useBuiltInSyncEnhance' | tr}} p.alert.alert-danger.width-limit span.glyphicon.glyphicon-info-sign = ' '