Skip to content

Commit

Permalink
fix: handle and prevent accidental damage to the configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
WhiteMinds committed Mar 12, 2024
1 parent 4a6576c commit a946c16
Show file tree
Hide file tree
Showing 10 changed files with 337 additions and 87 deletions.
24 changes: 18 additions & 6 deletions packages/electron/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import fs from 'fs'
import path from 'path'
import { JSONFile, JSONFileSync } from '@autorecord/shared'
import { logger } from './logger'

export async function readJSONFile<T = unknown>(filePath: string, defaultValue: T): Promise<T> {
if (!fs.existsSync(filePath)) return defaultValue

const buffer = await fs.promises.readFile(filePath)
return JSON.parse(buffer.toString('utf8')) as T
try {
const buffer = await fs.promises.readFile(filePath)
return JSON.parse(buffer.toString('utf8')) as T
} catch (error) {
logger.error('readJSONFile error', filePath, error)
return defaultValue
}
}

export function readJSONFileSync<T = unknown>(filePath: string, defaultValue: T): T {
if (!fs.existsSync(filePath)) return defaultValue

const buffer = fs.readFileSync(filePath)
return JSON.parse(buffer.toString('utf8')) as T
try {
const buffer = fs.readFileSync(filePath)
return JSON.parse(buffer.toString('utf8')) as T
} catch (error) {
logger.error('readJSONFileSync error', filePath, error)
return defaultValue
}
}

export async function writeJSONFile<T = unknown>(filePath: string, json: T): Promise<void> {
fs.mkdirSync(path.dirname(filePath), { recursive: true })
await fs.promises.writeFile(filePath, JSON.stringify(json))
await new JSONFile<T>(filePath).write(json)
}

export function writeJSONFileSync<T = unknown>(filePath: string, json: T): void {
fs.mkdirSync(path.dirname(filePath), { recursive: true })
fs.writeFileSync(filePath, JSON.stringify(json))
new JSONFileSync<T>(filePath).write(json)
}
1 change: 0 additions & 1 deletion packages/http-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"lodash": "^4.17.21",
"morgan": "^1.10.0",
"ramda": "^0.28.0",
"steno": "^1.0.0",
"subtitle": "^4.2.1",
"winston": "^3.8.2"
},
Expand Down
58 changes: 2 additions & 56 deletions packages/http-server/src/db/lowdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@
* 一些代码来用。
* from https://github.com/typicode/lowdb/tree/v3.0.0
*/
import fs from 'fs'
import { Writer } from 'steno'
import { Adapter } from '@autorecord/shared'

export interface Adapter<T> {
read: () => Promise<T | null>
write: (data: T) => Promise<void>
}
export * from '@autorecord/shared'

export class Low<T = unknown> {
adapter: Adapter<T>
Expand All @@ -34,56 +30,6 @@ export class Low<T = unknown> {
}
}

export class JSONFile<T> implements Adapter<T> {
#adapter: TextFile

constructor(filename: string) {
this.#adapter = new TextFile(filename)
}

async read(): Promise<T | null> {
const data = await this.#adapter.read()
if (data === null) {
return null
} else {
return JSON.parse(data) as T
}
}

write(obj: T): Promise<void> {
return this.#adapter.write(JSON.stringify(obj, null, 2))
}
}

export class TextFile implements Adapter<string> {
#filename: string
#writer: Writer

constructor(filename: string) {
this.#filename = filename
this.#writer = new Writer(filename)
}

async read(): Promise<string | null> {
let data

try {
data = await fs.promises.readFile(this.#filename, 'utf-8')
} catch (e) {
if ((e as NodeJS.ErrnoException).code === 'ENOENT') {
return null
}
throw e
}

return data
}

write(str: string): Promise<void> {
return this.#writer.write(str)
}
}

export class MissingAdapterError extends Error {
constructor() {
super()
Expand Down
18 changes: 12 additions & 6 deletions packages/http-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export * from './routes/api_types'
export async function startServer(opts: PickPartial<ServerOpts, 'getSettings' | 'setSettings' | 'logger'> = {}) {
const serverOpts: ServerOpts = {
...opts,
getSettings: opts.getSettings ?? defaultGetSettings,
getSettings: opts.getSettings ?? createDefaultGetSettings({ logger: opts.logger ?? console }),
setSettings: opts.setSettings ?? defaultSetSettings,
logger: opts.logger ?? console,
}
Expand Down Expand Up @@ -54,11 +54,17 @@ export async function startServer(opts: PickPartial<ServerOpts, 'getSettings' |

// TODO: Opts 的默认值代码似乎不应该放这里
const settingsConfigPath = path.join(paths.config, 'settings.json')
async function defaultGetSettings() {
return readJSONFile<Settings>(settingsConfigPath, {
notExitOnAllWindowsClosed: true,
noticeOnRecordStart: true,
})
function createDefaultGetSettings(opts: Pick<ServerOpts, 'logger'>) {
return async function defaultGetSettings() {
return readJSONFile<Settings>(
settingsConfigPath,
{
notExitOnAllWindowsClosed: true,
noticeOnRecordStart: true,
},
opts,
)
}
}
async function defaultSetSettings(newSettings: Settings) {
await writeJSONFile(settingsConfigPath, newSettings)
Expand Down
2 changes: 1 addition & 1 deletion packages/http-server/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function addRecorderWithAutoIncrementId(args: RecorderCreateOpts<Recorder
export async function initRecorderManager(serverOpts: ServerOpts): Promise<void> {
const { logger } = serverOpts

const managerConfig = readJSONFileSync<ManagerConfig>(managerConfigPath, defaultManagerConfig)
const managerConfig = readJSONFileSync<ManagerConfig>(managerConfigPath, defaultManagerConfig, serverOpts)

// 这里做一些旧版本 schema 升级的处理
if (managerConfig.ffmpegOutputArgs == null) {
Expand Down
34 changes: 25 additions & 9 deletions packages/http-server/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import fs from 'fs'
import path from 'path'
import * as R from 'ramda'
import { debounce, DebouncedFunc, DebounceSettings, memoize, throttle } from 'lodash'
import { JSONFile, JSONFileSync } from '@autorecord/shared'
import { ServerOpts } from './types'

export type PickPartial<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & Partial<Pick<T, K>>

Expand Down Expand Up @@ -43,28 +45,42 @@ export function ensureFileFolderExists(filePath: string) {
fs.mkdirSync(folder, { recursive: true })
}

export async function readJSONFile<T = unknown>(filePath: string, defaultValue: T): Promise<T> {
export async function readJSONFile<T = unknown>(
filePath: string,
defaultValue: T,
opts?: Pick<ServerOpts, 'logger'>,
): Promise<T> {
if (!fs.existsSync(filePath)) return defaultValue

const buffer = await fs.promises.readFile(filePath)
return JSON.parse(buffer.toString('utf8')) as T
try {
const buffer = await fs.promises.readFile(filePath)
return JSON.parse(buffer.toString('utf8')) as T
} catch (error) {
opts?.logger.error('readJSONFile error', filePath, error)
return defaultValue
}
}

export function readJSONFileSync<T = unknown>(filePath: string, defaultValue: T): T {
export function readJSONFileSync<T = unknown>(filePath: string, defaultValue: T, opts?: Pick<ServerOpts, 'logger'>): T {
if (!fs.existsSync(filePath)) return defaultValue

const buffer = fs.readFileSync(filePath)
return JSON.parse(buffer.toString('utf8')) as T
try {
const buffer = fs.readFileSync(filePath)
return JSON.parse(buffer.toString('utf8')) as T
} catch (error) {
opts?.logger.error('readJSONFileSync error', filePath, error)
return defaultValue
}
}

export async function writeJSONFile<T = unknown>(filePath: string, json: T): Promise<void> {
ensureFileFolderExists(filePath)
await fs.promises.writeFile(filePath, JSON.stringify(json))
await new JSONFile<T>(filePath).write(json)
}

export function writeJSONFileSync<T = unknown>(filePath: string, json: T): void {
fs.mkdirSync(path.dirname(filePath), { recursive: true })
fs.writeFileSync(filePath, JSON.stringify(json))
ensureFileFolderExists(filePath)
new JSONFileSync<T>(filePath).write(json)
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ export interface Settings {
export interface ClientAPI {
getVersion(): string
}

export * from './steno'
export * from './jsonfile'

0 comments on commit a946c16

Please sign in to comment.