Skip to content

Commit

Permalink
move http server for voucher to explorer
Browse files Browse the repository at this point in the history
add voucher jsonrpc handlers to explorer
  • Loading branch information
Zewasik committed Oct 1, 2024
1 parent a1ba2d5 commit fe9c037
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 0 deletions.
1 change: 1 addition & 0 deletions idea/explorer/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './code';
export * from './program';
export * from './message';
export * from './event';
export * from './voucher';
export * from './jsonrpc';
export * from './base';
6 changes: 6 additions & 0 deletions idea/explorer/src/errors/voucher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { JsonRpcError } from '../types';

export class VoucherNotFound implements JsonRpcError {
code = -32404;
message = 'Voucher not found';
}
61 changes: 61 additions & 0 deletions idea/explorer/src/jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import {
ParamGetMsgsToProgram,
ParamGetProgram,
ParamGetPrograms,
ParamGetVoucher,
ParamGetVouchers,
ParamMsgFromProgram,
ParamMsgToProgram,
ParamSetProgramMeta,
} from './types';
import { Cache } from './middlewares/caching';
import { redisConnect } from './middlewares/redis';
import { Retry } from './middlewares/retry';
import { VoucherNotFound } from './errors';

export class JsonRpcServer extends JsonRpc(JsonRpcBase) {
private _app: Express;
Expand All @@ -30,6 +33,52 @@ export class JsonRpcServer extends JsonRpc(JsonRpcBase) {
const result = await this.handleRequest(req.body);
res.json(result);
});

this._app.get('/api/voucher/:id', async (req, res) => {
const { genesis } = req.query;
if (!genesis) {
res.status(400).json({ error: 'Genesis not found in the request' });
return;
}

const voucherService = this._services.get(genesis.toString())?.voucher;
if (!voucherService) {
res.status(400).json({ error: 'Network is not supported' });
return;
}

try {
const voucher = await voucherService.getVoucher({ id: req.params.id, genesis: genesis.toString() });
res.json(voucher);
} catch (error) {
if (error instanceof VoucherNotFound) {
res.json(null);
return;
}
res.status(500).json({ error: 'Internal server error' });
}
});

this._app.post('/api/vouchers', async (req, res) => {
const { genesis } = req.query;
if (!genesis) {
res.status(400).json({ error: 'Genesis not found in the request' });
return;
}

const voucherService = this._services.get(genesis.toString())?.voucher;
if (!voucherService) {
res.status(400).json({ error: 'Network is not supported' });
return;
}

try {
const vouchers = await voucherService.getVouchers(req.body);
res.json(vouchers);
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
}

public async run() {
Expand Down Expand Up @@ -110,4 +159,16 @@ export class JsonRpcServer extends JsonRpc(JsonRpcBase) {
async eventData(params: ParamGetEvent) {
return this._services.get(params.genesis).event.getEvent(params);
}

@JsonRpcMethod('voucher.all')
@Cache(15)
async voucherAll(params: ParamGetVouchers) {
return this._services.get(params.genesis).voucher.getVouchers(params);
}

@JsonRpcMethod('voucher.data')
@Cache(15)
async voucherData(params: ParamGetVoucher) {
return this._services.get(params.genesis).voucher.getVoucher(params);
}
}
3 changes: 3 additions & 0 deletions idea/explorer/src/services/all-in-one.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import { CodeService } from './code';
import { EventService } from './event';
import { MessageService } from './message';
import { ProgramService } from './program';
import { VoucherService } from './voucher';

export class AllInOneService {
public code: CodeService;
public program: ProgramService;
public message: MessageService;
public event: EventService;
public voucher: VoucherService;

constructor(dataSource: DataSource) {
this.code = new CodeService(dataSource);
this.program = new ProgramService(dataSource);
this.message = new MessageService(dataSource);
this.event = new EventService(dataSource);
this.voucher = new VoucherService(dataSource);
}
}
93 changes: 93 additions & 0 deletions idea/explorer/src/services/voucher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { DataSource, Repository } from 'typeorm';
import { Voucher } from 'indexer-db';
import { Pagination } from '../decorators';
import { ParamGetVoucher, ParamGetVouchers, ResManyResult } from '../types';
import { VoucherNotFound } from '../errors';
import { RequiredParams } from '../decorators/required';

export class VoucherService {
private _repo: Repository<Voucher>;

constructor(dataSource: DataSource) {
this._repo = dataSource.getRepository(Voucher);
}

@RequiredParams(['id'])
async getVoucher({ id }: ParamGetVoucher) {
const v = await this._repo.findOne({ where: { id } });

if (!v) {
throw new VoucherNotFound();
}

return v;
}

@Pagination()
public async getVouchers({
id,
owner,
spender,
declined,
codeUploading,
programs,
limit,
offset,
expired,
}: ParamGetVouchers): Promise<ResManyResult<Voucher>> {
const qb = this._repo.createQueryBuilder('v');

if (id) {
if (id.length === 66) {
qb.andWhere('v.id = :id', { id });
} else {
qb.andWhere('v.id LIKE :id', { id: `%${id}%` });
}
}

if (declined !== undefined) {
qb.andWhere('v.isDeclined = :declined', { declined });
}

if (codeUploading !== undefined) {
qb.andWhere('v.codeUploading = :codeUploading', { codeUploading });
}

if (programs) {
let where = '(';
let params: Record<string, string> = {};

for (let i = 0; i < programs.length; i++) {
where += `${i > 0 ? ' OR ' : ''}v.programs::jsonb ? :p${i}`;
params[`p${i}`] = programs[i];
}
qb.andWhere(where + ')', params);
console.log(qb.getQuery());
}

if (expired !== undefined) {
const now = new Date();
if (expired) {
qb.andWhere('v.expiryAt < :now', { now });
} else {
qb.andWhere('v.expiryAt >= :now', { now });
}
}

if (owner && spender) {
qb.andWhere('(v.owner = :owner OR v.spender = :spender)', { owner, spender });
} else if (owner) {
qb.andWhere('v.owner = :owner', { owner });
} else if (spender) {
qb.andWhere('v.spender = :spender', { spender });
}

qb.limit(limit || 20);
qb.offset(offset || 0);
qb.orderBy('v.issuedAt', 'DESC');

const [result, count] = await qb.getManyAndCount();

return { result, count };
}
}
1 change: 1 addition & 0 deletions idea/explorer/src/types/requests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './event';
export * from './message';
export * from './program';
export * from './code';
export * from './voucher';
20 changes: 20 additions & 0 deletions idea/explorer/src/types/requests/voucher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IsString, Contains } from 'class-validator';
import { ParamPagination } from './common';

export class ParamGetVoucher extends ParamPagination {
@IsString()
@Contains('0x')
readonly id: string;
}

export class ParamGetVouchers extends ParamPagination {
@IsString()
@Contains('0x')
readonly id?: string;
readonly owner?: string;
readonly spender?: string;
readonly programs?: string[];
readonly codeUploading?: boolean;
readonly declined?: boolean;
readonly expired?: boolean;
}

0 comments on commit fe9c037

Please sign in to comment.