diff --git a/.env-default b/.env-default deleted file mode 100644 index ff97396d..00000000 --- a/.env-default +++ /dev/null @@ -1,5 +0,0 @@ -EXAMPLE_DRIVE_NAME="Internxt" -EXAMPLE_DRIVE_VERSION="2.0.4" -EXAMPLE_SYNC_ROOT_PATH="C:\Users\gcarl\Desktop\carpeta" -EXAMPLE_SERVER_ROOT_PATH="C:\Users\gcarl\Desktop\fakeserver" -EXAMPLE_DEFAULT_LOG_PATH="C:\Users\gcarl\AppData\Roaming\internxt-drive\logs\node-win.txt" diff --git a/.gitignore b/.gitignore index 6b5d116b..933b7ce6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ /addon.node /build /dist -/examples/filesInfo.json +/examples/tmp /node_modules /node-win.log /test-files diff --git a/bin/win32-x64-116/node-win.node b/bin/win32-x64-116/node-win.node deleted file mode 100644 index 88b11f50..00000000 Binary files a/bin/win32-x64-116/node-win.node and /dev/null differ diff --git a/examples/callbacks/index.ts b/examples/callbacks/index.ts index dbefba89..935d4bfe 100644 --- a/examples/callbacks/index.ts +++ b/examples/callbacks/index.ts @@ -1,6 +1,3 @@ export { default as onRenameCallbackWithCallback } from "./notify-rename.callback"; -export { default as onDeleteCallbackWithCallback } from "./notify-delete.callback"; export { default as onMessageCallback } from "./notify-message.callback"; export { default as onCancelFetchDataCallback } from "./cancel-fetch-data.callback"; -export { default as onFetchDataCallback } from "./notify-fetch-data.callback"; -export { default as onFileAddedCallback } from "./notify-added.callback"; \ No newline at end of file diff --git a/examples/callbacks/notify-added.callback.ts b/examples/callbacks/notify-added.callback.ts deleted file mode 100644 index 2bd20f0a..00000000 --- a/examples/callbacks/notify-added.callback.ts +++ /dev/null @@ -1,30 +0,0 @@ -function generateRandomNumber(min: number, max: number) { - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -type CallbackResponse = (aknowledge: boolean, id: string) => Promise; - -async function onFileAddedCallback( - filePath: string, - callback: CallbackResponse -) { - try { - let randomNumber = generateRandomNumber(10000, 60000); - console.log("[EXAMPLE] File added in callback: " + filePath); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); - // 2024-05-11 224346.png" - // primer argumento es el boolean que indica si se pudo crear el archivo o no en el cloud - // segundo argumento es el id del archivo creado en el cloud - const result = Math.random().toString(36).substring(2, 7); - await callback(true, result); - } catch (error) { - await callback(false, ""); - console.error(error); - } -} - -export default onFileAddedCallback; diff --git a/examples/callbacks/notify-delete.callback.ts b/examples/callbacks/notify-delete.callback.ts index cd506319..450bf396 100644 --- a/examples/callbacks/notify-delete.callback.ts +++ b/examples/callbacks/notify-delete.callback.ts @@ -1,24 +1,6 @@ -async function onDeleteCallback(fileId: string, callback: (response: boolean) => void) { - console.log("[EXAMPLE] On delete File ID: " + fileId); - const a = await (new Promise((resolve, reject) => { - try { - setTimeout(() => { - resolve(true); - }, 10) - } catch (err) { - reject(err); - } - })); +import { logger } from "@/logger"; - return a; -} - -function onDeleteCallbackWithCallback(fileId: string, callback: (response: boolean) => void) { - onDeleteCallback(fileId, callback).then((response) => { - callback(response); - }).catch((err) => { - callback(false); - }); -} - -export default onDeleteCallbackWithCallback; \ No newline at end of file +export const onDeleteCallback = (fileId: string, callback: (response: boolean) => void) => { + logger.info({ event: "onDelete", fileId }); + callback(true); +}; diff --git a/examples/callbacks/notify-fetch-data.callback.ts b/examples/callbacks/notify-fetch-data.callback.ts index 1f9b70bb..dc61e534 100644 --- a/examples/callbacks/notify-fetch-data.callback.ts +++ b/examples/callbacks/notify-fetch-data.callback.ts @@ -1,51 +1,16 @@ -import { ItemsInfoManager } from "../utils"; +import { getInfoItem } from "examples/info-items-manager"; -async function onFetchData(fileId: string): Promise { - console.log("[EXAMPLE] downloading file: " + fileId); - // simulating a download from a real server - const a = await (new Promise((resolve, reject) => { - try { +import { sleep } from "@/utils"; - setTimeout(() => { - resolve(true); - }, 1000) - } catch (err) { - reject(err); - } - })); +type CallbackResponse = (data: boolean, path: string, errorHandler?: () => void) => Promise<{ finished: boolean; progress: number }>; - return a; -} +export const onFetchDataCallback = async (id: string, callback: CallbackResponse) => { + const path = await getInfoItem(id); -type CallbackResponse = (data : boolean, path: string, errorHandler?: () => void) => Promise<{ finished: boolean, progress: number }>; - -async function onFetchDataCallback(fileId: string, callback: CallbackResponse ) { - console.log("[EXAMPLE] file id: " + fileId); - // simulate a download from a real server and response with the path of the downloaded file of a fake server - let finish = false; - onFetchData(fileId).then(async (response) => { - while (!finish) { - const itemsManager = await ItemsInfoManager.initialize('dist/examples/filesInfo.json') - const itemPath = itemsManager.get(fileId.replace(/\x00/g, '')) - - if (!itemPath) { - console.log("[EXAMPLE] error: file not found"); - finish = true; - break; - } - - const callbackResponse = await callback(response, itemPath); - finish = callbackResponse.finished; - if (finish) { - console.log("[EXAMPLE] finished"); - break; - }; - }; - - }).catch((err) => { - //callback(false, "C:\\Users\\gcarl\\Desktop\\fakeserver\\imagen.rar"); - console.log('[EXAMPLE] error:' + err); - }); -} - -export default onFetchDataCallback; \ No newline at end of file + let finish = false; + while (!finish) { + const result = await callback(true, path); + finish = result.finished; + await sleep(1000); + } +}; diff --git a/examples/info-items-manager.ts b/examples/info-items-manager.ts new file mode 100644 index 00000000..003925c6 --- /dev/null +++ b/examples/info-items-manager.ts @@ -0,0 +1,44 @@ +import { existsSync } from "fs"; +import { copyFile, mkdir, readFile, writeFile } from "fs/promises"; +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 () => { + if (!existsSync(infoItemsPath)) { + await writeFile(infoItemsPath, JSON.stringify({})); + } + + if (!existsSync(serverPath)) { + await mkdir(serverPath); + } +}; + +export const getInfoItems = async () => { + return JSON.parse(await readFile(infoItemsPath, "utf8")); +}; + +export const deleteInfoItems = async () => { + await writeFile(infoItemsPath, JSON.stringify({})); +}; + +export const addInfoItem = async (itemPath: string) => { + const fileName = basename(itemPath); + const serverItemPath = join(serverPath, fileName); + await copyFile(itemPath, serverItemPath); + + const id = v4(); + const infoItems = await getInfoItems(); + infoItems[id] = serverItemPath; + + await writeFile(infoItemsPath, JSON.stringify(infoItems, null, 2)); + return id; +}; + +export const getInfoItem = async (id: string) => { + const infoItems = await getInfoItems(); + return infoItems[id]; +}; diff --git a/examples/queueManager.ts b/examples/queueManager.ts index 97ff83d5..bbe4af8a 100644 --- a/examples/queueManager.ts +++ b/examples/queueManager.ts @@ -1,4 +1,8 @@ import { HandleAction, HandleActions } from "src/queue/queueManager"; + +import { logger } from "@/logger"; +import { sleep } from "@/utils"; + import { IQueueManager, QueueItem } from "../index"; export type QueueHandler = { @@ -8,9 +12,7 @@ export type QueueHandler = { handleChange?: HandleAction; handleChangeSize: HandleAction; }; -export async function sleep(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} + export class QueueManager implements IQueueManager { private _queue: QueueItem[] = []; @@ -29,7 +31,7 @@ export class QueueManager implements IQueueManager { } public enqueue(task: QueueItem): void { - console.debug(`Task enqueued: ${JSON.stringify(task)}`); + logger.debug({ fn: "enqueue", task }); this._queue.push(task); this.sortQueue(); if (!this.isProcessing) { @@ -53,13 +55,11 @@ export class QueueManager implements IQueueManager { } public async processNext(): Promise { - if (this._queue.length === 0) { - console.debug("No tasks in queue."); - return; - } const task = this._queue.shift(); if (!task) return; - console.debug(`Processing task: ${JSON.stringify(task)}`); + + logger.debug({ fn: "processNext", task }); + switch (task.type) { case "add": return await this.actions.add(task); @@ -78,12 +78,14 @@ export class QueueManager implements IQueueManager { } public async processAll(): Promise { + logger.debug({ fn: "processAll", queueLength: this._queue.length }); + this.isProcessing = true; while (this._queue.length > 0) { - await sleep(200); - console.debug("Processing all tasks. Queue length:", this._queue.length); await this.processNext(); + await sleep(200); } + this.isProcessing = false; } } diff --git a/examples/register.ts b/examples/register.ts index 66c22c8d..583cfdfa 100644 --- a/examples/register.ts +++ b/examples/register.ts @@ -1,123 +1,85 @@ +import { QueueItem, VirtualDrive } from "src"; + +import { logger } from "@/logger"; + +import { onCancelFetchDataCallback, onMessageCallback, onRenameCallbackWithCallback } from "./callbacks"; +import { onDeleteCallback } from "./callbacks/notify-delete.callback"; +import { onFetchDataCallback } from "./callbacks/notify-fetch-data.callback"; import { drive } from "./drive"; -import settings from "./settings"; -import { - onCancelFetchDataCallback, - onDeleteCallbackWithCallback, - onFetchDataCallback, - onFileAddedCallback, - onMessageCallback, - onRenameCallbackWithCallback, -} from "./callbacks"; -import { ItemsInfoManager, createFilesWithSize } from "./utils"; +import { addInfoItem, initInfoItems } from "./info-items-manager"; import { QueueManager } from "./queueManager"; -import { IQueueManager, QueueItem, VirtualDrive } from "src"; +import settings from "./settings"; import { generateRandomFilesAndFolders } from "./utils/generate-random-file-tree"; -console.log("Registering sync root: " + settings.syncRootPath); +logger.info("Registering sync root: " + settings.syncRootPath); drive.registerSyncRoot( settings.driveName, settings.driveVersion, "{12345678-1234-1234-1234-123456789012}", { - notifyDeleteCallback: onDeleteCallbackWithCallback, + notifyDeleteCallback: onDeleteCallback, notifyRenameCallback: onRenameCallbackWithCallback, - notifyFileAddedCallback: onFileAddedCallback, fetchDataCallback: onFetchDataCallback, cancelFetchDataCallback: onCancelFetchDataCallback, notifyMessageCallback: onMessageCallback, }, - settings.defaultIconPath + settings.defaultIconPath, ); -const handlerAdd = async (task: QueueItem) => { +const handleAdd = async (task: QueueItem) => { try { - console.log("[EXAMPLE] File added in callback: " + task.path); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); - const result = Math.random().toString(36).substring(2, 7); - await drive.convertToPlaceholder(task.path, result); - await drive.updateSyncStatus(task.path, task.isFolder, true); + logger.info({ fn: "handleAdd", path: task.path }); + const id = await addInfoItem(task.path); + drive.convertToPlaceholder(task.path, id); + // await drive.updateSyncStatus(task.path, task.isFolder, true); } catch (error) { - console.error(error); + logger.error(error, "handleAdd"); } }; const handleDehydrate = async (task: QueueItem) => { try { - console.log("[EXAMPLE] File dehydrated in callback: " + task.path); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); - console.log("Dehydrating file: " + task.path); - await drive.dehydrateFile(task.path); + logger.info({ fn: "handleDehydrate", path: task.path }); + drive.dehydrateFile(task.path); } catch (error) { - console.error(error); + logger.error(error, "handleDehydrate"); } }; const handleHydrate = async (task: QueueItem) => { try { - console.log("[EXAMPLE] File hydrated in callback: " + task.path); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); - - const tempPath = task.path.replace( - settings.syncRootPath, - settings.serverRootPath - ); - - console.log("Hydrating file: " + task.path); - // await drive.transferData(tempPath, task.path); - - console.log("[EXAMPLE] File trasnfer in callback: " + task.path); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); + logger.info({ fn: "handleHydrate", path: task.path }); + await drive.hydrateFile(task.path); } catch (error) { - console.error(error); + logger.error(error, "handleHydrate"); } }; const handleChangeSize = async (task: QueueItem) => { try { - console.log("[EXAMPLE] File size changed in callback: " + task.path); - await new Promise((resolve) => - setTimeout(() => { - resolve(undefined); - }, 1000) - ); + logger.info({ fn: "handleChangeSize", path: task.path }); const result = Math.random().toString(36).substring(2, 7); - await drive.convertToPlaceholder(task.path, result); - await drive.updateFileIdentity(task.path, result, false); + 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) { - console.error(error); + logger.error(error, "handleChangeSize"); } }; -const queueManager: IQueueManager = new QueueManager({ - handleAdd: handlerAdd, - handleHydrate: handleHydrate, - handleDehydrate: handleDehydrate, - handleChangeSize: handleChangeSize, +const queueManager = new QueueManager({ + handleAdd, + handleHydrate, + handleDehydrate, + handleChangeSize, }); drive.connectSyncRoot(); const fileGenerationOptions = { - rootPath: '', + rootPath: "", depth: 3, filesPerFolder: 3, foldersPerLevel: 3, @@ -127,26 +89,9 @@ const fileGenerationOptions = { (async () => { try { - const fileMap = await generateRandomFilesAndFolders(drive, fileGenerationOptions); - - createFilesWithSize(settings.syncRootPath, settings.serverRootPath); - - const itemsManager = await ItemsInfoManager.initialize() - - for (const key in fileMap) { - const value = fileMap[key]; - fileMap[key] = settings.serverRootPath + value.replace("/", "\\"); - } - - await itemsManager.add(fileMap); - - drive.watchAndWait( - settings.syncRootPath, - queueManager, - settings.watcherLogPath - ); - - console.log("Proceso de generación y vigilancia completado."); + await initInfoItems(); + // const fileMap = await generateRandomFilesAndFolders(drive, fileGenerationOptions); + drive.watchAndWait(settings.syncRootPath, queueManager, settings.watcherLogPath); } catch (error) { drive.disconnectSyncRoot(); VirtualDrive.unregisterSyncRoot(settings.syncRootPath); diff --git a/examples/settings.ts b/examples/settings.ts index 173e1f70..80069bc6 100644 --- a/examples/settings.ts +++ b/examples/settings.ts @@ -1,39 +1,17 @@ -import "dotenv/config"; -import path, { join } from "path"; +import { mkdirSync } from "fs"; +import { join } from "path"; import { cwd } from "process"; -import { z } from "zod"; -function sanitizePath(filePath: string): string { - return filePath.replace(/\n/g, "\\n"); -} - -function normalizePath(filePath: string) { - return sanitizePath(filePath.replace(/\\n/g, "\\n").replace(/\\/g, path.sep)); -} - -const envVarsSchema = z.object({ - EXAMPLE_DRIVE_NAME: z.string().min(1), - EXAMPLE_DRIVE_VERSION: z.string().min(1), - EXAMPLE_SYNC_ROOT_PATH: z.string().min(1), - EXAMPLE_DEFAULT_LOG_PATH: z.string().min(1), - EXAMPLE_SERVER_ROOT_PATH: z.string().min(1), - EXAMPLE_WATCHER_LOG_PATH: z.string().min(1), -}); - -const { data: envVars, error } = envVarsSchema.safeParse(process.env); - -if (error) { - throw new Error(`Error de configuración: ${error.message}`); -} +export const TMP_PATH = join(cwd(), "examples", "tmp"); +mkdirSync(TMP_PATH, { recursive: true }); const settings = { - driveName: envVars.EXAMPLE_DRIVE_NAME, - driveVersion: envVars.EXAMPLE_DRIVE_VERSION, - syncRootPath: normalizePath(envVars.EXAMPLE_SYNC_ROOT_PATH), - defaultLogPath: normalizePath(envVars.EXAMPLE_DEFAULT_LOG_PATH), + driveName: "Internxt", + driveVersion: "2.0.4", + syncRootPath: join(TMP_PATH, "sync-root"), + defaultLogPath: join(TMP_PATH, "drive.log"), defaultIconPath: join(cwd(), "assets", "icon.ico"), - serverRootPath: normalizePath(envVars.EXAMPLE_SERVER_ROOT_PATH), - watcherLogPath: normalizePath(envVars.EXAMPLE_WATCHER_LOG_PATH), + watcherLogPath: join(TMP_PATH, "watcher.log"), }; export default settings; diff --git a/examples/utils.ts b/examples/utils.ts index faabeb5c..5636667d 100644 --- a/examples/utils.ts +++ b/examples/utils.ts @@ -44,68 +44,4 @@ function createFilesWithSize(sourceFolder: string, destFolder: string): void { } -interface FilesInfo { - [uuid: string]: string; -} -class ItemsInfoManager { - private filePath: string; - private data: FilesInfo; - - private constructor(filePath: string, data?: FilesInfo) { - this.filePath = filePath; - this.data = data || {}; - } - - public static async initialize(filePath?: string): Promise { - const resolvedPath = filePath ? path.resolve(filePath) : path.join(__dirname, 'filesInfo.json'); - let data: FilesInfo; - - try { - const fileContent = await fs.promises.readFile(resolvedPath, 'utf8'); - data = JSON.parse(fileContent); - } catch (error) { - //@ts-ignore - if (error.code === 'ENOENT') { - data = {}; - await fs.promises.writeFile(resolvedPath, JSON.stringify(data)); - } else { - console.error('Error initializing filesInfo.json:', error); - throw error; - } - } - - return new ItemsInfoManager(resolvedPath, data); - } - - public async add(info: FilesInfo): Promise { - try { - this.data = { ...this.data, ...info }; - await fs.promises.writeFile(this.filePath, JSON.stringify(this.data, null, 2)); - } catch (error) { - console.error('Error adding data to filesInfo.json:', error); - } - } - - public async remove(uuid: string): Promise { - try { - if (this.data[uuid]) { - delete this.data[uuid]; - await fs.promises.writeFile(this.filePath, JSON.stringify(this.data, null, 2)); - } else { - console.log(`UUID ${uuid} not found.`); - } - } catch (error) { - console.error('Error removing data from filesInfo.json:', error); - } - } - - public get(uuid: string): string | undefined { - try { - return this.data[uuid]; - } catch (error) { - console.error('Error getting data from filesInfo.json:', error); - } - } -} - -export { ItemsInfoManager, createFilesWithSize }; \ No newline at end of file +export { createFilesWithSize }; \ No newline at end of file diff --git a/package.json b/package.json index d2da95d1..b8338c79 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ }, "dependencies": { "chokidar": "^3.6.0", - "dotenv": "^16.4.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "tsconfig-paths": "^4.2.0", diff --git a/src/addon.ts b/src/addon.ts index 07510417..81a2cc54 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -29,9 +29,9 @@ export type TAddon = { path: string, ): any; closeMutex(): any; - hydrateFile(path: string): Promise; + hydrateFile(path: string): Promise>; getPlaceholderAttribute(path: string): z.infer; - dehydrateFile(path: string): Promise; + dehydrateFile(path: string): z.infer; connectSyncRoot(path: string, callbacks: InputSyncCallbacks): z.infer; convertToPlaceholder(path: string, id: string): z.infer; deleteFileSyncRoot(path: string): any; diff --git a/src/addon/addon-zod.ts b/src/addon/addon-zod.ts index 3b37b540..dee05cf5 100644 --- a/src/addon/addon-zod.ts +++ b/src/addon/addon-zod.ts @@ -7,6 +7,7 @@ export const addonZod = { addLoggerPath: z.boolean(), connectSyncRoot: z.object({ hr: z.literal(0), connectionKey: z.string() }), convertToPlaceholder: z.boolean(), + dehydrateFile: z.boolean(), getFileIdentity: z.string(), getPlaceholderAttribute: z.object({ attribute: z.union([z.literal(0), z.literal(1), z.literal(2)]) }).transform(({ attribute }) => { if (attribute === 1) return "NOT_PINNED"; @@ -15,6 +16,7 @@ export const addonZod = { }), getPlaceholderState: z.object({ pinState: z.nativeEnum(PinState), syncState: z.nativeEnum(SyncState) }), getPlaceholderWithStatePending: z.array(z.string()), + hydrateFile: z.undefined(), registerSyncRoot: z.literal(0), updateSyncStatus: z.boolean(), unregisterSyncRoot: z.number(), diff --git a/src/utils.ts b/src/utils.ts index 986a7c71..8425be72 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,46 +1,3 @@ -import * as fs from 'fs'; -import * as path from 'path'; - -export function deleteAllSubfolders(directoryPath: string): void { - // Comprobar si el directorio existe - if (!fs.existsSync(directoryPath)) { - console.error('El directorio especificado no existe:', directoryPath); - return; - } - - // Leer todos los elementos del directorio - const items = fs.readdirSync(directoryPath); - - items.forEach(item => { - let itemPath = path.join(directoryPath, item); - let itemStats = fs.statSync(itemPath); - - // Si el elemento es una carpeta, eliminarla recursivamente - if (itemStats.isDirectory() ) { - deleteFolderRecursive(itemPath); - } - // Si el elemento es un archivo, eliminarlo - if (itemStats.isFile()){ - fs.unlinkSync(itemPath); - } - }); -} - -export function deleteFolderRecursive(folderPath: string): void { - if (fs.existsSync(folderPath)) { - fs.readdirSync(folderPath).forEach((file, index) => { - const currentPath = path.join(folderPath, file); - if (fs.statSync(currentPath).isDirectory()) { - deleteFolderRecursive(currentPath); - } else { - fs.unlinkSync(currentPath); - } - }); - - // Después de eliminar todos los subdirectorios y archivos, eliminar la carpeta - fs.rmdirSync(folderPath); - } -} - -// Uso de la función: -// deleteAllSubfolders('/ruta/del/directorio'); +export const sleep = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; diff --git a/src/virtual-drive.ts b/src/virtual-drive.ts index dc02ee32..95ac662d 100644 --- a/src/virtual-drive.ts +++ b/src/virtual-drive.ts @@ -1,6 +1,5 @@ import path, { join } from "path"; import fs from "fs"; -import { deleteAllSubfolders } from "./utils"; import { Worker } from "worker_threads"; import { Watcher } from "./watcher/watcher"; import { ExtraCallbacks, InputSyncCallbacks } from "./types/callbacks.type"; @@ -477,8 +476,8 @@ class VirtualDrive { return addon.closeMutex(); } - async dehydrateFile(itemPath: string): Promise { - return await addon.dehydrateFile(itemPath); + async dehydrateFile(itemPath: string) { + return addon.dehydrateFile(itemPath); } async hydrateFile(itemPath: string): Promise { diff --git a/src/watcher/detect-context-menu-action.service.ts b/src/watcher/detect-context-menu-action.service.ts index 8cdb9411..a2441af8 100644 --- a/src/watcher/detect-context-menu-action.service.ts +++ b/src/watcher/detect-context-menu-action.service.ts @@ -1,22 +1,39 @@ +import { Stats } from "fs"; + import { typeQueue } from "@/queue/queueManager"; -import { Attributes, PinState, SyncState } from "@/types/placeholder.type"; +import { PinState, SyncState } from "@/types/placeholder.type"; import { Watcher } from "./watcher"; export class DetectContextMenuActionService { - async execute({ self, details, path, isDirectory }: TProps) { + async execute({ self, details, path, isFolder }: TProps) { const { prev, curr } = details; - const status = await self.virtualDriveFn.CfGetPlaceHolderState(path); - self.writeLog("status", status); - - const attribute = await self.virtualDriveFn.CfGetPlaceHolderAttributes(path); - self.writeLog("attribute", attribute); + const status = self.virtualDriveFn.CfGetPlaceHolderState(path); + const attribute = self.virtualDriveFn.CfGetPlaceHolderAttributes(path); const itemId = self.virtualDriveFn.CfGetPlaceHolderIdentity(path); - self.writeLog("itemId", itemId); - const isInDevice = self.fileInDevice.has(path); + self.writeLog({ + event: "onRaw", + path, + status, + attribute, + itemId, + isInDevice, + prev: { + size: prev.size, + ctimeMs: prev.ctimeMs, + mtimeMs: prev.mtimeMs, + }, + curr: { + size: curr.size, + ctimeMs: curr.ctimeMs, + mtimeMs: curr.mtimeMs, + blocks: curr.blocks, + }, + }); + if ( prev.size === curr.size && prev.ctimeMs !== curr.ctimeMs && @@ -26,35 +43,45 @@ export class DetectContextMenuActionService { !isInDevice ) { self.fileInDevice.add(path); - self.queueManager.enqueue({ path, type: typeQueue.hydrate, isFolder: isDirectory, fileId: itemId }); + + if (curr.blocks !== 0) { + // This event is triggered from the addon + return "Doble click en el archivo"; + } + + self.queueManager.enqueue({ path, type: typeQueue.hydrate, isFolder, fileId: itemId }); return "Mantener siempre en el dispositivo"; } - // Verificar si es "Liberar espacio" if ( - prev.size == curr.size && // Tamaño no cambia - prev.ctimeMs != curr.ctimeMs && // ctime cambia - status.pinState == PinState.OnlineOnly && // Estado es OnlineOnly - status.syncState == SyncState.InSync // Estado es InSync + prev.size === curr.size && + prev.ctimeMs !== curr.ctimeMs && + status.pinState == PinState.OnlineOnly && + status.syncState == SyncState.InSync ) { + if (curr.blocks === 0) { + return "Liberando espacio"; + } + self.fileInDevice.delete(path); - self.queueManager.enqueue({ path, type: typeQueue.dehydrate, isFolder: isDirectory, fileId: itemId }); + self.queueManager.enqueue({ path, type: typeQueue.dehydrate, isFolder, fileId: itemId }); return "Liberar espacio"; } - if (prev.size != curr.size) { - self.queueManager.enqueue({ path, type: typeQueue.changeSize, isFolder: isDirectory, fileId: itemId }); + if (prev.size !== curr.size) { + self.queueManager.enqueue({ path, type: typeQueue.changeSize, isFolder, fileId: itemId }); self.fileInDevice.add(path); return "Cambio de tamaño"; } - - return null; } } type TProps = { self: Watcher; - details: any; + details: { + prev: Stats; + curr: Stats; + }; path: string; - isDirectory: boolean; + isFolder: boolean; }; diff --git a/src/watcher/events/on-add.service.unit.test.ts b/src/watcher/events/on-add.service.unit.test.ts index 511c6ee9..cafec510 100644 --- a/src/watcher/events/on-add.service.unit.test.ts +++ b/src/watcher/events/on-add.service.unit.test.ts @@ -17,8 +17,7 @@ describe("Watcher onAdd", () => { it('Should enqueue an "add" task if the file is new', () => { // Arrange - // @ts-ignore - watcher.virtualDriveFn.CfGetPlaceHolderIdentity.mockReturnValue(null); + watcher.virtualDriveFn.CfGetPlaceHolderIdentity.mockReturnValue(""); watcher.virtualDriveFn.CfGetPlaceHolderState.mockReturnValue({ pinState: PinState.Unspecified, syncState: SyncState.NotInSync, diff --git a/src/watcher/events/on-raw.service.ts b/src/watcher/events/on-raw.service.ts index ba46bb50..f79041c3 100644 --- a/src/watcher/events/on-raw.service.ts +++ b/src/watcher/events/on-raw.service.ts @@ -1,4 +1,4 @@ -import { statSync } from "fs"; +import { stat } from "fs/promises"; import { extname } from "path"; import { DetectContextMenuActionService } from "../detect-context-menu-action.service"; @@ -8,21 +8,15 @@ export class OnRawService { constructor(private readonly detectContextMenuAction: DetectContextMenuActionService = new DetectContextMenuActionService()) {} async execute({ self, event, path, details }: TProps) { - self.writeLog("onRaw", event, path, details); - - let isDirectory = false; - if (event === "change" && details.prev && details.curr) { - const item = statSync(path); - - if (item.isDirectory()) { - self.writeLog("Es un directorio", path); - isDirectory = true; + if (extname(path) === "") { + self.writeLog({ event: "onRaw", path, details: "No extension" }); return; } - if (extname(path) === "") { - self.writeLog("Archivo sin extensión ignorado", path); + const item = await stat(path); + if (item.isDirectory()) { + self.writeLog({ event: "onRaw", path, details: "Is directory" }); return; } @@ -32,10 +26,10 @@ export class OnRawService { // return; // } - const action = await this.detectContextMenuAction.execute({ self, details, path, isDirectory }); + const action = await this.detectContextMenuAction.execute({ self, details, path, isFolder: false }); if (action) { - self.writeLog(`Action detected: '${action}'`, path); + self.writeLog({ event: "onRaw", path, action }); } } } diff --git a/src/watcher/watcher.interface.ts b/src/watcher/watcher.interface.ts index 9e7df54d..bcdd1c84 100644 --- a/src/watcher/watcher.interface.ts +++ b/src/watcher/watcher.interface.ts @@ -1,21 +1,17 @@ -import { addonZod } from "@/addon/addon-zod"; -import { Status } from "src/types/placeholder.type"; import { z } from "zod"; +import { addonZod } from "@/addon/addon-zod"; + export interface IVirtualDriveFunctions { CfHydrate?: () => void; CfDehydrate?: () => void; CfAddItem: () => void; CfNotifyMessage?: () => void; - CfUpdateSyncStatus: ( - path: string, - sync: boolean, - isDirectory: boolean - ) => void; + CfUpdateSyncStatus: (path: string, sync: boolean, isDirectory: boolean) => void; UpdatePinState?: () => void; CfUpdateItem?: () => void; - CfGetPlaceHolderState: (path: string) => Status; - CfGetPlaceHolderIdentity: (path: string) => string; + CfGetPlaceHolderState: (path: string) => z.infer; + CfGetPlaceHolderIdentity: (path: string) => z.infer; CfGetPlaceHolderAttributes: (path: string) => z.infer; - CfConverToPlaceholder: (path: string, fileIdentity: string) => void; + CfConverToPlaceholder: (path: string, fileIdentity: string) => z.infer; } diff --git a/yarn.lock b/yarn.lock index 2f16261f..a653629b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1388,11 +1388,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dotenv@^16.4.1: - version "16.4.7" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" - integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== - ejs@^3.1.10: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"