mirror of
https://github.com/Cameri/nostream.git
synced 2025-07-15 00:02:22 +02:00
fix: lots of bugs
Signed-off-by: Ricardo Arturo Cabral Mejía <me@ricardocabral.io>
This commit is contained in:
@ -5,5 +5,5 @@
|
|||||||
nostream.localtest.me {
|
nostream.localtest.me {
|
||||||
tls /root/certs/nostream.localtest.me.pem /root/certs/nostream.localtest.me-key.pem
|
tls /root/certs/nostream.localtest.me.pem /root/certs/nostream.localtest.me-key.pem
|
||||||
|
|
||||||
reverse_proxy nostr-ts-relay:8008
|
reverse_proxy nostream:8008
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
relay:
|
nostream:
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/.nostr.local:/home/node/
|
- ${PWD}/.nostr.local:/home/node
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2.6.2-alpine
|
image: caddy:2.6.2-alpine
|
||||||
container_name: caddy
|
container_name: caddy
|
||||||
|
@ -4,7 +4,7 @@ services:
|
|||||||
container_name: tor
|
container_name: tor
|
||||||
user: toruser
|
user: toruser
|
||||||
depends_on:
|
depends_on:
|
||||||
- relay
|
- nostream
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/tor/torrc:/etc/tor/torrc
|
- ${PWD}/tor/torrc:/etc/tor/torrc
|
||||||
- ${PWD}/.nostr/tor/data:/var/lib/tor
|
- ${PWD}/.nostr/tor/data:/var/lib/tor
|
||||||
|
@ -38,8 +38,6 @@ services:
|
|||||||
# DEBUG: "primary:*"
|
# DEBUG: "primary:*"
|
||||||
# DEBUG: "worker:*"
|
# DEBUG: "worker:*"
|
||||||
# DEBUG: "knex:query"
|
# DEBUG: "knex:query"
|
||||||
env_file:
|
|
||||||
- test.env
|
|
||||||
user: node:node
|
user: node:node
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/.nostr:/home/node/.nostr
|
- ${PWD}/.nostr:/home/node/.nostr
|
||||||
|
@ -3,11 +3,12 @@ import { SubscriptionFilter } from './subscription'
|
|||||||
|
|
||||||
export interface IWebSocketServerAdapter extends EventEmitter, IWebServerAdapter {
|
export interface IWebSocketServerAdapter extends EventEmitter, IWebServerAdapter {
|
||||||
getConnectedClients(): number
|
getConnectedClients(): number
|
||||||
close(callback: () => void): void
|
close(callback?: () => void): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWebServerAdapter extends EventEmitter {
|
export interface IWebServerAdapter extends EventEmitter {
|
||||||
listen(port: number): void
|
listen(port: number): void
|
||||||
|
close(callback?: () => void): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export type Factory<TOutput = any, TInput = void> = (input: TInput) => TOutput
|
|||||||
|
|
||||||
export type DatabaseClient = Knex
|
export type DatabaseClient = Knex
|
||||||
|
|
||||||
export type DatabaseTransaction<T = any> = Knex.Transaction<T, T[]>
|
export type DatabaseTransaction<T extends Record<string, unknown> = any> = Knex.Transaction<T, T[]>
|
||||||
|
|
||||||
export interface ContextMetadata {
|
export interface ContextMetadata {
|
||||||
remoteAddress: SocketAddress
|
remoteAddress: SocketAddress
|
||||||
|
@ -154,7 +154,7 @@ export interface PaymentsProcessors {
|
|||||||
export interface Settings {
|
export interface Settings {
|
||||||
info: Info
|
info: Info
|
||||||
payments?: Payments
|
payments?: Payments
|
||||||
paymentProcessors?: PaymentsProcessors
|
paymentsProcessors?: PaymentsProcessors
|
||||||
network: Network
|
network: Network
|
||||||
workers?: Worker
|
workers?: Worker
|
||||||
limits?: Limits
|
limits?: Limits
|
||||||
|
@ -10,7 +10,7 @@ export class WebServerAdapter extends EventEmitter implements IWebServerAdapter
|
|||||||
public constructor(
|
public constructor(
|
||||||
protected readonly webServer: Server,
|
protected readonly webServer: Server,
|
||||||
) {
|
) {
|
||||||
debug('web server starting')
|
debug('created')
|
||||||
super()
|
super()
|
||||||
this.webServer
|
this.webServer
|
||||||
.on('error', this.onError.bind(this))
|
.on('error', this.onError.bind(this))
|
||||||
@ -40,8 +40,17 @@ export class WebServerAdapter extends EventEmitter implements IWebServerAdapter
|
|||||||
socket.end('HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n')
|
socket.end('HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public close(callback?: () => void): void {
|
||||||
|
this.webServer.removeAllListeners()
|
||||||
|
this.webServer.close()
|
||||||
|
if (typeof callback !== 'undefined') {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
debug('closed')
|
||||||
|
}
|
||||||
|
|
||||||
protected onClose() {
|
protected onClose() {
|
||||||
debug('stopped listening to incoming connections')
|
debug('stopped listening to incoming connections')
|
||||||
this.webServer.removeAllListeners()
|
this.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ export class WebSocketServerAdapter extends WebServerAdapter implements IWebSock
|
|||||||
>,
|
>,
|
||||||
private readonly settings: () => Settings,
|
private readonly settings: () => Settings,
|
||||||
) {
|
) {
|
||||||
|
debug('created')
|
||||||
super(webServer)
|
super(webServer)
|
||||||
|
|
||||||
this.webSocketsAdapters = new WeakMap()
|
this.webSocketsAdapters = new WeakMap()
|
||||||
@ -46,11 +47,20 @@ export class WebSocketServerAdapter extends WebServerAdapter implements IWebSock
|
|||||||
this.heartbeatInterval = setInterval(this.onHeartbeat.bind(this), WSS_CLIENT_HEALTH_PROBE_INTERVAL)
|
this.heartbeatInterval = setInterval(this.onHeartbeat.bind(this), WSS_CLIENT_HEALTH_PROBE_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
public close(callback: () => void): void {
|
public close(callback?: () => void): void {
|
||||||
this.onClose()
|
debug('closing')
|
||||||
|
clearInterval(this.heartbeatInterval)
|
||||||
|
this.webSocketServer.clients.forEach((webSocket: WebSocket) => {
|
||||||
|
debug('terminating client')
|
||||||
|
webSocket.terminate()
|
||||||
|
})
|
||||||
|
this.removeAllListeners()
|
||||||
|
this.webSocketServer.removeAllListeners()
|
||||||
this.webSocketServer.close(() => {
|
this.webSocketServer.close(() => {
|
||||||
this.webServer.close(callback)
|
this.webServer.close(callback)
|
||||||
|
super.close()
|
||||||
})
|
})
|
||||||
|
debug('closed')
|
||||||
}
|
}
|
||||||
|
|
||||||
private onBroadcast(event: Event) {
|
private onBroadcast(event: Event) {
|
||||||
@ -90,15 +100,6 @@ export class WebSocketServerAdapter extends WebServerAdapter implements IWebSock
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected onClose() {
|
protected onClose() {
|
||||||
debug('closing')
|
this.close()
|
||||||
clearInterval(this.heartbeatInterval)
|
|
||||||
this.webSocketServer.clients.forEach((webSocket: WebSocket) => {
|
|
||||||
debug('terminating client')
|
|
||||||
webSocket.terminate()
|
|
||||||
})
|
|
||||||
this.removeAllListeners()
|
|
||||||
this.webSocketServer.removeAllListeners()
|
|
||||||
super.onClose()
|
|
||||||
debug('closed')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,6 @@ export class AppWorker implements IRunnable {
|
|||||||
watcher.close()
|
watcher.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof callback !== 'undefined') {
|
this.adapter.close(callback)
|
||||||
this.adapter.close(callback)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
|
import { getMasterDbClient, getReadReplicaDbClient } from '../database/client'
|
||||||
import { createPaymentsProcessor } from './payments-processor-factory'
|
import { createPaymentsProcessor } from './payments-processor-factory'
|
||||||
import { createSettings } from './settings-factory'
|
import { createSettings } from './settings-factory'
|
||||||
import { EventRepository } from '../repositories/event-repository'
|
import { EventRepository } from '../repositories/event-repository'
|
||||||
import { getDbClient } from '../database/client'
|
|
||||||
import { InvoiceRepository } from '../repositories/invoice-repository'
|
import { InvoiceRepository } from '../repositories/invoice-repository'
|
||||||
import { MaintenanceWorker } from '../app/maintenance-worker'
|
import { MaintenanceWorker } from '../app/maintenance-worker'
|
||||||
import { PaymentsService } from '../services/payments-service'
|
import { PaymentsService } from '../services/payments-service'
|
||||||
import { UserRepository } from '../repositories/user-repository'
|
import { UserRepository } from '../repositories/user-repository'
|
||||||
|
|
||||||
export const maintenanceWorkerFactory = () => {
|
export const maintenanceWorkerFactory = () => {
|
||||||
const dbClient = getDbClient()
|
const dbClient = getMasterDbClient()
|
||||||
|
const rrDbClient = getReadReplicaDbClient()
|
||||||
const paymentsProcessor = createPaymentsProcessor()
|
const paymentsProcessor = createPaymentsProcessor()
|
||||||
const userRepository = new UserRepository(dbClient)
|
const userRepository = new UserRepository(dbClient)
|
||||||
const invoiceRepository = new InvoiceRepository(dbClient)
|
const invoiceRepository = new InvoiceRepository(dbClient)
|
||||||
const eventRepository = new EventRepository(dbClient)
|
const eventRepository = new EventRepository(dbClient, rrDbClient)
|
||||||
|
|
||||||
const paymentsService = new PaymentsService(
|
const paymentsService = new PaymentsService(
|
||||||
dbClient,
|
dbClient,
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
|
import { getMasterDbClient, getReadReplicaDbClient } from '../database/client'
|
||||||
import { createPaymentsProcessor } from './payments-processor-factory'
|
import { createPaymentsProcessor } from './payments-processor-factory'
|
||||||
import { createSettings } from './settings-factory'
|
import { createSettings } from './settings-factory'
|
||||||
import { EventRepository } from '../repositories/event-repository'
|
import { EventRepository } from '../repositories/event-repository'
|
||||||
import { getDbClient } from '../database/client'
|
|
||||||
import { InvoiceRepository } from '../repositories/invoice-repository'
|
import { InvoiceRepository } from '../repositories/invoice-repository'
|
||||||
import { PaymentsService } from '../services/payments-service'
|
import { PaymentsService } from '../services/payments-service'
|
||||||
import { UserRepository } from '../repositories/user-repository'
|
import { UserRepository } from '../repositories/user-repository'
|
||||||
|
|
||||||
export const createPaymentsService = () => {
|
export const createPaymentsService = () => {
|
||||||
const dbClient = getDbClient()
|
const dbClient = getMasterDbClient()
|
||||||
|
const rrDbClient = getReadReplicaDbClient()
|
||||||
const invoiceRepository = new InvoiceRepository(dbClient)
|
const invoiceRepository = new InvoiceRepository(dbClient)
|
||||||
const userRepository = new UserRepository(dbClient)
|
const userRepository = new UserRepository(dbClient)
|
||||||
const paymentsProcessor = createPaymentsProcessor()
|
const paymentsProcessor = createPaymentsProcessor()
|
||||||
const eventRepository = new EventRepository(dbClient)
|
const eventRepository = new EventRepository(dbClient, rrDbClient)
|
||||||
|
|
||||||
return new PaymentsService(
|
return new PaymentsService(
|
||||||
dbClient,
|
dbClient,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import { getMasterDbClient, getReadReplicaDbClient } from '../database/client'
|
||||||
import { createPaymentsProcessor } from './payments-processor-factory'
|
import { createPaymentsProcessor } from './payments-processor-factory'
|
||||||
import { createSettings } from './settings-factory'
|
import { createSettings } from './settings-factory'
|
||||||
import { EventRepository } from '../repositories/event-repository'
|
import { EventRepository } from '../repositories/event-repository'
|
||||||
import { getDbClient } from '../database/client'
|
|
||||||
import { IController } from '../@types/controllers'
|
import { IController } from '../@types/controllers'
|
||||||
import { InvoiceRepository } from '../repositories/invoice-repository'
|
import { InvoiceRepository } from '../repositories/invoice-repository'
|
||||||
import { PaymentsService } from '../services/payments-service'
|
import { PaymentsService } from '../services/payments-service'
|
||||||
@ -10,8 +10,9 @@ import { slidingWindowRateLimiterFactory } from './rate-limiter-factory'
|
|||||||
import { UserRepository } from '../repositories/user-repository'
|
import { UserRepository } from '../repositories/user-repository'
|
||||||
|
|
||||||
export const createPostInvoiceController = (): IController => {
|
export const createPostInvoiceController = (): IController => {
|
||||||
const dbClient = getDbClient()
|
const dbClient = getMasterDbClient()
|
||||||
const eventRepository = new EventRepository(dbClient)
|
const rrDbClient = getReadReplicaDbClient()
|
||||||
|
const eventRepository = new EventRepository(dbClient, rrDbClient)
|
||||||
const invoiceRepository = new InvoiceRepository(dbClient)
|
const invoiceRepository = new InvoiceRepository(dbClient)
|
||||||
const userRepository = new UserRepository(dbClient)
|
const userRepository = new UserRepository(dbClient)
|
||||||
const paymentsProcessor = createPaymentsProcessor()
|
const paymentsProcessor = createPaymentsProcessor()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import { getMasterDbClient, getReadReplicaDbClient } from '../database/client'
|
||||||
import { createPaymentsProcessor } from './payments-processor-factory'
|
import { createPaymentsProcessor } from './payments-processor-factory'
|
||||||
import { createSettings } from './settings-factory'
|
import { createSettings } from './settings-factory'
|
||||||
import { EventRepository } from '../repositories/event-repository'
|
import { EventRepository } from '../repositories/event-repository'
|
||||||
import { getDbClient } from '../database/client'
|
|
||||||
import { IController } from '../@types/controllers'
|
import { IController } from '../@types/controllers'
|
||||||
import { InvoiceRepository } from '../repositories/invoice-repository'
|
import { InvoiceRepository } from '../repositories/invoice-repository'
|
||||||
import { PaymentsService } from '../services/payments-service'
|
import { PaymentsService } from '../services/payments-service'
|
||||||
@ -9,8 +9,9 @@ import { UserRepository } from '../repositories/user-repository'
|
|||||||
import { ZebedeeCallbackController } from '../controllers/callbacks/zebedee-callback-controller'
|
import { ZebedeeCallbackController } from '../controllers/callbacks/zebedee-callback-controller'
|
||||||
|
|
||||||
export const createZebedeeCallbackController = (): IController => {
|
export const createZebedeeCallbackController = (): IController => {
|
||||||
const dbClient = getDbClient()
|
const dbClient = getMasterDbClient()
|
||||||
const eventRepository = new EventRepository(dbClient)
|
const rrDbClient = getReadReplicaDbClient()
|
||||||
|
const eventRepository = new EventRepository(dbClient, rrDbClient)
|
||||||
const invoiceRepotistory = new InvoiceRepository(dbClient)
|
const invoiceRepotistory = new InvoiceRepository(dbClient)
|
||||||
const userRepository = new UserRepository(dbClient)
|
const userRepository = new UserRepository(dbClient)
|
||||||
const paymentsProcessor = createPaymentsProcessor()
|
const paymentsProcessor = createPaymentsProcessor()
|
||||||
|
@ -29,6 +29,10 @@ export async function isRateLimited(remoteAddress: string, settings: Settings):
|
|||||||
ipWhitelist = [],
|
ipWhitelist = [],
|
||||||
} = settings.limits?.connection ?? {}
|
} = settings.limits?.connection ?? {}
|
||||||
|
|
||||||
|
if (typeof rateLimits === 'undefined') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (ipWhitelist.includes(remoteAddress)) {
|
if (ipWhitelist.includes(remoteAddress)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ export class EventRepository implements IEventRepository {
|
|||||||
ifElse(
|
ifElse(
|
||||||
isEmpty,
|
isEmpty,
|
||||||
() => andWhereRaw('1 = 0', bd),
|
() => andWhereRaw('1 = 0', bd),
|
||||||
forEach((criterion: string[]) => void orWhereRaw(
|
forEach((criterion: string) => void orWhereRaw(
|
||||||
'"event_tags" @> ?',
|
'"event_tags" @> ?',
|
||||||
[
|
[
|
||||||
JSON.stringify([[filterName[1], criterion]]) as any,
|
JSON.stringify([[filterName[1], criterion]]) as any,
|
||||||
@ -195,7 +195,7 @@ export class EventRepository implements IEventRepository {
|
|||||||
|
|
||||||
const toJSON = (input: any) => JSON.stringify(input)
|
const toJSON = (input: any) => JSON.stringify(input)
|
||||||
|
|
||||||
const row = applySpec({
|
const row = applySpec<DBEvent>({
|
||||||
event_id: pipe(prop('id'), toBuffer),
|
event_id: pipe(prop('id'), toBuffer),
|
||||||
event_pubkey: pipe(prop('pubkey'), toBuffer),
|
event_pubkey: pipe(prop('pubkey'), toBuffer),
|
||||||
event_created_at: prop('created_at'),
|
event_created_at: prop('created_at'),
|
||||||
|
@ -234,8 +234,8 @@ Amount: ${amount.toString()} ${unit}
|
|||||||
|
|
||||||
⚠️ By paying this invoice, you confirm that you have read and agree to the Terms of Service:
|
⚠️ By paying this invoice, you confirm that you have read and agree to the Terms of Service:
|
||||||
${terms.toString()}
|
${terms.toString()}
|
||||||
|
${invoice.expiresAt ? `
|
||||||
⏳ Expires at ${invoice.expiresAt.toISOString()}
|
⏳ Expires at ${invoice.expiresAt.toISOString()}` : ''}
|
||||||
|
|
||||||
${invoice.bolt11}`,
|
${invoice.bolt11}`,
|
||||||
tags: [
|
tags: [
|
||||||
|
@ -15,7 +15,7 @@ export enum SettingsFileTypes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SettingsStatic {
|
export class SettingsStatic {
|
||||||
static _settings: Settings
|
static _settings: Settings | undefined
|
||||||
|
|
||||||
public static getSettingsFileBasePath(): string {
|
public static getSettingsFileBasePath(): string {
|
||||||
return process.env.NOSTR_CONFIG_DIR ?? join(process.cwd(), '.nostr')
|
return process.env.NOSTR_CONFIG_DIR ?? join(process.cwd(), '.nostr')
|
||||||
@ -93,6 +93,10 @@ export class SettingsStatic {
|
|||||||
SettingsStatic._settings = mergeDeepRight({}, defaults)
|
SettingsStatic._settings = mergeDeepRight({}, defaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof SettingsStatic._settings === 'undefined') {
|
||||||
|
throw new Error('Unable to set settings')
|
||||||
|
}
|
||||||
|
|
||||||
return SettingsStatic._settings
|
return SettingsStatic._settings
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
debug('error reading config file at %s: %o', settingsFilePath, error)
|
debug('error reading config file at %s: %o', settingsFilePath, error)
|
||||||
|
Reference in New Issue
Block a user