diff --git a/.eslintrc.yml b/.eslintrc.yml index 45c7a2a8..187da487 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -11,7 +11,7 @@ globals: KOISHI_CONFIG: true extends: - - '@koishijs/eslint-config' + - '@cordisjs/eslint-config' plugins: - mocha diff --git a/README.md b/README.md index b811d99d..ee7e23e5 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ await ctx.start() ```ts import { Context } from '@satorijs/satori' -import router from '@satorijs/router' +import router from '@cordisjs/server' import telegram from '@satorijs/adapter-telegram' // your application will be listening http://localhost:8080 diff --git a/adapters/dingtalk/package.json b/adapters/dingtalk/package.json index 045752c5..7304578c 100644 --- a/adapters/dingtalk/package.json +++ b/adapters/dingtalk/package.json @@ -30,7 +30,7 @@ "chat" ], "devDependencies": { - "@satorijs/router": "^1.1.2" + "@cordisjs/server": "^0.1.3" }, "peerDependencies": { "@satorijs/satori": "^3.2.3" diff --git a/adapters/dingtalk/src/http.ts b/adapters/dingtalk/src/http.ts index c87033d6..45c01dc4 100644 --- a/adapters/dingtalk/src/http.ts +++ b/adapters/dingtalk/src/http.ts @@ -1,5 +1,5 @@ import { Adapter, Context, Logger } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import { DingtalkBot } from './bot' import crypto from 'node:crypto' import { Message } from './types' diff --git a/adapters/kook/package.json b/adapters/kook/package.json index d0388a04..1b435c9e 100644 --- a/adapters/kook/package.json +++ b/adapters/kook/package.json @@ -29,7 +29,7 @@ "chat" ], "devDependencies": { - "@satorijs/router": "^1.1.2" + "@cordisjs/server": "^0.1.3" }, "peerDependencies": { "@satorijs/satori": "^3.2.3" diff --git a/adapters/kook/src/http.ts b/adapters/kook/src/http.ts index 1655fd10..5770cb20 100644 --- a/adapters/kook/src/http.ts +++ b/adapters/kook/src/http.ts @@ -1,5 +1,5 @@ import { Adapter, Context, Logger, sanitize, Schema } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import { KookBot } from './bot' import { adaptSession } from './utils' diff --git a/adapters/lark/package.json b/adapters/lark/package.json index fa3aca3e..e14adee8 100644 --- a/adapters/lark/package.json +++ b/adapters/lark/package.json @@ -33,7 +33,7 @@ "chat" ], "devDependencies": { - "@satorijs/router": "^1.1.2" + "@cordisjs/server": "^0.1.3" }, "peerDependencies": { "@satorijs/satori": "^3.2.3" diff --git a/adapters/lark/src/http.ts b/adapters/lark/src/http.ts index 8fad4649..90424b1a 100644 --- a/adapters/lark/src/http.ts +++ b/adapters/lark/src/http.ts @@ -1,6 +1,6 @@ import internal from 'stream' import { Adapter, Context, Logger, Schema } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import { FeishuBot } from './bot' import { AllEvents } from './types' diff --git a/adapters/line/package.json b/adapters/line/package.json index 8c8da22c..6c73e868 100644 --- a/adapters/line/package.json +++ b/adapters/line/package.json @@ -29,7 +29,7 @@ "chat" ], "devDependencies": { - "@satorijs/router": "^1.1.2" + "@cordisjs/server": "^0.1.3" }, "peerDependencies": { "@satorijs/satori": "^3.2.3" diff --git a/adapters/line/src/http.ts b/adapters/line/src/http.ts index ece4ab23..57994dac 100644 --- a/adapters/line/src/http.ts +++ b/adapters/line/src/http.ts @@ -1,5 +1,5 @@ import { Adapter, Context } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import crypto from 'node:crypto' import { LineBot } from './bot' import { WebhookRequestBody } from './types' @@ -7,10 +7,10 @@ import { adaptSessions } from './utils' import internal from 'stream' export class HttpServer extends Adapter> { - static inject = ['router'] + static inject = ['server'] async connect(bot: LineBot) { - bot.ctx.router.post('/line', async (ctx) => { + bot.ctx.server.post('/line', async (ctx) => { const sign = ctx.headers['x-line-signature']?.toString() const parsed = ctx.request.body as WebhookRequestBody const { destination } = parsed @@ -29,7 +29,7 @@ export class HttpServer extends Adapter { + bot.ctx.server.get('/line/assets/:self_id/:message_id', async (ctx) => { const messageId = ctx.params.message_id const selfId = ctx.params.self_id const bot = this.bots.find((bot) => bot.selfId === selfId) @@ -45,7 +45,7 @@ export class HttpServer extends Adapter implements Login await this.context.parallel('bot-disconnect', this) await this.adapter?.disconnect(this) } catch (error) { - this.context.emit('internal/warning', error) + this.context.emit('internal/error', error) } finally { this.offline() } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index a611343b..3fbe5636 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,19 +3,21 @@ import { Awaitable, defineProperty, Dict } from 'cosmokit' import { Bot } from './bot' import { Session } from './session' import Schema from 'schemastery' -import Logger from 'reggol' import Quester from 'cordis-axios' +import * as logger from '@cordisjs/logger' import { Event, SendOptions } from '@satorijs/protocol' import h from '@satorijs/element' -h.warn = new Logger('element').warn +h.warn = new logger.Logger('element').warn // do not remove the `type` modifier // because `esModuleInterop` is not respected by esbuild export type { Fragment, Render } from '@satorijs/element' +export { Logger } from '@cordisjs/logger' + export { h, h as Element, h as segment } -export { Schema, Schema as z, Logger, Quester } +export { Schema, Schema as z, Quester } export * as Satori from '@satorijs/protocol' export * as Universal from '@satorijs/protocol' @@ -99,7 +101,7 @@ export interface Events extends cordis.Events { export interface Service extends Context.Associate<'service'> {} export class Service extends cordis.Service { - public logger: Logger + public logger: logger.Logger constructor(ctx: C, name: string, immediate?: boolean) { super(ctx, name, immediate) @@ -140,17 +142,8 @@ export class Context extends cordis.Context { constructor(config: Context.Config = {}) { super(config) - - this.baseDir = globalThis.process?.cwd() || '' + this.plugin(logger) this.http = new Quester(config.request) - - this.on('internal/warning', function (format, ...args) { - this.logger('app').warn(format, ...args) - }) - } - - logger(name: string) { - return new Logger(name, { [Context.current]: this }) } component(name: string, component: Component, options: Component.Options = {}) { diff --git a/packages/router/.npmignore b/packages/router/.npmignore deleted file mode 100644 index 7e5fcbc1..00000000 --- a/packages/router/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -tsconfig.tsbuildinfo diff --git a/packages/router/package.json b/packages/router/package.json deleted file mode 100644 index c4a4b204..00000000 --- a/packages/router/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "@satorijs/router", - "description": "Router plugin for cordis", - "version": "1.1.2", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "files": [ - "lib", - "src" - ], - "author": "Shigma ", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/satorijs/satori.git", - "directory": "packages/router" - }, - "bugs": { - "url": "https://github.com/satorijs/satori/issues" - }, - "homepage": "https://github.com/satorijs/satori/tree/master/packages/router", - "keywords": [ - "cordis", - "router", - "http", - "ws", - "websocket", - "server", - "service" - ], - "devDependencies": { - "@types/parseurl": "^1.3.2" - }, - "dependencies": { - "@koa/router": "^10.1.1", - "@types/koa": "*", - "@types/koa__router": "*", - "@types/ws": "^8.5.8", - "koa": "^2.14.2", - "koa-bodyparser": "^4.4.1", - "parseurl": "^1.3.3", - "path-to-regexp": "^6.2.1", - "ws": "^8.14.2" - }, - "peerDependencies": { - "@satorijs/satori": "^3.2.3" - } -} diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts deleted file mode 100644 index ec62c7bb..00000000 --- a/packages/router/src/index.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { Context, Logger, Schema } from '@satorijs/core' -import { MaybeArray, remove, trimSlash } from 'cosmokit' -import { createServer, IncomingMessage, Server } from 'http' -import { pathToRegexp } from 'path-to-regexp' -import parseUrl from 'parseurl' -import WebSocket from 'ws' -import KoaRouter from '@koa/router' -import Koa from 'koa' -import { listen } from './listen' - -declare module 'koa' { - // koa-bodyparser - interface Request { - body?: any - rawBody?: string - } -} - -declare module '@satorijs/core' { - interface Context { - router: Router - } - - interface Events { - 'router/ready'(this: Router): void - } -} - -type WebSocketCallback = (socket: WebSocket, request: IncomingMessage) => void - -export class WebSocketLayer { - clients = new Set() - regexp: RegExp - - constructor(private router: Router, path: MaybeArray, public callback?: WebSocketCallback) { - this.regexp = pathToRegexp(path) - } - - accept(socket: WebSocket, request: IncomingMessage) { - if (!this.regexp.test(parseUrl(request)!.pathname!)) return - this.clients.add(socket) - socket.addEventListener('close', () => { - this.clients.delete(socket) - }) - this.callback?.(socket, request) - return true - } - - close() { - remove(this.router.wsStack, this) - for (const socket of this.clients) { - socket.close() - } - } -} - -export class Router extends KoaRouter { - public _http: Server - public _ws: WebSocket.Server - public wsStack: WebSocketLayer[] = [] - - public host!: string - public port!: number - - private logger: Logger - - constructor(protected ctx: Context, public config: Router.Config) { - super() - this.logger = ctx.logger('router') - - // create server - const koa = new Koa() - koa.use(require('koa-bodyparser')({ - enableTypes: ['json', 'form', 'xml'], - jsonLimit: '10mb', - formLimit: '10mb', - textLimit: '10mb', - xmlLimit: '10mb', - })) - koa.use(this.routes()) - koa.use(this.allowedMethods()) - - this._http = createServer(koa.callback()) - this._ws = new WebSocket.Server({ - server: this._http, - }) - - this._ws.on('connection', (socket, request) => { - for (const manager of this.wsStack) { - if (manager.accept(socket, request)) return - } - socket.close() - }) - - ctx.decline(['selfUrl', 'host', 'port', 'maxPort']) - - if (config.selfUrl) { - config.selfUrl = trimSlash(config.selfUrl) - } - - ctx.on('ready', async () => { - const { host = '127.0.0.1', port } = config - if (!port) return - this.host = host - this.port = await listen(config) - this._http.listen(this.port, host) - this.logger.info('server listening at %c', this.selfUrl) - ctx.emit(this, 'router/ready') - }, true) - - ctx.on('dispose', () => { - if (config.port) { - this.logger.info('http server closing') - } - this._ws?.close() - this._http?.close() - }) - - ctx.on('event/router/ready', (ctx: Context, listener: Function) => { - if (!this[Context.filter](ctx) || !this.port) return - ctx.scope.ensure(async () => listener()) - return () => false - }) - } - - [Context.filter](ctx: Context) { - return ctx[Context.shadow].router === this.ctx[Context.shadow].router - } - - get selfUrl() { - const wildcard = ['0.0.0.0', '::'] - const host = wildcard.includes(this.host) ? '127.0.0.1' : this.host - return `http://${host}:${this.port}` - } - - /** - * hack into router methods to make sure that koa middlewares are disposable - */ - register(...args: Parameters) { - const layer = super.register(...args) - const context = this[Context.current] - context?.state.disposables.push(() => { - remove(this.stack, layer) - }) - return layer - } - - ws(path: MaybeArray, callback?: WebSocketCallback) { - const layer = new WebSocketLayer(this, path, callback) - this.wsStack.push(layer) - const context = this[Context.current] - context?.state.disposables.push(() => layer.close()) - return layer - } -} - -export namespace Router { - export interface Config { - host: string - port: number - maxPort?: number - selfUrl?: string - } - - export const Config: Schema = Schema.object({ - host: Schema.string().default('127.0.0.1').description('要监听的 IP 地址。如果将此设置为 `0.0.0.0` 将监听所有地址,包括局域网和公网地址。'), - port: Schema.natural().max(65535).description('要监听的初始端口号。'), - maxPort: Schema.natural().max(65535).description('允许监听的最大端口号。'), - selfUrl: Schema.string().role('link').description('应用暴露在公网的地址。'), - }) -} - -export default Router diff --git a/packages/router/src/listen.ts b/packages/router/src/listen.ts deleted file mode 100644 index 8026f8fb..00000000 --- a/packages/router/src/listen.ts +++ /dev/null @@ -1,40 +0,0 @@ -import net from 'net' - -export interface ListenOptions { - host: string - port: number - maxPort?: number -} - -export function listen({ host, port, maxPort = port }: ListenOptions) { - const server = net.createServer() - - return new Promise((resolve, reject) => { - function onListen() { - server.off('error', onError) - server.close((err) => { - err ? reject(err) : resolve(port) - }) - } - - function onError(err: NodeJS.ErrnoException) { - server.off('listening', onListen) - if (!(err.code === 'EADDRINUSE' || err.code === 'EACCES')) { - return reject(err) - } - port++ - if (port > maxPort) { - return reject(new Error('No open ports available')) - } - testPort() - } - - function testPort() { - server.once('error', onError) - server.once('listening', onListen) - server.listen(port, host) - } - - testPort() - }) -} diff --git a/packages/router/tsconfig.json b/packages/router/tsconfig.json deleted file mode 100644 index 6f11f324..00000000 --- a/packages/router/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.base", - "compilerOptions": { - "rootDir": "src", - "outDir": "lib", - "strict": true, - "noImplicitAny": false, - }, - "include": [ - "src", - ], -} diff --git a/packages/server-proxy/package.json b/packages/server-proxy/package.json index a6ee9188..b20befb7 100644 --- a/packages/server-proxy/package.json +++ b/packages/server-proxy/package.json @@ -27,6 +27,9 @@ "server", "service" ], + "devDependencies": { + "@cordisjs/server": "^0.1.3" + }, "peerDependencies": { "@satorijs/satori": "^3.2.3" } diff --git a/packages/server-proxy/src/index.ts b/packages/server-proxy/src/index.ts index f7498b76..9f3328d6 100644 --- a/packages/server-proxy/src/index.ts +++ b/packages/server-proxy/src/index.ts @@ -1,5 +1,5 @@ import { Context, Quester, sanitize, Schema } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import internal from 'stream' declare module '@satorijs/core' { diff --git a/packages/server-satori/package.json b/packages/server-satori/package.json index 778403fd..11aa00c6 100644 --- a/packages/server-satori/package.json +++ b/packages/server-satori/package.json @@ -35,7 +35,7 @@ "api" ], "devDependencies": { - "@satorijs/router": "^1.1.2" + "@cordisjs/server": "^0.1.3" }, "peerDependencies": { "@satorijs/satori": "^3.2.3" diff --git a/packages/server-satori/src/index.ts b/packages/server-satori/src/index.ts index 05aeaf35..f62f23bb 100644 --- a/packages/server-satori/src/index.ts +++ b/packages/server-satori/src/index.ts @@ -1,5 +1,5 @@ import { camelCase, Context, sanitize, Schema, Session, snakeCase, Time, Universal } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import WebSocket from 'ws' export const name = 'server' diff --git a/packages/server-temp/package.json b/packages/server-temp/package.json index f578c546..998a0eb1 100644 --- a/packages/server-temp/package.json +++ b/packages/server-temp/package.json @@ -27,6 +27,9 @@ "server", "service" ], + "devDependencies": { + "@cordisjs/server": "^0.1.3" + }, "peerDependencies": { "@satorijs/satori": "^3.2.3" } diff --git a/packages/server-temp/src/index.ts b/packages/server-temp/src/index.ts index fc0d1958..c8444103 100644 --- a/packages/server-temp/src/index.ts +++ b/packages/server-temp/src/index.ts @@ -1,5 +1,5 @@ import { Context, Dict, sanitize, Schema, Time } from '@satorijs/satori' -import {} from '@satorijs/router' +import {} from '@cordisjs/server' import { createReadStream } from 'fs' import { fileURLToPath } from 'url' import { mkdir, rm, writeFile } from 'fs/promises'