Implement mobile connection resumes
This commit is contained in:
@ -29,6 +29,18 @@ export class App {
|
|||||||
this.handleUrl(document.URL);
|
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) {
|
setHash(hash: string) {
|
||||||
const url = new URL(document.URL);
|
const url = new URL(document.URL);
|
||||||
url.hash = hash;
|
url.hash = hash;
|
||||||
@ -244,8 +256,8 @@ export class App {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.session.subscribe(response => {
|
this.session.subscribe(event => {
|
||||||
this.addMessage(response.data.data.message);
|
this.addMessage(event.data.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
src/main.ts
29
src/main.ts
@ -7,5 +7,32 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||||||
for (const noscript of document.getElementsByTagName("noscript")) {
|
for (const noscript of document.getElementsByTagName("noscript")) {
|
||||||
noscript.remove();
|
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;
|
||||||
|
}
|
||||||
|
53
src/usimp.ts
53
src/usimp.ts
@ -30,6 +30,13 @@ interface OutputEnvelopeJson {
|
|||||||
} | null,
|
} | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EventJson {
|
||||||
|
data: {
|
||||||
|
message: string,
|
||||||
|
}
|
||||||
|
uuid: string,
|
||||||
|
}
|
||||||
|
|
||||||
interface WellKnownJson {
|
interface WellKnownJson {
|
||||||
domain: DomainJson,
|
domain: DomainJson,
|
||||||
domain_servers: DomainServerJson[]
|
domain_servers: DomainServerJson[]
|
||||||
@ -149,6 +156,7 @@ export class Session {
|
|||||||
websocket: WebSocket | null;
|
websocket: WebSocket | null;
|
||||||
numRequests: number;
|
numRequests: number;
|
||||||
subscriptions: string[];
|
subscriptions: string[];
|
||||||
|
subscriptionEndpoints: {cb: (a: EventJson) => void}[];
|
||||||
|
|
||||||
constructor(domain: Domain) {
|
constructor(domain: Domain) {
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
@ -158,6 +166,28 @@ export class Session {
|
|||||||
this.httpBaseUrl = null;
|
this.httpBaseUrl = null;
|
||||||
this.websocket = null;
|
this.websocket = null;
|
||||||
this.subscriptions = [];
|
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> {
|
async chooseDomainServer(): Promise<{ http: number | null, ws: number | null } | undefined> {
|
||||||
@ -289,7 +319,7 @@ export class Session {
|
|||||||
responseData.duration = endTime - startTime;
|
responseData.duration = endTime - startTime;
|
||||||
return responseData;
|
return responseData;
|
||||||
} else {
|
} else {
|
||||||
return null; // TODO subscription id
|
return await this.waitForWebSocketResponse(req_nr, timeout);
|
||||||
}
|
}
|
||||||
} else if (this.httpBaseUrl) {
|
} else if (this.httpBaseUrl) {
|
||||||
const controller = new AbortController();
|
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++;
|
this.numRequests++;
|
||||||
if (this.websocket !== null) {
|
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);
|
this.subscriptions.push(subscription);
|
||||||
return subscription;
|
return subscription;
|
||||||
} else {
|
} else {
|
||||||
this.send('subscribe', {}, 60_000).then((res) => {
|
this.send('subscribe', {}, 60_000).then((res) => {
|
||||||
if (res.status === "success") {
|
if (res.status === "success") {
|
||||||
this.subscribe(cb);
|
this._subscribe(cb);
|
||||||
cb(res);
|
cb(res);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.subscribe(cb);
|
this._subscribe(cb);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.subscribe(cb);
|
this._subscribe(cb);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
return null; // TODO subscription id
|
return null; // TODO subscription id
|
||||||
|
Reference in New Issue
Block a user