Files
memind/mindspace-oa-drive/drive-service.mjs
T
john 6d5eb15b1b feat(mindspace): add per-user OA cloud drive with fds-style file manager
Expose authenticated /api/mindspace/v1/oa/drive APIs over each user's oa/ workspace and wire a MindSpace entry at /space/oa/drive.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 18:55:46 +08:00

85 lines
2.3 KiB
JavaScript

import { computeUserSpaceQuotaStats } from '../mindspace-space-quota.mjs';
import { createDriveContext } from './drive-context.mjs';
import { createDriveHandlers } from './drive-handlers.mjs';
import { createDriveRuntime } from './drive-runtime.mjs';
export function createMindSpaceOaDriveService({
h5Root,
getMindSpace = () => null,
getMindSpaceAssets = () => null,
getPool = () => null,
} = {}) {
if (!h5Root) {
throw new Error('createMindSpaceOaDriveService requires h5Root');
}
const runtimes = new Map();
function getRuntime(userId) {
const key = String(userId);
if (!runtimes.has(key)) {
const ctx = createDriveContext(h5Root, key);
const runtime = createDriveRuntime(ctx);
void runtime.bootstrap();
runtimes.set(key, runtime);
}
return runtimes.get(key);
}
async function getQuotaInfo(userId) {
const mindSpace = getMindSpace();
if (!mindSpace) return null;
const quota = await mindSpace.getQuota(userId);
if (!quota) return null;
const stats = computeUserSpaceQuotaStats({
quota_bytes: quota.quotaBytes,
used_bytes: quota.usedBytes,
reserved_bytes: quota.reservedBytes,
});
return {
quotaBytes: stats.quotaBytes,
usedBytes: stats.usedBytes,
reservedBytes: stats.reservedBytes,
availableBytes: Math.max(0, stats.availableBytes),
};
}
async function assertUploadAllowed(userId, sizeBytes) {
const required = Math.max(0, Number(sizeBytes) || 0);
if (!required) return;
const quota = await getQuotaInfo(userId);
if (!quota) return;
if (quota.availableBytes < required) {
throw Object.assign(new Error('剩余空间不足'), {
code: 'quota_exceeded',
details: {
requiredBytes: required,
availableBytes: Math.max(0, quota.availableBytes),
},
});
}
}
async function afterMutate(userId) {
const assets = getMindSpaceAssets();
if (assets?.syncWorkspaceAssets) {
await assets.syncWorkspaceAssets(userId, { categoryCode: 'oa' }).catch((error) => {
console.warn('[oa-drive] workspace sync failed:', error?.message ?? error);
});
}
}
const handlers = createDriveHandlers({
getRuntime,
getQuotaInfo,
assertUploadAllowed,
afterMutate,
});
return {
getRuntime,
handlers,
getPool,
};
}