Skip to content

Commit

Permalink
add monitor announce
Browse files Browse the repository at this point in the history
  • Loading branch information
dskvr committed Mar 9, 2024
1 parent 2dbe04b commit b91ad30
Show file tree
Hide file tree
Showing 20 changed files with 497 additions and 90 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
include:
- package: 'announce'
nodeVersion: '20'
typescript: 'true'
- package: 'logger'
nodeVersion: '20'
- package: 'seed'
Expand Down Expand Up @@ -65,6 +66,12 @@ jobs:
cd "${{ steps.find_package.outputs.the_path }}"
yarn install
- name: Pre-Publist
if: matrix.typescript == 'true'
run: |
cd "${{ steps.find_package.outputs.the_path }}"
yarn prepublish
- name: Publish Package
id: publish
uses: JS-DevTools/npm-publish@v3
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ ours.sh
packages/synx
packages/kinds
.npmrc
.ansible
.ansible
.envs
.configs
.docker
1 change: 1 addition & 0 deletions apps/nocapd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"license": "MIT",
"dependencies": {
"@nostr-fetch/adapter-nostr-tools": "0.14.1",
"@nostrwatch/announce": "^0.0.2",
"@nostrwatch/controlflow": "^0.0.2",
"@nostrwatch/logger": "^0.0.3",
"@nostrwatch/nocap": "^0.1.11",
Expand Down
14 changes: 12 additions & 2 deletions apps/nocapd/src/daemon.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import schedule from 'node-schedule'
import timestring from 'timestring'
import chalk from 'chalk'
import mapper from 'object-mapper'

import relaycache from '@nostrwatch/nwcache'
import { AnnounceMonitor } from '@nostrwatch/announce'
Expand Down Expand Up @@ -28,9 +29,18 @@ const maybeAnnounce = () => {
"nocapd.checks.options.timeout": "timeouts",
"nocapd.checks.options.expires": "interval",
"monitor.geo": "geo",
"monitor.owner": "owner"
"monitor.owner": "owner",
"publisher.to_relays": "relays",
"monitor.info": "profile"
}
const announce = AnnounceMonitor(mapper(config, map))
const conf = mapper(config, map)
const announce = new AnnounceMonitor(conf)
announce.generate()
announce.sign( process.env.DAEMON_PRIVKEY )
console.dir(conf)
console.dir(announce.events)
announce.publish( conf.relays )

}

const schedulePopulator = ($check) =>{
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
"private": true,
"version": "0.0.1",
"scripts": {
"deploy:nocapd@all": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/amsterdam -i .ansible/inventories/johannesburg -i .ansible/inventories/mumbai -i .ansible/inventories/newyork -i .ansible/inventories/saopaulo -i .ansible/inventories/seoul -i .ansible/inventories/siliconvalley -i .ansible/inventories/sydney",
"deploy:nocapd@theship": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/theship --ask-become-pass",
"deploy:nocapd@frankfurt": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/frankfurt --ask-become-pass"
"deploy:nocapd@frankfurt": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/frankfurt --ask-become-pass",
"deploy:nocapd@amsterdam": "ansible-playbook .ansible/nocapd/deploy.yaml -i .ansible/inventories/amsterdam"

},
"packageManager": "[email protected]^",
"devDependencies": {},
Expand Down
29 changes: 29 additions & 0 deletions packages/announce/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@nostrwatch/announce",
"version": "0.0.2",
"description": "Generates a NIP-66 10166 event, NIP-65 10002 event and NIP-01 0 events for monitors on *every* boot.",
"main": "dist/index.js",
"type": "module",
"scripts": {
"build": "tsc",
"test": "vitest",
"test-ui": "vitest --ui",
"prepublish": "yarn build"
},
"author": "",
"license": "ISC",
"dependencies": {
"nostr-geotags": "^0.5.0",
"nostr-tools": "^2.3.1"
},
"devDependencies": {
"@nostrwatch/publisher": "^0.2.0",
"@types/node": "^20.11.24",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"eslint": "^8.57.0",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"vitest": "^1.3.1"
}
}
67 changes: 67 additions & 0 deletions packages/announce/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { describe, it, expect } from 'vitest';
import { AnnounceMonitor } from './index'; // Adjust the import path based on your project structure

describe('AnnounceMonitor', () => {
it('should throw an error if options are not correctly provided', () => {
const options = {
geo: null, // Invalid type for testing purposes
};
expect(() => new AnnounceMonitor(options as any)).toThrow("geo must be object");
});

it('should correctly set up instance properties from options', () => {
const options = {
geo: {},
kinds: [1, 2],
timeouts: [1000, 2000],
counts: [10, 20],
owner: 'testOwner',
frequency: 'testFrequency',
};
const monitor = new AnnounceMonitor(options);
expect(monitor).toHaveProperty('geo', options.geo);
expect(monitor).toHaveProperty('kinds', options.kinds);
expect(monitor).toHaveProperty('timeouts', options.timeouts);
expect(monitor).toHaveProperty('counts', options.counts);
expect(monitor).toHaveProperty('owner', options.owner);
expect(monitor).toHaveProperty('frequency', options.frequency);
});

it('generate should return a valid event object', () => {
const options = {
geo: { lat: 10, lon: 20 },
kinds: [1],
timeouts: [1000],
counts: [10],
owner: 'testOwner',
frequency: 'testFrequency',
};
const monitor = new AnnounceMonitor(options);
const events = monitor.generate();
expect(events).toHaveProperty('kind');
expect(events["10166"].tags).toContainEqual(['frequency', 'testFrequency']);
expect(events["10166"].tags).toContainEqual(['owner', 'testOwner']);
expect(events["10166"].tags).toContainEqual(['k', '1']);
expect(events["10166"].tags).toContainEqual(['c', '10']);
expect(events["10166"].tags).toContainEqual(['timeout', '1000']);
// Assuming ngeotags function returns an array of geotags based on the provided geo object
});

it('verify should return a boolean', () => {
const options = {
geo: {},
kinds: [],
timeouts: [],
counts: [],
owner: 'testOwner',
frequency: 'testFrequency',
};
const monitor = new AnnounceMonitor(options);
const event = {
// Mock event structure that would be considered valid by verifyEvent
};
// Assuming verifyEvent function checks the validity of the event
// You would mock this function to return true or false based on the test case
expect(monitor.verify(event)).toBe(true);
});
});
129 changes: 129 additions & 0 deletions packages/announce/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { verifyEvent, finalizeEvent, SimplePool, Event } from "nostr-tools";
import ngeotags from "nostr-geotags";
import { Kind10166, Kind0, Kind10002 } from "@nostrwatch/publisher";

const NIP66_MONITOR_REGISTER = 10166;

interface GeoTagOption {
// Define properties of GeoTagOption if needed
}

// interface AnnounceMonitorOptions {
// geo?: object;
// kinds?: number[];
// timeouts?: number[];
// counts?: number[];
// owner?: string;
// frequency?: string;
// }


interface AnnounceMonitorOptions {
geo?: object;
kinds?: number[];
timeouts?: object;
counts?: number[];
owner?: string;
frequency?: string;
relays?: string[];
profile?: object;
}

export class AnnounceMonitor {
public events?: any = {};
public monReg?: any;
public monRelays: string[] = [];
public monProfile: any;
// private geo?: object;
// private kinds: number[];
// private timeouts: object;
// private counts: number[];
// private owner: string;
// private frequency: string;

constructor(options: AnnounceMonitorOptions) {
this.setup(options);
}

setup(options: AnnounceMonitorOptions): void {
// Destructuring options with default values
const {
geo = {},
kinds = [],
timeouts = {},
counts = [],
owner = '',
frequency = '',
profile = {},
relays = [],
} = options;

this.monReg = {}

if (!(geo instanceof Object)) throw new Error("geo must be object");
if (!(timeouts instanceof Object)) throw new Error("timeouts must be object");
if (!(kinds instanceof Array)) throw new Error("kinds must be array");
if (!(counts instanceof Array)) throw new Error("counts must be array");
if (typeof owner !== "string") throw new Error("owner must be string");
if (typeof frequency !== "string") throw new Error("frequency must be string");

if( !(relays instanceof Array) ) throw new Error("relays must be an array");
if( !(profile instanceof Object) ) throw new Error("profile must be an object");

// Assigning the validated options to class properties
this.monReg.geo = geo;
this.monReg.kinds = kinds;
this.monReg.timeouts = timeouts;
this.monReg.counts = counts;
this.monReg.owner = owner;
this.monReg.frequency = frequency;

this.monRelays = relays;
this.monProfile = profile;
}

generate(): any {
const $monReg = new Kind10166()
this.events["10166"] = $monReg.generateEvent({...this.monReg})

const $monRelays = new Kind10002()
if(this.monRelays.length)
this.events["10002"] = $monRelays.generateEvent([...this.monRelays])

const $monProfile = new Kind0()
if(Object.keys(this.monProfile).length)
this.events["0"] = $monProfile.generateEvent({...this.monProfile})
return this.events
}

sign(sk: Uint8Array): any {
if(!this.events) throw new Error("Event has not yet been generated (run generate() first)")
const signed: Event[] = []
Object.keys(this.events).forEach( kind => {
// console.log(`event kind: ${kind}`, this.events[kind])
this.events[kind] = finalizeEvent(this.events[kind], sk)
})
return signed
}

async publish( relays: string[] ): string[] {
if(!this.events) throw new Error("Event has not yet been generated")
const pubbedIds: string[] = []
const $pool = new SimplePool()
const kinds = Object.keys(this.events)
for(let i = 0; i < kinds.length; i++) {
const kind = kinds[i]
const promises = $pool.publish(relays, this.events[kind]).catch(console.error)
await Promise.all(promises)
console.log(this.events[kind].id, 'published to', relays.join(', '))
pubbedIds.push(this.events[kind].id)
}
return pubbedIds
}

static verify(ev: any): boolean {
return verifyEvent(ev);
}


}
11 changes: 11 additions & 0 deletions packages/announce/src/nostrwatch-publisher.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare module '@nostrwatch/publisher' {
export class Kind10166 {
generateEvent(args: any): any;
}
export class Kind0 {
generateEvent(args: any): any;
}
export class Kind10002 {
generateEvent(args: any): any;
}
}
15 changes: 15 additions & 0 deletions packages/announce/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "esnext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}
5 changes: 5 additions & 0 deletions packages/announce/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'vitest/config';

export default defineConfig({
// Configure your Vitest options here
});
9 changes: 7 additions & 2 deletions packages/publisher/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
export { Publisher } from './src/Publisher.js'

//named exports
export { Kind0 } from './src/kinds/Kind0.js'
export { Kind10002 } from './src/kinds/Kind10002.js'
export { Kind10166 } from './src/kinds/Kind10166.js'
export { Kind30066 } from './src/kinds/Kind30066.js'
export { Kind30166 } from './src/kinds/Kind30166.js'

//import for default export
import { Kind0 } from './src/kinds/Kind0.js'
import { Kind10002 } from './src/kinds/Kind10002.js'
import { Kind10166 } from './src/kinds/Kind10166.js'
import { Kind30066 } from './src/kinds/Kind30066.js'
import { Kind30166 } from './src/kinds/Kind30166.js'

export default {
Kind0,
Kind10002,
Kind10166,
Kind30066,
Kind30166,

Kind30166
}
2 changes: 1 addition & 1 deletion packages/publisher/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nostrwatch/publisher",
"version": "0.1.5",
"version": "0.2.0",
"type": "module",
"description": "Library for publishing nostr.watch relay status and publisher registration events",
"main": "index.js",
Expand Down
Loading

0 comments on commit b91ad30

Please sign in to comment.