feat: improve settings

This commit is contained in:
Ricardo Arturo Cabral Mejia 2022-09-20 05:07:27 +00:00
parent 17227107cb
commit 687a896d9e
No known key found for this signature in database
GPG Key ID: 5931EBF43A650245
3 changed files with 68 additions and 27 deletions

View File

@ -10,10 +10,11 @@ interface Info {
} }
interface EventIdLimits { interface EventIdLimits {
minimumZeroBits?: number minLeadingZeroBits?: number
} }
interface PubkeyLimits { interface PubkeyLimits {
minLeadingZeroBits: number
whitelist?: Pubkey[] whitelist?: Pubkey[]
blacklist?: Pubkey[] blacklist?: Pubkey[]
} }
@ -27,11 +28,11 @@ interface CreatedAtLimits {
/** /**
* Maximum number of seconds allowed before the current unix timestamp * Maximum number of seconds allowed before the current unix timestamp
*/ */
maximumNegativeDelta?: number maxNegativeDelta?: number
/** /**
* Maximum number of seconds allowed after the current unix timestamp * Maximum number of seconds allowed after the current unix timestamp
*/ */
maximumPositiveDelta?: number maxPositiveDelta?: number
} }
interface EventLimits { interface EventLimits {
@ -42,8 +43,8 @@ interface EventLimits {
} }
interface ClientSubscriptionLimits { interface ClientSubscriptionLimits {
maximumCount?: number maxSubscriptions?: number
maximumFilters?: number maxFilters?: number
} }
interface ClientLimits { interface ClientLimits {

View File

@ -6,6 +6,7 @@ import { WebSocketServer } from 'ws'
import { EventRepository } from './repositories/event-repository' import { EventRepository } from './repositories/event-repository'
import { getDbClient } from './database/client' import { getDbClient } from './database/client'
import { saveSettingsOnExit } from './utils/settings'
import { webSocketAdapterFactory } from './factories/websocket-adapter-factory' import { webSocketAdapterFactory } from './factories/websocket-adapter-factory'
import { WebSocketServerAdapter } from './adapters/web-socket-server-adapter' import { WebSocketServerAdapter } from './adapters/web-socket-server-adapter'
@ -24,7 +25,7 @@ if (cluster.isPrimary) {
cluster.on('exit', (deadWorker, code, signal) => { cluster.on('exit', (deadWorker, code, signal) => {
console.log(`worker ${deadWorker.process.pid} - exiting`) console.log(`worker ${deadWorker.process.pid} - exiting`)
if (signal === 'SIGINT') { if (code === 0 || signal === 'SIGINT') {
return return
} }
const worker = newWorker() const worker = newWorker()
@ -36,9 +37,16 @@ if (cluster.isPrimary) {
console.log('worker ' + newPID + ' born.') console.log('worker ' + newPID + ' born.')
}) })
process.on('exit', () => { const exitHandler = () => {
console.log('Primary exiting') console.log('Primary exiting')
})
saveSettingsOnExit()
process.exit(0)
}
process.on('SIGINT', exitHandler)
process.on('uncaughtException', exitHandler)
} else if (cluster.isWorker) { } else if (cluster.isWorker) {
const port = Number(process.env.SERVER_PORT) || 8008 const port = Number(process.env.SERVER_PORT) || 8008
@ -55,7 +63,7 @@ if (cluster.isPrimary) {
adapter.listen(port) adapter.listen(port)
process.on('SIGINT', () => { const exitHandler = () => {
wss.close(() => { wss.close(() => {
server.close(() => { server.close(() => {
dbClient.destroy(() => { dbClient.destroy(() => {
@ -63,7 +71,10 @@ if (cluster.isPrimary) {
}) })
}) })
}) })
}) }
process.on('SIGINT', exitHandler)
process.on('uncaughtException', exitHandler)
console.log(`worker ${process.pid} - listening on port ${port}`) console.log(`worker ${process.pid} - listening on port ${port}`)
} }

View File

@ -1,11 +1,17 @@
import { copyFileSync, readFileSync, unlinkSync, writeFileSync } from 'fs'
import cluster from 'cluster'
import { homedir } from 'os' import { homedir } from 'os'
import { join } from 'path' import { join } from 'path'
import { mergeDeepRight } from 'ramda' import { mergeDeepRight } from 'ramda'
import { readFileSync } from 'fs'
import { ISettings } from '../@types/settings' import { ISettings } from '../@types/settings'
import packageJson from '../../package.json' import packageJson from '../../package.json'
const getSettingsFilePath = (filename = 'settings.json') => join(
process.env.NOSTR_CONFIG_DIR ?? join(homedir(), '.nostr'),
filename,
)
let _settings: ISettings let _settings: ISettings
const getDefaultSettings = (): ISettings => ({ const getDefaultSettings = (): ISettings => ({
@ -19,54 +25,77 @@ const getDefaultSettings = (): ISettings => ({
limits: { limits: {
event: { event: {
eventId: { eventId: {
minimumZeroBits: 0, minLeadingZeroBits: 0,
}, },
kind: { kind: {
whitelist: [], whitelist: [],
blacklist: [], blacklist: [],
}, },
pubkey: { pubkey: {
minLeadingZeroBits: 0,
whitelist: [], whitelist: [],
blacklist: [], blacklist: [],
}, },
}, },
client: { client: {
subscription: { subscription: {
maximumCount: 10, maxSubscriptions: 10,
maximumFilters: 5, maxFilters: 10,
}, },
}, },
}, },
}) })
const createSettingsFromFile = (defaults: ISettings) => { const loadSettings = (path: string) => {
const contents = JSON.parse( console.log('loading settings', path)
return JSON.parse(
readFileSync( readFileSync(
join( path,
process.env.NOSTR_CONFIG_DIR ?? join(homedir(), '.nostr'),
'settings.json',
),
{ encoding: 'utf8' }, { encoding: 'utf8' },
), ),
) )
return mergeDeepRight(defaults, contents)
} }
const createSettings = (): ISettings => { const createSettings = (): ISettings => {
const path = getSettingsFilePath()
const defaults = getDefaultSettings()
try { try {
if (_settings) { if (_settings) {
return _settings return _settings
} }
_settings = createSettingsFromFile(getDefaultSettings()) _settings = mergeDeepRight(defaults, loadSettings(path))
return _settings return _settings
} catch (err) { } catch (error) {
console.error('Unable to read config file. Reason: %s', err.message) console.error('Unable to read config file. Reason: %s', error.message)
return getDefaultSettings() return defaults
} }
} }
export const saveSettings = (path: string, settings: ISettings) => {
console.log('saving settings')
return writeFileSync(
path,
JSON.stringify(settings, null, 2),
{ encoding: 'utf-8' }
)
}
export const Settings = createSettings() export const Settings = createSettings()
export const saveSettingsOnExit = () => {
if (cluster.isWorker) {
return
}
const path = getSettingsFilePath()
const backupPath = getSettingsFilePath(`settings-${Date.now()}.json`)
try {
copyFileSync(path, backupPath)
saveSettings(path, Settings)
unlinkSync(backupPath)
} catch (error) {
console.error('Unable to write config file. Reason: %s', error.message)
}
}