diff --git a/.gitignore b/.gitignore index 933b7ce6..2dd18401 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ /examples/tmp /node_modules /node-win.log +/package-lock.json /test-files /venv \ No newline at end of file diff --git a/examples/callbacks/cancel-fetch-data.callback.ts b/examples/callbacks/cancel-fetch-data.callback.ts index a95009ee..2e677aba 100644 --- a/examples/callbacks/cancel-fetch-data.callback.ts +++ b/examples/callbacks/cancel-fetch-data.callback.ts @@ -1,5 +1,5 @@ -async function onCancelFetchDataCallback(fileId: string) { - console.log("[EXAMPLE] cancel fetch data: ", fileId); -} +import { logger } from "@/logger"; -export default onCancelFetchDataCallback; \ No newline at end of file +export const cancelFetchDataCallback = (fileId: string) => { + logger.info({ event: "cancelFetchDataCallback", fileId }); +}; diff --git a/examples/callbacks/index.ts b/examples/callbacks/index.ts deleted file mode 100644 index 935d4bfe..00000000 --- a/examples/callbacks/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default as onRenameCallbackWithCallback } from "./notify-rename.callback"; -export { default as onMessageCallback } from "./notify-message.callback"; -export { default as onCancelFetchDataCallback } from "./cancel-fetch-data.callback"; diff --git a/examples/callbacks/notify-delete.callback.ts b/examples/callbacks/notify-delete.callback.ts index a5e379a0..96c69ba3 100644 --- a/examples/callbacks/notify-delete.callback.ts +++ b/examples/callbacks/notify-delete.callback.ts @@ -1,6 +1,6 @@ import { logger } from "@/logger"; export const notifyDeleteCallback = (fileId: string, callback: (response: boolean) => void) => { - logger.info({ event: "onDelete", fileId }); + logger.info({ event: "notifyDeleteCallback", fileId }); callback(true); }; diff --git a/examples/callbacks/notify-fetch-data.callback.ts b/examples/callbacks/notify-fetch-data.callback.ts index fa075951..0b9103cb 100644 --- a/examples/callbacks/notify-fetch-data.callback.ts +++ b/examples/callbacks/notify-fetch-data.callback.ts @@ -2,9 +2,9 @@ import { getInfoItem } from "examples/info-items-manager"; import { sleep } from "@/utils"; -type CallbackResponse = (data: boolean, path: string, errorHandler?: () => void) => Promise<{ finished: boolean; progress: number }>; +type TCallback = (data: boolean, path: string, errorHandler?: () => void) => Promise<{ finished: boolean; progress: number }>; -export const fetchDataCallback = async (id: string, callback: CallbackResponse) => { +export const fetchDataCallback = async (id: string, callback: TCallback) => { const path = await getInfoItem(id); let finish = false; diff --git a/examples/callbacks/notify-message.callback.ts b/examples/callbacks/notify-message.callback.ts index 1a92591b..41360739 100644 --- a/examples/callbacks/notify-message.callback.ts +++ b/examples/callbacks/notify-message.callback.ts @@ -1,16 +1,6 @@ -async function onMessageCallback( - message: string, - action: string, - errorName: string, - callback: (response: boolean) => void) { - try { - console.log("[EXAMPLE] Message received: ", message); - console.log("[EXAMPLE] Action: ", action); - console.log("[EXAMPLE] Error name: ", errorName); - await callback(true); - } catch (error) { - callback(false); - } -} +import { logger } from "@/logger"; -export default onMessageCallback; \ No newline at end of file +export const notifyMessageCallback = (message: string, action: string, errorName: string, callback: (response: boolean) => void) => { + logger.info({ event: "notifyMessageCallback", message, action, errorName }); + callback(true); +}; diff --git a/examples/callbacks/notify-rename.callback.ts b/examples/callbacks/notify-rename.callback.ts index 191daac2..e7c1c7db 100644 --- a/examples/callbacks/notify-rename.callback.ts +++ b/examples/callbacks/notify-rename.callback.ts @@ -1,27 +1,6 @@ -async function onRenameCallback(newName: string, fileId: string): Promise { - console.log("[EXAMPLE] File ID: " + fileId); - console.log("[EXAMPLE] New name: " + newName); +import { logger } from "@/logger"; - const a = await (new Promise((resolve, reject) => { - try { - - setTimeout(() => { - resolve(true); - }, 1000) - } catch (err) { - reject(err); - } - })); - - return a; -} - -function onRenameCallbackWithCallback(newName: string, fileId: string, responseCallback: (response: boolean) => void) { - onRenameCallback(newName, fileId).then((response) => { - responseCallback(response); - }).catch((err) => { - responseCallback(false); - }); -} - -export default onRenameCallbackWithCallback; \ No newline at end of file +export const notifyRenameCallback = (newName: string, fileId: string, callback: (response: boolean) => void) => { + logger.info({ event: "notifyRenameCallback", newName, fileId }); + callback(true); +}; diff --git a/examples/drive.ts b/examples/drive.ts index 7e029d5f..0bd967e2 100644 --- a/examples/drive.ts +++ b/examples/drive.ts @@ -1,7 +1,5 @@ import VirtualDrive from "@/virtual-drive"; + import settings from "./settings"; -export const drive = new VirtualDrive( - settings.syncRootPath, - settings.defaultLogPath -); +export const drive = new VirtualDrive(settings.syncRootPath, settings.defaultLogPath); diff --git a/examples/get-state.ts b/examples/get-state.ts index 8783d8e3..4fe84bce 100644 --- a/examples/get-state.ts +++ b/examples/get-state.ts @@ -1,7 +1,10 @@ -import { drive } from "./drive"; import yargs from "yargs"; +import z from "zod"; + +import { logger } from "@/logger"; + +import { drive } from "./drive"; -// Configura yargs const argv = yargs .command("file", "El path del archivo para obtener el estado", { path: { @@ -13,14 +16,13 @@ const argv = yargs .help() .alias("help", "h").argv; -//@ts-ignore -if (argv.file) { - //@ts-ignore - const path = argv.file; +const { data } = z.object({ file: z.string() }).safeParse(argv); + +if (data) { + const path = data.file; const state = drive.getPlaceholderState(path); - console.log(`${path} state:`, state); - const states = drive.getPlaceholderWithStatePending(); - console.log(`states:`, states); + const pendingStates = drive.getPlaceholderWithStatePending(); + logger.info({ state, pendingStates }); } else { - console.log("Por favor especifica un archivo con --file "); + console.error("Por favor especifica un archivo con --file "); } diff --git a/examples/handlers/handle-add.ts b/examples/handlers/handle-add.ts new file mode 100644 index 00000000..f9d5fae9 --- /dev/null +++ b/examples/handlers/handle-add.ts @@ -0,0 +1,16 @@ +import { drive } from "examples/drive"; +import { addInfoItem } from "examples/info-items-manager"; + +import { logger } from "@/logger"; +import { QueueItem } from "@/queue/queueManager"; +import { v4 } from "uuid"; + +export const handleAdd = async (task: QueueItem) => { + try { + logger.info({ fn: "handleAdd", task }); + const id = task.isFolder ? v4() : addInfoItem(task.path); + drive.convertToPlaceholder(task.path, id); + } catch (error) { + logger.error(error, "handleAdd"); + } +}; diff --git a/examples/handlers/handle-change-size.ts b/examples/handlers/handle-change-size.ts new file mode 100644 index 00000000..21cbd697 --- /dev/null +++ b/examples/handlers/handle-change-size.ts @@ -0,0 +1,16 @@ +import { drive } from "examples/drive"; + +import { logger } from "@/logger"; +import { QueueItem } from "@/queue/queueManager"; + +export const handleChangeSize = async (task: QueueItem) => { + try { + logger.info({ fn: "handleChangeSize", path: task.path }); + const result = Math.random().toString(36).substring(2, 7); + drive.convertToPlaceholder(task.path, result); + drive.updateFileIdentity(task.path, result, false); + drive.updateSyncStatus(task.path, task.isFolder, true); + } catch (error) { + logger.error(error, "handleChangeSize"); + } +}; diff --git a/examples/handlers/handle-dehydrate.ts b/examples/handlers/handle-dehydrate.ts new file mode 100644 index 00000000..4a75e3bd --- /dev/null +++ b/examples/handlers/handle-dehydrate.ts @@ -0,0 +1,13 @@ +import { drive } from "examples/drive"; + +import { logger } from "@/logger"; +import { QueueItem } from "@/queue/queueManager"; + +export const handleDehydrate = async (task: QueueItem) => { + try { + logger.info({ fn: "handleDehydrate", path: task.path }); + drive.dehydrateFile(task.path); + } catch (error) { + logger.error(error, "handleDehydrate"); + } +}; diff --git a/examples/handlers/handle-hydrate.ts b/examples/handlers/handle-hydrate.ts new file mode 100644 index 00000000..941bb210 --- /dev/null +++ b/examples/handlers/handle-hydrate.ts @@ -0,0 +1,13 @@ +import { drive } from "examples/drive"; + +import { logger } from "@/logger"; +import { QueueItem } from "@/queue/queueManager"; + +export const handleHydrate = async (task: QueueItem) => { + try { + logger.info({ fn: "handleHydrate", path: task.path }); + await drive.hydrateFile(task.path); + } catch (error) { + logger.error(error, "handleHydrate"); + } +}; diff --git a/examples/info-items-manager.ts b/examples/info-items-manager.ts index 003925c6..74cf1643 100644 --- a/examples/info-items-manager.ts +++ b/examples/info-items-manager.ts @@ -1,44 +1,44 @@ -import { existsSync } from "fs"; -import { copyFile, mkdir, readFile, writeFile } from "fs/promises"; +import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import { basename, join } from "path"; import { v4 } from "uuid"; + import { TMP_PATH } from "./settings"; const infoItemsPath = join(TMP_PATH, "info-items.json"); const serverPath = join(TMP_PATH, "fake-server"); -export const initInfoItems = async () => { +export const initInfoItems = () => { if (!existsSync(infoItemsPath)) { - await writeFile(infoItemsPath, JSON.stringify({})); + writeFileSync(infoItemsPath, JSON.stringify({})); } if (!existsSync(serverPath)) { - await mkdir(serverPath); + mkdirSync(serverPath); } }; -export const getInfoItems = async () => { - return JSON.parse(await readFile(infoItemsPath, "utf8")); +export const getInfoItems = () => { + return JSON.parse(readFileSync(infoItemsPath, "utf8")); }; -export const deleteInfoItems = async () => { - await writeFile(infoItemsPath, JSON.stringify({})); +export const deleteInfoItems = () => { + writeFileSync(infoItemsPath, JSON.stringify({})); }; -export const addInfoItem = async (itemPath: string) => { +export const addInfoItem = (itemPath: string) => { const fileName = basename(itemPath); const serverItemPath = join(serverPath, fileName); - await copyFile(itemPath, serverItemPath); - + copyFileSync(itemPath, serverItemPath); + const id = v4(); - const infoItems = await getInfoItems(); + const infoItems = getInfoItems(); infoItems[id] = serverItemPath; - - await writeFile(infoItemsPath, JSON.stringify(infoItems, null, 2)); + + writeFileSync(infoItemsPath, JSON.stringify(infoItems, null, 2)); return id; }; -export const getInfoItem = async (id: string) => { - const infoItems = await getInfoItems(); +export const getInfoItem = (id: string) => { + const infoItems = getInfoItems(); return infoItems[id]; }; diff --git a/examples/populate.ts b/examples/populate.ts new file mode 100644 index 00000000..4857ea51 --- /dev/null +++ b/examples/populate.ts @@ -0,0 +1,30 @@ +import VirtualDrive from "@/virtual-drive"; + +import { execSync } from "child_process"; +import { join } from "path"; +import { v4 } from "uuid"; + +import settings from "./settings"; + +const rootFile1 = join(settings.syncRootPath, v4()); +const rootFile2ChangeSize = join(settings.syncRootPath, `change-size-${v4()}.txt`); +const rootFile3 = join(settings.syncRootPath, `${v4()}.txt`); +const rootFile3Moved = join(settings.syncRootPath, `moved-${v4()}.txt`); +const rootFile4 = join(settings.syncRootPath, `${v4()}.txt`); +const rootFolder1 = join(settings.syncRootPath, v4()); +const rootFolder2 = join(settings.syncRootPath, v4()); +const folder1File1 = join(rootFolder1, `${v4()}.pdf`); +const folder1Folder1 = join(rootFolder1, v4()); +const folder1Folder1File1 = join(folder1Folder1, `${v4()}.xlsx`); + +execSync(`echo Hello, world! > ${rootFile1}`); // Sync +execSync(`echo Hello, world! > ${rootFile2ChangeSize}`); +execSync(`echo Hello, world! >> ${rootFile2ChangeSize}`); // Sync +execSync(`echo Hello, world! > ${rootFile3}`); +execSync(`type nul > ${rootFile4}`); // No sync (0 bytes) +execSync(`mv ${rootFile3} ${rootFile3Moved}`); // Sync +execSync(`mkdir ${rootFolder1}`); // Sync +execSync(`mkdir ${rootFolder2}`); // Cloud (no files inside) +execSync(`echo Hello, world! > ${folder1File1}`); // Sync +execSync(`mkdir ${folder1Folder1}`); // Sync +execSync(`echo Hello, world! > ${folder1Folder1File1}`); // Sync diff --git a/examples/register.ts b/examples/register.ts index e7a10c9d..5fa55164 100644 --- a/examples/register.ts +++ b/examples/register.ts @@ -1,106 +1,34 @@ import { logger } from "@/logger"; import { QueueManager } from "@/queue/queue-manager"; -import { QueueItem } from "@/queue/queueManager"; import VirtualDrive from "@/virtual-drive"; -import { onCancelFetchDataCallback, onMessageCallback, onRenameCallbackWithCallback } from "./callbacks"; +import { cancelFetchDataCallback } from "./callbacks/cancel-fetch-data.callback"; import { notifyDeleteCallback } from "./callbacks/notify-delete.callback"; import { fetchDataCallback } from "./callbacks/notify-fetch-data.callback"; +import { notifyMessageCallback } from "./callbacks/notify-message.callback"; +import { notifyRenameCallback } from "./callbacks/notify-rename.callback"; import { drive } from "./drive"; -import { addInfoItem, initInfoItems } from "./info-items-manager"; +import { handleAdd } from "./handlers/handle-add"; +import { handleChangeSize } from "./handlers/handle-change-size"; +import { handleDehydrate } from "./handlers/handle-dehydrate"; +import { handleHydrate } from "./handlers/handle-hydrate"; +import { initInfoItems } from "./info-items-manager"; import settings from "./settings"; -import { generateRandomFilesAndFolders } from "./utils/generate-random-file-tree"; -logger.info("Registering sync root: " + settings.syncRootPath); - -drive.registerSyncRoot( - settings.driveName, - settings.driveVersion, - "{12345678-1234-1234-1234-123456789012}", - { - notifyDeleteCallback, - notifyRenameCallback: onRenameCallbackWithCallback, - fetchDataCallback, - cancelFetchDataCallback: onCancelFetchDataCallback, - notifyMessageCallback: onMessageCallback, - }, - settings.iconPath, -); - -const handleAdd = async (task: QueueItem) => { - try { - logger.info({ fn: "handleAdd", path: task.path }); - const id = await addInfoItem(task.path); - drive.convertToPlaceholder(task.path, id); - } catch (error) { - logger.error(error, "handleAdd"); - } -}; - -const handleDehydrate = async (task: QueueItem) => { - try { - logger.info({ fn: "handleDehydrate", path: task.path }); - drive.dehydrateFile(task.path); - } catch (error) { - logger.error(error, "handleDehydrate"); - } -}; - -const handleHydrate = async (task: QueueItem) => { - try { - logger.info({ fn: "handleHydrate", path: task.path }); - await drive.hydrateFile(task.path); - } catch (error) { - logger.error(error, "handleHydrate"); - } -}; - -const handleChangeSize = async (task: QueueItem) => { - try { - logger.info({ fn: "handleChangeSize", path: task.path }); - const result = Math.random().toString(36).substring(2, 7); - drive.convertToPlaceholder(task.path, result); - drive.updateFileIdentity(task.path, result, false); - await drive.updateSyncStatus(task.path, task.isFolder, true); - // await drive.updateFileSize(task.path); - } catch (error) { - logger.error(error, "handleChangeSize"); - } -}; - -const handlers = { - handleAdd, - handleHydrate, - handleDehydrate, - handleChangeSize, -}; - -const notify = { - onTaskSuccess: async () => logger.info({ fn: "onTaskSuccess" }), - onTaskProcessing: async () => logger.info({ fn: "onTaskProcessing" }), -}; +const callbacks = { notifyDeleteCallback, notifyRenameCallback, fetchDataCallback, cancelFetchDataCallback, notifyMessageCallback }; +const handlers = { handleAdd, handleHydrate, handleDehydrate, handleChangeSize }; +const notify = { onTaskSuccess: async () => undefined, onTaskProcessing: async () => undefined }; const queueManager = new QueueManager(handlers, notify, settings.queuePersistPath); +drive.registerSyncRoot(settings.driveName, settings.driveVersion, settings.providerid, callbacks, settings.iconPath); drive.connectSyncRoot(); -const fileGenerationOptions = { - rootPath: "", - depth: 3, - filesPerFolder: 3, - foldersPerLevel: 3, - meanSize: 5000000, - stdDev: 6000000, -}; - -(async () => { - try { - await initInfoItems(); - // const fileMap = await generateRandomFilesAndFolders(drive, fileGenerationOptions); - drive.watchAndWait(settings.syncRootPath, queueManager, settings.watcherLogPath); - } catch (error) { - drive.disconnectSyncRoot(); - VirtualDrive.unregisterSyncRoot(settings.syncRootPath); - console.log("[EXAMPLE] error: " + error); - } -})(); +try { + initInfoItems(); + drive.watchAndWait(settings.syncRootPath, queueManager, settings.watcherLogPath); +} catch (error) { + logger.error(error); + drive.disconnectSyncRoot(); + VirtualDrive.unregisterSyncRoot(settings.syncRootPath); +} diff --git a/examples/settings.ts b/examples/settings.ts index 76b1d2a8..0653b85a 100644 --- a/examples/settings.ts +++ b/examples/settings.ts @@ -8,6 +8,7 @@ mkdirSync(TMP_PATH, { recursive: true }); const settings = { driveName: "Internxt", driveVersion: "2.0.4", + providerid: "{12345678-1234-1234-1234-123456789012}", syncRootPath: join(TMP_PATH, "sync-root"), iconPath: join(cwd(), "assets", "icon.ico"), defaultLogPath: join(TMP_PATH, "drive.log"), diff --git a/examples/unregister.ts b/examples/unregister.ts index 1883c06d..6c57ca89 100644 --- a/examples/unregister.ts +++ b/examples/unregister.ts @@ -1,29 +1,7 @@ -//@ts-ignore -import VirtualDrive from "../src/virtual-drive"; +import VirtualDrive from "@/virtual-drive"; + +import { deleteInfoItems } from "./info-items-manager"; import settings from "./settings"; -import path from "path"; -import fs from "fs"; VirtualDrive.unregisterSyncRoot(settings.syncRootPath); - -// delete persistence file -const filePath = path.join(__dirname, "filesInfo.json"); - -fs.promises - .access(filePath, fs.constants.F_OK) - .then(() => { - // El archivo existe, procede a borrarlo - return fs.promises.unlink(filePath); - }) - .then(() => { - console.log("[EXAMPLE] fileInfo.json deleted successfully"); - }) - .catch((error) => { - if (error.code === "ENOENT") { - // El archivo no existe, no es necesario borrarlo - console.log("[EXAMPLE] fileInfo.json does not exist, no need to be deleted"); - } else { - // Ocurrió otro error - console.error("Error:", error); - } - }); +deleteInfoItems(); diff --git a/package.json b/package.json index 6a38f2e9..9441881c 100644 --- a/package.json +++ b/package.json @@ -16,16 +16,13 @@ "build:ts": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json", "config:gyp": "python gyp.config.py", "build": "python gyp.config.py && node-gyp clean && node-gyp configure build && yarn build:ts", - "========== Dev Examples ==========": "", - "dev:register": "nodemon", - "dev:get-state": "ts-node -r tsconfig-paths/register ./examples/get-state.ts", - "dev:unregister": "ts-node -r tsconfig-paths/register ./examples/unregister.ts", - "dev:disconnect": "ts-node -r tsconfig-paths/register ./examples/disconnect.ts", - "========== Prod Examples ==========": "", + "========== Examples ==========": "", "prod:register": "node ./dist/examples/register.js", - "prod:get-state": "node ./dist/examples/get-state.js", - "prod:unregister": "node ./dist/examples/unregister.js", - "prod:disconnect": "node ./dist/examples/disconnect.js" + "register": "nodemon", + "populate": "ts-node -r tsconfig-paths/register ./examples/populate.ts", + "get-state": "ts-node -r tsconfig-paths/register ./examples/get-state.ts", + "unregister": "ts-node -r tsconfig-paths/register ./examples/unregister.ts", + "disconnect": "ts-node -r tsconfig-paths/register ./examples/disconnect.ts" }, "author": "", "license": "ISC",