feat: integrate client and server sharing workflows
This commit is contained in:
1 parent
42b93ae2d8
commit
7406e2fe37
101 files changed
+3153
-253
No files matched your search
@@ -0,0 +1,48 @@
|
||||
import { saveResource } from '../database';
|
||||
import type { Item, Share } from '../types';
|
||||
import { getSession, sessions } from './sessions';
|
||||
import { apiFetch } from './http';
|
||||
import { toShareInfo, type ShareWire } from './wire';
|
||||
import { flushOutbox, persistPlan } from './transfer';
|
||||
import { publishShare } from './presentation';
|
||||
import { encodeManifest } from './shareManifest';
|
||||
import { readShareInfo, releaseOwner } from './shareState';
|
||||
|
||||
export async function sealShare(id: string): Promise<Share> {
|
||||
const { session, resource } = await getSession(id);
|
||||
if (resource.kind !== 'share' || resource.state !== 'draft' || !session.can('owner')) throw new Error('此分享已封存');
|
||||
if (!(await flushOutbox(resource, session))) throw new Error('网络连接失败,请稍后重试');
|
||||
const before = await readShareInfo(session, resource);
|
||||
if (before.state === 'sealed') return toShareInfo(before, resource);
|
||||
if ((resource.draftItems ?? []).some((item) => item.state.kind !== 'complete')) throw new Error('还有内容没有上传完成');
|
||||
if (!resource.pendingManifestId) {
|
||||
const bytes = encodeManifest(resource.manifestEntries ?? []);
|
||||
const plan = session.encryptBytes(bytes, { kind: 'manifest' }, { gated: false });
|
||||
await persistPlan(resource, plan);
|
||||
resource.pendingManifestId = plan.itemId;
|
||||
await saveResource(resource);
|
||||
}
|
||||
if (!(await flushOutbox(resource, session))) throw new Error('清单上传暂停,请重试');
|
||||
let raw: ShareWire;
|
||||
try {
|
||||
const response = await apiFetch(`/shares/${id}/finish`, {
|
||||
method: 'POST', headers: { ...session.authHeaders('owner'), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ manifest_item_id: resource.pendingManifestId }),
|
||||
});
|
||||
raw = await response.json() as ShareWire;
|
||||
} catch (error) {
|
||||
raw = await readShareInfo(session, resource).catch(() => { throw error; });
|
||||
if (raw.state !== 'sealed') throw error;
|
||||
}
|
||||
const items = resource.draftItems ?? [];
|
||||
if (sessions.get(id)?.can('owner')) await releaseOwner(session, resource, raw);
|
||||
const sealed = toShareInfo(raw, resource);
|
||||
publishShare(id, { t: 'share', share: sealed });
|
||||
const remaining = new Map(raw.items.map((item) => [item.item_id, item.downloads_left]));
|
||||
for (const draft of items) {
|
||||
const item: Item = draft.kind === 'file' ? { ...draft, remaining: remaining.get(draft.id) ?? null } : draft;
|
||||
publishShare(id, { t: 'item', item });
|
||||
}
|
||||
publishShare(id, { t: 'ready' });
|
||||
return sealed;
|
||||
}
|
||||
Reference in new issue
Block a user