HelloSun commited on
Commit
ea0bac9
·
verified ·
1 Parent(s): c59a319

CheerpX + Alpine x86_64 + opencode

Browse files
Files changed (4) hide show
  1. .gitattributes +1 -0
  2. index.html +50 -18
  3. rootfs.ext2 +3 -0
  4. sw.js +96 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ rootfs.ext2 filter=lfs diff=lfs merge=lfs -text
index.html CHANGED
@@ -1,19 +1,51 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <!doctype html>
2
+ <html><head><meta charset="utf-8"><title>opencode web</title>
3
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css">
4
+ <style>html,body{margin:0;height:100%;background:#000}#console{height:100%}</style>
5
+ </head><body><div id="console"></div>
6
+ <script>
7
+ // Cross-origin isolation (needed by CheerpX) via service worker, since static hosting cannot set headers.
8
+ if ("serviceWorker" in navigator && !crossOriginIsolated) {
9
+ navigator.serviceWorker.register("sw.js").then(reg => {
10
+ if (reg.active && navigator.serviceWorker.controller) return;
11
+ navigator.serviceWorker.addEventListener("controllerchange", () => location.reload());
12
+ if (reg.active) location.reload();
13
+ });
14
+ }
15
+ </script>
16
+ <script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.js"></script>
17
+ <script type="module">
18
+ const CX_URL = "https://cxrtnc.leaningtech.com/1.4.0/cx.esm.js";
19
+ const term = new Terminal({ cursorBlink: true, convertEol: true, fontFamily: "monospace" });
20
+ term.open(document.getElementById("console"));
21
+ term.focus();
22
+ term.write("opencode web: loading CheerpX + Alpine...\r\n");
23
+ try {
24
+ if (!crossOriginIsolated) throw new Error("page is not cross-origin isolated yet (service worker reload pending)");
25
+ const CheerpX = await import(CX_URL);
26
+ const blockDevice = await CheerpX.HttpBytesDevice.create("rootfs.ext2");
27
+ const cache = await CheerpX.IDBDevice.create("opencode-web-v1");
28
+ const overlay = await CheerpX.OverlayDevice.create(blockDevice, cache);
29
+ const webDevice = await CheerpX.WebDevice.create("");
30
+ const dataDevice = await CheerpX.DataDevice.create();
31
+ const cx = await CheerpX.Linux.create({ mounts: [
32
+ { type: "ext2", dev: overlay, path: "/" },
33
+ { type: "dir", dev: webDevice, path: "/web" },
34
+ { type: "dir", dev: dataDevice, path: "/data" },
35
+ { type: "devs", path: "/dev" },
36
+ { type: "devpts", path: "/dev/pts" },
37
+ { type: "proc", path: "/proc" },
38
+ { type: "sys", path: "/sys" },
39
+ ] });
40
+ const readFn = cx.setCustomConsole((buf, vt) => { if (vt === 1) term.write(new Uint8Array(buf)); }, term.cols, term.rows);
41
+ term.onData(s => { for (let i = 0; i < s.length; i++) readFn(s.charCodeAt(i)); });
42
+ await cx.run("/bin/sh", ["-c", "opencode; exec /bin/sh -l"], {
43
+ env: ["HOME=/root", "TERM=xterm-256color", "PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin", "LANG=C.UTF-8"],
44
+ cwd: "/root", uid: 0, gid: 0,
45
+ });
46
+ } catch (e) {
47
+ term.write("\r\nERROR: " + e + "\r\n");
48
+ console.error(e);
49
+ }
50
+ </script>
51
+ </body></html>
rootfs.ext2 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3f7eb81ae52e5b19cc21c569ccae3d43491075494a350fe48fb78972d58893b7
3
+ size 662700032
sw.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function handleFetch(request) {
2
+ // Perform the original fetch request and store the result in order to modify the response.
3
+ try {
4
+ var r = await fetch(request);
5
+ }
6
+ catch (e) {
7
+ console.error(e)
8
+ }
9
+ if (r.status === 0) {
10
+ return r;
11
+ }
12
+ // We add headers to the original response its headers, in order to enable cross-origin-isolation. And make it independent of the server config.
13
+ const newHeaders = new Headers(r.headers);
14
+ // COEP & COOP for cross-origin-isolation.
15
+ newHeaders.set("Cross-Origin-Embedder-Policy", "require-corp");
16
+ newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
17
+ newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
18
+ /**
19
+ * This workaround is necessary due to a limitation of CheerpOS, which relies on the response URL being set to the resolved URL.
20
+ * When constructing a new response object, the URL is not set by the Response() constructor and the serviceworker respondwith() method will set the url to event.request.url in case of an empty string.
21
+ * To address this, we set the location URL to the resolved response URL and set the status code to 301 in the new Response object.
22
+ * This causes the request to bounce back to the serviceworker from Cheerpos, with the event.request.url now set to the resolved URL, which allows the respondWith method to properly set the response URL in our new response.
23
+ * https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith.
24
+ */
25
+ if (r.redirected === true)
26
+ newHeaders.set("location", r.url);
27
+ // In case of a redirection, we set the status to 301, and body to null, in order to not transfer too much data needlessly
28
+ const moddedResponse = new Response(r.redirected === true ? null : r.body, {
29
+ headers: newHeaders,
30
+ status: r.redirected === true ? 301 : r.status,
31
+ statusText: r.statusText,
32
+ });
33
+ return moddedResponse;
34
+ }
35
+
36
+ function serviceWorkerInit() {
37
+ // Init the service worker.
38
+ self.addEventListener("install", () => self.skipWaiting());
39
+ self.addEventListener("activate", e => e.waitUntil(self.clients.claim()));
40
+ // Listen for fetch requests and call handleFetch function.
41
+ self.addEventListener("fetch", function (e) {
42
+ try {
43
+ e.respondWith(handleFetch(e.request));
44
+ } catch (err) {
45
+ console.log("Serviceworker NetworkError:" + err);
46
+ }
47
+ });
48
+ }
49
+
50
+ async function doRegister() {
51
+ try {
52
+ const registration = await navigator.serviceWorker.register(window.document.currentScript.src);
53
+ console.log("Service Worker registered", registration.scope);
54
+ // EventListener to make sure that the page gets reloaded when a new serviceworker gets installed.
55
+ // f.e on first access.
56
+ registration.addEventListener("updatefound", () => {
57
+ console.log("Reloading the page to transfer control to the Service Worker.");
58
+ try {
59
+ window.location.reload();
60
+ } catch (err) {
61
+ console.log("Service Worker failed reloading the page. ERROR:" + err);
62
+ };
63
+ });
64
+ // When the registration is active, but it's not controlling the page, we reload the page to have it take control.
65
+ // This f.e occurs when you hard-reload (shift + refresh). https://www.w3.org/TR/service-workers/#navigator-service-worker-controller
66
+ if (registration.active && !navigator.serviceWorker.controller) {
67
+ console.log("Reloading the page to transfer control to the Service Worker.");
68
+ try {
69
+ window.location.reload();
70
+ } catch (err) {
71
+ console.log("Service Worker failed reloading the page. ERROR:" + err);
72
+ };
73
+ }
74
+ }
75
+ catch {
76
+ console.error("Service Worker failed to register:", e)
77
+ }
78
+ }
79
+
80
+ async function serviceWorkerRegister() {
81
+ if (window.crossOriginIsolated) return;
82
+ if (!window.isSecureContext) {
83
+ console.log("Service Worker not registered, a secure context is required.");
84
+ return;
85
+ }
86
+ // Register the service worker and reload the page to transfer control to the serviceworker.
87
+ if ("serviceWorker" in navigator)
88
+ await doRegister();
89
+ else
90
+ console.log("Service worker is not supported in this browser");
91
+ }
92
+
93
+ if (typeof window === 'undefined') // If the script is running in a Service Worker context
94
+ serviceWorkerInit()
95
+ else // If the script is running in the browser context
96
+ serviceWorkerRegister();