sardines-built-in-services
Version:
A built-in service provider for sardines.js
119 lines (109 loc) • 4.16 kB
text/typescript
import { utils } from 'sardines-core'
import { StorageBase } from './base'
import * as fs from 'fs'
import * as path from 'path'
import * as proc from 'process'
import { Stream } from 'stream';
export interface FileStorageSettings {
root: string
}
export interface FileObject {
path?: string
content?: string
stream?: Stream
}
export enum FileStorageReturnType {
path = 'path',
content = 'content',
stream = 'stream'
}
export interface FileIdentity {
name: string
subId?: FileIdentity
returnType?: FileStorageReturnType
}
export const parsePathIntoFileIdentity = (filepath: string): FileIdentity|null => {
let id: FileIdentity|null = null
if (!filepath || filepath === '/') return null
let subdirs = (filepath[0] === '/' ? filepath.substr(1) : filepath).split('/')
let pre: FileIdentity|null = id
for (let item of subdirs) {
if (!id) {
id = {name: item}
pre = id!
} else {
pre!.subId = {name: item}
pre = pre!.subId
}
}
return id!
}
export const parseFileIdentityIntoPath = (identity: FileIdentity): string => {
let result = ''
let pre = identity
result += '/' + pre.name
while (pre.subId) {
pre = pre.subId
result += '/' + pre.name
}
return result
}
const mkdir = (dir: string) => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {recursive: true})
} else if (!fs.lstatSync(dir).isDirectory()) {
throw utils.unifyErrMesg(`Invalid file storage directory ${dir}`, 'storage', 'file')
}
}
export class FileStorage extends StorageBase {
private root: string
constructor(settings: FileStorageSettings) {
super()
this.root = path.resolve(proc.cwd(), settings.root)
mkdir(this.root)
}
async get(tableName: string, identity: FileIdentity): Promise<FileObject|null> {
let result: FileObject|null = null
const baseDir = path.resolve(this.root, tableName?`./${tableName}`:'')
if (!fs.existsSync(baseDir) || !fs.lstatSync(baseDir).isDirectory()) {
throw utils.unifyErrMesg(`table ${tableName} does not exist`, 'storage', 'file')
}
const filepath = path.resolve(baseDir, './' + (typeof identity === 'string'? identity:parseFileIdentityIntoPath(identity)))
if (!fs.existsSync(filepath) || !fs.lstatSync(filepath).isFile()) {
// throw utils.unifyErrMesg(`invalid file identity`, 'storage', 'file')
return result
}
const returnType: FileStorageReturnType = identity.returnType ? identity.returnType : FileStorageReturnType.content
switch(returnType) {
case FileStorageReturnType.content:
result = {
content: fs.readFileSync(filepath, {encoding: 'utf8'})
}
break
case FileStorageReturnType.path:
result = {path: filepath}
break
case FileStorageReturnType.stream:
result = {
stream: fs.createReadStream(filepath, {encoding: 'utf8'})
}
break
default:
break
}
return result
}
async set(tableName: string, obj: FileObject|null, identity: FileIdentity|string) {
const baseDir = path.resolve(this.root, tableName?`./${tableName}`:'')
mkdir(baseDir)
const filepath = path.resolve(baseDir, './' + (typeof identity === 'string'? identity:parseFileIdentityIntoPath(identity)))
if (!obj && fs.existsSync(filepath)) fs.unlinkSync(filepath)
else if (obj && obj.content) {
fs.writeFileSync(filepath, obj.content, {encoding: 'utf8'})
} else if (obj && obj.path && fs.existsSync(obj.path) && fs.lstatSync(obj.path).isFile()) {
fs.createReadStream(obj.path, {encoding: 'utf8'}).pipe(fs.createWriteStream(filepath, {encoding: 'utf8', autoClose: true}))
} else if (obj && obj.stream) {
obj.stream.pipe(fs.createWriteStream(filepath, {encoding: 'utf8', autoClose: true}))
}
}
}