Files
SnowLuma/packages/protocol/src/oidb-services/flash-transfer/prepare-upload.ts
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

115 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// OIDB 0x12a9_100 — prepare-upload(大文件分片上传前申请 sliceupload rkey)。
// sub=100,uinForm=true。sub=100 的 payload 在 f2(sub=103 在 f12),结构完全不同。
// 响应 f2.f1 是 sliceupload rkey;秒传(文件已在服务端)时 f1 缺失,deserialize 返回 null。
import { protobuf_decode, protobuf_encode } from '@snowluma/proton';
import type { OidbBase } from '@snowluma/proto-defs/oidb';
import type {
FlashPrepareUploadReq,
FlashPrepareUploadResp,
} from '@snowluma/proto-defs/oidb-actions/flash-transfer';
import { invokeOidb, type OidbSender } from '../../oidb-service';
let seqCounter = 200;
export namespace PrepareUpload {
export const command = 0x12a9;
export const subCommand = 100;
export const uinForm = true;
export interface Params {
filesetUuid: string;
fileUuid: string;
fileName: string;
fileSize: number;
sha1: string; // 40 hex
/** fileset 内序号(1,2,3...),与 0x93d0 commit f6 一致。缩略图序号在主文件之后递增。 */
fileIndex: number;
/** 格式码:与 commit f7 一致(mp4=2, rar/zip=4)。主文件 filesetWrap.f7 用此值;
* 缩略图固定 png=26/jpg=2。 */
formatCode: number;
/** 缩略图类型:undefined=主文件, 'png'=png 缩略图, 'jpg'=jpg 缩略图。
* 主文件下载入口需要缩略图关联才会被服务端填充,缩略图字段差异据此切换。 */
thumbType?: 'png' | 'jpg';
width?: number; // 缩略图宽(主文件=0)
height?: number; // 缩略图高(主文件=0)
}
export type Deps = OidbSender;
export const serialize = (_ctx: Deps, p: Params): FlashPrepareUploadReq => {
// 缩略图与主文件字段差异:config.f103、FileInfo.f5.f1/f6/f7/f9、filesetWrap.f6/f7。
// filesetWrap.f4 统一用 fileIndex(主文件和缩略图都从 facade 传入,保证与 commit f6 一致)。
const isThumb = p.thumbType !== undefined;
const isJpg = p.thumbType === 'jpg';
return {
head: {
sub: { seq: seqCounter++, sub: 100 },
config: {
field101: 2,
field102: 4,
field103: isThumb ? (isJpg ? 24 : 23) : 22,
field200: 5,
},
field3: { field1: 1 },
},
payload: {
wrapper: {
fileInfo: {
fileSize: p.fileSize,
md5: '', // sub=100 不带 MD5
sha1: p.sha1,
fileName: p.fileName,
field5: { field1: isJpg ? 1 : 0, field2: 0, field3: 0, field4: 0 },
field6: p.width ?? 0,
field7: p.height ?? 0,
field8: 0,
field9: isJpg ? 0 : 1,
},
field2: 0, // wrapper.f2=0(varint,不是 fileId)
},
field2: 1,
field3: 0,
field4: 0,
field5: 0,
field6: {
field1: { field1: 0, field2: {} },
field2: { field3: {} },
field3: { field11: {}, field12: {} },
field10: 0,
},
field7: 0,
field8: 0,
filesetWrap: {
filesetUuid: p.filesetUuid,
uploadKey: p.filesetUuid,
fileUuid: p.fileUuid,
field4: p.fileIndex,
field5: 0,
field6: isThumb ? 1 : 0, // 缩略图=1, 主文件=0
field7: isThumb ? (isJpg ? 2 : 26) : p.formatCode, // 主文件=formatCode(mp4=2), png缩略图=26, jpg缩略图=2
field8: {},
field9: 1,
field10: 0,
field11: 0,
field12: 0,
field13: 0,
field14: 0,
},
},
};
};
export const deserialize = (_ctx: Deps, body: FlashPrepareUploadResp): string | null => {
// sub-100 resp f2={f1:rkey}(正常上传,CAES/CAIS/CAQS/CAMS)。
// 秒传(文件已在服务端)时 f2 无 f1(rkey),返回 null,调用方仍要 apply,
// 只跳过 sliceupload。
return body.rkeyWrap?.rkey ?? null;
};
export const encode = (env: OidbBase<FlashPrepareUploadReq>): Uint8Array =>
protobuf_encode<OidbBase<FlashPrepareUploadReq>>(env);
export const decode = (bytes: Uint8Array): OidbBase<FlashPrepareUploadResp> =>
protobuf_decode<OidbBase<FlashPrepareUploadResp>>(bytes);
export const invoke = (deps: Deps, params: Params): Promise<string | null> =>
invokeOidb(deps, PrepareUpload, params);
}