diff --git a/index.html b/index.html index 72d578b..2878283 100644 --- a/index.html +++ b/index.html @@ -234,7 +234,7 @@ async function handlePrimaryButtonClick() { let [file, buffer] = await filereader().catch(e => alert('(ERROR) ' + new String(e ?? 'Unable to read data'))); writable = await handle.createWritable().catch(() => null); - major = await Rpc2.invoke('ready', file.name, new Uint8Array(buffer).toBase64()); + major = await Rpc2.invoke('loads', { params: [file.name, new Uint8Array(buffer).toBase64()] }); $.get('#fileLabel').innerText = file.name; $.get('#fromLabel').innerText = parameters.account; $.all('.columns').forEach(e => e.dispatchEvent(new Event('change'))); @@ -268,7 +268,7 @@ async function handlePrimaryButtonClick() { options.start += $('#offset').valueAsNumber * $('#chunksize').valueAsNumber; } - await Rpc2.invoke('begin', options, parameters); + await Rpc2.invoke('begin', { params: [options, parameters] }); break; case 'RUNNING': await Rpc2.invoke('pause'); @@ -323,7 +323,7 @@ $.set('#nospam', 'change', (e) => { }); $.set('#region', 'change', async (e) => { - unique = await Rpc2.invoke('unique', e.target.value).catch(() => new Object()); + unique = await Rpc2.invoke('unique', { params: [e.target.value] }).catch(() => new Object()); $('#groupby').dispatchEvent(new Event('change')); }); @@ -402,7 +402,7 @@ for (let element of $.all('.params')) { } while (await new Promise(o => setTimeout(o, 1000, true))) { - let history = await Rpc2.invoke('history').catch(() => []); + let history = await Rpc2.invoke('logs').catch(() => []); let logs = Array.from(history); for (let record of logs) { @@ -433,7 +433,7 @@ while (await new Promise(o => setTimeout(o, 1000, true))) { case 'CLOSING': if (writable) try { $.all('#actions > button').forEach(e => e.disabled = true); - let data = await filereader().then(([_, b]) => Rpc2.invoke('merge', new Uint8Array(b).toBase64())); + let data = await filereader().then(([_, b]) => Rpc2.invoke('merge', { params: [new Uint8Array(b).toBase64()] })); await writable.write(Uint8Array.fromBase64(data)); await writable.close(); await Rpc2.notify('close'); @@ -464,6 +464,7 @@ while (await new Promise(o => setTimeout(o, 1000, true))) { let rate = done / uptime; let remaining = rate > 0 ? Math.floor((total - count) / rate) : 0; $('#remainingLabel').innerText = remaining > 0 ? `${Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en')} (${(rate * 60).toFixed(2)}/min)` : ''; + await Rpc2.notify('acknowledge'); break; case 'STANDBY': $('#send > span.text').innerText = 'Resume'; diff --git a/main.py b/main.py index 7c022be..192e37a 100644 --- a/main.py +++ b/main.py @@ -99,10 +99,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): return result - sp.set('begin', begin) - sp.set('pause', pause) - sp.set('resume', resume) - sp.set('unique', unique) + sp.add(begin, pause, resume, unique) sp.set('status', lambda: status.name) sp.set('uptime', lambda: timer.delta()) @@ -237,26 +234,29 @@ def main(driver: Chrome, logger = logging.getLogger('main')): cls.timer.clear() cls.timer.start() return True - + @classmethod def perform(cls): if cls.timer.delta() > parameters['timeout']: raise cls sleep(0.2); return True + class Acknowledge(Action): + @classmethod + def prepare(cls): + return status == Status.RUNNING + class Cancel(Action): @classmethod def prepare(cls): nonlocal status status = Status.RUNNING return True - + @classmethod def perform(cls): - nonlocal status - status = Status.READY driver.switch_to.window(driver.window_handles[0]) raise cls - + class Close(Action): @classmethod def prepare(cls): @@ -266,23 +266,16 @@ def main(driver: Chrome, logger = logging.getLogger('main')): @classmethod def prepare(cls): return True - + @classmethod def perform(cls): driver.switch_to.window(driver.current_window_handle) raise cls flow = ActionFlow() - flow.append(Wait) - flow.append(Timeout) - flow.append(Cancel) - flow.append(Close) - flow.append(Skip) - + flow.stage(Wait, Acknowledge, Timeout, Cancel, Close, Skip) + sp.add(pairs=[ (k.lower(), v) for k, v in flow ]) sp.set('actions', lambda: flow.capabilities()) - sp.set('cancel', lambda: flow.queue(Cancel)) - sp.set('close', lambda: flow.queue(Close)) - sp.set('skip', lambda: flow.queue(Skip)) def loads(name: str, b64: str): from base64 import b64decode @@ -307,7 +300,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): flow.allow(Cancel) status = Status.READY return limit - + def merge(b64: str): from base64 import b64decode, b64encode from openpyxl import load_workbook @@ -317,7 +310,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): index = headers.index(column.sent) buffer = BytesIO(data) target = load_workbook(buffer) - + for row in range(options.get('start'), limit + 1): c1 = wb.active.cell(row, index + 1) c2 = target.active.cell(row, index + 1) @@ -330,8 +323,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): result = b64encode(io.getbuffer()).decode('ascii') return result - sp.set('ready', loads) - sp.set('merge', merge) + sp.add(loads, merge) sp.set('progress', lambda: progress) def save(): @@ -382,10 +374,10 @@ def main(driver: Chrome, logger = logging.getLogger('main')): driver.switch_to.window(driver.window_handles[0]) continue except Exception as e: - logger.error('Error while loading data', exc_info=e) status = Status.IDLE + logger.error('Error while loading data', exc_info=e) continue - + index = 2 attempts = 0 tz = ZoneInfo(locale.timezone) @@ -439,8 +431,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): logger.debug('Unable to close off email compose windows', exc_info=e) break - flow.allow(Cancel) - flow.allow(Skip) + flow.allow(Skip, Cancel) flow.react(Wait) progress['email'] = str(email) logger.info('[%d/%d] Sending to %s', index-1, limit-1, email) @@ -522,7 +513,6 @@ def main(driver: Chrome, logger = logging.getLogger('main')): flow.react(Wait) click("div.io-ox-mail-compose-window button[data-action='send']") except Cancel: - status = Status.IDLE break except (Next, Skip) as e: progress[e.__class__.__name__.lower()] += 1 @@ -554,11 +544,21 @@ def main(driver: Chrome, logger = logging.getLogger('main')): status = Status.STANDBY continue + try: + logger.info('Waiting for client to acknowledge...') + flow.deter(Cancel, Skip, Wait) + flow.allow(Acknowledge) + flow.react(Timeout) + except Acknowledge: + pass + except Exception as e: + logger.error('RPC communication failed', exc_info=e) + sp.pop('exit')() + if options.get('writable'): try: logger.info('Saving document...') status = Status.CLOSING - flow.allow(Wait, False) flow.allow(Close) flow.react(Timeout) except Close: @@ -567,10 +567,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')): logger.warning('RPC communication failed', exc_info=e) save() - flow.allow(Timeout, False) - flow.allow(Close, False) - flow.allow(Cancel, False) - flow.allow(Skip, False) + flow.deter(Acknowledge, Timeout, Close) driver.switch_to.window(driver.window_handles[0]) status = Status.IDLE logger.info('Done') diff --git a/requirements.txt b/requirements.txt index 7983d71..c623624 100644 Binary files a/requirements.txt and b/requirements.txt differ