Skip to content

Commit

Permalink
feat: init nip-11
Browse files Browse the repository at this point in the history
  • Loading branch information
ZigBalthazar committed Dec 12, 2024
1 parent a10a704 commit c72face
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 3 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.3.0",
"@nestjs/schedule": "^4.1.1",
"@nestjs/serve-static": "^4.0.2",
"@nestjs/swagger": "^7.1.17",
"@nestjs/terminus": "^10.2.3",
"@nestjs/typeorm": "^10.0.2",
Expand Down
13 changes: 10 additions & 3 deletions src/modules/config/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import { Injectable } from '@nestjs/common';

import { ConfigRepository } from './config.repository';
import type { UpdateConfigDto } from './dto/update-config.dto';
import { EventEmitter } from 'node:stream';

@Injectable()
export class ConfigService {
constructor(private readonly configRepo: ConfigRepository) {}
export class ConfigService extends EventEmitter {

Check failure on line 8 in src/modules/config/config.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/modules/config/config.service.ts#L8

Prefer `EventTarget` over `EventEmitter` (unicorn/prefer-event-target)
constructor(private readonly configRepo: ConfigRepository) {
super();
}

async getConfig() {
return this.configRepo.findOne();
Expand All @@ -20,6 +23,10 @@ export class ConfigService {

config.assign(props);

return this.configRepo.save(config);
const res = await this.configRepo.save(config);

Check failure on line 26 in src/modules/config/config.service.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/modules/config/config.service.ts#L26

Placing a void expression inside another expression is forbidden. Move it to its own statement instead (@typescript-eslint/no-confusing-void-expression)

this.emit('CONFIG-UPDATED', res);

return res;
}
}
150 changes: 150 additions & 0 deletions src/shared/controllers/nip11.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { Controller, Get, Req, Res } from '@nestjs/common';

Check failure on line 1 in src/shared/controllers/nip11.controller.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/shared/controllers/nip11.controller.ts#L1

Run autofix to sort these imports! (simple-import-sort/imports)
import { Request, Response } from 'express';
import { ConfigService } from '../../../src/modules/config/config.service';
import { ConfigDto } from '../../../src/modules/config/dto/config.dto';

Check failure on line 4 in src/shared/controllers/nip11.controller.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/shared/controllers/nip11.controller.ts#L4

All imports in the declaration are only used as types. Use `import type` (@typescript-eslint/consistent-type-imports)
import { ApiTags } from '@nestjs/swagger';

@Controller()
@ApiTags("NIP-11")

Check failure on line 8 in src/shared/controllers/nip11.controller.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/shared/controllers/nip11.controller.ts#L8

Replace `"NIP-11"` with `'NIP-11'` (prettier/prettier)

Check failure on line 8 in src/shared/controllers/nip11.controller.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/shared/controllers/nip11.controller.ts#L8

Strings must use singlequote (@typescript-eslint/quotes)
export class Nip11Controller {
private CONFIG: ConfigDto | null = null;

constructor(private readonly configService: ConfigService) {
this.initializeConfigListener();
}

@Get()
async handleRequest(@Req() req: Request, @Res() res: Response): Promise<void> {
if (!this.CONFIG) {
await this.setConfig();
}

const { id, createdAt, updatedAt, ...config } = this.CONFIG!;

if (req.headers['accept'] === 'application/nostr+json') {
res.json(config);
}

res.type('text/html').send(this.generateHtmlResponse(config));
}

private async setConfig(): Promise<void> {
const config = await this.configService.getConfig();
this.CONFIG = config?.toDto() as ConfigDto;
}

private initializeConfigListener(): void {
this.configService.on('CONFIG-UPDATED', async () => {
await this.setConfig();
});
}

private generateHtmlResponse(config: Omit<ConfigDto, 'id' | 'createdAt' | 'updatedAt'>): string {
const currentYear = new Date().getFullYear();

const tableRows = Object.entries(config)
.map(([key, value]) => {
const displayValue = typeof value === 'object' && value !== null ? JSON.stringify(value, null, 2) : value;
return `
<tr>
<td><strong>${key}</strong></td>
<td>${displayValue}</td>
</tr>`;
})
.join('');

return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>NIP-11 ${config.name}</title>
<style>
body {
font-family: 'Roboto', Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f9f9fb;
color: #333;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: #ffffff;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
max-width: 800px;
text-align: center;
overflow: hidden;
}
.logo {
width: 240px;
margin: 0 auto 20px;
}
h1 {
font-size: 2rem;
color: #2c3e50;
margin-bottom: 20px;
}
p {
font-size: 1rem;
color: #555;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
table th, table td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
}
table th {
background-color: #f4f4f9;
font-weight: bold;
color: #2c3e50;
}
table tr:nth-child(even) {
background-color: #f9f9fb;
}
table tr:hover {
background-color: #f1f1f1;
}
.footer {
margin-top: 20px;
font-size: 0.9rem;
color: #999;
}
</style>
</head>
<body>
<div class="container">
<img src="/assets/logo.png" alt="Relay Logo" class="logo" />
<h1>${config.name}</h1>
<p>
This relay supports the Nostr protocol. Use the <code>application/nostr+json</code>
Accept header to get detailed information about this relay.
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody>
${tableRows}
</tbody>
</table>
<div class="footer">&copy; ${currentYear} <a href="https://dezh.tech" target="_blank" rel="noopener noreferrer">Dezh Technologies</a>. All rights reserved.</div>
</div>
</body>
</html>`;
}
}
11 changes: 11 additions & 0 deletions src/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@ import { Global, Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { RedisModule } from '@nestjs-modules/ioredis';
import { ServeStaticModule } from '@nestjs/serve-static';


import { TelegramNotificationStrategy } from './notification/telegram.strategy';
import { ApiConfigService } from './services/api-config.service';
import { NotificationService } from './services/notification.service';
import { Nip11Controller } from './controllers/nip11.controller';
import { join } from 'path';
import { ServicesConfigModule } from '../../src/modules/config/config.module';

const providers: Provider[] = [ConfigService, ApiConfigService, NotificationService, TelegramNotificationStrategy];

@Global()
@Module({
providers,
imports: [
ServicesConfigModule,
TypeOrmModule.forRootAsync({
imports: [SharedModule],
useFactory: (configService: ApiConfigService) => configService.mongoConfig,
Expand All @@ -24,7 +30,12 @@ const providers: Provider[] = [ConfigService, ApiConfigService, NotificationServ
useFactory: (configService: ApiConfigService) => configService.redisConfig,
inject: [ApiConfigService],
}),
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', '..', 'assets'),
serveRoot: '/assets',
}),
],
controllers: [Nip11Controller],
exports: [...providers],
})
export class SharedModule {}
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,13 @@
jsonc-parser "3.3.1"
pluralize "8.0.0"

"@nestjs/serve-static@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-4.0.2.tgz#f003bbd90922bdc73d0261edacf001dfef174c96"
integrity sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ==
dependencies:
path-to-regexp "0.2.5"

"@nestjs/swagger@^7.1.17":
version "7.4.2"
resolved "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.4.2.tgz"
Expand Down Expand Up @@ -6778,6 +6785,11 @@ path-to-regexp@0.1.10:
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz"
integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==

path-to-regexp@0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.2.5.tgz#0b426991e387fc4c675de23557f358715eb66fb0"
integrity sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q==

path-to-regexp@3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz"
Expand Down

0 comments on commit c72face

Please sign in to comment.