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,85 @@
|
||||
import type { ParsedChannelLink } from '@/lib/channelLink';
|
||||
import type { ParsedShareLink } from '@/lib/shareLink';
|
||||
import type { WorkspaceApi } from './api';
|
||||
import type { ShareApi } from './shareApi';
|
||||
import { callWorker, subscribeWorker } from './workerClient';
|
||||
import type { ArchiveEntry, ChannelInfo, ConnectionState, CreateOptions, Share, ShareEvent, ShareSettings, WorkspaceEvent } from './types';
|
||||
|
||||
const API_BASE = import.meta.env.VITE_WEBDROP_API_URL ?? '/api/v1';
|
||||
|
||||
function reportChannelUnavailable(id: string, onEvent: (event: WorkspaceEvent) => void): void {
|
||||
onEvent({ t: 'connection', state: 'offline' });
|
||||
onEvent({ t: 'ready' });
|
||||
void id;
|
||||
}
|
||||
|
||||
export const realApi: WorkspaceApi = {
|
||||
createChannel: (options: CreateOptions, captchaToken?: string) => callWorker<ChannelInfo>('createChannel', { options, captchaToken, apiBase: API_BASE }),
|
||||
joinChannel: (link: ParsedChannelLink) => callWorker<ChannelInfo>('joinChannel', { link, apiBase: API_BASE }),
|
||||
listSaved: () => callWorker<ChannelInfo[]>('listChannels', { apiBase: API_BASE }),
|
||||
forget: (id) => callWorker<void>('forgetChannel', { id, apiBase: API_BASE }),
|
||||
|
||||
connect(channelId, onEvent) {
|
||||
activeChannelId = channelId;
|
||||
activeShareId = '';
|
||||
const unsubscribe = subscribeWorker<WorkspaceEvent>(channelId, onEvent);
|
||||
void callWorker<boolean>('connectChannel', { id: channelId, apiBase: API_BASE }).catch(() => reportChannelUnavailable(channelId, onEvent));
|
||||
return () => {
|
||||
unsubscribe();
|
||||
void callWorker('stopChannel', { id: channelId, apiBase: API_BASE });
|
||||
};
|
||||
},
|
||||
|
||||
sendText: (text) => callWorker<void>('sendText', { id: currentChannelId(), text, apiBase: API_BASE }),
|
||||
sendFiles: (files) => callWorker<void>('sendFiles', { id: currentChannelId(), files, apiBase: API_BASE }),
|
||||
editText: (id, text) => callWorker<void>('editChannelText', { id: currentChannelId(), itemId: id, text, apiBase: API_BASE }),
|
||||
resolveConflict: (id, choice) => callWorker<void>('resolveTextConflict', { id: currentChannelId(), itemId: id, choice, apiBase: API_BASE }),
|
||||
remove: (id) => callWorker<void>('removeChannelItem', { id: currentChannelId(), itemId: id, apiBase: API_BASE }),
|
||||
setSnapshot: (text) => callWorker<void>('updateSnapshot', { id: currentChannelId(), text, apiBase: API_BASE }),
|
||||
getBlob: (id, versionId) => callWorker<Blob>('getChannelBlob', { id: currentChannelId(), itemId: id, versionId, apiBase: API_BASE }),
|
||||
listArchive: (_id: string): Promise<ArchiveEntry[]> => callWorker<ArchiveEntry[]>('listArchive', { id: currentChannelId(), apiBase: API_BASE }),
|
||||
markSeen: (id) => callWorker<void>('markChannelSeen', { id: currentChannelId(), itemId: id, apiBase: API_BASE }),
|
||||
};
|
||||
|
||||
export const realShareApi: ShareApi = {
|
||||
createDraft: (settings: ShareSettings, captchaToken?: string) => callWorker<Share>('createShare', { settings, captchaToken, apiBase: API_BASE }),
|
||||
listSaved: () => callWorker<Share[]>('listShares', { apiBase: API_BASE }),
|
||||
updateSettings: (id, patch) => callWorker<Share>('updateShareSettings', { id, patch, apiBase: API_BASE }),
|
||||
seal: (id) => callWorker<Share>('sealShare', { id, apiBase: API_BASE }),
|
||||
join: (link: ParsedShareLink) => callWorker<Share>('joinShare', { link, apiBase: API_BASE }),
|
||||
forget: (id) => callWorker<void>('forgetShare', { id, apiBase: API_BASE }),
|
||||
|
||||
connect(shareId, onEvent) {
|
||||
activeShareId = shareId;
|
||||
activeChannelId = '';
|
||||
const unsubscribe = subscribeWorker<ShareEvent>(shareId, onEvent);
|
||||
void callWorker<void>('connectShare', { id: shareId, apiBase: API_BASE }).catch((error: unknown) => {
|
||||
onEvent({ t: 'error', message: error instanceof Error ? error.message : '无法打开分享' });
|
||||
onEvent({ t: 'ready' });
|
||||
});
|
||||
return () => {
|
||||
unsubscribe();
|
||||
void callWorker('stopShare', { id: shareId, apiBase: API_BASE });
|
||||
};
|
||||
},
|
||||
|
||||
addText: (text) => callWorker<void>('addShareText', { id: currentShareId(), text, apiBase: API_BASE }),
|
||||
editText: (id, text) => callWorker<void>('editShareText', { id: currentShareId(), itemId: id, text, apiBase: API_BASE }),
|
||||
addFiles: (files) => callWorker<void>('addShareFiles', { id: currentShareId(), files, apiBase: API_BASE }),
|
||||
removeItem: (id) => callWorker<void>('removeShareItem', { id: currentShareId(), itemId: id, apiBase: API_BASE }),
|
||||
getBlob: (id) => callWorker<Blob>('getShareBlob', { id: currentShareId(), itemId: id, apiBase: API_BASE }),
|
||||
listArchive: (_id: string): Promise<ArchiveEntry[]> => callWorker<ArchiveEntry[]>('listArchive', { id: currentShareId(), apiBase: API_BASE }),
|
||||
};
|
||||
|
||||
let activeChannelId = '';
|
||||
let activeShareId = '';
|
||||
|
||||
function currentChannelId(): string {
|
||||
return activeChannelId;
|
||||
}
|
||||
|
||||
function currentShareId(): string {
|
||||
return activeShareId;
|
||||
}
|
||||
|
||||
export function simulateConnection(_state: ConnectionState): void {}
|
||||
Reference in new issue
Block a user