🔄 Synchronize Biome linting rules between relay and frontend
🛠️ Apply identical Biome configuration from frontend to relay service 🧹 Ensure consistent code formatting and quality standards across components 📝 Maintain unified development experience throughout the project
This commit is contained in:
parent
4bd0839669
commit
a4134fa416
9 changed files with 273 additions and 195 deletions
240
index.ts
240
index.ts
|
@ -1,9 +1,15 @@
|
|||
import { NSchema as n } from "jsr:@nostrify/nostrify";
|
||||
import { Database } from 'jsr:@db/sqlite';
|
||||
import { NSchema as n } from 'jsr:@nostrify/nostrify';
|
||||
import type {
|
||||
NostrClientREQ,
|
||||
NostrEvent,
|
||||
NostrFilter,
|
||||
} from "jsr:@nostrify/types";
|
||||
} from 'jsr:@nostrify/types';
|
||||
import { encodeBase64 } from 'jsr:@std/encoding@0.224/base64';
|
||||
import { randomBytes } from '@noble/ciphers/webcrypto';
|
||||
import * as nostrTools from '@nostr/tools';
|
||||
import { nip44 } from '@nostr/tools';
|
||||
import { MIN_POW, POW_TO_MINE } from './consts.ts';
|
||||
import {
|
||||
getCCNPrivateKey,
|
||||
getCCNPubkey,
|
||||
|
@ -15,56 +21,48 @@ import {
|
|||
isValidJSON,
|
||||
parseATagQuery,
|
||||
randomTimeUpTo2DaysInThePast,
|
||||
} from "./utils.ts";
|
||||
import * as nostrTools from "@nostr/tools";
|
||||
import { nip44 } from "@nostr/tools";
|
||||
import { randomBytes } from "@noble/ciphers/webcrypto";
|
||||
import { encodeBase64 } from "jsr:@std/encoding@0.224/base64";
|
||||
import { Database } from "jsr:@db/sqlite";
|
||||
import { mixQuery, sql, sqlPartial } from "./utils/queries.ts";
|
||||
import { log, setupLogger } from "./utils/logs.ts";
|
||||
import { getEveFilePath } from "./utils/files.ts";
|
||||
import { MIN_POW, POW_TO_MINE } from "./consts.ts";
|
||||
} from './utils.ts';
|
||||
import { getEveFilePath } from './utils/files.ts';
|
||||
import { log, setupLogger } from './utils/logs.ts';
|
||||
import { mixQuery, sql, sqlPartial } from './utils/queries.ts';
|
||||
|
||||
await setupLogger();
|
||||
|
||||
if (!Deno.env.has("ENCRYPTION_KEY")) {
|
||||
if (!Deno.env.has('ENCRYPTION_KEY')) {
|
||||
log.error(
|
||||
`Missing ENCRYPTION_KEY. Please set it in your env.\nA new one has been generated for you: ENCRYPTION_KEY="${
|
||||
encodeBase64(
|
||||
randomBytes(32),
|
||||
)
|
||||
}"`,
|
||||
`Missing ENCRYPTION_KEY. Please set it in your env.\nA new one has been generated for you: ENCRYPTION_KEY="${encodeBase64(
|
||||
randomBytes(32),
|
||||
)}"`,
|
||||
);
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
const db = new Database(await getEveFilePath("db"));
|
||||
const db = new Database(await getEveFilePath('db'));
|
||||
const pool = new nostrTools.SimplePool();
|
||||
const relays = [
|
||||
"wss://relay.arx-ccn.com/",
|
||||
"wss://relay.dannymorabito.com/",
|
||||
"wss://nos.lol/",
|
||||
"wss://nostr.einundzwanzig.space/",
|
||||
"wss://nostr.massmux.com/",
|
||||
"wss://nostr.mom/",
|
||||
"wss://nostr.wine/",
|
||||
"wss://purplerelay.com/",
|
||||
"wss://relay.damus.io/",
|
||||
"wss://relay.goodmorningbitcoin.com/",
|
||||
"wss://relay.lexingtonbitcoin.org/",
|
||||
"wss://relay.nostr.band/",
|
||||
"wss://relay.primal.net/",
|
||||
"wss://relay.snort.social/",
|
||||
"wss://strfry.iris.to/",
|
||||
"wss://cache2.primal.net/v1",
|
||||
'wss://relay.arx-ccn.com/',
|
||||
'wss://relay.dannymorabito.com/',
|
||||
'wss://nos.lol/',
|
||||
'wss://nostr.einundzwanzig.space/',
|
||||
'wss://nostr.massmux.com/',
|
||||
'wss://nostr.mom/',
|
||||
'wss://nostr.wine/',
|
||||
'wss://purplerelay.com/',
|
||||
'wss://relay.damus.io/',
|
||||
'wss://relay.goodmorningbitcoin.com/',
|
||||
'wss://relay.lexingtonbitcoin.org/',
|
||||
'wss://relay.nostr.band/',
|
||||
'wss://relay.primal.net/',
|
||||
'wss://relay.snort.social/',
|
||||
'wss://strfry.iris.to/',
|
||||
'wss://cache2.primal.net/v1',
|
||||
];
|
||||
|
||||
export function runMigrations(db: Database, latestVersion: number) {
|
||||
const migrations = Deno.readDirSync(`${import.meta.dirname}/migrations`);
|
||||
for (const migrationFile of migrations) {
|
||||
const migrationVersion = Number.parseInt(
|
||||
migrationFile.name.split("-")[0],
|
||||
migrationFile.name.split('-')[0],
|
||||
10,
|
||||
);
|
||||
|
||||
|
@ -76,34 +74,31 @@ export function runMigrations(db: Database, latestVersion: number) {
|
|||
const migrationSql = Deno.readTextFileSync(
|
||||
`${import.meta.dirname}/migrations/${migrationFile.name}`,
|
||||
);
|
||||
db.run("BEGIN TRANSACTION");
|
||||
db.run('BEGIN TRANSACTION');
|
||||
try {
|
||||
db.run(migrationSql);
|
||||
const end = Date.now();
|
||||
const durationMs = end - start;
|
||||
sql`
|
||||
INSERT INTO migration_history (migration_version, migration_name, executed_at, duration_ms, status) VALUES (${migrationVersion}, ${migrationFile.name}, ${
|
||||
new Date().toISOString()
|
||||
}, ${durationMs}, 'success');
|
||||
INSERT INTO migration_history (migration_version, migration_name, executed_at, duration_ms, status) VALUES (${migrationVersion}, ${migrationFile.name}, ${new Date().toISOString()}, ${durationMs}, 'success');
|
||||
db.run("COMMIT TRANSACTION");
|
||||
`(db);
|
||||
} catch (e) {
|
||||
db.run("ROLLBACK TRANSACTION");
|
||||
const error = e instanceof Error
|
||||
? e
|
||||
: typeof e === "string"
|
||||
? new Error(e)
|
||||
: new Error(JSON.stringify(e));
|
||||
db.run('ROLLBACK TRANSACTION');
|
||||
const error =
|
||||
e instanceof Error
|
||||
? e
|
||||
: typeof e === 'string'
|
||||
? new Error(e)
|
||||
: new Error(JSON.stringify(e));
|
||||
const end = Date.now();
|
||||
const durationMs = end - start;
|
||||
sql`
|
||||
INSERT INTO migration_history (migration_version, migration_name, executed_at, duration_ms, status, error_message) VALUES (${migrationVersion}, ${migrationFile.name}, ${
|
||||
new Date().toISOString()
|
||||
}, ${durationMs}, 'failed', ${error.message});
|
||||
INSERT INTO migration_history (migration_version, migration_name, executed_at, duration_ms, status, error_message) VALUES (${migrationVersion}, ${migrationFile.name}, ${new Date().toISOString()}, ${durationMs}, 'failed', ${error.message});
|
||||
`(db);
|
||||
throw e;
|
||||
}
|
||||
db.run("END TRANSACTION");
|
||||
db.run('END TRANSACTION');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +106,8 @@ export function runMigrations(db: Database, latestVersion: number) {
|
|||
async function createEncryptedEvent(
|
||||
event: nostrTools.VerifiedEvent,
|
||||
): Promise<nostrTools.VerifiedEvent> {
|
||||
if (!event.id) throw new Error("Event must have an ID");
|
||||
if (!event.sig) throw new Error("Event must be signed");
|
||||
if (!event.id) throw new Error('Event must have an ID');
|
||||
if (!event.sig) throw new Error('Event must be signed');
|
||||
const ccnPubKey = await getCCNPubkey();
|
||||
const ccnPrivateKey = await getCCNPrivateKey();
|
||||
const randomPrivateKey = nostrTools.generateSecretKey();
|
||||
|
@ -129,7 +124,7 @@ async function createEncryptedEvent(
|
|||
kind: 1059,
|
||||
created_at: randomTimeUpTo2DaysInThePast(),
|
||||
content: nip44.encrypt(JSON.stringify(seal), conversationKey),
|
||||
tags: [["p", ccnPubKey]],
|
||||
tags: [['p', ccnPubKey]],
|
||||
pubkey: randomPrivateKeyPubKey,
|
||||
};
|
||||
const minedGiftWrap = nostrTools.nip13.minePow(giftWrapTemplate, POW_TO_MINE);
|
||||
|
@ -143,20 +138,20 @@ async function decryptEvent(
|
|||
const ccnPrivkey = await getCCNPrivateKey();
|
||||
|
||||
if (event.kind !== 1059) {
|
||||
throw new Error("Cannot decrypt event -- not a gift wrap");
|
||||
throw new Error('Cannot decrypt event -- not a gift wrap');
|
||||
}
|
||||
|
||||
const pow = nostrTools.nip13.getPow(event.id);
|
||||
|
||||
if (pow < MIN_POW) {
|
||||
throw new Error("Cannot decrypt event -- PoW too low");
|
||||
throw new Error('Cannot decrypt event -- PoW too low');
|
||||
}
|
||||
|
||||
const conversationKey = nip44.getConversationKey(ccnPrivkey, event.pubkey);
|
||||
const seal = JSON.parse(nip44.decrypt(event.content, conversationKey));
|
||||
if (!seal) throw new Error("Cannot decrypt event -- no seal");
|
||||
if (!seal) throw new Error('Cannot decrypt event -- no seal');
|
||||
if (seal.kind !== 13) {
|
||||
throw new Error("Cannot decrypt event subevent -- not a seal");
|
||||
throw new Error('Cannot decrypt event subevent -- not a seal');
|
||||
}
|
||||
const content = JSON.parse(nip44.decrypt(seal.content, conversationKey));
|
||||
return content as nostrTools.VerifiedEvent;
|
||||
|
@ -174,7 +169,7 @@ function addEventToDb(
|
|||
|
||||
if (existingEvent) throw new EventAlreadyExistsException();
|
||||
try {
|
||||
db.run("BEGIN TRANSACTION");
|
||||
db.run('BEGIN TRANSACTION');
|
||||
|
||||
if (isReplaceableEvent(decryptedEvent.kind)) {
|
||||
sql`
|
||||
|
@ -187,7 +182,7 @@ function addEventToDb(
|
|||
}
|
||||
|
||||
if (isAddressableEvent(decryptedEvent.kind)) {
|
||||
const dTag = decryptedEvent.tags.find((tag) => tag[0] === "d")?.[1];
|
||||
const dTag = decryptedEvent.tags.find((tag) => tag[0] === 'd')?.[1];
|
||||
if (dTag) {
|
||||
sql`
|
||||
UPDATE events
|
||||
|
@ -209,7 +204,7 @@ function addEventToDb(
|
|||
}
|
||||
|
||||
if (isCCNReplaceableEvent(decryptedEvent.kind)) {
|
||||
const dTag = decryptedEvent.tags.find((tag) => tag[0] === "d")?.[1];
|
||||
const dTag = decryptedEvent.tags.find((tag) => tag[0] === 'd')?.[1];
|
||||
sql`
|
||||
UPDATE events
|
||||
SET replaced = 1
|
||||
|
@ -259,9 +254,9 @@ function addEventToDb(
|
|||
}
|
||||
}
|
||||
}
|
||||
db.run("COMMIT TRANSACTION");
|
||||
db.run('COMMIT TRANSACTION');
|
||||
} catch (e) {
|
||||
db.run("ROLLBACK TRANSACTION");
|
||||
db.run('ROLLBACK TRANSACTION');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +276,8 @@ async function setupAndSubscribeToExternalEvents() {
|
|||
|
||||
if (!isInitialized) runMigrations(db, -1);
|
||||
|
||||
const latestVersion = sql`
|
||||
const latestVersion =
|
||||
sql`
|
||||
SELECT migration_version FROM migration_history WHERE status = 'success' ORDER BY migration_version DESC LIMIT 1
|
||||
`(db)[0]?.migration_version ?? -1;
|
||||
|
||||
|
@ -291,7 +287,7 @@ async function setupAndSubscribeToExternalEvents() {
|
|||
relays,
|
||||
[
|
||||
{
|
||||
"#p": [ccnPubkey],
|
||||
'#p': [ccnPubkey],
|
||||
kinds: [1059],
|
||||
},
|
||||
],
|
||||
|
@ -303,7 +299,7 @@ async function setupAndSubscribeToExternalEvents() {
|
|||
}
|
||||
if (knownOriginalEvents.indexOf(event.id) >= 0) return;
|
||||
if (!nostrTools.verifyEvent(event)) {
|
||||
log.warn("Invalid event received");
|
||||
log.warn('Invalid event received');
|
||||
return;
|
||||
}
|
||||
if (encryptedEventIsInDb(event)) return;
|
||||
|
@ -328,20 +324,19 @@ async function setupAndSubscribeToExternalEvents() {
|
|||
const ccnCreationEventTemplate = {
|
||||
kind: 0,
|
||||
content: JSON.stringify({
|
||||
display_name: "New CCN",
|
||||
name: "New CCN",
|
||||
display_name: 'New CCN',
|
||||
name: 'New CCN',
|
||||
bot: true,
|
||||
}),
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [["p", ccnPubkey]],
|
||||
tags: [['p', ccnPubkey]],
|
||||
};
|
||||
const ccnCreationEvent = nostrTools.finalizeEvent(
|
||||
ccnCreationEventTemplate,
|
||||
await getCCNPrivateKey(),
|
||||
);
|
||||
const encryptedCCNCreationEvent = await createEncryptedEvent(
|
||||
ccnCreationEvent,
|
||||
);
|
||||
const encryptedCCNCreationEvent =
|
||||
await createEncryptedEvent(ccnCreationEvent);
|
||||
if (timerCleaned) return; // in case we get an event before the timer is cleaned
|
||||
await Promise.any(pool.publish(relays, encryptedCCNCreationEvent));
|
||||
}, 10000);
|
||||
|
@ -375,20 +370,20 @@ function filtersMatchingEvent(
|
|||
if (!filters) continue;
|
||||
const isMatching = filters.every((filter) =>
|
||||
Object.entries(filter).every(([type, value]) => {
|
||||
if (type === "ids") return value.includes(event.id);
|
||||
if (type === "kinds") return value.includes(event.kind);
|
||||
if (type === "authors") return value.includes(event.pubkey);
|
||||
if (type === "since") return event.created_at >= value;
|
||||
if (type === "until") return event.created_at <= value;
|
||||
if (type === "limit") return event.created_at <= value;
|
||||
if (type.startsWith("#")) {
|
||||
if (type === 'ids') return value.includes(event.id);
|
||||
if (type === 'kinds') return value.includes(event.kind);
|
||||
if (type === 'authors') return value.includes(event.pubkey);
|
||||
if (type === 'since') return event.created_at >= value;
|
||||
if (type === 'until') return event.created_at <= value;
|
||||
if (type === 'limit') return event.created_at <= value;
|
||||
if (type.startsWith('#')) {
|
||||
const tagName = type.slice(1);
|
||||
return event.tags.some(
|
||||
(tag: string[]) => tag[0] === tagName && value.includes(tag[1]),
|
||||
);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}),
|
||||
);
|
||||
if (isMatching) matching.push(subscription);
|
||||
}
|
||||
|
@ -398,15 +393,13 @@ function filtersMatchingEvent(
|
|||
function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
||||
const [, subscriptionId, ...filters] = request;
|
||||
if (connection.subscriptions.has(subscriptionId)) {
|
||||
return log.warn("Duplicate subscription ID");
|
||||
return log.warn('Duplicate subscription ID');
|
||||
}
|
||||
|
||||
log.info(
|
||||
`New subscription: ${subscriptionId} with filters: ${
|
||||
JSON.stringify(
|
||||
filters,
|
||||
)
|
||||
}`,
|
||||
`New subscription: ${subscriptionId} with filters: ${JSON.stringify(
|
||||
filters,
|
||||
)}`,
|
||||
);
|
||||
|
||||
let query = sqlPartial`SELECT * FROM events WHERE replaced = 0`;
|
||||
|
@ -425,19 +418,19 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
query = mixQuery(query, sqlPartial`(`);
|
||||
|
||||
const filter = Object.entries(filters[i]).filter(([type, value]) => {
|
||||
if (type === "ids") return value.length > 0;
|
||||
if (type === "authors") return value.length > 0;
|
||||
if (type === "kinds") return value.length > 0;
|
||||
if (type.startsWith("#")) return value.length > 0;
|
||||
if (type === "since") return value > 0;
|
||||
if (type === "until") return value > 0;
|
||||
if (type === 'ids') return value.length > 0;
|
||||
if (type === 'authors') return value.length > 0;
|
||||
if (type === 'kinds') return value.length > 0;
|
||||
if (type.startsWith('#')) return value.length > 0;
|
||||
if (type === 'since') return value > 0;
|
||||
if (type === 'until') return value > 0;
|
||||
return false;
|
||||
});
|
||||
|
||||
for (let j = 0; j < filter.length; j++) {
|
||||
const [type, value] = filter[j];
|
||||
|
||||
if (type === "ids") {
|
||||
if (type === 'ids') {
|
||||
const uniqueIds = [...new Set(value)];
|
||||
query = mixQuery(query, sqlPartial`id IN (`);
|
||||
for (let k = 0; k < uniqueIds.length; k++) {
|
||||
|
@ -452,7 +445,7 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
query = mixQuery(query, sqlPartial`)`);
|
||||
}
|
||||
|
||||
if (type === "authors") {
|
||||
if (type === 'authors') {
|
||||
const uniqueAuthors = [...new Set(value)];
|
||||
query = mixQuery(query, sqlPartial`pubkey IN (`);
|
||||
for (let k = 0; k < uniqueAuthors.length; k++) {
|
||||
|
@ -467,7 +460,7 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
query = mixQuery(query, sqlPartial`)`);
|
||||
}
|
||||
|
||||
if (type === "kinds") {
|
||||
if (type === 'kinds') {
|
||||
const uniqueKinds = [...new Set(value)];
|
||||
query = mixQuery(query, sqlPartial`kind IN (`);
|
||||
for (let k = 0; k < uniqueKinds.length; k++) {
|
||||
|
@ -482,16 +475,16 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
query = mixQuery(query, sqlPartial`)`);
|
||||
}
|
||||
|
||||
if (type.startsWith("#")) {
|
||||
if (type.startsWith('#')) {
|
||||
const tag = type.slice(1);
|
||||
const uniqueValues = [...new Set(value)];
|
||||
query = mixQuery(query, sqlPartial`(`);
|
||||
for (let k = 0; k < uniqueValues.length; k++) {
|
||||
const tagValue = uniqueValues[k] as string;
|
||||
if (tag === "a") {
|
||||
if (tag === 'a') {
|
||||
const aTagInfo = parseATagQuery(tagValue);
|
||||
|
||||
if (aTagInfo.dTag && aTagInfo.dTag !== "") {
|
||||
if (aTagInfo.dTag && aTagInfo.dTag !== '') {
|
||||
if (isCCNReplaceableEvent(aTagInfo.kind)) {
|
||||
// CCN replaceable event reference
|
||||
query = mixQuery(
|
||||
|
@ -561,11 +554,11 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
query = mixQuery(query, sqlPartial`)`);
|
||||
}
|
||||
|
||||
if (type === "since") {
|
||||
if (type === 'since') {
|
||||
query = mixQuery(query, sqlPartial`created_at >= ${value}`);
|
||||
}
|
||||
|
||||
if (type === "until") {
|
||||
if (type === 'until') {
|
||||
query = mixQuery(query, sqlPartial`created_at <= ${value}`);
|
||||
}
|
||||
|
||||
|
@ -588,10 +581,13 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
const rawTags = sql`SELECT * FROM event_tags_view WHERE event_id = ${
|
||||
events[i].id
|
||||
}`(connection.db);
|
||||
const tagsByIndex = new Map<number, {
|
||||
name: string;
|
||||
values: Map<number, string>;
|
||||
}>();
|
||||
const tagsByIndex = new Map<
|
||||
number,
|
||||
{
|
||||
name: string;
|
||||
values: Map<number, string>;
|
||||
}
|
||||
>();
|
||||
|
||||
for (const tag of rawTags) {
|
||||
let tagData = tagsByIndex.get(tag.tag_index);
|
||||
|
@ -629,9 +625,9 @@ function handleRequest(connection: UserConnection, request: NostrClientREQ) {
|
|||
sig: events[i].sig,
|
||||
};
|
||||
|
||||
connection.socket.send(JSON.stringify(["EVENT", subscriptionId, event]));
|
||||
connection.socket.send(JSON.stringify(['EVENT', subscriptionId, event]));
|
||||
}
|
||||
connection.socket.send(JSON.stringify(["EOSE", subscriptionId]));
|
||||
connection.socket.send(JSON.stringify(['EOSE', subscriptionId]));
|
||||
|
||||
connection.subscriptions.set(subscriptionId, filters);
|
||||
}
|
||||
|
@ -642,8 +638,8 @@ async function handleEvent(
|
|||
) {
|
||||
const valid = nostrTools.verifyEvent(event);
|
||||
if (!valid) {
|
||||
connection.socket.send(JSON.stringify(["NOTICE", "Invalid event"]));
|
||||
return log.warn("Invalid event");
|
||||
connection.socket.send(JSON.stringify(['NOTICE', 'Invalid event']));
|
||||
return log.warn('Invalid event');
|
||||
}
|
||||
|
||||
const encryptedEvent = await createEncryptedEvent(event);
|
||||
|
@ -651,19 +647,19 @@ async function handleEvent(
|
|||
addEventToDb(event, encryptedEvent);
|
||||
} catch (e) {
|
||||
if (e instanceof EventAlreadyExistsException) {
|
||||
log.warn("Event already exists");
|
||||
log.warn('Event already exists');
|
||||
return;
|
||||
}
|
||||
}
|
||||
await Promise.any(pool.publish(relays, encryptedEvent));
|
||||
|
||||
connection.socket.send(JSON.stringify(["OK", event.id, true, "Event added"]));
|
||||
connection.socket.send(JSON.stringify(['OK', event.id, true, 'Event added']));
|
||||
|
||||
const filtersThatMatchEvent = filtersMatchingEvent(event, connection);
|
||||
|
||||
for (let i = 0; i < filtersThatMatchEvent.length; i++) {
|
||||
const filter = filtersThatMatchEvent[i];
|
||||
connection.socket.send(JSON.stringify(["EVENT", filter, event]));
|
||||
connection.socket.send(JSON.stringify(['EVENT', filter, event]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -680,10 +676,10 @@ function handleClose(connection: UserConnection, subscriptionId: string) {
|
|||
Deno.serve({
|
||||
port: 6942,
|
||||
handler: (request) => {
|
||||
if (request.headers.get("upgrade") === "websocket") {
|
||||
if (request.headers.get('upgrade') === 'websocket') {
|
||||
if (!isLocalhost(request)) {
|
||||
return new Response(
|
||||
"Forbidden. Please read the Arx-CCN documentation for more information on how to interact with the relay.",
|
||||
'Forbidden. Please read the Arx-CCN documentation for more information on how to interact with the relay.',
|
||||
{ status: 403 },
|
||||
);
|
||||
}
|
||||
|
@ -692,31 +688,31 @@ Deno.serve({
|
|||
|
||||
const connection = new UserConnection(socket, new Map(), db);
|
||||
|
||||
socket.onopen = () => log.info("User connected");
|
||||
socket.onopen = () => log.info('User connected');
|
||||
socket.onmessage = (event) => {
|
||||
log.debug(`Received: ${event.data}`);
|
||||
if (typeof event.data !== "string" || !isValidJSON(event.data)) {
|
||||
return log.warn("Invalid request");
|
||||
if (typeof event.data !== 'string' || !isValidJSON(event.data)) {
|
||||
return log.warn('Invalid request');
|
||||
}
|
||||
const data = JSON.parse(event.data);
|
||||
if (!isArray(data)) return log.warn("Invalid request");
|
||||
if (!isArray(data)) return log.warn('Invalid request');
|
||||
|
||||
const msg = n.clientMsg().parse(data);
|
||||
switch (msg[0]) {
|
||||
case "REQ":
|
||||
case 'REQ':
|
||||
return handleRequest(connection, n.clientREQ().parse(data));
|
||||
case "EVENT":
|
||||
case 'EVENT':
|
||||
return handleEvent(connection, n.clientEVENT().parse(data)[1]);
|
||||
case "CLOSE":
|
||||
case 'CLOSE':
|
||||
return handleClose(connection, n.clientCLOSE().parse(data)[1]);
|
||||
default:
|
||||
return log.warn("Invalid request");
|
||||
return log.warn('Invalid request');
|
||||
}
|
||||
};
|
||||
socket.onclose = () => log.info("User disconnected");
|
||||
socket.onclose = () => log.info('User disconnected');
|
||||
|
||||
return response;
|
||||
}
|
||||
return new Response("Eve Relay");
|
||||
return new Response('Eve Relay');
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue