Skip to content

Commit

Permalink
relay members event
Browse files Browse the repository at this point in the history
  • Loading branch information
BlowaterNostr committed May 12, 2024
1 parent 7fd7017 commit 3017bd2
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 14 deletions.
7 changes: 7 additions & 0 deletions events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type Event_Base = {
export enum Kind_V2 {
ChannelCreation = "ChannelCreation",
ChannelEdition = "ChannelEdition",
RelayMember = "RelayMember",
}

export type ChannelCreation = Event_Base & {
Expand All @@ -23,4 +24,10 @@ export type ChannelEdition = Event_Base & {
name: string;
};

export type EventRelayMembers = Event_Base & {
kind: Kind_V2.RelayMember;
created_at: number;
members: string[]; // the pubkey of members
};

export type Event_V2 = ChannelCreation | ChannelEdition;
1 change: 1 addition & 0 deletions graphql-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const typeDefs = gql`
relayInformation: RelayInformation
channel(name: String!): Channel
deleted_events: [String!]!
members: [String!]!
}
type Mutation {
Expand Down
45 changes: 40 additions & 5 deletions main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ import { SubscriptionMap, ws_handler } from "./ws.ts";
import { render } from "https://esm.sh/[email protected]";
import { RootResolver } from "./resolvers/root.ts";
import * as gql from "https://esm.sh/[email protected]";
import { Policy } from "./resolvers/policy.ts";
import { func_GetRelayMembers, Policy } from "./resolvers/policy.ts";
import { func_ResolvePolicyByKind } from "./resolvers/policy.ts";
import { NostrEvent, NostrKind, parseJSON, PublicKey, verify_event_v2, verifyEvent } from "./_libs.ts";
import {
NostrEvent,
NostrKind,
parseJSON,
PrivateKey,
PublicKey,
verify_event_v2,
verifyEvent,
} from "./_libs.ts";
import { PolicyStore } from "./resolvers/policy.ts";
import { Policies } from "./resolvers/policy.ts";
import {
event_v1_schema_sqlite,
event_schema_sqlite,
func_DeleteEventsFromPubkey,
func_GetDeletedEventIDs,
func_GetEventCount,
Expand Down Expand Up @@ -44,6 +52,7 @@ import {
} from "./channel.ts";
import { func_GetChannelByID } from "./channel.ts";
import { DB } from "https://deno.land/x/[email protected]/mod.ts";
import { get_relay_members } from "./resolvers/policy.ts";

const schema = gql.buildSchema(gql.print(typeDefs));

Expand Down Expand Up @@ -86,24 +95,30 @@ export async function run(args: {
admin?: PublicKey;
default_policy: DefaultPolicy;
default_information?: RelayInformationStringify;
system_key: string | PrivateKey;
kv?: Deno.Kv;
_debug?: boolean;
}): Promise<Error | Relay> {
const isDenoDeploy = Deno.env.get("DENO_DEPLOYMENT_ID") !== undefined;

//------------------
// argument checking
// Deno KV
let kv = args.kv;
if (kv == undefined) {
kv = await Deno.openKv();
}

// SQLite Database
let db: DB | undefined;
let get_channel_by_id: func_GetChannelByID;
if (!isDenoDeploy) {
db = new DB("relayed.db");
db.execute(`${sqlite_schema}${event_v1_schema_sqlite}`);
db.execute(`${sqlite_schema}${event_schema_sqlite}`);
get_channel_by_id = get_channel_by_id_sqlite(db);
}

// Administrator Keys
let admin_pubkey: string | undefined | PublicKey | Error = args.default_information?.pubkey;
if (admin_pubkey == undefined) {
const env_pubkey = Deno.env.get(ENV_relayed_pubkey);
Expand All @@ -120,6 +135,17 @@ export async function run(args: {
return admin_pubkey;
}

// Relay Key
let system_key: string | PrivateKey | Error = args.system_key;
if (typeof system_key == "string") {
system_key = PrivateKey.FromString(system_key);
if (system_key instanceof Error) {
return system_key;
}
}
// argument checking done
//-----------------------

const { default_policy } = args;
///////////////
const connections = new Map<WebSocket, SubscriptionMap>();
Expand All @@ -129,7 +155,13 @@ export async function run(args: {
});

const get_all_policies = Policies(kv);
const policyStore = new PolicyStore(default_policy, kv, await get_all_policies());
const policyStore = new PolicyStore({
default_policy,
kv,
system_account: system_key,
initial_policies: await get_all_policies(),
db,
});
const relayInformationStore = new RelayInformationStore(
kv,
{
Expand Down Expand Up @@ -168,6 +200,7 @@ export async function run(args: {
write_replaceable_event: eventStore.write_replaceable_event,
policyStore,
relayInformationStore,
get_relay_members: get_relay_members(db),
kv,
db: db,
// get_channel_by_name: get_channel_by_name(db)
Expand Down Expand Up @@ -224,6 +257,7 @@ const root_handler = (
policyStore: PolicyStore;
relayInformationStore: RelayInformationStore;
// get_channel_by_name: func_GetChannelByName;
get_relay_members: func_GetRelayMembers;
kv: Deno.Kv;
db?: DB;
_debug: boolean;
Expand Down Expand Up @@ -323,6 +357,7 @@ const graphql_handler = (
delete_event: func_DeleteEvent;
delete_events_from_pubkey: func_DeleteEventsFromPubkey;
get_deleted_event_ids: func_GetDeletedEventIDs;
get_relay_members: func_GetRelayMembers;
},
) =>
async (req: Request) => {
Expand Down
9 changes: 8 additions & 1 deletion resolvers/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ function isMatched(event: NostrEvent, filter: NostrFilter) {
ps.length == 0 && es.length == 0);
}

export const event_v1_schema_sqlite = `
export const event_schema_sqlite = `
CREATE TABLE IF NOT exists events_v1 (
id TEXT PRIMARY KEY,
pubkey TEXT NOT NULL,
Expand All @@ -290,6 +290,13 @@ CREATE TABLE IF NOT exists events_v1 (
created_at INTEGER NOT NULL,
event JSON NOT NULL
);
CREATE TABLE IF NOT exists events_v2 (
id TEXT PRIMARY KEY,
pubkey TEXT NOT NULL,
kind TEXT NOT NULL,
event JSON NOT NULL
);
`;

// export const get_events_with_filter = (db: DB) => (filter: NostrFilter) => {
Expand Down
74 changes: 67 additions & 7 deletions resolvers/policy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { NostrKind, PublicKey } from "../_libs.ts";
import { DB } from "https://deno.land/x/[email protected]/mod.ts";
import { NostrAccountContext, NostrKind, parseJSON, PrivateKey, PublicKey, sign_event_v2 } from "../_libs.ts";
import { DefaultPolicy } from "../main.tsx";
import { Event_V2, EventRelayMembers, Kind_V2 } from "../events.ts";

export const Policies = (kv: Deno.Kv) =>
async function () {
Expand All @@ -25,19 +27,23 @@ export class PolicyStore {
policies = new Map<NostrKind, Policy>();

constructor(
private default_policy: DefaultPolicy,
private kv: Deno.Kv,
initial_policies: Policy[],
private readonly args: {
default_policy: DefaultPolicy;
kv: Deno.Kv;
system_account: PrivateKey;
initial_policies: Policy[];
db?: DB;
},
) {
for (const policy of initial_policies) {
for (const policy of args.initial_policies) {
this.policies.set(policy.kind, policy);
}
}

resolvePolicyByKind = async (kind: NostrKind): Promise<Policy> => {
const policy = this.policies.get(kind);
if (policy == undefined) {
const default_policy = this.default_policy;
const default_policy = this.args.default_policy;
let allow_this_kind: boolean;
if (default_policy.allowed_kinds == "all") {
allow_this_kind = true;
Expand Down Expand Up @@ -90,7 +96,61 @@ export class PolicyStore {
policy.block = blocks;
}
this.policies.set(args.kind, policy);
await this.kv.set(["policy", args.kind], policy);
await this.args.kv.set(["policy", args.kind], policy);

{
// WIP
// generate new relay member list
if (this.args.db) {
if (args.kind == NostrKind.TEXT_NOTE) {
const event = await sign_event_v2(this.args.system_account, {
pubkey: this.args.system_account.toPublicKey().hex,
kind: Kind_V2.RelayMember,
members: Array.from(policy.allow),
created_at: Date.now(),
});
// warn: could throw
try {
this.args.db.query(
`INSERT INTO events_v2 (id, pubkey, kind, event) VALUES (?, ?, ?, ?);`,
[event.id, event.pubkey, event.kind, JSON.stringify(event)],
);
} catch (e) {
console.log(event);
console.error(e);
}
}
} else {
console.log("Feature Not Supported in this environment: Relay Members");
}
}
return policy;
};
}

export type func_GetRelayMembers = () => Promise<undefined | EventRelayMembers | Error>;
export const get_relay_members = (db?: DB): func_GetRelayMembers => async () => {
if (!db) {
return new Error("get_relay_members is not supported");
}
const rows = db.query<[string]>(
"select event from events_v2 where kind = (?)",
[Kind_V2.RelayMember],
);

const events = [] as EventRelayMembers[];
for (const row of rows) {
const relay_member_event = parseJSON<EventRelayMembers>(row[0]);
if (relay_member_event instanceof Error) {
return relay_member_event;
}
events.push(relay_member_event);
}
if (events.length == 0) {
return;
}

const event = events.sort((e1, e2) => e1.created_at - e2.created_at)[0];
console.log(event);
return event;
};
15 changes: 14 additions & 1 deletion resolvers/root.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PolicyStore } from "./policy.ts";
import { func_GetRelayMembers, PolicyStore } from "./policy.ts";
import { Policies } from "./policy.ts";
import { RelayInformationStore } from "./nip11.ts";
import {
Expand All @@ -24,6 +24,7 @@ export function RootResolver({ deps }: {
delete_event: func_DeleteEvent;
delete_events_from_pubkey: func_DeleteEventsFromPubkey;
get_deleted_event_ids: func_GetDeletedEventIDs;
get_relay_members: func_GetRelayMembers;
};
}) {
return {
Expand All @@ -41,6 +42,7 @@ function Queries(deps: {
get_events_by_kinds: func_GetEventsByKinds;
// get_channel_by_name: func_GetChannelByName;
get_deleted_event_ids: func_GetDeletedEventIDs;
get_relay_members: func_GetRelayMembers;
}) {
return {
policies: Policies(deps.kv),
Expand Down Expand Up @@ -70,6 +72,17 @@ function Queries(deps: {
deleted_events: async () => {
return deps.get_deleted_event_ids();
},
members: async () => {
const members = await deps.get_relay_members();
if (members instanceof Error) {
console.error(members);
throw members;
}
if (members == undefined) {
return [];
}
return members.members;
},
};
}

Expand Down

0 comments on commit 3017bd2

Please sign in to comment.