Skip to content

Commit

Permalink
prettier logging and embed version on compile
Browse files Browse the repository at this point in the history
  • Loading branch information
huumn committed Jun 18, 2023
1 parent 3df4a61 commit b9a05eb
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 96 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ simplicity, ease of use, extensibility, scalability, performance, security

0. [install postgres](https://www.postgresql.org/download/) and run it (welcome
to app programming)
1. [download the latest booger release](https://github.com/stackernews/booger/releases/latest) and unzip it
1. [download the latest booger release](https://github.com/stackernews/booger/releases/latest)
and unzip it
2. run `./booger` and your nostr relay is listening on `127.0.0.1:8006`

# how to run (locally from source)
Expand Down Expand Up @@ -119,7 +120,7 @@ Configuration values passed via cli take precedence over those in `env` and

```txt
[keyan booger]🍏 ./booger --help
booger - a nostr relay v0.0.0
booger - a nostr relay
Docs: https://github.com/stackernews/booger/blob/main/README.md
Bugs: https://github.com/stackernews/booger/issues
Expand Down
78 changes: 41 additions & 37 deletions conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,43 @@ import { parse as flagsParse } from 'std/flags/mod.ts'
import { loadSync } from 'std/dotenv/mod.ts'
import { deepMerge } from 'std/collections/deep_merge.ts'

export const CONFIG = `// default configuration file for booger
const args = flagsParse(Deno.args, {
string: [
'config',
'port',
'bind',
'db',
'db-stats',
'db-limits',
'dotenv',
'plugs-dir',
'plugs-builtin-use',
'__compiled-version',
],
boolean: ['init', 'help', 'version'],
alias: {
c: 'config',
p: 'port',
b: 'bind',
d: 'db',
s: 'db-stats',
l: 'db-limits',
e: 'dotenv',
i: 'init',
v: 'version',
h: 'help',
},
unknown: (arg) => {
console.log(`error: unexpected argument '${arg}'`)
console.log()
console.log(`For more information, try '--help'.`)
Deno.exit(1)
},
})

const VERSION = args['__compiled-version'] ?? 'X.X.X'

const CONFIG = `// default configuration file for booger
// booger will look for this file in the directory it is run from
// or you can specify a path with the --config flag
// you can always generate a default config file with the --init flag
Expand Down Expand Up @@ -40,7 +76,7 @@ export const CONFIG = `// default configuration file for booger
40
],
"Software": "https://github.com/stackernews/booger",
"Version": "v0.0.0"
"Version": "${VERSION}"
},
// configuration related to booger plugs
Expand Down Expand Up @@ -145,43 +181,10 @@ export const CONFIG = `// default configuration file for booger
}
}`

const args = flagsParse(Deno.args, {
string: [
'config',
'port',
'bind',
'db',
'db-stats',
'db-limits',
'dotenv',
'plugs-dir',
'plugs-builtin-use',
],
boolean: ['init', 'help', 'version'],
alias: {
c: 'config',
p: 'port',
b: 'bind',
d: 'db',
s: 'db-stats',
l: 'db-limits',
e: 'dotenv',
i: 'init',
v: 'version',
h: 'help',
},
unknown: (arg) => {
console.log(`error: unexpected argument '${arg}'`)
console.log()
console.log(`For more information, try '--help'.`)
Deno.exit(1)
},
})

const config = jsoncParse(CONFIG)

if (args.help) {
const HELP = `booger - a nostr relay v0.0.0
const HELP = `booger - a nostr relay ${VERSION}
Docs: https://github.com/stackernews/booger/blob/main/README.md
Bugs: https://github.com/stackernews/booger/issues
Expand Down Expand Up @@ -224,7 +227,7 @@ Options:
}

if (args.version) {
console.log(`booger v0.0.0`)
console.log(`booger ${VERSION}`)
console.log(
`deno ${Deno.version.deno} (${Deno.build.arch}-${Deno.build.vendor}-${Deno.build.os})`,
)
Expand Down Expand Up @@ -302,6 +305,7 @@ if (args.dotenv) {
}

const envConfig = delUndefined({
version: VERSION,
port: Deno.env.get('PORT'),
bind: Deno.env.get('BIND'),
db: Deno.env.get('DB'),
Expand Down
4 changes: 2 additions & 2 deletions deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
// sub-run takes $DENO_EXT and $DENO_PERMS and runs deno run
"sub-run": "deno run $DENO_EXT $DENO_PERMS --unstable index.js",
// sub-compile takes $DENO_EXT and $DENO_PERMS and runs deno compile
"sub-compile": "deno compile $DENO_EXT $DENO_PERMS --unstable --include=./plugs/builtin/validate/validate-sub.js --include=./plugs/builtin/validate/validate-event.js --include=./plugs/builtin/limits/limits.js --include=./plugs/builtin/stats/stats.js ./index.js",
"sub-compile": "deno compile $DENO_EXT $DENO_PERMS --unstable --include=./plugs/builtin/validate/validate-sub.js --include=./plugs/builtin/validate/validate-event.js --include=./plugs/builtin/limits/limits.js --include=./plugs/builtin/stats/stats.js ./index.js -- --__compiled-version=$BOOGER_VER",
// sub-release adds $DENO_TARGET for all the target platforms and runs sub-sub-release
"sub-release": "DENO_TARGET=x86_64-unknown-linux-gnu deno task sub-sub-release && DENO_TARGET=x86_64-pc-windows-msvc deno task sub-sub-release && DENO_TARGET=x86_64-apple-darwin deno task sub-sub-release && DENO_TARGET=aarch64-apple-darwin deno task sub-sub-release",
// sub-sub-release adds $DENO_EXT using both $DENO_TARGET and $DENO_REL (specifies the target and output directory) then runs sub-compile
// after compiling, it zips the binary using $BOOGER_VER provided to the original task
"sub-sub-release": "DENO_EXT=\"--target=$DENO_TARGET -o ./release/$DENO_REL/$DENO_TARGET/booger\" deno task sub-compile && sh -c \"chmod +x ./release/$DENO_REL/$DENO_TARGET/booger*\" && sh -c \"zip -j ./release/booger-$BOOGER_VER-$DENO_REL-$DENO_TARGET.zip ./release/$DENO_REL/$DENO_TARGET/booger*\""
"sub-sub-release": "DENO_EXT=\"--target=$DENO_TARGET -o ./release/$DENO_REL/$DENO_TARGET/booger\" deno task sub-compile && sh -c \"chmod +x ./release/$DENO_REL/$DENO_TARGET/booger*\" && sh -c \"zip -j ./release/booger-v$BOOGER_VER-$DENO_REL-$DENO_TARGET.zip ./release/$DENO_REL/$DENO_TARGET/booger*\""
},
"imports": {
"std/": "https://deno.land/std@0.191.0/",
Expand Down
14 changes: 14 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ import {
import { forEachEvent, listen, pgInit, storeNotify } from './pg.js'
import { plugsAction, plugsInit } from './plugs.js'

console.log(`\x1b[32m
▄▄▄▄ ▒█████ ▒█████ ▄████ ▓█████ ██▀███
▓█████▄ ▒██▒ ██▒▒██▒ ██▒ ██▒ ▀█▒▓█ ▀ ▓██ ▒ ██▒
▒██▒ ▄██▒██░ ██▒▒██░ ██▒▒██░▄▄▄░▒███ ▓██ ░▄█ ▒ \x1b[0m booger ${CONFIG.version} \x1b[32m
▒██░█▀ ▒██ ██░▒██ ██░░▓█ ██▓▒▓█ ▄ ▒██▀▀█▄ \x1b[0m deno ${Deno.version.deno} \x1b[32m
░▓█ ▀█▓░ ████▓▒░░ ████▓▒░░▒▓███▀▒░▒████▒░██▓ ▒██▒
░▒▓███▀▒░ ▒░▒░▒░ ░ ▒░▒░▒░ ░▒ ▒ ░░ ▒░ ░░ ▒▓ ░▒▓░ \x1b[0m port ${CONFIG.port} \x1b[32m
▒░▒ ░ ░ ▒ ▒░ ░ ▒ ▒░ ░ ░ ░ ░ ░ ░▒ ░ ▒░ \x1b[0m pid ${Deno.pid} \x1b[32m
░ ░ ░ ░ ░ ▒ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░
░ ░ ░ ░ ░ ░ ░ ░ ░
\x1b[0m`)

const sockets = new Map() // map[socket id][websocket]
sqliteInit()
await pgInit()
Expand Down
94 changes: 48 additions & 46 deletions pg.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,69 @@
import CONFIG from "./conf.js";
import postgres from "postgres";
import remodel from "./remodel.js";
import migrations from "./migrations/index.js";
import CONFIG from './conf.js'
import postgres from 'postgres'
import remodel from './remodel.js'
import migrations from './migrations/index.js'

let pg;
let pg

export async function pgInit() {
self.addEventListener("unload", async () => await pg?.end());
pg = await crennect(CONFIG.db);
self.addEventListener('unload', async () => await pg?.end())
pg = await crennect(CONFIG.db)
await remodel(pg, {
migrations,
table: "booger_migrations",
});
table: 'booger_migrations',
})
}

export async function listen(handleEvent) {
await pg.listen("event", handleEvent);
await pg.listen('event', handleEvent)
}

export async function storeNotify(event) {
const { id, pubkey, created_at: createdAt, kind, tags } = event;
const { id, pubkey, created_at: createdAt, kind, tags } = event
// nip 16 ephemeral
if (kind >= 20000 && kind < 30000) {
return await pg.notify("event", JSON.stringify(event));
return await pg.notify('event', JSON.stringify(event))
}

// nip 26 delegation
const delegator = tags.find(([t]) => t === "delegation")?.at(1);
const delegator = tags.find(([t]) => t === 'delegation')?.at(1)

await pg.begin((pg) => {
const line = [];
const line = []

// nip 1, 3, and 16 replaceable kinds
if (kind === 0 || kind === 3 || (kind >= 10000 && kind < 20000)) {
line.push(pg`DELETE FROM event WHERE kind = ${kind}
AND pubkey = ${pubkey} AND created_at < ${createdAt}`);
AND pubkey = ${pubkey} AND created_at < ${createdAt}`)
}

// nip 1 event
line.push(pg`
INSERT INTO event (id, pubkey, delegator, created_at, kind, raw)
VALUES (${id}, ${pubkey}, ${delegator}, ${createdAt}, ${kind},
${JSON.stringify(event)})`);
${JSON.stringify(event)})`)

let firstD = true;
let firstD = true
for (const [tag, ...values] of tags) {
// nip 1 tags
line.push(pg`INSERT INTO tag (event_id, tag, values)
VALUES (${id}, ${tag}, ${values})`);
VALUES (${id}, ${tag}, ${values})`)

// nip 9 delete referenced event
if (kind === 5 && tag === "e" && values.length) {
if (kind === 5 && tag === 'e' && values.length) {
line.push(pg`DELETE FROM event WHERE id = ${values[0]}
AND pubkey = ${pubkey}`);
AND pubkey = ${pubkey}`)
}

// nip 40 expiration
if (tag === "expiration") {
if (tag === 'expiration') {
line.push(pg`UPDATE event SET expires_at = ${Number(values[0])}
WHERE id = ${id}`);
WHERE id = ${id}`)
}

// nip 33 parameterized replacement
if (kind >= 30000 && kind < 40000 && firstD && tag === "d") {
firstD = false;
if (kind >= 30000 && kind < 40000 && firstD && tag === 'd') {
firstD = false
line.push(
pg`DELETE FROM event
WHERE kind = ${kind}
Expand All @@ -75,12 +75,12 @@ export async function storeNotify(event) {
WHERE event.id = tag.event_id
AND tag.tag = 'd'
AND COALESCE(tag.values[1], '') = COALESCE(${values[0]}, ''))`,
);
)
}
}

return line;
});
return line
})
}

export async function forEachEvent(filters, cb) {
Expand Down Expand Up @@ -118,10 +118,10 @@ export async function forEachEvent(filters, cb) {
GROUP BY event.id
HAVING count(filter_tag.tag) = (SELECT count(*) FROM filter_tag)
ORDER BY event.created_at DESC
LIMIT ${limit}`.values().cursor(100);
LIMIT ${limit}`.values().cursor(100)

for await (const rows of cursor) {
rows.forEach((row) => cb(row[0]));
rows.forEach((row) => cb(row[0]))
}
}
}
Expand All @@ -135,32 +135,34 @@ function connect(url) {
undefined: null,
},
},
);
)
}

export async function crennect(url) {
try {
const pgTry = connect(url);
await pgTry`SELECT 1`; // conn doesn't happen until first query
return pgTry;
const pgTry = connect(url)
await pgTry`SELECT 1` // conn doesn't happen until first query
return pgTry
} catch (e) {
if (e.code === "3D000") { // database does not exist
if (e.code === '3D000') { // database does not exist
try {
const urlObj = new URL(url);
const db = urlObj.pathname.slice(1);

console.log(`database ${db} does not exist, attempting to create ...`);
urlObj.pathname = "/postgres"; // common default
const tempPg = postgres(urlObj);
await tempPg.unsafe(`CREATE DATABASE ${db}`);
await tempPg.end();
console.log(`created ${db} successfully`);
const urlObj = new URL(url)
const db = urlObj.pathname.slice(1)

console.log(`db ${db} does not exist, attempting to create ...`)
urlObj.pathname = '/postgres' // common default
const tempPg = postgres(urlObj)
await tempPg.unsafe(`CREATE DATABASE ${db}`)
await tempPg.end()
console.log(
`\x1b[A\x1b[Kdb ${db} does not exist, attempting to create ... created ${db}`,
)
} catch {
throw e;
throw e
}

return connect(url);
return connect(url)
}
throw e;
throw e
}
}
8 changes: 3 additions & 5 deletions plugs.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export async function plugsInit() {
name: basename(builtin, '.js') ||
basename(builtin, '.ts'),
})
await plugInit(worker, 'builtin ' + basename(builtin, '.js'))
await plugInit(worker, basename(builtin, '.js') + ' (builtin)')
}
}

Expand Down Expand Up @@ -125,12 +125,10 @@ export async function plugsAction(action, conn, data) {
async function plugInit(worker, name) {
// register the plug
await new Promise((resolve, reject) => {
console.log(`plug registering ${name}...`)

setTimeout(() =>
reject(
new Error(
`${name} did not respond to 'getactions' within 5s. Is it a web worker?`,
`plug ${name} did not respond to 'getactions' within 5s. Is it a web worker?`,
),
), 5000)

Expand All @@ -143,7 +141,7 @@ async function plugInit(worker, name) {
Deno.exit(1)
}
}
console.log(`plug registered ${name} for actions: ${data.join(', ')}`)
console.log(`plug ${name} registered for actions: ${data.join(', ')}`)
resolve()
}
worker.onerror = reject
Expand Down
1 change: 0 additions & 1 deletion plugs/builtin/limits/limits.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export async function pgInit() {
self.onmessage = async ({ data }) => {
if (data === 'getactions') {
await pgInit()

self.postMessage(['event', 'sub', 'unsub', 'connect', 'disconnect'])
return
}
Expand Down
1 change: 0 additions & 1 deletion plugs/builtin/stats/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export async function pgInit() {
self.onmessage = async ({ data }) => {
if (data === 'getactions') {
await pgInit()

self.postMessage([
'connect',
'disconnect',
Expand Down
Loading

0 comments on commit b9a05eb

Please sign in to comment.