-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwc-layer-install.js
More file actions
62 lines (60 loc) · 2.64 KB
/
wc-layer-install.js
File metadata and controls
62 lines (60 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
async function extractBinaryFromTgz(url, binaryName) {
const r = await fetch(url)
if (!r.ok) throw new Error('fetch failed: ' + url + ' ' + r.status)
const ds = new DecompressionStream('gzip')
const reader = r.body.pipeThrough(ds).getReader()
let pending = new Uint8Array(0)
function concat(a, b) { const c = new Uint8Array(a.length + b.length); c.set(a); c.set(b, a.length); return c }
while (true) {
const { done, value } = await reader.read()
if (value) pending = concat(pending, value)
let off = 0
while (pending.length - off >= 512) {
const hdr = pending.slice(off, off + 512)
const name = new TextDecoder().decode(hdr.slice(0, 100)).replace(/\0/g, '').trim()
if (!name) { off += 512; continue }
const szOct = new TextDecoder().decode(hdr.slice(124, 136)).replace(/\0/g, '').trim()
const sz = parseInt(szOct, 8) || 0
const blocks = Math.ceil(sz / 512) * 512
if (pending.length - off < 512 + blocks) break
const baseName = name.split('/').pop()
if (baseName === binaryName && sz > 0) return pending.slice(off + 512, off + 512 + sz)
off += 512 + blocks
}
if (off > 0) pending = pending.slice(off)
if (done) break
}
throw new Error('binary not found in tgz: ' + binaryName)
}
async function writeToOpfs(dirHandle, name, bytes) {
const fh = await dirHandle.getFileHandle(name, {create:true})
const w = await fh.createWritable()
await w.write(bytes)
await w.close()
}
export async function installLayerBinaries(layerIds) {
if (!layerIds || !layerIds.length) return { mounts: [], extraPaths: [] }
const r = await fetch('./containers/layers.json')
if (!r.ok) throw new Error('layers.json fetch failed: ' + r.status)
const all = await r.json()
const root = await navigator.storage.getDirectory()
const homeRoot = await root.getDirectoryHandle('home', {create:true})
.then(h => h.getDirectoryHandle('root', {create:true}))
const localDir = await homeRoot.getDirectoryHandle('.local', {create:true})
const binHandle = await localDir.getDirectoryHandle('bin', {create:true})
const extraEnv = []
for (const id of layerIds) {
const layer = all.find(l => l.id === id)
if (!layer) continue
if (layer.binaryUrl && layer.binaryName) {
let exists = false
try { await binHandle.getFileHandle(layer.binaryName); exists = true } catch(e) {}
if (!exists) {
const bytes = await extractBinaryFromTgz(layer.binaryUrl, layer.binaryName)
await writeToOpfs(binHandle, layer.binaryName, bytes)
}
}
if (layer.extraEnv) extraEnv.push(...layer.extraEnv)
}
return { mounts: [], extraPaths: ['/root/.local/bin'], extraEnv }
}