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