generated from Labyricorn/labyricorn-project-template
Step 5 Complete
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { ProtocolError } from './validation.js';
|
||||
|
||||
export function exhibitURL(value, base) {
|
||||
if (!value.trim()) throw new Error('Enter an exhibit URL or served path.');
|
||||
const url = new URL(value.trim(), base);
|
||||
if (!['http:', 'https:'].includes(url.protocol) || url.origin !== new URL(base).origin || url.username || url.password) {
|
||||
throw new Error('Enter a same-origin HTTP exhibit URL or served path.');
|
||||
}
|
||||
return url.href;
|
||||
}
|
||||
|
||||
// Frame lifecycle only; protocol negotiation remains in ExhibitHost.
|
||||
export class ExhibitConnection {
|
||||
constructor({ host, createFrame, transport, base, changed = () => {}, loadTimeoutMs = 15000 }) {
|
||||
Object.assign(this, { host, createFrame, transport, base, changed, loadTimeoutMs });
|
||||
this.frame = null; this.url = ''; this.loading = false; this.generation = 0;
|
||||
}
|
||||
disconnect() {
|
||||
this.generation++; clearTimeout(this.timer); this.loading = false;
|
||||
this.frame?.remove(); this.frame = null; this.host.disconnect(); this.changed();
|
||||
}
|
||||
load(value) {
|
||||
const url = exhibitURL(value, this.base); // Invalid input preserves the active exhibit.
|
||||
this.disconnect(); this.url = url; this.loading = true;
|
||||
const generation = this.generation;
|
||||
const frame = this.createFrame(); this.frame = frame;
|
||||
frame.addEventListener('load', () => {
|
||||
if (generation !== this.generation) return;
|
||||
clearTimeout(this.timer); this.loading = false; this.attach();
|
||||
});
|
||||
this.timer = setTimeout(() => {
|
||||
if (generation !== this.generation) return;
|
||||
this.disconnect();
|
||||
this.host.report(new ProtocolError('LOAD_TIMEOUT', 'Exhibit did not finish loading. Check the served path and reconnect.'));
|
||||
}, this.loadTimeoutMs);
|
||||
frame.src = url; this.changed();
|
||||
}
|
||||
async attach() {
|
||||
if (!this.frame || this.loading) return;
|
||||
const generation = this.generation;
|
||||
try { await this.host.connect(this.transport(this.frame)); }
|
||||
catch (error) { if (generation === this.generation && !error.code) this.host.report(error); }
|
||||
this.changed();
|
||||
}
|
||||
reconnect() {
|
||||
if (this.frame && !this.loading) return this.attach();
|
||||
if (this.url) this.load(this.url);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user