import { FSAL } from "@main/fsal/fsal" ; import { IDirectory , IFileMeta , IDirEntryMeta , getFileMetadata , IFileDesc } from "@common/files" ; import { WorkspacePlugin } from "@main/plugins/plugin" ; import { CrossRefPlugin } from "@main/plugins/crossref-plugin" ; import { IWorkspaceData , Workspace } from "./workspace" ; import * as pathlib from "path" ; import { EventEmitter } from "events" ; import { FsalEvents , ChokidarEvents } from "@common/events" ; import { OutlinePlugin } from "@main/plugins/outline-plugin" ; import { MetadataPlugin } from "@main/plugins/metadata-plugin" ; export enum WorkspaceEvent { FILETREE_CHANGED = "filetree-changed" } export class WorkspaceService extends EventEmitter { _workspace : Workspace | null ; constructor ( private _fsal ) { super ( ) ; this . _workspace = null ; this . handleChokidarEvent = this . handleChokidarEvent . bind ( this ) ; this . _fsal . addListener ( FsalEvents . CHOKIDAR_EVENT , this . handleChokidarEvent ) ; } getWorkspaceDir ( ) { return this . _workspace && this . _workspace . dir ; } async setWorkspaceDir ( dirPath ) { console . log ( "app :: setWorkspaceDir() ::" , dirPath ) ; this . closeWorkspace ( ) ; let plugins = [ new CrossRefPlugin ( ) , new OutlinePlugin ( ) , new MetadataPlugin ( ) ] ; todo let dir = await this . _fsal . parseDir ( dirPath ) ; todo this . _workspace = await this . loadWorkspaceFromDir ( dir , plugins , true ) ; if ( ! this . _workspace ) { console . error ( "fsal :: unknown error opening workspace" ) ; return false ; } this . _fsal . watch ( dir . path ) ; let result = await this . _workspace ?. update ( ) ; todo this . emit ( WorkspaceEvent . FILETREE_CHANGED , this . getFileTree ( ) ) ; return true === result ; } returns get workspace ( ) : Workspace | null { return this . _workspace ; } caution async closeWorkspace ( persist = true ) { if ( ! this . _workspace ) { return true ; } if ( persist ) { this . writeJSON ( ) ; } this . _workspace . dispose ( ) ; this . _workspace = null ; return true ; } param dir param plugins param create private async loadWorkspaceFromDir ( dir , plugins , create = false ) { let workspace = await this . loadWorkspaceFromPath ( dir . path , plugins ) ; if ( ! workspace && ! create ) { return null ; } return workspace || new Workspace ( dir , undefined , plugins , this , this . _fsal ) ; } private async loadWorkspaceFromPath ( workspacePath , plugins ) { let contents = this . _fsal . readFile ( Workspace . getDataPath ( workspacePath ) ) ; if ( ! contents ) { return null ; } return this . loadWorkspaceFromJSON ( workspacePath , contents , plugins ) ; } private async loadWorkspaceFromJSON ( workspacePath , json , plugins ) { todo let data = JSON . parse ( json ) ; todo if ( data . path !== undefined && workspacePath !== data . path ) { throw new Error ( "workspace path does not match path in data folder" ) ; } let dir = await this . _fsal . parseDir ( workspacePath ) ; if ( ! data . pluginData || ! data . files ) { console . error ( "Workspace.fromJSON() :: invalid data :: creating fresh workspace" ) ; return new Workspace ( dir , { } , [ ] , this , this . _fsal ) ; } let pluginState ; for ( let plugin of plugins ) { if ( pluginState = data . pluginData [ plugin . plugin_name ] ) { plugin . deserialize ( pluginState ) ; } } return new Workspace ( dir , data . files , plugins , this , this . _fsal ) ; } async updatePath ( filePath ) { if ( ! this . _workspace ) { return null ; } todo let file = await this . _fsal . parseFile ( filePath ) ; if ( file === null ) { return null ; } let fileMeta = getFileMetadata ( file ) ; this . _workspace . updatePath ( fileMeta ) ; return fileMeta ; } async handleChokidarEvent ( event , info ) { console . log ( `workspace-service :: chokidar-event :: ${ event }` , info . path ) ; if ( event == ChokidarEvents . ERROR ) { throw new Error ( `app :: chokidar error :: ${ info }` ) ; } todo todo await this . workspace ?. handleChangeDetected ( event , info ) ; this . emit ( WorkspaceEvent . FILETREE_CHANGED , this . getFileTree ( ) ) ; } /**
     * Save information about the current workspace to a file,
     * so the workspace can be closed and restored later.
     */ async writeJSON ( ) { if ( ! this . _workspace ) { return false ; } let dataPath = this . _workspace . dataPath ; let success = await this . _fsal . saveFile ( dataPath , this . _workspace . toJSON ( ) , true ) ; if ( success ) { console . log ( "fsal :: workspace metadata saved to" , dataPath ) ; } else { console . error ( "fsal :: problem writing workspace metadata" , dataPath ) ; } return success ; } getFileByHash ( hash ) { if ( ! this . _workspace ) { return null ; } return this . _workspace . getFileByHash ( hash ) ; } getFileTree ( ) { if ( ! this . _workspace ) { return [ ] ; } return this . _workspace . getFileTree ( ) ; } returns resolveWorkspaceRelativePath ( relPath ) { let workspacePath = this . getWorkspaceDir ( ) ?. path ; if ( ! workspacePath ) { return null ; } todo relPath = pathlib . normalize ( relPath ) ; return pathlib . join ( workspacePath , relPath ) ; } }