Skip to content

Commit 4a5e9ee

Browse files
committed
example/gm_run_exclusive.js
1 parent bbb083a commit 4a5e9ee

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

example/gm_run_exclusive.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// ==UserScript==
2+
// @name GM.runExclusive Demo
3+
// @namespace https://docs.scriptcat.org/
4+
// @version 0.1.0
5+
// @match https://example.com/*?runExclusive*
6+
// @grant GM.runExclusive
7+
// @grant GM.setValue
8+
// @grant GM.getValue
9+
// @run-at document-start
10+
// @allFrames
11+
// ==/UserScript==
12+
13+
(async function () {
14+
'use strict';
15+
16+
const delayMatch = location.href.match(/runExclusive(\d+)/);
17+
const timeDelay = delayMatch ? +delayMatch[1] : 0;
18+
const isWorker = !!timeDelay;
19+
20+
/* ---------- Shared UI helpers ---------- */
21+
const panel = document.createElement('div');
22+
Object.assign(panel.style, {
23+
position: 'fixed',
24+
top: '10px',
25+
right: '10px',
26+
background: '#1e1e1e',
27+
color: '#e0e0e0',
28+
padding: '14px',
29+
borderRadius: '8px',
30+
fontFamily: 'monospace',
31+
zIndex: 99999,
32+
maxWidth: '420px'
33+
});
34+
document.documentElement.appendChild(panel);
35+
36+
const logContainer = document.createElement('div');
37+
panel.appendChild(logContainer);
38+
39+
const getTimeWithMilliseconds = date => `${date.toLocaleTimeString('it-US')}.${date.getMilliseconds()}`;
40+
41+
const log = (msg, color = '#ccc') => {
42+
const line = document.createElement('div');
43+
line.textContent = `[${getTimeWithMilliseconds(new Date())}] ${msg}`;
44+
line.style.color = color;
45+
logContainer.appendChild(line);
46+
};
47+
48+
/* ======================================================
49+
MAIN PAGE (Controller)
50+
====================================================== */
51+
if (!isWorker) {
52+
panel.innerHTML = `
53+
<h3 style="margin-top:0">GM.runExclusive Demo</h3>
54+
<p>Pick worker durations (ms):</p>
55+
<input id="durations" value="1200,2400,3800"
56+
style="width:100%;margin-bottom:8px">
57+
<button id="run">Run Demo</button>
58+
<button id="reset">Reset Counters</button>
59+
<hr>
60+
<div id="iframeContainer"></div>
61+
`;
62+
63+
const iframeContainer = panel.querySelector('#iframeContainer');
64+
65+
panel.querySelector('#reset').onclick = async () => {
66+
await GM.setValue('mValue01', 0);
67+
await GM.setValue('order', 0);
68+
iframeContainer.innerHTML = '';
69+
log('Shared counters reset', '#ff0');
70+
};
71+
72+
panel.querySelector('#run').onclick = async () => {
73+
iframeContainer.innerHTML = '';
74+
await GM.setValue('mValue01', 0);
75+
await GM.setValue('order', 0);
76+
77+
const delays = panel
78+
.querySelector('#durations')
79+
.value.split(',')
80+
.map(v => +v.trim())
81+
.filter(Boolean);
82+
83+
log(`Launching workers: ${delays.join(', ')}`, '#0f0');
84+
85+
delays.forEach(delay => {
86+
const iframe = document.createElement('iframe');
87+
iframe.src = `${location.pathname}?runExclusive${delay}`;
88+
iframe.style.width = '100%';
89+
iframe.style.height = '220px';
90+
iframe.style.border = '1px solid #444';
91+
iframe.style.marginTop = '8px';
92+
iframeContainer.appendChild(iframe);
93+
});
94+
};
95+
96+
window.addEventListener('message', (e) => {
97+
if (e.data?.type !== 'close-worker') return;
98+
const iframes = iframeContainer.querySelectorAll('iframe');
99+
for (const iframe of iframes) {
100+
if (iframe.src.includes(`runExclusive${e.data.delay}`)) {
101+
iframe.remove();
102+
log(`Closed worker ${e.data.delay}ms`, '#ff9800');
103+
return;
104+
}
105+
}
106+
});
107+
108+
return;
109+
}
110+
111+
/* ======================================================
112+
WORKER IFRAME
113+
====================================================== */
114+
115+
const closeBtn = document.createElement('button');
116+
closeBtn.textContent = 'Close worker';
117+
Object.assign(closeBtn.style, {
118+
marginTop: '8px',
119+
padding: '4px 8px',
120+
cursor: 'pointer'
121+
});
122+
closeBtn.onclick = () => {
123+
window.parent.postMessage({ type: 'close-worker', delay: timeDelay }, '*');
124+
};
125+
panel.appendChild(closeBtn);
126+
127+
log(`Worker ${timeDelay}ms loaded`, '#fff');
128+
log('Waiting for exclusive lock…', '#0af');
129+
130+
const startWait = performance.now();
131+
132+
const result = await GM.runExclusive('demo-lock-key', async () => {
133+
const waited = Math.round(performance.now() - startWait);
134+
135+
const order = (await GM.getValue('order')) + 1;
136+
await GM.setValue('order', order);
137+
138+
log(`Lock acquired (#${order}, waited ${waited}ms)`, '#0f0');
139+
140+
const val = await GM.getValue('mValue01');
141+
await GM.setValue('mValue01', val + timeDelay);
142+
143+
log(`Working ${timeDelay}ms…`, '#ff0');
144+
await new Promise(r => setTimeout(r, timeDelay));
145+
146+
const final = await GM.getValue('mValue01');
147+
log(`Done. Shared value = ${final}`, '#f55');
148+
149+
return { order, waited, final };
150+
});
151+
152+
log(`Result: ${JSON.stringify(result)}`, '#fff');
153+
154+
})();

0 commit comments

Comments
 (0)