Skip to content

Commit

Permalink
refactor: file prefix replace utils & add unit test (janhq#1676)
Browse files Browse the repository at this point in the history
* refactor: file prefix replace utils

* chore: add unit tests for core module
  • Loading branch information
louis-jan authored Jan 22, 2024
1 parent fc3a5c9 commit 99d083d
Show file tree
Hide file tree
Showing 21 changed files with 204 additions and 386 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ lint: check-file-counts
# Testing
test: lint
yarn build:test
yarn test:unit
yarn test

# Builds and publishes the app
Expand Down
3 changes: 0 additions & 3 deletions core/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@ coverage
.vscode
.idea
dist
compiled
.awcache
.rpt2_cache
docs
7 changes: 7 additions & 0 deletions core/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1',
},
}
8 changes: 7 additions & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"module": "dist/core.es5.js",
"typings": "dist/types/index.d.ts",
"files": [
"dist"
"dist",
"types"
],
"author": "Jan <[email protected]>",
"exports": {
Expand All @@ -38,18 +39,23 @@
},
"scripts": {
"lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'",
"test": "jest",
"prebuild": "rimraf dist",
"build": "tsc --module commonjs && rollup -c rollup.config.ts",
"start": "rollup -c rollup.config.ts -w"
},
"devDependencies": {
"jest": "^25.4.0",
"@types/jest": "^29.5.11",
"@types/node": "^12.0.2",
"eslint-plugin-jest": "^23.8.2",
"rollup": "^2.38.5",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"ts-jest": "^26.1.1",
"tslib": "^2.6.2",
"typescript": "^5.2.2"
}
Expand Down
82 changes: 41 additions & 41 deletions core/src/node/api/routes/download.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
import { DownloadRoute } from '../../../api'
import { join } from 'path'
import { userSpacePath } from '../../extension/manager'
import { DownloadManager } from '../../download'
import { HttpServer } from '../HttpServer'
import { createWriteStream } from 'fs'
import { DownloadRoute } from "../../../api";
import { join } from "path";
import { userSpacePath } from "../../extension/manager";
import { DownloadManager } from "../../download";
import { HttpServer } from "../HttpServer";
import { createWriteStream } from "fs";
import { normalizeFilePath } from "../../path";

export const downloadRouter = async (app: HttpServer) => {
app.post(`/${DownloadRoute.downloadFile}`, async (req, res) => {
const strictSSL = !(req.query.ignoreSSL === 'true');
const proxy = req.query.proxy?.startsWith('http') ? req.query.proxy : undefined;
const body = JSON.parse(req.body as any)
const strictSSL = !(req.query.ignoreSSL === "true");
const proxy = req.query.proxy?.startsWith("http") ? req.query.proxy : undefined;
const body = JSON.parse(req.body as any);
const normalizedArgs = body.map((arg: any) => {
if (typeof arg === 'string' && arg.includes('file:/')) {
return join(userSpacePath, arg.replace('file:/', ''))
if (typeof arg === "string") {
return join(userSpacePath, normalizeFilePath(arg));
}
return arg
})
return arg;
});

const localPath = normalizedArgs[1]
const fileName = localPath.split('/').pop() ?? ''
const localPath = normalizedArgs[1];
const fileName = localPath.split("/").pop() ?? "";

const request = require('request')
const progress = require('request-progress')
const rq = request({ url: normalizedArgs[0], strictSSL, proxy })
const request = require("request");
const progress = require("request-progress");

const rq = request({ url: normalizedArgs[0], strictSSL, proxy });
progress(rq, {})
.on('progress', function (state: any) {
console.log('download onProgress', state)
.on("progress", function (state: any) {
console.log("download onProgress", state);
})
.on('error', function (err: Error) {
console.log('download onError', err)
.on("error", function (err: Error) {
console.log("download onError", err);
})
.on('end', function () {
console.log('download onEnd')
.on("end", function () {
console.log("download onEnd");
})
.pipe(createWriteStream(normalizedArgs[1]))
.pipe(createWriteStream(normalizedArgs[1]));

DownloadManager.instance.setRequest(fileName, rq)
})
DownloadManager.instance.setRequest(fileName, rq);
});

app.post(`/${DownloadRoute.abortDownload}`, async (req, res) => {
const body = JSON.parse(req.body as any)
const body = JSON.parse(req.body as any);
const normalizedArgs = body.map((arg: any) => {
if (typeof arg === 'string' && arg.includes('file:/')) {
return join(userSpacePath, arg.replace('file:/', ''))
if (typeof arg === "string") {
return join(userSpacePath, normalizeFilePath(arg));
}
return arg
})
return arg;
});

const localPath = normalizedArgs[0]
const fileName = localPath.split('/').pop() ?? ''
console.debug('fileName', fileName)
const rq = DownloadManager.instance.networkRequests[fileName]
DownloadManager.instance.networkRequests[fileName] = undefined
rq?.abort()
})
}
const localPath = normalizedArgs[0];
const fileName = localPath.split("/").pop() ?? "";
const rq = DownloadManager.instance.networkRequests[fileName];
DownloadManager.instance.networkRequests[fileName] = undefined;
rq?.abort();
});
};
1 change: 1 addition & 0 deletions core/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './download'
export * from './module'
export * from './api'
export * from './log'
export * from './path'
9 changes: 9 additions & 0 deletions core/src/node/path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Normalize file path
* Remove all file protocol prefix
* @param path
* @returns
*/
export function normalizeFilePath(path: string): string {
return path.replace(/^(file:[\\/]+)([^:\s]+)$/, "$2");
}
12 changes: 12 additions & 0 deletions core/tests/node/path.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { normalizeFilePath } from "../../src/node/path";

describe("Test file normalize", () => {
test("returns no file protocol prefix on Unix", async () => {
expect(normalizeFilePath("file://test.txt")).toBe("test.txt");
expect(normalizeFilePath("file:/test.txt")).toBe("test.txt");
});
test("returns no file protocol prefix on Windows", async () => {
expect(normalizeFilePath("file:\\\\test.txt")).toBe("test.txt");
expect(normalizeFilePath("file:\\test.txt")).toBe("test.txt");
});
});
2 changes: 1 addition & 1 deletion core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"declarationDir": "dist/types",
"outDir": "dist/lib",
"importHelpers": true,
"typeRoots": ["node_modules/@types"]
"types": ["@types/jest"]
},
"include": ["src"]
}
100 changes: 51 additions & 49 deletions electron/handlers/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import request from 'request'
import { createWriteStream, renameSync } from 'fs'
import { DownloadEvent, DownloadRoute } from '@janhq/core'
const progress = require('request-progress')
import { DownloadManager } from '@janhq/core/node'
import { DownloadManager, normalizeFilePath } from '@janhq/core/node'

export function handleDownloaderIPCs() {
/**
Expand Down Expand Up @@ -54,66 +54,68 @@ export function handleDownloaderIPCs() {
* @param url - The URL to download the file from.
* @param fileName - The name to give the downloaded file.
*/
ipcMain.handle(DownloadRoute.downloadFile, async (_event, url, fileName, network) => {
const strictSSL = !network?.ignoreSSL;
const proxy = network?.proxy?.startsWith('http') ? network.proxy : undefined;
const userDataPath = join(app.getPath('home'), 'jan')
if (
typeof fileName === 'string' &&
(fileName.includes('file:/') || fileName.includes('file:\\'))
) {
fileName = fileName.replace('file:/', '').replace('file:\\', '')
}
const destination = resolve(userDataPath, fileName)
const rq = request({ url, strictSSL, proxy })
ipcMain.handle(
DownloadRoute.downloadFile,
async (_event, url, fileName, network) => {
const strictSSL = !network?.ignoreSSL
const proxy = network?.proxy?.startsWith('http')
? network.proxy
: undefined
const userDataPath = join(app.getPath('home'), 'jan')
if (typeof fileName === 'string') {
fileName = normalizeFilePath(fileName)
}
const destination = resolve(userDataPath, fileName)
const rq = request({ url, strictSSL, proxy })

// Put request to download manager instance
DownloadManager.instance.setRequest(fileName, rq)
// Put request to download manager instance
DownloadManager.instance.setRequest(fileName, rq)

// Downloading file to a temp file first
const downloadingTempFile = `${destination}.download`

progress(rq, {})
.on('progress', function (state: any) {
WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadUpdate,
{
...state,
fileName,
}
)
})
.on('error', function (err: Error) {
WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadError,
{
fileName,
err,
}
)
})
.on('end', function () {
if (DownloadManager.instance.networkRequests[fileName]) {
// Finished downloading, rename temp file to actual file
renameSync(downloadingTempFile, destination)
// Downloading file to a temp file first
const downloadingTempFile = `${destination}.download`

progress(rq, {})
.on('progress', function (state: any) {
WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadSuccess,
DownloadEvent.onFileDownloadUpdate,
{
...state,
fileName,
}
)
DownloadManager.instance.setRequest(fileName, undefined)
} else {
})
.on('error', function (err: Error) {
WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadError,
{
fileName,
err: { message: 'aborted' },
err,
}
)
}
})
.pipe(createWriteStream(downloadingTempFile))
})
})
.on('end', function () {
if (DownloadManager.instance.networkRequests[fileName]) {
// Finished downloading, rename temp file to actual file
renameSync(downloadingTempFile, destination)

WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadSuccess,
{
fileName,
}
)
DownloadManager.instance.setRequest(fileName, undefined)
} else {
WindowManager?.instance.currentWindow?.webContents.send(
DownloadEvent.onFileDownloadError,
{
fileName,
err: { message: 'aborted' },
}
)
}
})
.pipe(createWriteStream(downloadingTempFile))
}
)
}
7 changes: 2 additions & 5 deletions electron/handlers/fileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { userSpacePath, getResourcePath } from './../utils/path'
import fs from 'fs'
import { join } from 'path'
import { FileStat } from '@janhq/core'
import { normalizeFilePath } from '@janhq/core/node'

/**
* Handles file system extensions operations.
Expand Down Expand Up @@ -42,11 +43,7 @@ export function handleFileMangerIPCs() {
ipcMain.handle(
FileManagerRoute.fileStat,
async (_event, path: string): Promise<FileStat | undefined> => {
const normalizedPath = path
.replace(`file://`, '')
.replace(`file:/`, '')
.replace(`file:\\\\`, '')
.replace(`file:\\`, '')
const normalizedPath = normalizeFilePath(path)

const fullPath = join(userSpacePath, normalizedPath)
const isExist = fs.existsSync(fullPath)
Expand Down
10 changes: 2 additions & 8 deletions electron/handlers/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ipcMain } from 'electron'
import { FileSystemRoute } from '@janhq/core'
import { userSpacePath } from '../utils/path'
import { join } from 'path'
import { normalizeFilePath } from '@janhq/core/node'
/**
* Handles file system operations.
*/
Expand All @@ -15,14 +16,7 @@ export function handleFsIPCs() {
...args.map((arg) =>
typeof arg === 'string' &&
(arg.includes(`file:/`) || arg.includes(`file:\\`))
? join(
userSpacePath,
arg
.replace(`file://`, '')
.replace(`file:/`, '')
.replace(`file:\\\\`, '')
.replace(`file:\\`, '')
)
? join(userSpacePath, normalizeFilePath(arg))
: arg
)
)
Expand Down
8 changes: 2 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,15 @@
],
"nohoist": [
"uikit",
"uikit/*",
"core",
"core/*",
"electron",
"electron/**",
"web",
"web/**",
"server",
"server/**"
"server"
]
},
"scripts": {
"lint": "yarn workspace jan lint && yarn workspace jan-web lint",
"test:unit": "yarn workspace @janhq/core test",
"test": "yarn workspace jan test:e2e",
"copy:assets": "cpx \"models/**\" \"electron/models/\" && cpx \"docs/openapi/**\" \"electron/docs/openapi\"",
"dev:electron": "yarn copy:assets && yarn workspace jan dev",
Expand Down
Loading

0 comments on commit 99d083d

Please sign in to comment.