@@ -27,6 +27,8 @@
|
|||||||
4CE6DF0427F7A08200C66700 /* damusUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */; };
|
4CE6DF0427F7A08200C66700 /* damusUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */; };
|
||||||
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 4CE6DF1127F7A2B300C66700 /* Starscream */; };
|
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 4CE6DF1127F7A2B300C66700 /* Starscream */; };
|
||||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; };
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; };
|
||||||
|
4CEE2AEB2805AEA300AB5EEF /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = 4CEE2AEA2805AEA300AB5EEF /* secp256k1 */; };
|
||||||
|
4CEE2AED2805B22500AB5EEF /* NostrRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -69,6 +71,8 @@
|
|||||||
4CE6DF0127F7A08200C66700 /* damusUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITests.swift; sourceTree = "<group>"; };
|
4CE6DF0127F7A08200C66700 /* damusUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITests.swift; sourceTree = "<group>"; };
|
||||||
4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
4CE6DF0327F7A08200C66700 /* damusUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = damusUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||||
4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConnection.swift; sourceTree = "<group>"; };
|
4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConnection.swift; sourceTree = "<group>"; };
|
||||||
|
4CEE2AE72804F57C00AB5EEF /* libsecp256k1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsecp256k1.a; sourceTree = "<group>"; };
|
||||||
|
4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrRequest.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -76,6 +80,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
4CEE2AEB2805AEA300AB5EEF /* secp256k1 in Frameworks */,
|
||||||
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */,
|
4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */,
|
||||||
4C75EFAA28049C9F0006080F /* CachedAsyncImage in Frameworks */,
|
4C75EFAA28049C9F0006080F /* CachedAsyncImage in Frameworks */,
|
||||||
);
|
);
|
||||||
@@ -119,6 +124,7 @@
|
|||||||
4C75EFB428049D790006080F /* Relay.swift */,
|
4C75EFB428049D790006080F /* Relay.swift */,
|
||||||
4C75EFB628049D990006080F /* RelayPool.swift */,
|
4C75EFB628049D990006080F /* RelayPool.swift */,
|
||||||
4C75EFBA2804A34C0006080F /* ProofOfWork.swift */,
|
4C75EFBA2804A34C0006080F /* ProofOfWork.swift */,
|
||||||
|
4CEE2AEC2805B22500AB5EEF /* NostrRequest.swift */,
|
||||||
);
|
);
|
||||||
path = Nostr;
|
path = Nostr;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -130,6 +136,7 @@
|
|||||||
4CE6DEF627F7A08200C66700 /* damusTests */,
|
4CE6DEF627F7A08200C66700 /* damusTests */,
|
||||||
4CE6DF0027F7A08200C66700 /* damusUITests */,
|
4CE6DF0027F7A08200C66700 /* damusUITests */,
|
||||||
4CE6DEE427F7A08100C66700 /* Products */,
|
4CE6DEE427F7A08100C66700 /* Products */,
|
||||||
|
4CEE2AE62804F57B00AB5EEF /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -182,6 +189,14 @@
|
|||||||
path = damusUITests;
|
path = damusUITests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4CEE2AE62804F57B00AB5EEF /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4CEE2AE72804F57C00AB5EEF /* libsecp256k1.a */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@@ -201,6 +216,7 @@
|
|||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
4CE6DF1127F7A2B300C66700 /* Starscream */,
|
4CE6DF1127F7A2B300C66700 /* Starscream */,
|
||||||
4C75EFA928049C9F0006080F /* CachedAsyncImage */,
|
4C75EFA928049C9F0006080F /* CachedAsyncImage */,
|
||||||
|
4CEE2AEA2805AEA300AB5EEF /* secp256k1 */,
|
||||||
);
|
);
|
||||||
productName = damus;
|
productName = damus;
|
||||||
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
productReference = 4CE6DEE327F7A08100C66700 /* damus.app */;
|
||||||
@@ -277,6 +293,7 @@
|
|||||||
packageReferences = (
|
packageReferences = (
|
||||||
4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */,
|
4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */,
|
||||||
4C75EFA828049C9F0006080F /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */,
|
4C75EFA828049C9F0006080F /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */,
|
||||||
|
4CEE2AE92805AEA300AB5EEF /* XCRemoteSwiftPackageReference "secp256k1" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@@ -330,6 +347,7 @@
|
|||||||
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */,
|
||||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
|
||||||
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */,
|
4CE6DEE727F7A08100C66700 /* damusApp.swift in Sources */,
|
||||||
|
4CEE2AED2805B22500AB5EEF /* NostrRequest.swift in Sources */,
|
||||||
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
|
||||||
4C75EFB528049D790006080F /* Relay.swift in Sources */,
|
4C75EFB528049D790006080F /* Relay.swift in Sources */,
|
||||||
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
|
4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */,
|
||||||
@@ -506,6 +524,10 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)",
|
||||||
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus;
|
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -536,6 +558,10 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(PROJECT_DIR)",
|
||||||
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus;
|
PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -679,6 +705,14 @@
|
|||||||
minimumVersion = 4.0.0;
|
minimumVersion = 4.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
4CEE2AE92805AEA300AB5EEF /* XCRemoteSwiftPackageReference "secp256k1" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/GigaBitcoin/secp256k1.swift";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 0.5.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
@@ -692,6 +726,11 @@
|
|||||||
package = 4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */;
|
package = 4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */;
|
||||||
productName = Starscream;
|
productName = Starscream;
|
||||||
};
|
};
|
||||||
|
4CEE2AEA2805AEA300AB5EEF /* secp256k1 */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 4CEE2AE92805AEA300AB5EEF /* XCRemoteSwiftPackageReference "secp256k1" */;
|
||||||
|
productName = secp256k1;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 4CE6DEDB27F7A08100C66700 /* Project object */;
|
rootObject = 4CE6DEDB27F7A08100C66700 /* Project object */;
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
{
|
{
|
||||||
"pins" : [
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "secp256k1.swift",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/GigaBitcoin/secp256k1.swift",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "abe7c8232970c1fd57f4c77590bce2c868df7137",
|
||||||
|
"version" : "0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "starscream",
|
"identity" : "starscream",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ struct ContentView: View {
|
|||||||
.onReceive(NotificationCenter.default.publisher(for: .post)) { obj in
|
.onReceive(NotificationCenter.default.publisher(for: .post)) { obj in
|
||||||
let post = obj.object as! NostrPost
|
let post = obj.object as! NostrPost
|
||||||
print("post \(post.content)")
|
print("post \(post.content)")
|
||||||
|
let pubkey = ""
|
||||||
|
let privkey = ""
|
||||||
|
let new_ev = NostrEvent(content: post.content, pubkey: pubkey)
|
||||||
|
new_ev.sign(privkey: privkey)
|
||||||
|
self.pool?.send(.event(new_ev))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +134,7 @@ struct ContentView: View {
|
|||||||
self.sub_id = sub_id
|
self.sub_id = sub_id
|
||||||
}
|
}
|
||||||
print("subscribing to \(sub_id)")
|
print("subscribing to \(sub_id)")
|
||||||
self.pool?.send(filters: filters, sub_id: sub_id)
|
self.pool?.send(.subscribe(.init(filters: filters, sub_id: sub_id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle_event(relay_id: String, conn_event: NostrConnectionEvent) {
|
func handle_event(relay_id: String, conn_event: NostrConnectionEvent) {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CommonCrypto
|
||||||
|
import secp256k1
|
||||||
|
|
||||||
struct OtherEvent {
|
struct OtherEvent {
|
||||||
let event_id: String
|
let event_id: String
|
||||||
@@ -17,15 +19,84 @@ struct KeyEvent {
|
|||||||
let relay_url: String
|
let relay_url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NostrEvent: Decodable, Identifiable {
|
class NostrEvent: Codable, Identifiable {
|
||||||
let id: String
|
var id: String
|
||||||
|
var sig: String
|
||||||
|
var tags: [[String]]
|
||||||
|
|
||||||
|
// cached field for pow calc
|
||||||
|
var pow: Int?
|
||||||
|
|
||||||
let pubkey: String
|
let pubkey: String
|
||||||
let created_at: Int64
|
let created_at: Int64
|
||||||
let kind: Int
|
let kind: Int
|
||||||
let tags: [[String]]
|
|
||||||
let content: String
|
let content: String
|
||||||
let sig: String
|
|
||||||
var pow: Int?
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case id, sig, tags, pubkey, created_at, kind, content
|
||||||
|
}
|
||||||
|
|
||||||
|
init(content: String, pubkey: String, kind: Int = 1, tags: [[String]] = []) {
|
||||||
|
self.id = ""
|
||||||
|
self.sig = ""
|
||||||
|
|
||||||
|
self.content = content
|
||||||
|
self.pubkey = pubkey
|
||||||
|
self.kind = kind
|
||||||
|
self.tags = tags
|
||||||
|
self.created_at = Int64(Date().timeIntervalSince1970)
|
||||||
|
|
||||||
|
self.calculate_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculate_id() {
|
||||||
|
self.id = calculate_event_id(ev: self)
|
||||||
|
self.pow = count_hash_leading_zero_bits(self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: timeout
|
||||||
|
/*
|
||||||
|
func mine_id(pow: Int, done: @escaping (String) -> ()) {
|
||||||
|
let nonce_ind = self.ensure_nonce_tag()
|
||||||
|
let nonce: Int64 = 0
|
||||||
|
|
||||||
|
DispatchQueue.global(qos: .background).async {
|
||||||
|
while
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private func ensure_nonce_tag() -> Int {
|
||||||
|
for (i, tags) in self.tags.enumerated() {
|
||||||
|
for tag in tags {
|
||||||
|
if tags.count == 2 && tag == "nonce" {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tags.append(["nonce", "0"])
|
||||||
|
return self.tags.count - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func sign(privkey: String) {
|
||||||
|
self.sig = sign_event(privkey: privkey, ev: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sign_event(privkey: String, ev: NostrEvent) -> String {
|
||||||
|
let priv_key_bytes = try! privkey.byteArray()
|
||||||
|
let key = try! secp256k1.Signing.PrivateKey(rawRepresentation: priv_key_bytes)
|
||||||
|
|
||||||
|
// Extra params for custom signing
|
||||||
|
|
||||||
|
var aux_rand = random_bytes(count: 64)
|
||||||
|
var digest = try! ev.id.byteArray()
|
||||||
|
|
||||||
|
// API allows for signing variable length messages
|
||||||
|
let signature = try! key.schnorr.signature(message: &digest, auxiliaryRand: &aux_rand)
|
||||||
|
|
||||||
|
return hex_encode(signature.rawRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode_nostr_event(txt: String) -> NostrResponse? {
|
func decode_nostr_event(txt: String) -> NostrResponse? {
|
||||||
@@ -42,3 +113,62 @@ func decode_data<T: Decodable>(_ data: Data) -> T? {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func event_commitment(ev: NostrEvent, tags: String) -> String {
|
||||||
|
return "[0,\"\(ev.pubkey)\",\(ev.created_at),\(ev.kind),\(tags),\"\(ev.content)\"]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculate_event_id(ev: NostrEvent) -> String {
|
||||||
|
let tags_encoder = JSONEncoder()
|
||||||
|
let tags_data = try! tags_encoder.encode(ev.tags)
|
||||||
|
let tags = String(decoding: tags_data, as: UTF8.self)
|
||||||
|
|
||||||
|
let target = event_commitment(ev: ev, tags: tags)
|
||||||
|
let target_data = target.data(using: .utf8)!
|
||||||
|
let hash = sha256(target_data)
|
||||||
|
|
||||||
|
return hex_encode(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func sha256(_ data: Data) -> Data {
|
||||||
|
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||||
|
data.withUnsafeBytes {
|
||||||
|
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
|
||||||
|
}
|
||||||
|
return Data(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexchar(_ val: UInt8) -> UInt8 {
|
||||||
|
if val < 10 {
|
||||||
|
return 48 + val;
|
||||||
|
}
|
||||||
|
if val < 16 {
|
||||||
|
return 97 + val - 10;
|
||||||
|
}
|
||||||
|
assertionFailure("impossiburu")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func hex_encode(_ data: Data) -> String {
|
||||||
|
var str = ""
|
||||||
|
for c in data {
|
||||||
|
let c1 = hexchar(c >> 4)
|
||||||
|
let c2 = hexchar(c & 0xF)
|
||||||
|
|
||||||
|
str.append(Character(Unicode.Scalar(c1)))
|
||||||
|
str.append(Character(Unicode.Scalar(c2)))
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func random_bytes(count: Int) -> Data {
|
||||||
|
var data = Data(count: count)
|
||||||
|
_ = data.withUnsafeMutableBytes { mutableBytes in
|
||||||
|
SecRandomCopyBytes(kSecRandomDefault, count, mutableBytes)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|||||||
18
damus/Nostr/NostrRequest.swift
Normal file
18
damus/Nostr/NostrRequest.swift
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// NostrRequest.swift
|
||||||
|
// damus
|
||||||
|
//
|
||||||
|
// Created by William Casarin on 2022-04-12.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct NostrSubscribe {
|
||||||
|
let filters: [NostrFilter]
|
||||||
|
let sub_id: String
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NostrRequest {
|
||||||
|
case subscribe(NostrSubscribe)
|
||||||
|
case event(NostrEvent)
|
||||||
|
}
|
||||||
@@ -35,9 +35,9 @@ class RelayConnection: WebSocketDelegate {
|
|||||||
socket.disconnect()
|
socket.disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(_ filters: [NostrFilter], sub_id: String) {
|
func send(_ req: NostrRequest) {
|
||||||
guard let req = make_nostr_req(filters, sub_id: sub_id) else {
|
guard let req = make_nostr_req(req) else {
|
||||||
print("failed to encode nostr req: \(filters)")
|
print("failed to encode nostr req: \(req)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
socket.write(string: req)
|
socket.write(string: req)
|
||||||
@@ -71,7 +71,23 @@ class RelayConnection: WebSocketDelegate {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func make_nostr_req(_ filters: [NostrFilter], sub_id: String) -> String? {
|
func make_nostr_req(_ req: NostrRequest) -> String? {
|
||||||
|
switch req {
|
||||||
|
case .subscribe(let sub):
|
||||||
|
return make_nostr_subscription_req(sub.filters, sub_id: sub.sub_id)
|
||||||
|
case .event(let ev):
|
||||||
|
return make_nostr_push_event(ev: ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func make_nostr_push_event(ev: NostrEvent) -> String? {
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
let event_data = try! encoder.encode(ev)
|
||||||
|
let event = String(decoding: event_data, as: UTF8.self)
|
||||||
|
return "[\"EVENT\",\(event)]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func make_nostr_subscription_req(_ filters: [NostrFilter], sub_id: String) -> String? {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
var req = "[\"REQ\",\"\(sub_id)\""
|
var req = "[\"REQ\",\"\(sub_id)\""
|
||||||
for filter in filters {
|
for filter in filters {
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ class RelayPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(filters: [NostrFilter], sub_id: String, to: [String]? = nil) {
|
func send(_ req: NostrRequest, to: [String]? = nil) {
|
||||||
let relays = to.map{ get_relays($0) } ?? self.relays
|
let relays = to.map{ get_relays($0) } ?? self.relays
|
||||||
|
|
||||||
for relay in relays {
|
for relay in relays {
|
||||||
if relay.connection.isConnected {
|
if relay.connection.isConnected {
|
||||||
relay.connection.send(filters, sub_id: sub_id)
|
relay.connection.send(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,5 +63,5 @@ struct EventView: View {
|
|||||||
func calculate_pow_color(_ pow: Int) -> Color
|
func calculate_pow_color(_ pow: Int) -> Color
|
||||||
{
|
{
|
||||||
let x = Double(pow) / 30.0;
|
let x = Double(pow) / 30.0;
|
||||||
return Color(.sRGB, red: 2.0 * (1.0 - x), green: 2.0 * x, blue: 0, opacity: 1.0)
|
return Color(.sRGB, red: 2.0 * (1.0 - x), green: 2.0 * x, blue: 0, opacity: 0.5)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user