Skip to content

Commit

Permalink
update data and response structure
Browse files Browse the repository at this point in the history
  • Loading branch information
dskvr committed Nov 28, 2023
1 parent ae049c8 commit 889eed5
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 97 deletions.
13 changes: 8 additions & 5 deletions packages/controlflow/queues.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import dotenv from 'dotenv'
import { Queue } from 'bullmq';
import { Queue, QueueEvents, Worker } from 'bullmq';
import { RedisConnectionDetails } from '@nostrwatch/utils'

dotenv.config()

const Trawler = (qopts) => {
const Trawler = (qopts={}) => {
qopts = { connection: RedisConnectionDetails(), ...qopts }
return new Queue('Trawler', qopts)
}

const Nocapd = (qopts) => {
const Nocapd = (qopts={}) => {
qopts = { connection: RedisConnectionDetails(), ...qopts }
return new Queue('Nocapd', qopts)
}

const RestApi = (qopts) => {
const RestApi = (qopts={}) => {
qopts = { connection: RedisConnectionDetails(), ...qopts }
return new Queue('Nocapd', qopts)
}

export {
Trawler,
Nocapd,
RestApi
RestApi,
Queue as BullQueue,
QueueEvents as BullQueueEvents,
Worker as BullWorker,
}
12 changes: 5 additions & 7 deletions packages/nocap/adapters/default/DnsAdapterDefault/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ class DnsAdapterDefault {
this.$ = parent
}
async check_dns(){
let result, data = {}
if(this.$.results.get('network') !== 'clearnet')
return this.$.logger.warn('DNS check skipped for url not accessible over clearnet')
let err = false
let url = this.$.url.replace('wss://', '').replace('ws://', '')
const query = `https://1.1.1.1/dns-query?name=${url}`
const headers = { accept: 'application/dns-json' }
const response = await fetch( query, { headers } ).catch((e) => { err = e })
if(err) return this.$.throw(err)
const dns = await response.json().catch((e) => { err = e })
if(err) return this.$.throw(err)
const ipv4 = dns?.Answer?.length ? this.filterIPv4FromDoh(dns) : []
const ipv6 = dns?.Answer?.length ? this.filterIPv6FromDoh(dns) : []
const result = { dns, ipv4, ipv6 }
const response = await fetch( query, { headers } ).catch((e) => { result = { status: "error", message: e.message, data } })
data = await response.json()
if(!result)
result = { status: "success", data }
this.$.finish('dns', result)
}

Expand Down
8 changes: 4 additions & 4 deletions packages/nocap/adapters/default/EveryAdapterDefault/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import DnsAdapterDefault from '@nostrwatch/nocap-dns-adapter-default'
import GeoAdapterDefault from '@nostrwatch/nocap-geo-adapter-default'
import WebsocketAdapterDefault from '@nostrwatch/nocap-relay-adapter-default'
import InfoAdapterDefault from '@nostrwatch/nocap-info-adapter-default'
import RelayAdapterDefault from '@nostrwatch/nocap-relay-adapter-default'
import SslAdapterDefault from '@nostrwatch/nocap-ssl-adapter-default'
import DnsAdapterDefault from '@nostrwatch/nocap-dns-adapter-default'
import GeoAdapterDefault from '@nostrwatch/nocap-geo-adapter-default'

export default {
WebsocketAdapterDefault,
DnsAdapterDefault,
GeoAdapterDefault,
InfoAdapterDefault,
RelayAdapterDefault,
SslAdapterDefault
}
15 changes: 7 additions & 8 deletions packages/nocap/adapters/default/GeoAdapterDefault/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@ import { fetch } from 'cross-fetch'
}

async check_geo(){
let err
let endpoint
const ipArr = this.$.results.get('ipv4')
const ip = ipArr[ipArr?.length-1]
if(!ip)
this.$.finish('geo', { geo: { error: 'No IP address. Run dns check first.' }})
const ips = this.$.results.getIps('ipv4')
const ip = ips[ips?.length-1]
if(typeof ip !== 'string')
return this.$.finish('geo', { status: "error", message: 'No IP address. Run `dns` check first.', data: {} })
if(this.config?.auth?.ip_api_key)
endpoint = `https://pro.ip-api.com/json/${ip}?key=${this.config.auth.ip_api_key}`
else
endpoint = `http://ip-api.com/json/${ip}`
const headers = { 'accept': 'application/json' }
const response = await fetch(endpoint, { headers }).catch(e => err=e)
if(err) return this.throw(err)
const json = await response.json()
const result = { geo: json }
delete response.query
delete response.status
const result = { status: "success", data: await response.json() }
this.$.finish('geo', result)
}
}
Expand Down
13 changes: 8 additions & 5 deletions packages/nocap/adapters/default/InfoAdapterDefault/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class InfoAdapterDefault {
}

async check_info(){
let result, data = {}
const controller = new AbortController();
const { signal } = controller;
const url = new URL(this.$.url),
Expand All @@ -15,14 +16,16 @@ class InfoAdapterDefault {
url.protocol = 'https:'

this.$.timeouts.create('info', this.$.config.info_timeout, () => controller.abort())

try {
const response = await fetch(url.toString(), { method, headers, signal })
const json = await response.json()
const result = { info: json }
this.$.finish('info', result)
data = await response.json()
}
catch(e) {
result = { status: "error", message: e.message, data }
}
catch(e) { return this.$.throw(e) }
if(!result)
result = { status: "success", data }
this.$.finish('info', result)
}
}

Expand Down
19 changes: 8 additions & 11 deletions packages/nocap/adapters/default/SslAdapterDefault/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,22 @@ class SslAdapterDefault {
}

async check_ssl(){
let result, data = {}
const url = new URL(this.$.url)
const hostname = url.hostname
const timeout = this.$.config?.ssl_timeout? this.$.config.ssl_timeout: 1000
console.log(this.sslCheckerOptions(hostname, url.port))
const response = await sslChecker(hostname, this.sslCheckerOptions(url.port))
response.adapter = 'DefaultSslAdapter'
response.checked_at = new Date()
response.cert = await sslCertificate.get(hostname, timeout)
response.cert.issuer = response?.cert?.issuer || {}
response.validFor.push(await sslValidator.validateSSL(response.cert.pemEncoded, { domain: url.hostname }))
response.validFor = [...new Set(response.validFor)].filter( domain => domain instanceof String && domain !== "" )
const result = { ssl: response }
const sslCheckerResponse = await sslChecker(hostname, this.sslCheckerOptions(url.port)).catch( (e) => { result = { status: "error", status: "error", message: e.message, data } } )
const sslCertificateResponse = await sslCertificate.get(hostname, timeout).catch( (e) => { result = { status: "error", message: e.message, data } } )
data.days_remaining = sslCheckerResponse.daysRemaining
data.valid = sslCheckerResponse.valid
data = {...data, ...sslCertificateResponse }
if(!result)
result = { status: "success", data }
this.$.finish('ssl', result)
}

sslCheckerOptions(port){
return { method: "GET", port: port || 443 }
}

}

export default SslAdapterDefault
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import WebSocket from 'ws';

class RelayAdapterDefault {
class WebsocketAdapterDefault {

constructor(parent){
this.$ = parent
Expand Down Expand Up @@ -80,4 +80,4 @@ class RelayAdapterDefault {
}
}

export default RelayAdapterDefault
export default WebsocketAdapterDefault
67 changes: 40 additions & 27 deletions packages/nocap/src/classes/Base.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export default class {
//
this.adaptersInitialized = false
this.adapters = {}
this.adaptersValid = ['relay', 'info', 'geo', 'dns','ssl']
this.adaptersValid = ['websocket', 'info', 'geo', 'dns','ssl']
//
this.checks = ['connect', 'read', 'write', 'info', 'geo', 'dns', 'ssl']
this.checks = ['connect', 'read', 'write', 'info', 'dns', 'geo', 'ssl']
//
this.config = new ConfigInterface(config)
this.results = new ResultInterface()
Expand Down Expand Up @@ -75,7 +75,7 @@ export default class {
async check(keys){
if(keys === "all") {
await this.check(this.checks)
return this.results.dump()
return this.results.raw()
}

if(typeof keys === 'string')
Expand All @@ -96,8 +96,8 @@ export default class {
this.defaultAdapters()
await this.start(key)
const result = await this.promises.get(key).promise
if(result?.error) {
this.on_check_error( key, result )
if(result.status === "error") {
this.on_check_error( key, { status: "error", message: result.message } )
}
return result
}
Expand Down Expand Up @@ -139,15 +139,19 @@ export default class {
return deferred.promise
}

async finish(key, result={}){
async finish(key, data={}){
this.logger.debug(`${key}: finish()`)
this.current = null
this.latency.finish(key)
result[`${key}Latency`] = this.latency.duration(key)
this.results.set('url', this.url)
this.results.set(`${key}Latency`, result[`${key}Latency`])
this.results.setMany(result)
this.promises.get(key).resolve(result)
const url = this.results.get('url')
const network = this.results.get('network')
const adapter_key = this.routeAdapter(key)
const adapter_name = this.adapters[adapter_key].constructor.name
const adapters = [ ...new Set( this.results.get('adapters').concat([adapter_name]) ) ]
const checked_at = Date.now()
data.duration = this.latency.duration(key)
this.results.setMany({ checked_at, adapters, [key]: {...data} })
this.promises.get(key).resolve({ url, network, checked_at, adapters, ...data })
this.on_change()
}

Expand All @@ -166,7 +170,7 @@ export default class {
if(this.isConnecting())
setTimeout(waitForConnection, 100)
if(this.isClosed())
return rejectPrecheck({ error: true, reason: new Error(`Cannot check ${key}, websocket connection to relay is closed`) })
return rejectPrecheck({ status: "error", message: new Error(`Cannot check ${key}, websocket connection to relay is closed`) })
}

const prechecker = async () => {
Expand Down Expand Up @@ -197,23 +201,23 @@ export default class {
if( this.isConnected() )
return resolvePrecheck()
else
return rejectPrecheck({ error: true, reason: new Error(`Cannot check ${key}, websocket connection could not be established`) })
return rejectPrecheck({ status: "error", message: `Cannot check ${key}, websocket connection could not be established` })
}

//Websocket is open, key is connect, reject precheck and directly resolve check deferred promise with cached result to bypass starting the connect check.
if(keyIsConnect && this.isConnected()) {
this.logger.debug(`${key}: prechecker(): websocket is open, key is connect`)
// this.logger.debug(`precheck(${key}):prechecker():websocket is open, key is connect`)
rejectPrecheck({ error: false, reason: 'Cannot check connect because websocket is already connected, returning cached result'})
rejectPrecheck({ status: "error", message: 'Cannot check connect because websocket is already connected, returning cached result'})
}

//Websocket is not connecting, key is not connect
if( !keyIsConnect && !this.isConnected()) {
this.logger.debug(`${key}: prechecker(): websocket is not connecting, key is not connect`)
const error = { error: true, reason: new Error(`Cannot check ${key}, no active websocket connection to relay`) }
const error = { status: "error", message: `Cannot check ${key}, no active websocket connection to relay` }
if(connectAttempted){
this.logger.debug(`${key}: prechecker(): websocket is not connecting, key is not connect, connectAttempted is true`)
this.logger.warn(`Error in ${key} precheck: ${error.reason}`)
this.logger.warn(`Error in ${key} precheck: ${error.message}`)
return rejectPrecheck(error)
}
const result = await this.check('connect')
Expand Down Expand Up @@ -347,7 +351,7 @@ export default class {
* @returns null
*/
on_notice(notice){
console.log(notice)
this.logger.info(notice)
this.track('relay', 'notice', notice)
this.cbcall('notice')
if(this?.adapters?.relay?.handle_notice)
Expand Down Expand Up @@ -397,6 +401,18 @@ export default class {
this?.handle_auth(challenge)
}

/**
* on_check_error
* Implementation specific Event triggered by Check.finish
*
* @private
* @returns null
*/
on_check_error(key, err){
this.cbcall('error', key, err)
this.track(key, 'error', err)
}

/**
* on_change
* Implementation specific Event triggered by Check.finish
Expand All @@ -414,9 +430,8 @@ export default class {
* @private
* @returns null
*/
handle_connect_check(success){
const result = { connect: success }
this.finish('connect', result, this.promises.get('connect').resolve)
handle_connect_check(data){
this.finish('connect', { data }, this.promises.get('connect').resolve)
}

/**
Expand All @@ -425,9 +440,8 @@ export default class {
* @private
* @returns null
*/
handle_read_check(success){
const result = { read: success }
this.finish('read', result, this.promises.get('read').resolve)
handle_read_check(data){
this.finish('read', { data }, this.promises.get('read').resolve)
}

/**
Expand All @@ -436,9 +450,8 @@ export default class {
* @private
* @returns null
*/
handle_write_check(success){
const result = { write: success }
this.finish('write', result, this.promises.get('write').resolve)
handle_write_check(data){
this.finish('write', { data }, this.promises.get('write').resolve)
}

/**
Expand Down Expand Up @@ -526,7 +539,7 @@ export default class {
case 'connect':
case 'read':
case 'write':
return 'relay'
return 'websocket'
case 'info':
case 'geo':
case 'dns':
Expand Down
7 changes: 4 additions & 3 deletions packages/nocap/src/classes/Validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class Validator {
throw new Error(`${this.constructor.name} property ${key} is not of type ${typeof value}`)
}

set(key, value) {
_set(key, value) {
this.validate(key, value)
this[key] = value
}
Expand All @@ -18,7 +18,7 @@ export class Validator {
})
}

get(key) {
_get(key) {
this.validate(key)
return this[key]
}
Expand All @@ -30,10 +30,11 @@ export class Validator {
}, {})
}

dump(){
raw(){
return { ...Object.keys(this.defaults).reduce((acc, key) => {
acc[key] = this[key]
return acc
}, {}) }
}

}
2 changes: 1 addition & 1 deletion packages/nocap/src/classes/Validator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Validator', () => {
it('should dump all properties except defaults', () => {
validator.name = 'Bob';
validator.age = 40;
const dumped = validator.dump();
const dumped = validator.raw();

expect(dumped).toEqual({ name: 'Bob', age: 40 });
expect(dumped.defaults).toBeUndefined();
Expand Down
Loading

0 comments on commit 889eed5

Please sign in to comment.