Skip to content

Commit

Permalink
refactor: use tegg v3 (#370)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: use SingletonProto instead of ContextProto

Co-authored-by: killagu <killa123@126.com>
  • Loading branch information
fengmk2 and killagu authored Jan 17, 2023
1 parent fff032b commit 8e3acae
Show file tree
Hide file tree
Showing 145 changed files with 467 additions and 1,056 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
node-version: ${{ matrix.node-version }}

- name: Install Dependencies
run: npm i
run: npm i -g npminstall && npminstall

- name: Continuous Integration
run: npm run ci
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,6 @@ dist
.tern-port

.idea
.DS_Store
run
!test/ctx_register.js
49 changes: 19 additions & 30 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,30 @@

```bash
# 启动本地依赖服务
$ docker-compose up -d
docker-compose up -d

# 关闭本地依赖服务
$ docker-compose down
docker-compose down
```

> 手动初始化依赖服务参见[文档](./docs/setup.md)

## 本地开发

### 安装依赖

```bash
$ npm install
npm install
```

### 开发运行

```bash
# 初始化数据库
$ MYSQL_DATABASE=cnpmcore npm run prepare-database
MYSQL_DATABASE=cnpmcore npm run prepare-database

# 启动 Web 服务
$ npm run dev
npm run dev

# 访问
curl -v http://127.0.0.1:7001
Expand All @@ -41,22 +40,9 @@ curl -v http://127.0.0.1:7001
### 单元测试

```bash
$ npm run test
npm run test
```

编写单测规范:

- assert 断言库必须使用 require 引入

```ts
import assert = require('assert');
```

> CAUTION: don't use `import assert from 'assert'`
> Just use old style import assert = require('assert') for assert module. This is limitation.
> See https://github.com/power-assert-js/espower-typescript#caution-dont-use-import-assert-from-assert

## 项目结构

```
Expand All @@ -80,29 +66,32 @@ app
```

common:

- util:全局工具类
- adapter:外部服务调用

core:

- entity:核心模型,实现业务行为
- event:异步事件定义,以及消费,串联业务
- service:核心业务
- util:服务 core 内部,不对外暴露

repository:

- model:ORM 模型,数据定义
- XXXRepository: 仓储接口,存储、查询过程

port:
- controller:HTTP controller

- controller:HTTP controller

## Controller 开发指南

目前只支持 HTTP 协议的 Controller,代码在 `app/port/controller` 目录下。
基于类继承的模式来实现,类关系大致如下:

```
```txt
+----------------------+ +----------------------+ +---------------+
| PackageController.ts | | PackageTagController | | XxxController |
+---------------+------+ +---+------------------+ +--+------------+
Expand Down Expand Up @@ -130,15 +119,15 @@ port:
例如会封装 PackageEntity、PackageVersionEntity 等查询方法。

```ts
// try to get package entity, throw NotFoundError when package not exists
private async getPackageEntity(scope: string, name: string) {
const packageEntity = await this.packageRepository.findPackage(scope, name);
if (!packageEntity) {
const fullname = getFullname(scope, name);
throw new NotFoundError(`${fullname} not found`);
}
return packageEntity;
// try to get package entity, throw NotFoundError when package not exists
private async getPackageEntity(scope: string, name: string) {
const packageEntity = await this.packageRepository.findPackage(scope, name);
if (!packageEntity) {
const fullname = getFullname(scope, name);
throw new NotFoundError(`${fullname} not found`);
}
return packageEntity;
}
```

### 请求合法性校验三部曲
Expand Down
12 changes: 8 additions & 4 deletions app/common/FileUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { setTimeout } from 'timers/promises';
import path from 'path';
import url from 'url';
import { randomBytes } from 'crypto';
import { EggContextHttpClient } from 'egg';
import { EggContextHttpClient, HttpClientResponse } from 'egg';
import dayjs from './dayjs';

export async function createTempfile(dataDir: string, filename: string) {
Expand Down Expand Up @@ -37,9 +37,13 @@ export async function downloadToTempfile(httpclient: EggContextHttpClient,
}
throw lastError;
}

export interface Tempfile {
tmpfile: string;
headers: HttpClientResponse['res']['headers'];
timing: HttpClientResponse['res']['timing'];
}
async function _downloadToTempfile(httpclient: EggContextHttpClient,
dataDir: string, url: string, ignoreDownloadStatuses?: number[]) {
dataDir: string, url: string, ignoreDownloadStatuses?: number[]): Promise<Tempfile> {
const tmpfile = await createTempfile(dataDir, url);
const writeStream = createWriteStream(tmpfile);
try {
Expand All @@ -50,7 +54,7 @@ async function _downloadToTempfile(httpclient: EggContextHttpClient,
writeStream,
timing: true,
followRedirect: true,
});
}) as HttpClientResponse;
if (status === 404 || (ignoreDownloadStatuses && ignoreDownloadStatuses.includes(status))) {
const err = new Error(`Not found, status(${status})`);
err.name = 'DownloadNotFoundError';
Expand Down
4 changes: 2 additions & 2 deletions app/common/adapter/CacheAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {
ContextProto,
SingletonProto,
AccessLevel,
Inject,
} from '@eggjs/tegg';
import { Redis } from 'ioredis';

const ONE_DAY = 3600 * 24;

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class CacheAdapter {
Expand Down
4 changes: 2 additions & 2 deletions app/common/adapter/NFSAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Readable } from 'stream';
import {
ContextProto,
SingletonProto,
AccessLevel,
Inject,
} from '@eggjs/tegg';
Expand All @@ -12,7 +12,7 @@ import { IncomingHttpHeaders } from 'http';

const INSTANCE_NAME = 'nfsAdapter';

@ContextProto({
@SingletonProto({
name: INSTANCE_NAME,
accessLevel: AccessLevel.PUBLIC,
})
Expand Down
20 changes: 12 additions & 8 deletions app/common/adapter/NPMRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import {
EggLogger,
EggContextHttpClient,
EggAppConfig,
HttpClientRequestOptions,
HttpClientResponse,
} from 'egg';
import { HttpMethod } from 'urllib/src/Request';

type HttpMethod = HttpClientRequestOptions['method'];

const INSTANCE_NAME = 'npmRegistry';

export type RegistryResponse = { method: HttpMethod } & HttpClientResponse;

@ContextProto({
name: INSTANCE_NAME,
accessLevel: AccessLevel.PUBLIC,
Expand All @@ -35,7 +40,7 @@ export class NPMRegistry {
this.registryHost = registryHost;
}

public async getFullManifests(fullname: string, retries = 3) {
public async getFullManifests(fullname: string, retries = 3): Promise<RegistryResponse> {
// set query t=timestamp, make sure CDN cache disable
// cache=0 is sync worker request flag
const url = `${this.registry}/${encodeURIComponent(fullname)}?t=${Date.now()}&cache=0`;
Expand All @@ -60,7 +65,7 @@ export class NPMRegistry {
}

// app.put('/:name/sync', sync.sync);
public async createSyncTask(fullname: string) {
public async createSyncTask(fullname: string): Promise<RegistryResponse> {
const url = `${this.registry}/${encodeURIComponent(fullname)}/sync?sync_upstream=true&nodeps=true`;
// {
// ok: true,
Expand All @@ -70,18 +75,18 @@ export class NPMRegistry {
}

// app.get('/:name/sync/log/:id', sync.getSyncLog);
public async getSyncTask(fullname: string, id: string, offset: number) {
public async getSyncTask(fullname: string, id: string, offset: number): Promise<RegistryResponse> {
const url = `${this.registry}/${encodeURIComponent(fullname)}/sync/log/${id}?offset=${offset}`;
// { ok: true, syncDone: syncDone, log: log }
return await this.request('GET', url);
}

public async getDownloadRanges(registry: string, fullname: string, start: string, end: string) {
public async getDownloadRanges(registry: string, fullname: string, start: string, end: string): Promise<RegistryResponse> {
const url = `${registry}/downloads/range/${start}:${end}/${encodeURIComponent(fullname)}`;
return await this.request('GET', url);
}

private async request(method: HttpMethod, url: string, params?: object, options?: object) {
private async request(method: HttpMethod, url: string, params?: object, options?: object): Promise<RegistryResponse> {
const res = await this.httpclient.request(url, {
method,
data: params,
Expand All @@ -91,11 +96,10 @@ export class NPMRegistry {
followRedirect: true,
gzip: true,
...options,
});
}) as HttpClientResponse;
this.logger.info('[NPMRegistry:request] %s %s, status: %s', method, url, res.status);
return {
method,
url,
...res,
};
}
Expand Down
4 changes: 2 additions & 2 deletions app/common/adapter/changesStream/CnpmcoreChangesStream.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ContextProto } from '@eggjs/tegg';
import { SingletonProto } from '@eggjs/tegg';
import { RegistryType } from '../../../common/enum/Registry';
import { Registry } from '../../../core/entity/Registry';
import { E500 } from 'egg-errors';
import { AbstractChangeStream, RegistryChangesStream } from './AbstractChangesStream';

@ContextProto()
@SingletonProto()
@RegistryChangesStream(RegistryType.Cnpmcore)
export class CnpmcoreChangesStream extends AbstractChangeStream {

Expand Down
4 changes: 2 additions & 2 deletions app/common/adapter/changesStream/CnpmjsorgChangesStream.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ContextProto } from '@eggjs/tegg';
import { SingletonProto } from '@eggjs/tegg';
import { RegistryType } from '../../../common/enum/Registry';
import { Registry } from '../../../core/entity/Registry';
import { E500 } from 'egg-errors';
import { AbstractChangeStream, RegistryChangesStream } from './AbstractChangesStream';

const MAX_LIMIT = 10000;

@ContextProto()
@SingletonProto()
@RegistryChangesStream(RegistryType.Cnpmjsorg)
export class CnpmjsorgChangesStream extends AbstractChangeStream {

Expand Down
4 changes: 2 additions & 2 deletions app/common/adapter/changesStream/NpmChangesStream.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ContextProto } from '@eggjs/tegg';
import { SingletonProto } from '@eggjs/tegg';
import { E500 } from 'egg-errors';
import { RegistryType } from '../../../common/enum/Registry';
import { Registry } from '../../../core/entity/Registry';
import { AbstractChangeStream, ChangesStreamChange, RegistryChangesStream } from './AbstractChangesStream';

@ContextProto()
@SingletonProto()
@RegistryChangesStream(RegistryType.Npm)
export class NpmChangesStream extends AbstractChangeStream {

Expand Down
4 changes: 2 additions & 2 deletions app/core/service/BinarySyncerService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { rm } from 'fs/promises';
import {
AccessLevel,
ContextProto,
SingletonProto,
Inject,
} from '@eggjs/tegg';
import {
Expand Down Expand Up @@ -50,7 +50,7 @@ function isoNow() {
return new Date().toISOString();
}

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class BinarySyncerService extends AbstractService {
Expand Down
4 changes: 2 additions & 2 deletions app/core/service/BugVersionService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AccessLevel, ContextProto, Inject } from '@eggjs/tegg';
import { AccessLevel, SingletonProto, Inject } from '@eggjs/tegg';
import { EggLogger } from 'egg';
import pMap from 'p-map';
import { BugVersion } from '../entity/BugVersion';
Expand All @@ -7,7 +7,7 @@ import { DistRepository } from '../../repository/DistRepository';
import { getScopeAndName } from '../../common/PackageUtil';
import { CacheService } from './CacheService';

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class BugVersionService {
Expand Down
4 changes: 2 additions & 2 deletions app/core/service/CacheService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
AccessLevel,
ContextProto,
SingletonProto,
Inject,
} from '@eggjs/tegg';
import { CacheAdapter } from '../../common/adapter/CacheAdapter';
Expand Down Expand Up @@ -30,7 +30,7 @@ type TotalData = {
};
const TOTAL_DATA_KEY = '__TOTAL_DATA__';

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class CacheService extends AbstractService {
Expand Down
4 changes: 2 additions & 2 deletions app/core/service/ChangesStreamService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import os from 'os';
import { setTimeout } from 'timers/promises';
import {
AccessLevel,
ContextProto,
SingletonProto,
EggObjectFactory,
Inject,
} from '@eggjs/tegg';
Expand All @@ -21,7 +21,7 @@ import { getScopeAndName } from '../../common/PackageUtil';
import { ScopeManagerService } from './ScopeManagerService';
import { PackageRepository } from '../../repository/PackageRepository';

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class ChangesStreamService extends AbstractService {
Expand Down
4 changes: 2 additions & 2 deletions app/core/service/CreateHookTriggerService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AccessLevel, ContextProto, Inject } from '@eggjs/tegg';
import { AccessLevel, SingletonProto, Inject } from '@eggjs/tegg';
import { AbstractService } from '../../common/AbstractService';
import { HookType } from '../../common/enum/Hook';
import { TaskState } from '../../common/enum/Task';
Expand All @@ -12,7 +12,7 @@ import { TaskService } from './TaskService';
import { isoNow } from '../../common/LogUtil';
import { getScopeAndName } from '../../common/PackageUtil';

@ContextProto({
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class CreateHookTriggerService extends AbstractService {
Expand Down
Loading

0 comments on commit 8e3acae

Please sign in to comment.