Skip to content

Commit

Permalink
feat(temp): add server-temp
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Apr 11, 2024
1 parent e687e94 commit 93536a0
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/temp/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
tsconfig.tsbuildinfo
34 changes: 34 additions & 0 deletions packages/temp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@cordisjs/server-temp",
"description": "Temp server plugin for cordis",
"version": "0.3.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"src"
],
"author": "Shigma <shigma10826@gmail.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/cordisjs/server.git",
"directory": "packages/temp"
},
"bugs": {
"url": "https://github.com/cordisjs/server/issues"
},
"homepage": "https://github.com/cordisjs/server/tree/main/packages/temp",
"keywords": [
"cordis",
"router",
"http",
"temporary",
"server",
"service",
"plugin"
],
"devDependencies": {
"undios": "^0.3.2"
}
}
104 changes: 104 additions & 0 deletions packages/temp/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Context, Schema, Service } from 'cordis'
import { Dict, sanitize, Time } from 'cosmokit'
import {} from '@cordisjs/server'
import {} from 'undios'
import { createReadStream } from 'fs'
import { fileURLToPath } from 'url'
import { mkdir, rm, writeFile } from 'fs/promises'
import { Readable } from 'stream'

declare module 'cordis' {
interface Context {
'server.temp': TempServer
}
}

export interface Entry {
path: string
url: string
dispose?: () => void
}

class TempServer extends Service {
static [Service.provide] = 'server.temp'
static inject = ['server', 'http']

public path: string
public selfUrl!: string
public baseDir!: string
public entries: Dict<Entry> = Object.create(null)

constructor(protected ctx: Context, public config: TempServer.Config) {
super(ctx, 'server.temp', true)
const logger = ctx.logger('temp')

this.path = sanitize(config.path)
this.selfUrl = config.selfUrl || ctx.server.config.selfUrl!
if (!this.selfUrl) {
logger.warn('missing selfUrl configuration')
}

ctx.server.get(this.path + '/:name', async (koa) => {
logger.debug(koa.params.name)
const entry = this.entries[koa.params.name]
if (!entry) return koa.status = 404
koa.body = createReadStream(entry.path)
})

ctx.on('ready', () => this.start())
ctx.on('dispose', () => this.stop())
}

async start() {
this.baseDir = this.ctx.baseDir + '/temp/' + Math.random().toString(36).slice(2) + '/'
await mkdir(this.baseDir, { recursive: true })
this.ctx.server.temp = this
}

async stop() {
await rm(this.baseDir, { recursive: true })
}

async create(data: string | Buffer | ReadableStream): Promise<Entry> {
const name = Math.random().toString(36).slice(2)
const url = this.selfUrl + this.path + '/' + name
let path: string
if (typeof data === 'string') {
if (new URL(data).protocol === 'file:') {
path = fileURLToPath(data)
} else {
const stream = await this.ctx.http.get(data, { responseType: 'stream' })
path = this.baseDir + name
await writeFile(path, Readable.fromWeb(stream))
}
} else {
path = this.baseDir + name
await writeFile(path, data instanceof ReadableStream ? Readable.fromWeb(data as any) : data)
}
return this[Context.origin].effect(() => {
const timer = setTimeout(() => dispose(), this.config.maxAge)
const dispose = async () => {
clearTimeout(timer)
delete this.entries[name]
if (path.startsWith(this.baseDir)) await rm(path)
}
return this.entries[name] = { path, url, dispose }
})
}
}

namespace TempServer {
export interface Config {
path: string
selfUrl?: string
maxAge?: number
}

export const Config: Schema<Config> = Schema.object({
path: Schema.string().default('/temp'),
selfUrl: Schema.string().role('link').description('此服务暴露在公网的地址。缺省时将使用全局配置。'),
maxAge: Schema.number().default(Time.minute * 5).description('临时文件的默认最大存活时间。'),
})
}

export default TempServer
12 changes: 12 additions & 0 deletions packages/temp/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib",
"strict": true,
"noImplicitAny": false,
},
"include": [
"src",
],
}

0 comments on commit 93536a0

Please sign in to comment.