-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: reduce IPC & API handlers - shared node logics (janhq#2011)
- Loading branch information
Showing
51 changed files
with
789 additions
and
965 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { AppRoute, DownloadRoute, ExtensionRoute, FileManagerRoute, FileSystemRoute } from '../../../api' | ||
import { Downloader } from '../processors/download' | ||
import { FileSystem } from '../processors/fs' | ||
import { Extension } from '../processors/extension' | ||
import { FSExt } from '../processors/fsExt' | ||
import { App } from '../processors/app' | ||
|
||
export class RequestAdapter { | ||
downloader: Downloader | ||
fileSystem: FileSystem | ||
extension: Extension | ||
fsExt: FSExt | ||
app: App | ||
|
||
constructor(observer?: Function) { | ||
this.downloader = new Downloader(observer) | ||
this.fileSystem = new FileSystem() | ||
this.extension = new Extension() | ||
this.fsExt = new FSExt() | ||
this.app = new App() | ||
} | ||
|
||
// TODO: Clearer Factory pattern here | ||
process(route: string, ...args: any) { | ||
if (route in DownloadRoute) { | ||
return this.downloader.process(route, ...args) | ||
} else if (route in FileSystemRoute) { | ||
return this.fileSystem.process(route, ...args) | ||
} else if (route in ExtensionRoute) { | ||
return this.extension.process(route, ...args) | ||
} else if (route in FileManagerRoute) { | ||
return this.fsExt.process(route, ...args) | ||
} else if (route in AppRoute) { | ||
return this.app.process(route, ...args) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { CoreRoutes } from '../../../api' | ||
import { RequestAdapter } from './adapter' | ||
|
||
export type Handler = (route: string, args: any) => any | ||
|
||
export class RequestHandler { | ||
handler: Handler | ||
adataper: RequestAdapter | ||
|
||
constructor(handler: Handler, observer?: Function) { | ||
this.handler = handler | ||
this.adataper = new RequestAdapter(observer) | ||
} | ||
|
||
handle() { | ||
CoreRoutes.map((route) => { | ||
this.handler(route, async (...args: any[]) => { | ||
const values = await this.adataper.process(route, ...args) | ||
return values | ||
}) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './HttpServer' | ||
export * from './routes' | ||
export * from './restful/v1' | ||
export * from './common/handler' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export abstract class Processor { | ||
abstract process(key: string, ...args: any[]): any | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { basename, isAbsolute, join, relative } from 'path' | ||
|
||
import { AppRoute } from '../../../api' | ||
import { Processor } from './Processor' | ||
import { getAppConfigurations as appConfiguration, updateAppConfiguration } from '../../helper' | ||
import { log as writeLog, logServer as writeServerLog } from '../../helper/log' | ||
import { appResourcePath } from '../../helper/path' | ||
|
||
export class App implements Processor { | ||
observer?: Function | ||
|
||
constructor(observer?: Function) { | ||
this.observer = observer | ||
} | ||
|
||
process(key: string, ...args: any[]): any { | ||
const instance = this as any | ||
const func = instance[key] | ||
return func(...args) | ||
} | ||
|
||
/** | ||
* Joins multiple paths together, respect to the current OS. | ||
*/ | ||
joinPath(args: any[]) { | ||
return join(...args) | ||
} | ||
|
||
/** | ||
* Checks if the given path is a subdirectory of the given directory. | ||
* | ||
* @param _event - The IPC event object. | ||
* @param from - The path to check. | ||
* @param to - The directory to check against. | ||
* | ||
* @returns {Promise<boolean>} - A promise that resolves with the result. | ||
*/ | ||
isSubdirectory(from: any, to: any) { | ||
const rel = relative(from, to) | ||
const isSubdir = rel && !rel.startsWith('..') && !isAbsolute(rel) | ||
|
||
if (isSubdir === '') return false | ||
else return isSubdir | ||
} | ||
|
||
/** | ||
* Retrieve basename from given path, respect to the current OS. | ||
*/ | ||
baseName(args: any) { | ||
return basename(args) | ||
} | ||
|
||
/** | ||
* Log message to log file. | ||
*/ | ||
log(args: any) { | ||
writeLog(args) | ||
} | ||
|
||
/** | ||
* Log message to log file. | ||
*/ | ||
logServer(args: any) { | ||
writeServerLog(args) | ||
} | ||
|
||
getAppConfigurations() { | ||
return appConfiguration() | ||
} | ||
|
||
async updateAppConfiguration(args: any) { | ||
await updateAppConfiguration(args) | ||
} | ||
|
||
/** | ||
* Start Jan API Server. | ||
*/ | ||
async startServer(args?: any) { | ||
const { startServer } = require('@janhq/server') | ||
return startServer({ | ||
host: args?.host, | ||
port: args?.port, | ||
isCorsEnabled: args?.isCorsEnabled, | ||
isVerboseEnabled: args?.isVerboseEnabled, | ||
schemaPath: join(await appResourcePath(), 'docs', 'openapi', 'jan.yaml'), | ||
baseDir: join(await appResourcePath(), 'docs', 'openapi'), | ||
}) | ||
} | ||
|
||
/** | ||
* Stop Jan API Server. | ||
*/ | ||
stopServer() { | ||
const { stopServer } = require('@janhq/server') | ||
return stopServer() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { resolve, sep } from 'path' | ||
import { DownloadEvent } from '../../../api' | ||
import { normalizeFilePath } from '../../helper/path' | ||
import { getJanDataFolderPath } from '../../helper' | ||
import { DownloadManager } from '../../helper/download' | ||
import { createWriteStream, renameSync } from 'fs' | ||
import { Processor } from './Processor' | ||
import { DownloadState } from '../../../types' | ||
|
||
export class Downloader implements Processor { | ||
observer?: Function | ||
|
||
constructor(observer?: Function) { | ||
this.observer = observer | ||
} | ||
|
||
process(key: string, ...args: any[]): any { | ||
const instance = this as any | ||
const func = instance[key] | ||
return func(this.observer, ...args) | ||
} | ||
|
||
downloadFile(observer: any, url: string, localPath: string, network: any) { | ||
const request = require('request') | ||
const progress = require('request-progress') | ||
|
||
const strictSSL = !network?.ignoreSSL | ||
const proxy = network?.proxy?.startsWith('http') ? network.proxy : undefined | ||
if (typeof localPath === 'string') { | ||
localPath = normalizeFilePath(localPath) | ||
} | ||
const array = localPath.split(sep) | ||
const fileName = array.pop() ?? '' | ||
const modelId = array.pop() ?? '' | ||
|
||
const destination = resolve(getJanDataFolderPath(), localPath) | ||
const rq = request({ url, strictSSL, proxy }) | ||
|
||
// Put request to download manager instance | ||
DownloadManager.instance.setRequest(localPath, rq) | ||
|
||
// Downloading file to a temp file first | ||
const downloadingTempFile = `${destination}.download` | ||
|
||
progress(rq, {}) | ||
.on('progress', (state: any) => { | ||
const downloadState: DownloadState = { | ||
...state, | ||
modelId, | ||
fileName, | ||
downloadState: 'downloading', | ||
} | ||
console.log('progress: ', downloadState) | ||
observer?.(DownloadEvent.onFileDownloadUpdate, downloadState) | ||
DownloadManager.instance.downloadProgressMap[modelId] = downloadState | ||
}) | ||
.on('error', (error: Error) => { | ||
const currentDownloadState = DownloadManager.instance.downloadProgressMap[modelId] | ||
const downloadState: DownloadState = { | ||
...currentDownloadState, | ||
downloadState: 'error', | ||
} | ||
if (currentDownloadState) { | ||
DownloadManager.instance.downloadProgressMap[modelId] = downloadState | ||
} | ||
|
||
observer?.(DownloadEvent.onFileDownloadError, downloadState) | ||
}) | ||
.on('end', () => { | ||
const currentDownloadState = DownloadManager.instance.downloadProgressMap[modelId] | ||
if (currentDownloadState && DownloadManager.instance.networkRequests[localPath]) { | ||
// Finished downloading, rename temp file to actual file | ||
renameSync(downloadingTempFile, destination) | ||
const downloadState: DownloadState = { | ||
...currentDownloadState, | ||
downloadState: 'end', | ||
} | ||
observer?.(DownloadEvent.onFileDownloadSuccess, downloadState) | ||
DownloadManager.instance.downloadProgressMap[modelId] = downloadState | ||
} | ||
}) | ||
.pipe(createWriteStream(downloadingTempFile)) | ||
} | ||
|
||
abortDownload(observer: any, fileName: string) { | ||
const rq = DownloadManager.instance.networkRequests[fileName] | ||
if (rq) { | ||
DownloadManager.instance.networkRequests[fileName] = undefined | ||
rq?.abort() | ||
} else { | ||
observer?.(DownloadEvent.onFileDownloadError, { | ||
fileName, | ||
error: 'aborted', | ||
}) | ||
} | ||
} | ||
|
||
resumeDownload(observer: any, fileName: any) { | ||
DownloadManager.instance.networkRequests[fileName]?.resume() | ||
} | ||
|
||
pauseDownload(observer: any, fileName: any) { | ||
DownloadManager.instance.networkRequests[fileName]?.pause() | ||
} | ||
} |
Oops, something went wrong.