NostrScript
NostrScript is a WebAssembly implementation that interacts with Damus. It enables dynamic scripting that can be used to power custom list views, enabling pluggable algorithms. The web has JavaScript, Damus has NostrScript. NostrScripts can be written in any language that compiles to WASM. This commit adds a WASM interpreter I've written as a mostly-single C file for portability and embeddability. In the future we could JIT-compile these for optimal performance if NostrScripts get large and complicated. For now an interpreter is simple enough for algorithm list view plugins. Changelog-Added: Add initial NostrScript implementation Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
@@ -12,6 +12,28 @@ struct NostrSubscribe {
|
||||
let sub_id: String
|
||||
}
|
||||
|
||||
|
||||
enum NostrRequestType {
|
||||
case typical(NostrRequest)
|
||||
case custom(String)
|
||||
|
||||
var is_write: Bool {
|
||||
guard case .typical(let req) = self else {
|
||||
return true
|
||||
}
|
||||
|
||||
return req.is_write
|
||||
}
|
||||
|
||||
var is_read: Bool {
|
||||
guard case .typical(let req) = self else {
|
||||
return true
|
||||
}
|
||||
|
||||
return req.is_read
|
||||
}
|
||||
}
|
||||
|
||||
enum NostrRequest {
|
||||
case subscribe(NostrSubscribe)
|
||||
case unsubscribe(String)
|
||||
@@ -31,4 +53,5 @@ enum NostrRequest {
|
||||
var is_read: Bool {
|
||||
return !is_write
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -99,15 +99,25 @@ final class RelayConnection: ObservableObject {
|
||||
isConnected = false
|
||||
isConnecting = false
|
||||
}
|
||||
|
||||
func send(_ req: NostrRequest) {
|
||||
guard let req = make_nostr_req(req) else {
|
||||
print("failed to encode nostr req: \(req)")
|
||||
return
|
||||
}
|
||||
|
||||
func send_raw(_ req: String) {
|
||||
socket.send(.string(req))
|
||||
}
|
||||
|
||||
func send(_ req: NostrRequestType) {
|
||||
switch req {
|
||||
case .typical(let req):
|
||||
guard let req = make_nostr_req(req) else {
|
||||
print("failed to encode nostr req: \(req)")
|
||||
return
|
||||
}
|
||||
send_raw(req)
|
||||
|
||||
case .custom(let req):
|
||||
send_raw(req)
|
||||
}
|
||||
}
|
||||
|
||||
private func receive(event: WebSocketEvent) {
|
||||
switch event {
|
||||
case .connected:
|
||||
|
||||
@@ -14,8 +14,9 @@ struct RelayHandler {
|
||||
}
|
||||
|
||||
struct QueuedRequest {
|
||||
let req: NostrRequest
|
||||
let req: NostrRequestType
|
||||
let relay: String
|
||||
let skip_ephemeral: Bool
|
||||
}
|
||||
|
||||
struct SeenEvent: Hashable {
|
||||
@@ -178,18 +179,18 @@ class RelayPool {
|
||||
return c
|
||||
}
|
||||
|
||||
func queue_req(r: NostrRequest, relay: String) {
|
||||
func queue_req(r: NostrRequestType, relay: String, skip_ephemeral: Bool) {
|
||||
let count = count_queued(relay: relay)
|
||||
guard count <= 10 else {
|
||||
print("can't queue, too many queued events for \(relay)")
|
||||
return
|
||||
}
|
||||
|
||||
print("queueing request: \(r) for \(relay)")
|
||||
request_queue.append(QueuedRequest(req: r, relay: relay))
|
||||
print("queueing request for \(relay)")
|
||||
request_queue.append(QueuedRequest(req: r, relay: relay, skip_ephemeral: skip_ephemeral))
|
||||
}
|
||||
|
||||
func send(_ req: NostrRequest, to: [String]? = nil, skip_ephemeral: Bool = true) {
|
||||
func send_raw(_ req: NostrRequestType, to: [String]? = nil, skip_ephemeral: Bool = true) {
|
||||
let relays = to.map{ get_relays($0) } ?? self.relays
|
||||
|
||||
for relay in relays {
|
||||
@@ -206,7 +207,7 @@ class RelayPool {
|
||||
}
|
||||
|
||||
guard relay.connection.isConnected else {
|
||||
queue_req(r: req, relay: relay.id)
|
||||
queue_req(r: req, relay: relay.id, skip_ephemeral: skip_ephemeral)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -214,6 +215,10 @@ class RelayPool {
|
||||
}
|
||||
}
|
||||
|
||||
func send(_ req: NostrRequest, to: [String]? = nil, skip_ephemeral: Bool = true) {
|
||||
send_raw(.typical(req), to: to, skip_ephemeral: skip_ephemeral)
|
||||
}
|
||||
|
||||
func get_relays(_ ids: [String]) -> [Relay] {
|
||||
// don't include ephemeral relays in the default list to query
|
||||
relays.filter { ids.contains($0.id) }
|
||||
@@ -231,7 +236,7 @@ class RelayPool {
|
||||
}
|
||||
|
||||
print("running queueing request: \(req.req) for \(relay_id)")
|
||||
self.send(req.req, to: [relay_id])
|
||||
self.send_raw(req.req, to: [relay_id], skip_ephemeral: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user