forked from
tokono.ma/diffuse
A music player that connects to your cloud/distributed storage.
1import type { App } from "./elm/types"
2
3
4/**
5 * Load:
6 *
7 * 1. Redirect to HTTPS if using the `diffuse.sh` domain (subdomains included).
8 * 2. Fail if not a secure context.
9 * 3. Set up service worker, ensure it's ready and then continue initialisation.
10 */
11export async function load({ isNativeWrapper } : { isNativeWrapper: boolean }): Promise<ServiceWorkerRegistration> {
12 return new Promise((resolve, reject) => {
13 if (location.hostname.endsWith("diffuse.sh") && location.protocol === "http:") {
14 location.href = location.href.replace("http://", "https://")
15 reject("Just a moment, redirecting to HTTPS.")
16
17 } else if (!self.isSecureContext) {
18 reject(`
19 This app only works on a <a class="underline" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#When_is_a_context_considered_secure">secure context</a>, HTTPS & localhost, and modern browsers.
20 `)
21
22 } else if ("serviceWorker" in navigator) {
23 // Service worker
24 window.addEventListener("load", () => {
25 navigator.serviceWorker
26 .getRegistrations()
27 .then(async registrations => {
28 const serverIsOnline = navigator.onLine && await fetch(`${location.origin}?ping=1`)
29 .then(r => r.text())
30 .then(a => a === "false" ? false : true)
31
32 if (isNativeWrapper) await Promise.all(
33 registrations.map(r => r.unregister())
34 )
35
36 if (serverIsOnline) return navigator.serviceWorker.register(
37 "service-worker.js",
38 // { type: "module" }
39 )
40
41 if (registrations[0]) return registrations
42
43 throw new Error("Web server is offline")
44 })
45 .then(() => navigator.serviceWorker.ready)
46 .then(resolve)
47 .catch(err => {
48 const isFirefox = navigator.userAgent.toLowerCase().includes("firefox")
49
50 console.error(err)
51 return reject(
52 location.protocol === "https:" || location.hostname === "localhost"
53 ? "Failed to start the service worker." + (isFirefox ? " Make sure the setting <strong>Delete cookies and site data when Firefox is closed</strong> is off, or Diffuse's domain is added as an exception." : "")
54 : "Failed to start the service worker, try using HTTPS."
55 )
56 })
57 })
58
59 }
60 })
61}
62
63
64/**
65 * Link.
66 */
67export function link(
68 { app, isNativeWrapper, reg } : { app: App, isNativeWrapper: boolean, reg: ServiceWorkerRegistration }
69) {
70 if (reg.installing) console.log("🧑✈️ Service worker is installing")
71 const initialInstall = reg.installing
72
73 initialInstall?.addEventListener("statechange", function() {
74 if (this.state === "activated") {
75 console.log("🧑✈️ Service worker is activated")
76 app.ports.installedNewServiceWorker.send(null)
77 }
78 })
79
80 if (reg.waiting) {
81 console.log("🧑✈️ A new version of Diffuse is available")
82 app.ports.installingNewServiceWorker.send(null)
83 app.ports.installedNewServiceWorker.send(null)
84 }
85
86 if (initialInstall?.state === "activated") {
87 console.log("🧑✈️ Service worker is activated")
88 app.ports.installedNewServiceWorker.send(null)
89 }
90
91 reg.addEventListener("updatefound", () => {
92 const newWorker = reg.installing
93 if (!newWorker) return
94
95 // No worker was installed yet, so we'll only want to track the state changes
96 if (newWorker !== initialInstall) {
97 console.log("🧑✈️ A new version of Diffuse is available")
98 app.ports.installingNewServiceWorker.send(null)
99 }
100
101 newWorker.addEventListener("statechange", (e: any) => {
102 console.log("🧑✈️ Service worker is", e.target.state)
103 if (e.target.state === "installed") app.ports.installedNewServiceWorker.send(null)
104 })
105 })
106
107 // Check for service worker updates and every hour after that
108 if (!isNativeWrapper && navigator.onLine) {
109 reg.update()
110 setInterval(() => reg.update(), 1 * 1000 * 60 * 60)
111 }
112}