Skip to content

Commit

Permalink
feat: Ioc, Di, structure and character api
Browse files Browse the repository at this point in the history
  • Loading branch information
BIYUEHU committed Jun 9, 2024
1 parent 82fa140 commit 3144781
Show file tree
Hide file tree
Showing 27 changed files with 622 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ lib
*.tgz
*.log
tsconfig.tsbuildinfo

.env
9 changes: 9 additions & 0 deletions packages/core/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../.eslintrc",

"rules": {
"class-methods-use-this": "off",
"no-useless-constructor": "off",
"no-empty-function": "off"
}
}
3 changes: 0 additions & 3 deletions packages/core/.gitignore

This file was deleted.

33 changes: 33 additions & 0 deletions packages/core/data/ArimuraRomi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "有村ロミ",
"romaji": "Arimura Romi",
"gender": "FEMALE",
"alias": ["比村茜", "有村路美", "Himura Akane"],
"images": ["https://mzh.moegirl.org.cn/File:%E6%9C%89%E6%9D%91%E3%83%AD%E3%83%9F.png"],
"url": ["https://mzh.moegirl.org.cn/%E6%9C%89%E6%9D%91%E8%B7%AF%E7%BE%8E"],
"description": "有村路美是由GLOVETY制作的游戏《爱因斯坦携爱敬上》及其衍生作品的登场角色,女主角之一。",
"comment": "倾尽一切只为你,感性而又可爱,热烈而又长情,对理工男来说简直是梦中情人般的理想存在。",
"hitokoto": "当城市之中亮起灯火时,夜空的繁星便黯然失色。",
"birthday": 1000137600000,
"actor": "月野姬彩",
"hair": "粉发",
"eyeColor": "蓝瞳",
"height": 149,
"bust": 77,
"waist": 51,
"hip": 78,
"tags": [
"高中生",
"优等生",
"同班同学",
"天才少女",
"科学家",
"水手服",
"超短裙",
"四分之三袜",
"发夹",
"耳坠",
"贫乳",
"短发"
]
}
5 changes: 5 additions & 0 deletions packages/core/data/HonmaMisuzu.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "本間心鈴",
"romaji": "Honma Misuzu",
"gender": "FEMALE"
}
6 changes: 5 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@
"dependencies": {
"@kotori-bot/logger": "^1.3.1",
"@prisma/client": "^5.15.0",
"inversify": "^6.0.2",
"inversify-koa-utils": "^1.0.0",
"koa": "^2.15.3",
"koa-bodyparser": "^4.4.1",
"koa-router": "^12.0.1"
"koa-router": "^12.0.1",
"reflect-metadata": "^0.2.2",
"tsukiko": "^1.2.6"
},
"devDependencies": {
"@types/koa": "^2.15.0",
Expand Down
12 changes: 6 additions & 6 deletions packages/core/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ model Character {
id Int @id @default(autoincrement()) // 唯一标识符
// 必要数据
name String // 角色名(日语原名)
romanized String // 角色名罗马音
romaji String // 角色名罗马音
gender Gender // 角色性别
// 基本数据
alias String? // 角色中文名、昵称、别名(字符串数组)
Expand All @@ -53,8 +53,8 @@ model Character {
actor Actor? @relation(fields: [actorId], references: [id]) // 角色声优
actorId Int?
// 关联数据
series Series @relation(fields: [seriesId], references: [id]) // 角色所属系列作品
seriesId Int
series Series? @relation(fields: [seriesId], references: [id]) // 角色所属系列作品
seriesId Int?
collections CharacterWithCollection[] // 角色所属收藏夹
tags CharacterWithTag[] // 角色萌点
// 额外数据
Expand All @@ -64,7 +64,7 @@ model Character {
height Int? // 角色身高
bust Int? // 角色胸围
waist Int? // 角色腰围
hip String? // 角色臀围
hip Int? // 角色臀围
createdAt DateTime @default(now())
Expand All @@ -81,11 +81,11 @@ model Actor {

model Series {
id Int @id @default(autoincrement())
title String // 作品名字
name String // 作品名字
genre SeriesGenre // 作品类型,如动漫、漫画、视觉小说、游戏、轻小说等
characters Character[]
@@unique([id, title])
@@unique([id, name])
}

model Tag {
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/app/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class HttpError extends Error {
public readonly status: number;

public constructor(message: string, status: number = 400) {
super(message);
this.name = 'HttpError';
this.status = status;
}
}

export default HttpError;
69 changes: 65 additions & 4 deletions packages/core/src/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,70 @@
import 'reflect-metadata';
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import router from '../router';
import { inject, injectable } from 'inversify';
import { InversifyKoaServer } from 'inversify-koa-utils';
import { TsuError } from 'tsukiko';
import container, { Symbols } from '../container';
import Logger from '../utils/logger';
import HttpError from './error';

const app = new Koa();
@injectable()
export class Application {
private readonly server: InversifyKoaServer;

app.use(bodyParser()).use(router.routes()).use(router.allowedMethods());
private initialize() {
this.server.setConfig((app) => {
app.use(bodyParser());
app.use(async (ctx, next) => {
const { method, url, body } = ctx.request;
this.logger.label(method.toUpperCase()).record(url, /* headers, */ JSON.stringify(body));
try {
await next();
} catch (err) {
if (err instanceof HttpError) {
ctx.status = err.status;
ctx.body = { message: err.message };
} else if (err instanceof TsuError) {
ctx.status = 400;
ctx.body = { message: err.message };
} else {
ctx.status = 500;
ctx.body = { message: 'Internal Server Error' };
}
app.emit('error', err);
}

export default app;
// if (!ctx.body) ctx.status = ctx.method.toLocaleUpperCase() === 'POST' ? 201 : 204;
});
app.on('error', (err) => {
this.logger.error(err);
});
});
}

public readonly logger: Logger;

public readonly instance: Koa;

public readonly listen: Koa['listen'];

public constructor(
@inject(Symbols.ServerFactory)
serverFactory: (...args: ConstructorParameters<typeof InversifyKoaServer>) => InversifyKoaServer,
@inject(Symbols.Logger) logger: Logger
) {
this.server = serverFactory(container, undefined, { rootPath: '/api' });
this.logger = logger;

this.initialize();
this.instance = this.server.build();
this.listen = this.instance.listen.bind(this.instance);
}
}

export function createApplication() {
if (!container.isBound(Symbols.Application)) container.bind(Symbols.Application).to(Application);
return container.get<Application>(Symbols.Application);
}

export default createApplication;
10 changes: 10 additions & 0 deletions packages/core/src/container/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Container } from 'inversify';
import { Symbols } from './symbols';
import modules from './modules';

export { Symbols };

export const container = new Container();
container.load(...modules);

export default container;
36 changes: 36 additions & 0 deletions packages/core/src/container/modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ContainerModule } from 'inversify';
import { InversifyKoaServer, TYPE, interfaces } from 'inversify-koa-utils';
import { PrismaClient } from '@prisma/client';
import Logging from '@kotori-bot/logger';
import { Symbols } from './symbols';
import database from '../utils/db';
import CharacterController from '../router/controller/character.controller';
import CharacterService from '../router/service/character.service';
import Logger from '../utils/logger';

const commonContainerModule = new ContainerModule((bind) => {
/* Server Module */
bind(Symbols.ServerFactory).toFactory(
() =>
(...args: ConstructorParameters<typeof InversifyKoaServer>) =>
new InversifyKoaServer(...args)
);
/* Database Module */
bind(Symbols.DatabaseFactory).toFactory(() => () => new PrismaClient());
bind(Symbols.Database).to(database);
/* Logger Module */
bind(Symbols.LoggerFactory).toFactory(
() =>
(...args: ConstructorParameters<typeof Logging>) =>
new Logging(...args)
);
bind(Symbols.Logger).to(Logger);
});

const routerContainerModule = new ContainerModule((bind) => {
/* Character Router */
bind<interfaces.Controller>(TYPE.Controller).to(CharacterController).whenTargetNamed(Symbols.CharacterController);
bind(Symbols.CharacterService).to(CharacterService);
});

export default [routerContainerModule, commonContainerModule];
16 changes: 16 additions & 0 deletions packages/core/src/container/symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const Symbols = {
Application: Symbol.for('Application'),
/* Common Modules */
ServerFactory: Symbol.for('Factory<Server>'),
DatabaseFactory: Symbol.for('Factory<Database>'),
Database: Symbol.for('Database'),
LoggerFactory: Symbol.for('Factory<Logger>'),
Logger: Symbol.for('Logger'),
AuthFactory: Symbol.for('Factory<Auth>'),
Auth: Symbol.for('Auth'),
/* Router Modules */
CharacterController: 'CharacterController',
CharacterService: Symbol.for('CharacterService')
};

export default Symbols;
21 changes: 0 additions & 21 deletions packages/core/src/controller/character.controller.ts

This file was deleted.

7 changes: 4 additions & 3 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logger from '@kotori-bot/logger';
import app from './app';
import createApplication from './app';
import config from './config';

const app = createApplication();

app.listen(config.port, () => {
logger.info(`Server is running on port ${config.port}`);
app.logger.info(`Server is running on port ${config.port}`);
});
5 changes: 0 additions & 5 deletions packages/core/src/model/index.ts

This file was deleted.

11 changes: 0 additions & 11 deletions packages/core/src/router/character.router.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/core/src/router/config.router.ts

This file was deleted.

28 changes: 28 additions & 0 deletions packages/core/src/router/controller/character.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Response } from 'koa';
import { controller, httpGet, httpPost, interfaces, requestBody, requestParam, response } from 'inversify-koa-utils';
import { inject, injectable } from 'inversify';
import { Symbols } from '../../container';
import CharacterService from '../service/character.service';

@controller('/character')
@injectable()
class CharacterController implements interfaces.Controller {
public constructor(@inject(Symbols.CharacterService) private readonly service: CharacterService) {}

@httpGet('/:id')
async get(@requestParam('id') id: string, @response() res: Response) {
res.body = await this.service.get(Number(id));
}

@httpGet('/')
async getAll(@response() res: Response) {
res.body = await this.service.getAll();
}

@httpPost('/')
async post(@requestBody() body: unknown, @response() res: Response) {
res.status = await this.service.create(body);
}
}

export default CharacterController;
12 changes: 0 additions & 12 deletions packages/core/src/router/index.ts

This file was deleted.

23 changes: 0 additions & 23 deletions packages/core/src/router/routes.ts

This file was deleted.

Loading

0 comments on commit 3144781

Please sign in to comment.