A music player that connects to your cloud/distributed storage.
at main 4.0 kB view raw
1// 2// User 3// (づ。◕‿‿◕。)づ 4// 5// Related to the user layer. 6 7 8// @ts-ignore 9import * as TaskPort from "elm-taskport" 10 11import type { App } from "./elm/types" 12 13import * as crypto from "../crypto" 14 15import { decryptIfNeeded, encryptIfPossible, SECRET_KEY_LOCATION } from "./common" 16import { parseJsonIfNeeded, toCache } from "./common" 17 18 19const ports: Record<string, any> = {} 20const taskPorts: Record<string, any> = {} 21 22 23// Crypto 24// ====== 25 26taskPorts.fabricateSecretKey = async passphrase => { 27 const data = await crypto.keyFromPassphrase(passphrase) 28 return toCache(SECRET_KEY_LOCATION, data) 29} 30 31 32 33// Dropbox 34// ------- 35 36taskPorts.fromDropbox = ({ fileName, token }) => { 37 return fetch("https://content.dropboxapi.com/2/files/download", { 38 method: "POST", 39 headers: { 40 "Authorization": "Bearer " + token, 41 "Dropbox-API-Arg": JSON.stringify({ path: "/" + fileName }) 42 } 43 }) 44 .then(r => r.ok ? r.text() : r.json()) 45 .then(r => r.error ? null : r) 46 .then(decryptIfNeeded) 47 .then(parseJsonIfNeeded) 48} 49 50 51taskPorts.toDropbox = async ({ fileName, data, token }) => { 52 const json = JSON.stringify(data) 53 const params = { 54 path: "/" + fileName, 55 mode: "overwrite", 56 mute: true 57 } 58 59 return fetch("https://content.dropboxapi.com/2/files/upload", { 60 method: "POST", 61 headers: { 62 "Authorization": "Bearer " + token, 63 "Content-Type": "application/octet-stream", 64 "Dropbox-API-Arg": JSON.stringify(params) 65 }, 66 body: await encryptIfPossible(json) 67 }) 68} 69 70 71 72// IPFS 73// ---- 74 75const IPFS_ROOT = "/Applications/Diffuse/" 76 77 78taskPorts.fromIpfs = ({ apiOrigin, fileName }) => { 79 const path = IPFS_ROOT + fileName 80 81 return fetch(apiOrigin + "/api/v0/files/read?arg=" + encodeURIComponent(path), { method: "POST" }) 82 .then(r => r.ok ? r.text() : r.json()) 83 .then(r => r.Code === 0 ? null : r) 84 .then(decryptIfNeeded) 85 .then(parseJsonIfNeeded) 86} 87 88 89taskPorts.toIpfs = ({ apiOrigin, fileName, data }) => { 90 const json = JSON.stringify(data) 91 const params = new URLSearchParams({ 92 arg: IPFS_ROOT + fileName, 93 create: "true", 94 offset: "0", 95 parents: "true", 96 truncate: "true" 97 }).toString() 98 99 return encryptIfPossible(json).then(possiblyEncryptedData => { 100 const formData = new FormData() 101 102 formData.append("data", possiblyEncryptedData) 103 104 return fetch( 105 apiOrigin + "/api/v0/files/write?" + params, 106 { method: "POST", body: formData } 107 ) 108 }) 109} 110 111 112 113// Remote Storage 114// -------------- 115 116let rs 117let rsClient 118 119 120async function remoteStorage(userAddress: string, token: string) { 121 if (!rs) { 122 const { default: RemoteStorage } = await import("remotestoragejs") 123 124 rs = new RemoteStorage({ cache: false }) 125 rs.access.claim("diffuse", "rw") 126 127 rsClient = rs.scope("/diffuse/") 128 129 return new Promise(resolve => { 130 rs.on("connected", resolve) 131 rs.connect(userAddress, token) 132 }) 133 134 } else { 135 return Promise.resolve() 136 137 } 138} 139 140 141ports.deconstructRemoteStorage = _app => _ => { 142 rs = null 143 rsClient = null 144} 145 146 147taskPorts.fromRemoteStorage = ({ fileName, userAddress, token }) => { 148 return remoteStorage(userAddress, token) 149 .then(_ => rsClient.getFile(fileName)) 150 .then(r => r.data) 151 .then(decryptIfNeeded) 152 .then(parseJsonIfNeeded) 153} 154 155 156taskPorts.toRemoteStorage = ({ data, fileName, userAddress, token }) => { 157 const json = JSON.stringify(data) 158 159 return remoteStorage(userAddress, token) 160 .then(_ => encryptIfPossible(json)) 161 .then(data => rsClient.storeFile("application/json", fileName, data)) 162} 163 164 165 166// EXPORT 167// ====== 168 169function registerPorts(app: App) { 170 Object.keys(ports).forEach(name => { 171 const fn = ports[ name ](app) 172 app.ports[ name ].subscribe(fn) 173 }) 174} 175 176function registerTaskPorts() { 177 Object.keys(taskPorts).forEach(name => { 178 const fn = taskPorts[ name ] 179 TaskPort.register(name, fn) 180 }) 181} 182 183 184export const TaskPorts = { register: registerTaskPorts } 185export const Ports = { register: registerPorts }