Implement mobile connection resumes

This commit is contained in:
2022-08-27 02:59:38 +02:00
parent 426e120e21
commit 5fdf49555f
3 changed files with 89 additions and 9 deletions

View File

@ -29,6 +29,18 @@ export class App {
this.handleUrl(document.URL);
}
close() {
if (this.session) this.session.close();
}
sleep() {
if (this.session) this.session.sleep();
}
async wakeup() {
if (this.session) await this.session.wakeup();
}
setHash(hash: string) {
const url = new URL(document.URL);
url.hash = hash;
@ -244,8 +256,8 @@ export class App {
}
});
this.session.subscribe(response => {
this.addMessage(response.data.data.message);
this.session.subscribe(event => {
this.addMessage(event.data.message);
});
}
}

View File

@ -7,5 +7,32 @@ window.addEventListener("DOMContentLoaded", () => {
for (const noscript of document.getElementsByTagName("noscript")) {
noscript.remove();
}
new Locutus.App();
const locutus = new Locutus.App();
if (isMobilePlatform()) {
console.log("MOBILE");
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === 'hidden') {
locutus.sleep();
} else if (document.visibilityState === 'visible') {
locutus.wakeup().then();
}
});
} else {
console.log("DESKTOP");
window.addEventListener("beforeunload", (evt) => {
locutus.close();
});
}
});
function isMobilePlatform(): boolean {
if (window.matchMedia("(any-pointer:coarse)").matches) return true;
const ua = navigator.userAgent;
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {
return true;
} else if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {
return true;
}
return false;
}

View File

@ -30,6 +30,13 @@ interface OutputEnvelopeJson {
} | null,
}
interface EventJson {
data: {
message: string,
}
uuid: string,
}
interface WellKnownJson {
domain: DomainJson,
domain_servers: DomainServerJson[]
@ -149,6 +156,7 @@ export class Session {
websocket: WebSocket | null;
numRequests: number;
subscriptions: string[];
subscriptionEndpoints: {cb: (a: EventJson) => void}[];
constructor(domain: Domain) {
this.domain = domain;
@ -158,6 +166,28 @@ export class Session {
this.httpBaseUrl = null;
this.websocket = null;
this.subscriptions = [];
this.subscriptionEndpoints = [];
}
close() {
if (this.websocket && (this.websocket.readyState !== WebSocket.CLOSING && this.websocket.readyState !== WebSocket.CLOSED)) {
this.websocket.close();
this.subscriptions = [];
this.websocket = null;
this.server = null;
}
}
sleep() {
this.close();
}
async wakeup() {
await this.chooseDomainServer();
await this.ping();
for (const endpoint of this.subscriptionEndpoints) {
await this._subscribe(endpoint.cb);
}
}
async chooseDomainServer(): Promise<{ http: number | null, ws: number | null } | undefined> {
@ -289,7 +319,7 @@ export class Session {
responseData.duration = endTime - startTime;
return responseData;
} else {
return null; // TODO subscription id
return await this.waitForWebSocketResponse(req_nr, timeout);
}
} else if (this.httpBaseUrl) {
const controller = new AbortController();
@ -369,25 +399,36 @@ export class Session {
});
}
async subscribe(cb: (a: OutputEnvelopeJson) => void) {
async subscribe(cb: (a: EventJson) => void) {
this.subscriptionEndpoints.push({cb: cb});
await this._subscribe(cb);
}
private async _subscribe(cb: (a: EventJson) => void) {
this.numRequests++;
if (this.websocket !== null) {
let subscription = await this.send('subscribe', {}, 60_000, false, cb);
const subscription = await this.send('subscribe', {}, 60_000, false, (res) => {
if (res.data && res.data.events) {
for (const event of res.data.events) {
cb(event);
}
}
});
this.subscriptions.push(subscription);
return subscription;
} else {
this.send('subscribe', {}, 60_000).then((res) => {
if (res.status === "success") {
this.subscribe(cb);
this._subscribe(cb);
cb(res);
} else {
setTimeout(() => {
this.subscribe(cb);
this._subscribe(cb);
}, 1000);
}
}).catch(() => {
setTimeout(() => {
this.subscribe(cb);
this._subscribe(cb);
}, 1000);
});
return null; // TODO subscription id