| |
| |
| |
| |
|
|
| const PROXY = '/b2proxy'; |
|
|
| async function proxyCall(action, path, extraHeaders = {}, body = null) { |
| const opts = { |
| method: 'POST', |
| headers: { |
| 'X-Action': action, |
| 'X-Path': path, |
| ...extraHeaders |
| } |
| }; |
| if (body) opts.body = body; |
|
|
| const res = await fetch(PROXY, opts); |
| if (!res.ok) { |
| const txt = await res.text(); |
| throw new Error(txt || `err-027 β HTTP ${res.status}`); |
| } |
| return res.json(); |
| } |
|
|
| |
| async function b2Upload(file, path, onProgress) { |
| |
| const buf = await file.arrayBuffer(); |
|
|
| |
| const hash = await crypto.subtle.digest('SHA-1', buf); |
| const sha1 = Array.from(new Uint8Array(hash)) |
| .map(b => b.toString(16).padStart(2, '0')).join(''); |
|
|
| |
| |
| return new Promise((resolve, reject) => { |
| const xhr = new XMLHttpRequest(); |
| xhr.open('POST', PROXY); |
| xhr.setRequestHeader('X-Action', 'upload'); |
| xhr.setRequestHeader('X-Path', path); |
| xhr.setRequestHeader('X-Content-Type', file.type || 'application/octet-stream'); |
| xhr.setRequestHeader('X-Sha1', sha1); |
| xhr.setRequestHeader('Content-Type', 'application/octet-stream'); |
|
|
| xhr.upload.onprogress = e => { |
| if (e.lengthComputable && onProgress) |
| onProgress(Math.round(e.loaded / e.total * 100)); |
| }; |
|
|
| xhr.onload = () => { |
| if (xhr.status === 200) { |
| resolve(path); |
| } else { |
| reject(new Error(`err-009 β Upload esuat: ${xhr.status}`)); |
| } |
| }; |
| xhr.onerror = () => reject(new Error('err-027 β Eroare retea la upload')); |
| xhr.send(buf); |
| }); |
| } |
|
|
| |
| async function b2List(prefix) { |
| try { |
| const data = await proxyCall('list', prefix); |
| return data.files || []; |
| } catch(e) { |
| console.error('b2List:', e.message); |
| return []; |
| } |
| } |
|
|
| |
| async function b2Delete(key) { |
| try { |
| await proxyCall('delete', key); |
| } catch(e) { |
| console.error('b2Delete:', e.message); |
| } |
| } |
|
|