Merge pull request #2200 from tridactyl/fix_repeat

Fix #1538: synchronise repeat between tabs and bg
This commit is contained in:
Oliver Blanthorn 2020-03-02 15:30:55 +00:00 committed by GitHub
commit 09f6831b0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 16 deletions

View file

@ -33,6 +33,7 @@ import * as locks from "@src/lib/locks"
excmds: excmds_background,
convert,
config,
controller,
dom,
download_background,
itertools,

View file

@ -149,6 +149,7 @@ import * as locks from "@src/lib/locks"
commandline_content,
convert,
config,
controller,
dom,
editor,
excmds,

View file

@ -2749,7 +2749,7 @@ async function getnexttabs(tabid: number, n?: number) {
*/
//#both
export async function repeat(n = 1, ...exstr: string[]) {
let cmd = controller.last_ex_str
let cmd = state.last_ex_str
if (exstr.length > 0) cmd = exstr.join(" ")
logger.debug("repeating " + cmd + " " + n + " times")
for (let i = 0; i < n; i++) {

View file

@ -785,6 +785,7 @@ export class default_config {
performance: "warning",
state: "warning",
styling: "warning",
locks: "warning",
}
/**

View file

@ -1,5 +1,6 @@
import Logger from "@src/lib/logging"
import { parser as exmode_parser } from "@src/parsers/exmode"
import state from "@src/state"
const logger = new Logger("controller")
@ -8,15 +9,13 @@ export function setExCmds(excmds: any) {
stored_excmds = excmds
}
export let last_ex_str = ""
/** Parse and execute ExCmds */
export async function acceptExCmd(exstr: string): Promise<any> {
// TODO: Errors should go to CommandLine.
try {
const [func, args] = exmode_parser(exstr, stored_excmds)
// Stop the repeat excmd from recursing.
if (func !== stored_excmds[""].repeat) last_ex_str = exstr
if (func !== stored_excmds[""].repeat) state.last_ex_str = exstr
try {
return await func(...args)
} catch (e) {

View file

@ -2,6 +2,9 @@
import {messageAllTabs} from "@src/lib/messaging"
import {v1 as uuid} from "uuid"
import * as Logging from "@src/lib/logging"
const logger = new Logging.Logger("locks")
export const OWNED_LOCKS = new Set()
@ -11,21 +14,49 @@ export const ID = uuid()
const now = () => (new Date()).getTime() + Math.random() // getTime is accurate only to ms, so fake microseconds with random
export async function acquire(lockname: string) {
export async function acquire(lockname: string, timeout = 2000) {
if (OWNED_LOCKS.has(lockname) || DESIRED_LOCKS.hasOwnProperty(lockname)) return;
const time = now()
DESIRED_LOCKS[lockname] = time
await Promise.all([
browser.runtime.sendMessage({type: "lock", command: "acquire", args: [lockname, time, ID]}),
messageAllTabs("lock", "acquire", [lockname, time, ID])]
)
const a = await Promise.race([
Promise.all([
browser.runtime.sendMessage({type: "lock", command: "acquire", args: [lockname, time, ID]}),
messageAllTabs("lock", "acquire", [lockname, time, ID]),
]),
new Promise(resolve => setTimeout(
() => {
resolve("ERROR: LOST THE RACE")
},
timeout)), // Take the lock anyway after timeout
])
if (a === "ERROR: LOST THE RACE") {logger.warning("lock " + lockname + " was taken without confirmation")}
delete DESIRED_LOCKS[lockname]
OWNED_LOCKS.add(lockname)
}
/**
* Execute func after acquiring a named lock. If func takes longer than timeout, release the lock early.
* Returns the value of func.
*/
export async function withlock(lockname: string, func, timeout = 500) {
await acquire(lockname)
const p = (async () => func())() // Ensure function is promisified
const a = await Promise.race([
p,
new Promise(resolve => setTimeout(
() => {
resolve("ERROR: LOST THE RACE")
},
timeout)), // Release the lock anyway after timeout
])
if (a === "ERROR: LOST THE RACE") {logger.warning("lock " + lockname + " was released early")}
release(lockname)
return p
}
export async function release(lockname: string) {
OWNED_LOCKS.delete(lockname)
}

View file

@ -29,6 +29,7 @@ class State {
jumppos: undefined,
},
]
last_ex_str: string = "echo"
}
// Don't change these from const or you risk breaking the Proxy below.
@ -57,9 +58,7 @@ const state = (new Proxy(overlay, {
/** Persist sets to storage "immediately" */
set(target, property, value) {
(async () => {
await locks.acquire("state")
locks.withlock("state", async () => {
logger.debug("State changed!", property, value)
target[property] = value
browser.storage.local.set({ state: target } as any)
@ -73,10 +72,7 @@ const state = (new Proxy(overlay, {
// I haven't had time to get my head around them
browser.runtime.sendMessage({type: "state", command: "stateUpdate", args: [{state: target}]}),
])
// Release named lock
locks.release("state")
})()
})
return true
},