fix: task slicing limit calculation

This commit is contained in:
2026-06-05 16:48:24 +08:00
parent a4d47d8b85
commit 789f341aeb
3 changed files with 35 additions and 49 deletions
+21 -23
View File
@@ -173,11 +173,11 @@
<div class="inline-flex">
<div class="pure-u-1-2">
<label for="offset">Offset</label>
<input id="offset" class="slicing local-only pure-u-23-24" type="number" min="0" disabled/>
<input id="offset" class="slicing local-only pure-u-23-24" type="number" min="0" value="0" disabled/>
</div>
<div class="pure-u-1-2">
<label for="limit">Max. (limit)</label>
<input id="limit" class="slicing local-only pure-u-23-24" type="number" readonly disabled/>
<input id="limit" class="slicing local-only pure-u-23-24" type="number" min="0" value="0" readonly disabled/>
</div>
</div>
</div>
@@ -188,8 +188,8 @@
<script type="module">
import { default as $, LogRecord, Rpc2 } from '/';
let limit = 0;
let length = 0;
let major = 0;
let minor = 0;
let busy = false;
let status = null;
let locale = null;
@@ -199,7 +199,7 @@ let filereader = null;
let subcategories = [];
window.addEventListener('beforeunload', (e) => {
writable?.abort().catch(() => void 0);
writable?.abort();
Rpc2.notify('exit');
e.preventDefault();
e.returnValue = '';
@@ -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);
limit = await Rpc2.invoke('ready', file.name, new Uint8Array(buffer).toBase64());
major = await Rpc2.invoke('ready', 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')));
@@ -265,7 +265,7 @@ async function handlePrimaryButtonClick() {
if (options.slice) {
options.start = $('#offset').valueAsNumber * $('#chunksize').valueAsNumber + 2;
options.limit = length;
options.limit = Math.min(minor || major, $('#chunksize').valueAsNumber);
options.subcategories = subcategories.length > 0 ? subcategories: null;
}
@@ -374,26 +374,19 @@ $.set('#groupby', 'change', (e) => {
$.set('#subcategory', 'change', (e) => {
if (!unique) return;
subcategories = Array.from(e.target.options).filter(o => o.selected).map(o => o.value);
length = Object.entries(unique).filter(([k]) => subcategories.includes(k)).reduce((o, [_, v]) => o + v, 0);
minor = Object.entries(unique).filter(([k]) => subcategories.includes(k)).reduce((o, [_, v]) => o + v, 0);
$('#chunksize').dispatchEvent(new Event('change'));
});
$.set('#chunksize', 'change', (e) => {
let n = length || limit;
let size = Math.floor(n / e.target.valueAsNumber);
$('#limit').value = size;
$('#offset').max = size;
let limit = minor || major - 1;
let value = Math.floor(limit / e.target.valueAsNumber);
$('#limit').value = value;
$('#offset').max = value;
$('#offset').value = 0;
$('#offset').dispatchEvent(new Event('change'));
});
$.set('#offset', 'change', (e) => {
let n = length || limit;
let size = $('#chunksize').valueAsNumber;
let offset = n - size * e.target.valueAsNumber;
length = Math.min(size, offset);
});
for (let item of Array.from(locales)) {
$('#locale').add(new Option(item.name.toUpperCase(), item.name));
$('#locale').dispatchEvent(new Event('change'));
@@ -455,16 +448,21 @@ while (await new Promise(o => setTimeout(o, 1000, true))) {
$('#send').classList.add('pulse');
$('#timezoneLabel').innerText = Temporal.Now.zonedDateTimeISO(locale.timezone).toLocaleString(locale.name);
let { done, email, subject, recipient } = await Rpc2.invoke('progress').catch(() => new Object());
$('#progressLabel').innerText = `${parseFloat(done / (length || limit) * 100).toFixed(2)}% (${done}/${length || limit})`
let { done, skip, email, subject, recipient } = await Rpc2.invoke('progress').catch(() => new Object());
let index = done + skip;
let limit = minor || major - 1;
let chunk = $('#chunksize').valueAsNumber;
let total = $('#slice').checked ? Math.min(chunk, limit - chunk * $('#offset').valueAsNumber) : limit;
$('#progressLabel').innerText = `${parseFloat(index / total * 100).toFixed(2)}% (${index}/${total})`
$('#subjectLabel').innerText = subject ?? '';
$('#recipientLabel').innerText = recipient ? `${recipient} <${email}>` : email ?? '';
let uptime = await Rpc2.invoke('uptime').catch(() => 0);
$('#uptimeLabel').innerText = Temporal.Duration.from({ seconds: uptime }).round({ largestUnit: 'hours' }).toLocaleString('en', { style: 'digital' });
let rate = done / uptime
let remaining = done ? Math.floor(((length || limit) - done) / rate) : 0;
let rate = index / uptime
let remaining = index ? Math.floor((total - index) / rate) : 0;
$('#remainingLabel').innerText = remaining ? `${Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en')} (${rate.toFixed(2)}/min)` : '';
break;
case 'STANDBY':
+14 -26
View File
@@ -283,9 +283,9 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
flow.append(Skip)
sp.set('actions', lambda: flow.capabilities())
sp.set('cancel', lambda: flow.do(Cancel, force=True))
sp.set('close', lambda: flow.do(Close, force=True))
sp.set('skip', lambda: flow.do(Skip, force=True))
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
@@ -353,9 +353,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
while True:
try:
flow.allow(Wait)
flow.do(Wait)
flow.react()
flow.react(Wait)
progress.clear()
driver.switch_to.window(driver.window_handles[1])
subject = get_subject()
@@ -377,16 +375,13 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
logger.info('Timezone: %s', locale.timezone)
progress['done'] = 0
progress['skip'] = 0
progress['subject'] = subject
logger.info('Done')
except Cancel:
status = Status.IDLE
driver.switch_to.window(driver.window_handles[0])
continue
except StopIteration:
logger.error('Invalid locale: %s', options.get('locale'))
status = Status.IDLE
continue
except Exception as e:
logger.error('Error while loading data', exc_info=e)
status = Status.IDLE
@@ -399,8 +394,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
while index <= limit:
try:
flow.do(Wait)
flow.react()
flow.react(Wait)
attempts += 1
name = cell(index, column.recipient).value
email = cell(index, column.email).value
@@ -447,8 +441,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
flow.allow(Cancel)
flow.allow(Skip)
flow.do(Wait)
flow.react()
flow.react(Wait)
progress['email'] = str(email)
progress['recipient'] = str(name)
logger.info('[%d/%d] Sending to %s', index-1, limit-1, email)
@@ -464,8 +457,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
if error is not None and not options.get('force'):
raise error
flow.do(Wait)
flow.react()
flow.react(Wait)
click("ul.classic-toolbar button[aria-label='Edit copy']")
until(ready)
locate("div.io-ox-mail-compose-window iframe", condition=EC.frame_to_be_available_and_switch_to_it)
@@ -495,8 +487,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
clean = target.text == hello
driver.switch_to.default_content()
flow.do(Wait)
flow.react()
flow.react(Wait)
click("div.io-ox-mail-compose-window div[data-extension-id='to'] > div.mail-input")
box = locate("div.io-ox-mail-compose-window div[data-extension-id='to'] > div.mail-input input.token-input.tt-input[tabindex='0']")
box.send_keys(str(email) + Keys.ENTER)
@@ -514,8 +505,7 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
target.send_keys(template)
clean = target.get_attribute('value') == template
flow.do(Wait)
flow.react()
flow.react(Wait)
box = locate("div.io-ox-mail-compose-window .mail-input .tokenfield .token")
recipient = box.get_attribute('innerText').strip()
@@ -527,10 +517,10 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
logger.warning('Malformed email content detected; retrying (%d)...', attempts)
continue
flow.do(Wait)
flow.react()
flow.react(Wait)
click("div.io-ox-mail-compose-window button[data-action='send']")
except Skip:
progress['skip'] += 1
index += 1
attempts = 0
continue
@@ -566,13 +556,11 @@ def main(driver: Chrome, logger = logging.getLogger('main')):
if options.get('writable'):
try:
logger.info('Saving document...')
status = Status.CLOSING
flow.allow(Wait, False)
flow.allow(Timeout)
flow.allow(Close)
logger.info('Saving document...')
flow.do(Timeout, force=True)
flow.react()
flow.react(Timeout)
except Close:
pass
except Exception as e:
BIN
View File
Binary file not shown.