Skip to content

Commit

Permalink
Adding Nostr adapter library
Browse files Browse the repository at this point in the history
  • Loading branch information
christroutner committed Dec 15, 2024
1 parent ef72bd9 commit 08efd21
Showing 1 changed file with 136 additions and 0 deletions.
136 changes: 136 additions & 0 deletions lib/adapters/nostr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
Adapter library for working with Nostr.
*/

// Global npm libraries
import BchNostr from 'bch-nostr'
import { RelayPool } from 'nostr'
import RetryQueue from '@chris.troutner/retry-queue'
import * as nip19 from 'nostr-tools/nip19'

class NostrAdapter {
constructor (localConfig = { nostrRelay: '', nostrTopic: '' }) {
this.relayWs = localConfig.nostrRelay //
this.topic = localConfig.nostrTopic

if (!this.relayWs) {
throw new Error(
'"nostrRelay" must be passed when instantiate NostrAdapter'
)
}

if (!this.topic) {
throw new Error(
'"nostrTopic" must be passed when instantiate NostrAdapter'
)
}

// Encapsulate dependencies
this.bchNostr = new BchNostr()
this.RelayPool = RelayPool
this.retryQueue = new RetryQueue({
concurrency: 1,
attempts: 5,
retryPeriod: 1000
})

// Bind the 'this' object
this.start = this.start.bind(this)
this.post = this.post.bind(this)
this.read = this.read.bind(this)
this.eventId2note = this.eventId2note.bind(this)
}

// Create nostr keys.
// NOTE: WIF must be provided in this function instead the constructor function
// we can provide it after app wallet creation.
async start (WIF) {
try {
if (!WIF || typeof WIF !== 'string') {
throw new Error('WIF must be a string!')
}

const { privKeyBuf, nostrPubKey } =
this.bchNostr.keys.createNostrPubKeyFromWif({ wif: WIF })

this.privKeyBuf = privKeyBuf
this.nostrPubKey = nostrPubKey

console.log(`Nostr Pub Key : ${nostrPubKey}`)

return true
} catch (error) {
console.log(`Error in nostr.js/start() ${error.message} `)
throw error
}
}

// Post a message over the instance-topic.
async post (msg = '') {
try {
if (!msg || typeof msg !== 'string') {
throw new Error('msg must be a string!')
}

const inObj = {
kind: 867,
privKeyBuf: this.privKeyBuf,
nostrPubKey: this.nostrPubKey,
relayWs: this.relayWs,
msg,
tags: [['t', this.topic]]
}
const eventId = await this.retryQueue.addToQueue(this.bchNostr.post.uploadToNostr, inObj)
return eventId
} catch (error) {
console.log(`Error in nostr.js/post() ${error.message} `)
throw error
}
}

// Read a message over the instance-topic.
async read (limit = 10) {
try {
if (typeof limit !== 'number' || limit < 1) {
throw new Error('Limit must be greater than 0')
}

const relays = [this.relayWs]
const pool = this.RelayPool(relays)

const nostrData = new Promise((resolve, reject) => {
const messages = []

pool.on('open', (relay) => {
// relay.subscribe('REQ', { ids: [eventId] })
relay.subscribe('REQ', { limit, kinds: [867], '#t': [this.topic] })
})

pool.on('eose', (relay) => {
relay.close()
resolve(messages)
})

pool.on('event', (relay, subId, ev) => {
// console.log('ev: ', ev)
messages.push({ content: ev.content, eventId: ev.id })
})
})

const messages = await nostrData

return messages
} catch (error) {
console.log(`Error in nostr.js/read() ${error.message} `)
throw error
}
}

// Convert an Event ID into a `noteabc..` syntax that Astral expects.
// This can be used to generate a link to Astral to display the post.
eventId2note(eventId) {
return nip19.noteEncode(eventId)
}
}

export default NostrAdapter

0 comments on commit 08efd21

Please sign in to comment.