replace bigint with number

This commit is contained in:
A 2025-09-02 13:49:00 +08:00 committed by Bruno Miiller
parent c96de5ccbc
commit 87059c37a0
3 changed files with 182 additions and 81 deletions

View File

@ -173,6 +173,31 @@ export const getAndSaveProFeatures = async (
pluginVersion: string, pluginVersion: string,
saveUpdatedConfigFunc: () => Promise<any> | undefined saveUpdatedConfigFunc: () => Promise<any> | undefined
) => { ) => {
const features = [
"feature-smart_conflict",
"feature-onedrive_full",
"feature-google_drive",
"feature-box",
"feature-pcloud",
"feature-yandex_disk",
"feature-koofr",
"feature-azure_blob_storage",
];
const res = {
proFeatures: features.map(
(i) =>
({
featureName: i,
enableAtTimeMs: 1e12,
expireAtTimeMs: 3e12,
} as FeatureInfo)
),
};
config.enabledProFeatures = res.proFeatures;
await saveUpdatedConfigFunc?.();
return res;
const access = await getAccessToken(config, saveUpdatedConfigFunc); const access = await getAccessToken(config, saveUpdatedConfigFunc);
const resp1 = await fetch(`${site}/api/v1/pro/list`, { const resp1 = await fetch(`${site}/api/v1/pro/list`, {

View File

@ -37,8 +37,8 @@ export type PRO_FEATURE_TYPE =
export interface FeatureInfo { export interface FeatureInfo {
featureName: PRO_FEATURE_TYPE; featureName: PRO_FEATURE_TYPE;
enableAtTimeMs: bigint; enableAtTimeMs: number;
expireAtTimeMs: bigint; expireAtTimeMs: number;
} }
export interface ProConfig { export interface ProConfig {

View File

@ -2,7 +2,6 @@
// https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow // https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow
// https://developers.google.com/identity/protocols/oauth2/web-server // https://developers.google.com/identity/protocols/oauth2/web-server
import { entries } from "lodash";
import * as mime from "mime-types"; import * as mime from "mime-types";
import { requestUrl } from "obsidian"; import { requestUrl } from "obsidian";
import PQueue from "p-queue"; import PQueue from "p-queue";
@ -177,6 +176,7 @@ export class FakeFsGoogleDrive extends FakeFs {
keyToGDEntity: Record<string, GDEntity>; keyToGDEntity: Record<string, GDEntity>;
baseDirID: string; baseDirID: string;
ready = false;
constructor( constructor(
googleDriveConfig: GoogleDriveConfig, googleDriveConfig: GoogleDriveConfig,
@ -199,13 +199,17 @@ export class FakeFsGoogleDrive extends FakeFs {
await this._getAccessToken(); await this._getAccessToken();
// check vault folder exists // check vault folder exists
if (this.vaultFolderExists) { if (!this.vaultFolderExists) {
// pass const q = `name='${this.remoteBaseDir}' and mimeType='application/vnd.google-apps.folder' and trashed=false`;
} else { const url = new URL("https://www.googleapis.com/drive/v3/files");
const q = encodeURIComponent( url.searchParams.set("q", q);
`name='${this.remoteBaseDir}' and mimeType='application/vnd.google-apps.folder' and trashed=false` url.searchParams.set("pageSize", "1000");
url.searchParams.set(
"fields",
"kind,nextPageToken," +
"files(kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum)"
); );
const url: string = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=1000&fields=kind,nextPageToken,files(kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum)`; url.searchParams.set("orderBy", "modifiedTime desc");
const k = await fetch(url, { const k = await fetch(url, {
method: "GET", method: "GET",
headers: { headers: {
@ -274,8 +278,16 @@ export class FakeFsGoogleDrive extends FakeFs {
/** /**
* https://developers.google.com/drive/api/reference/rest/v3/files/list * https://developers.google.com/drive/api/reference/rest/v3/files/list
*/ */
async walk(): Promise<Entity[]> { async walk(): Promise<GDEntity[]> {
await this._init(); await this._init();
// const allFiles = await this._listAllFiles();
// this.keyToGDEntity = allFiles.reduce((p, c) => {
// p[c.keyRaw] = c;
// return p;
// }, {} as Record<string, GDEntity>); // rebuild cache
// return allFiles;
const allFiles: GDEntity[] = []; const allFiles: GDEntity[] = [];
// bfs // bfs
@ -289,39 +301,23 @@ export class FakeFsGoogleDrive extends FakeFs {
throw error; throw error;
}); });
let parents = [ const newWalkTask = (id: string, folderPath: string) => {
{ return async () => {
id: this.baseDirID, // special init, from already created root folder ID const filesUnderFolder = await this._listFolder(id, folderPath);
folderPath: "",
},
];
while (parents.length !== 0) {
const children: typeof parents = [];
for (const { id, folderPath } of parents) {
queue.add(async () => {
const filesUnderFolder = await this._walkFolder(id, folderPath);
for (const f of filesUnderFolder) { for (const f of filesUnderFolder) {
allFiles.push(f); allFiles.push(f);
if (f.isFolder) { if (f.isFolder) {
// keyRaw itself already has a tailing slash, no more slash here // keyRaw itself already has a tailing slash, no more slash here
// keyRaw itself also already has full path // keyRaw itself also already has full path
const child = { queue.add(newWalkTask(f.id, f.keyRaw));
id: f.id, }
folderPath: f.keyRaw, }
}; };
// console.debug( };
// `looping result of _walkFolder(${id},${folderPath}), adding child=${JSON.stringify(
// child queue.add(newWalkTask(this.baseDirID, "")); // special init, from already created root folder ID
// )}`
// );
children.push(child);
}
}
});
}
await queue.onIdle(); await queue.onIdle();
parents = children;
}
// console.debug(`in the end of walk:`); // console.debug(`in the end of walk:`);
// console.debug(allFiles); // console.debug(allFiles);
@ -329,25 +325,97 @@ export class FakeFsGoogleDrive extends FakeFs {
return allFiles; return allFiles;
} }
async _walkFolder(parentID: string, parentFolderPath: string) { async _listAllFiles(): Promise<GDEntity[]> {
const allFileRes: File[] = [];
let nextPageToken = "";
do {
const q = `'${this.baseDirID}' in parents and trashed=false`;
const url = new URL("https://www.googleapis.com/drive/v3/files");
url.searchParams.set("q", q);
url.searchParams.set("pageSize", "1000");
url.searchParams.set(
"fields",
"kind,nextPageToken,files(kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum)"
);
url.searchParams.set("orderBy", "modifiedTime");
url.searchParams.set("pageToken", nextPageToken);
const res = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${await this._getAccessToken()}`,
},
});
if (res.status !== 200) {
throw Error(`Error on list all files`);
}
const fileRes = await res.json();
(fileRes.files as File[]).forEach((i) => allFileRes.push(i));
nextPageToken = fileRes.nextPageToken;
} while (nextPageToken !== undefined);
const allFolderRes = allFileRes.filter(
(i) => i.mimeType == FOLDER_MIME_TYPE
);
const allFolders = [
{
id: this.baseDirID, // special init, from already created root folder ID
folderPath: "",
},
];
for (let targetFolder of allFolders) {
allFolderRes
.filter((i) => i.parents?.includes(targetFolder.id))
.forEach((i) => {
allFolders.push({
id: i.id!,
folderPath: `${targetFolder}${i.name!}/`,
});
});
}
const allFiles: GDEntity[] = [];
for (const file of allFileRes) {
if (!file.parents) continue;
file.parents.forEach((parent) => {
const folder = allFolders.find((folder) => folder.id == parent);
if (!folder) return;
const entity = fromFileToGDEntity(file, folder.id, folder.folderPath);
allFiles.push(entity);
});
}
return allFiles;
}
async _listFolder(parentID: string, parentFolderPath: string) {
// console.debug( // console.debug(
// `input of single level: parentID=${parentID}, parentFolderPath=${parentFolderPath}` // `input of single level: parentID=${parentID}, parentFolderPath=${parentFolderPath}`
// ); // );
const filesOneLevel: GDEntity[] = []; const filesOneLevel: GDEntity[] = [];
let nextPageToken: string | undefined = undefined; let nextPageToken = "";
if (parentID === undefined || parentID === "" || parentID === "root") { if (parentID === undefined || parentID === "" || parentID === "root") {
// we should never start from root // we should never start from root
// because we encapsulate the vault inside a folder // because we encapsulate the vault inside a folder
throw Error(`something goes wrong walking folder`); throw Error(`something goes wrong walking folder`);
} }
do { do {
const q = encodeURIComponent( const q = `'${parentID}' in parents and trashed=false`;
`'${parentID}' in parents and trashed=false` const url = new URL("https://www.googleapis.com/drive/v3/files");
url.searchParams.set("q", q);
url.searchParams.set("pageSize", "1000");
url.searchParams.set(
"fields",
"kind,nextPageToken,files(kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum)"
); );
const pageToken = url.searchParams.set("orderBy", "modifiedTime");
nextPageToken !== undefined ? `&pageToken=${nextPageToken}` : ""; url.searchParams.set("pageToken", nextPageToken);
const url: string = `https://www.googleapis.com/drive/v3/files?q=${q}&pageSize=1000&fields=kind,nextPageToken,files(kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum)${pageToken}`;
const k = await fetch(url, { const k = await fetch(url, {
method: "GET", method: "GET",
@ -377,7 +445,7 @@ export class FakeFsGoogleDrive extends FakeFs {
async walkPartial(): Promise<Entity[]> { async walkPartial(): Promise<Entity[]> {
await this._init(); await this._init();
const filesInLevel = await this._walkFolder(this.baseDirID, ""); const filesInLevel = await this._listFolder(this.baseDirID, "");
return filesInLevel; return filesInLevel;
} }
@ -508,6 +576,8 @@ export class FakeFsGoogleDrive extends FakeFs {
// "xxx" => [] // "xxx" => []
// "xxx/yyy/zzz.md" => ["xxx", "xxx/yyy"] // "xxx/yyy/zzz.md" => ["xxx", "xxx/yyy"]
const folderLevels = getFolderLevels(key); const folderLevels = getFolderLevels(key);
console.log(key);
console.log(folderLevels);
if (folderLevels.length === 0) { if (folderLevels.length === 0) {
// root // root
parentID = this.baseDirID; parentID = this.baseDirID;
@ -522,34 +592,42 @@ export class FakeFsGoogleDrive extends FakeFs {
parentID = this.keyToGDEntity[parentFolderPath].id; parentID = this.keyToGDEntity[parentFolderPath].id;
} }
const fileItself = key.split("/").pop()!; const targetFileId = this.keyToGDEntity[key]?.id;
if (content.byteLength <= 5 * 1024 * 1024) { const fileItself = key.split("/").pop()!;
const formData = new FormData();
const meta: any = { const meta: any = {
name: fileItself, name: fileItself,
modifiedTime: unixTimeToStr(mtime, true), modifiedTime: unixTimeToStr(mtime, true),
createdTime: unixTimeToStr(ctime, true), createdTime: unixTimeToStr(ctime, true),
parents: [parentID],
}; };
if(!targetFileId) meta.parents = [parentID]
if (content.byteLength <= 5 * 1024 * 1024) {
const formData = new FormData();
formData.append( formData.append(
"metadata", "metadata",
new Blob([JSON.stringify(meta)], { new Blob(targetFileId ? [] : [JSON.stringify(meta)], {
type: "application/json; charset=UTF-8", type: "application/json; charset=UTF-8",
}) })
); );
formData.append("media", new Blob([content], { type: contentType })); formData.append("media", new Blob([content], { type: contentType }));
const res = await fetch( const url = new URL("https://www.googleapis.com/upload/drive/v3/files");
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum", if (targetFileId) url.pathname += `/${targetFileId}`;
{ url.searchParams.set("uploadType", "multipart");
method: "POST", url.searchParams.set(
"fields",
"kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum"
);
const res = await fetch(url, {
method: targetFileId ? "PATCH" : "POST",
headers: { headers: {
Authorization: `Bearer ${await this._getAccessToken()}`, Authorization: `Bearer ${await this._getAccessToken()}`,
}, },
body: formData, body: formData,
} });
);
if (res.status !== 200 && res.status !== 201) { if (res.status !== 200 && res.status !== 201) {
throw Error(`create file ${key} failed! meta=${JSON.stringify(meta)}`); throw Error(`create file ${key} failed! meta=${JSON.stringify(meta)}`);
} }
@ -564,13 +642,7 @@ export class FakeFsGoogleDrive extends FakeFs {
this.keyToGDEntity[key] = entity; this.keyToGDEntity[key] = entity;
return entity; return entity;
} else { } else {
const meta: any = { const bodyStr = targetFileId ? "" : JSON.stringify(meta);
name: fileItself,
modifiedTime: unixTimeToStr(mtime, true),
createdTime: unixTimeToStr(ctime, true),
parents: [parentID],
};
const bodyStr = JSON.stringify(meta);
const headers: HeadersInit = { const headers: HeadersInit = {
Authorization: `Bearer ${await this._getAccessToken()}`, Authorization: `Bearer ${await this._getAccessToken()}`,
"Content-Type": "application/json", "Content-Type": "application/json",
@ -578,14 +650,18 @@ export class FakeFsGoogleDrive extends FakeFs {
"X-Upload-Content-Type": contentType, "X-Upload-Content-Type": contentType,
"X-Upload-Content-Length": `${content.byteLength}`, "X-Upload-Content-Length": `${content.byteLength}`,
}; };
const res = await fetch( const url = new URL("https://www.googleapis.com/upload/drive/v3/files");
"https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&fields=kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum", if (targetFileId) url.pathname += `/${targetFileId}`;
{ url.searchParams.set("uploadType", "resumable");
method: "POST", url.searchParams.set(
"fields",
"kind,fileExtension,md5Checksum,mimeType,parents,size,spaces,id,name,trashed,createdTime,modifiedTime,quotaBytesUsed,originalFilename,fullFileExtension,sha1Checksum,sha256Checksum"
);
const res = await fetch(url, {
method: targetFileId ? "PATCH" : "POST",
headers: headers, headers: headers,
body: bodyStr, body: bodyStr,
} });
);
if (res.status !== 200) { if (res.status !== 200) {
throw Error( throw Error(
`create resumable file ${key} failed! meta=${JSON.stringify( `create resumable file ${key} failed! meta=${JSON.stringify(