183 lines
5.1 KiB
JavaScript
183 lines
5.1 KiB
JavaScript
(function (root) {
|
|
'use strict';
|
|
|
|
var S = root.AutoMirrorShared;
|
|
var STORAGE_KEY = 'runtimeState';
|
|
var loaded = false;
|
|
var loading = false;
|
|
var callbacks = [];
|
|
var memory = {
|
|
lastMainFrameUrls: {},
|
|
tabStates: {}
|
|
};
|
|
|
|
function getStorageArea() {
|
|
if (chrome.storage && chrome.storage.session) return chrome.storage.session;
|
|
return chrome.storage.local;
|
|
}
|
|
|
|
function tabKey(tabId) {
|
|
return String(tabId);
|
|
}
|
|
|
|
function plainMap(value) {
|
|
var result = {};
|
|
if (!value || typeof value !== 'object') return result;
|
|
|
|
Object.keys(value).forEach(function (key) {
|
|
if (value[key]) result[key] = value[key];
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function normalizeTabState(state) {
|
|
state = state && typeof state === 'object' ? state : {};
|
|
|
|
return {
|
|
ruleId: state.ruleId || '',
|
|
path: state.path || '',
|
|
startedAt: Number(state.startedAt || 0),
|
|
triedHosts: plainMap(state.triedHosts),
|
|
redirects: Number(state.redirects || 0),
|
|
lastRedirectFrom: state.lastRedirectFrom || '',
|
|
lastRedirectTo: state.lastRedirectTo || '',
|
|
lastRedirectAt: Number(state.lastRedirectAt || 0),
|
|
lastTriggerUrl: state.lastTriggerUrl || '',
|
|
lastTriggerAt: Number(state.lastTriggerAt || 0)
|
|
};
|
|
}
|
|
|
|
function normalizeRuntimeState(raw) {
|
|
raw = raw && typeof raw === 'object' ? raw : {};
|
|
|
|
var tabStates = {};
|
|
Object.keys(raw.tabStates || {}).forEach(function (key) {
|
|
tabStates[key] = normalizeTabState(raw.tabStates[key]);
|
|
});
|
|
|
|
return {
|
|
lastMainFrameUrls: plainMap(raw.lastMainFrameUrls),
|
|
tabStates: tabStates
|
|
};
|
|
}
|
|
|
|
function flushCallbacks() {
|
|
var pending = callbacks.slice();
|
|
callbacks = [];
|
|
pending.forEach(function (callback) {
|
|
callback();
|
|
});
|
|
}
|
|
|
|
function load(callback) {
|
|
if (loaded) {
|
|
callback();
|
|
return;
|
|
}
|
|
|
|
callbacks.push(callback);
|
|
if (loading) return;
|
|
|
|
loading = true;
|
|
try {
|
|
var defaults = {};
|
|
defaults[STORAGE_KEY] = memory;
|
|
getStorageArea().get(defaults, function (items) {
|
|
memory = normalizeRuntimeState(items && items[STORAGE_KEY]);
|
|
loaded = true;
|
|
loading = false;
|
|
flushCallbacks();
|
|
});
|
|
} catch (e) {
|
|
memory = normalizeRuntimeState(memory);
|
|
loaded = true;
|
|
loading = false;
|
|
flushCallbacks();
|
|
}
|
|
}
|
|
|
|
function save() {
|
|
if (!loaded) return;
|
|
|
|
try {
|
|
var payload = {};
|
|
payload[STORAGE_KEY] = normalizeRuntimeState(memory);
|
|
getStorageArea().set(payload);
|
|
} catch (e) {
|
|
// Runtime state is a convenience layer; redirect events can rebuild it.
|
|
}
|
|
}
|
|
|
|
function getLastMainFrameUrl(tabId, callback) {
|
|
load(function () {
|
|
callback(memory.lastMainFrameUrls[tabKey(tabId)] || '');
|
|
});
|
|
}
|
|
|
|
function setLastMainFrameUrl(tabId, url) {
|
|
load(function () {
|
|
memory.lastMainFrameUrls[tabKey(tabId)] = String(url || '');
|
|
save();
|
|
});
|
|
}
|
|
|
|
function getTabState(tabId, rule, sourceUrlObj, callback) {
|
|
load(function () {
|
|
var key = tabKey(tabId);
|
|
var path = S.getPath(sourceUrlObj);
|
|
var now = Date.now();
|
|
var oldState = normalizeTabState(memory.tabStates[key]);
|
|
|
|
if (
|
|
!oldState.startedAt ||
|
|
oldState.ruleId !== rule.id ||
|
|
oldState.path !== path ||
|
|
now - oldState.startedAt > 5 * 60 * 1000
|
|
) {
|
|
oldState = {
|
|
ruleId: rule.id,
|
|
path: path,
|
|
startedAt: now,
|
|
triedHosts: {},
|
|
redirects: 0,
|
|
lastRedirectFrom: '',
|
|
lastRedirectTo: '',
|
|
lastRedirectAt: 0,
|
|
lastTriggerUrl: '',
|
|
lastTriggerAt: 0
|
|
};
|
|
memory.tabStates[key] = oldState;
|
|
save();
|
|
} else {
|
|
memory.tabStates[key] = oldState;
|
|
}
|
|
|
|
callback(oldState);
|
|
});
|
|
}
|
|
|
|
function saveTabState(tabId, state) {
|
|
load(function () {
|
|
memory.tabStates[tabKey(tabId)] = normalizeTabState(state);
|
|
save();
|
|
});
|
|
}
|
|
|
|
function clearTab(tabId) {
|
|
load(function () {
|
|
delete memory.lastMainFrameUrls[tabKey(tabId)];
|
|
delete memory.tabStates[tabKey(tabId)];
|
|
save();
|
|
});
|
|
}
|
|
|
|
root.AutoMirrorRuntimeState = {
|
|
getLastMainFrameUrl: getLastMainFrameUrl,
|
|
setLastMainFrameUrl: setLastMainFrameUrl,
|
|
getTabState: getTabState,
|
|
saveTabState: saveTabState,
|
|
clearTab: clearTab
|
|
};
|
|
})(typeof globalThis !== 'undefined' ? globalThis : this);
|