update client

This commit is contained in:
callebtc
2023-02-08 09:55:49 +01:00
parent 123cfb56ae
commit c4fbeb83d7
3 changed files with 47 additions and 36 deletions

12
main.py
View File

@@ -7,6 +7,14 @@ import time
import datetime import datetime
def print_status(client):
print("")
for relay in client.relay_manager.relays.values():
connected_text = "🟢" if relay.connected else "🔴"
status_text = f"{connected_text} ⬆️ {relay.num_sent_events} ⬇️ {relay.num_received_events} ⚠️ {relay.error_counter} ⏱️ {relay.ping} ms - {relay.url.split('//')[1]}"
print(status_text)
async def dm(): async def dm():
print("This is an example NIP-04 DM flow") print("This is an example NIP-04 DM flow")
pk = input("Enter your privatekey to post from (enter nothing for a random one): ") pk = input("Enter your privatekey to post from (enter nothing for a random one): ")
@@ -36,6 +44,7 @@ async def dm():
) )
print(f"Subscribing to DMs to {to_pubk_hex}") print(f"Subscribing to DMs to {to_pubk_hex}")
while True: while True:
print_status(client)
msg = input("\nEnter message: ") msg = input("\nEnter message: ")
client.dm(msg, PublicKey(bytes.fromhex(to_pubk_hex))) client.dm(msg, PublicKey(bytes.fromhex(to_pubk_hex)))
@@ -84,11 +93,12 @@ async def post():
t.start() t.start()
while True: while True:
print_status(sender_client)
msg = input("\nEnter post: ") msg = input("\nEnter post: ")
sender_client.post(msg) sender_client.post(msg)
if input("Enter 1 for DM, 2 for Posts (Default: 1)") or 1 == 1: if input("Enter '1' for DM, '2' for Posts (Default: 1):") or 1 == 1:
# write a DM and receive DMs # write a DM and receive DMs
asyncio.run(dm()) asyncio.run(dm())
else: else:

View File

@@ -6,8 +6,7 @@ from typing import List
from secp256k1 import PrivateKey, PublicKey from secp256k1 import PrivateKey, PublicKey
from hashlib import sha256 from hashlib import sha256
from nostr.message_type import ClientMessageType from .message_type import ClientMessageType
class EventKind(IntEnum): class EventKind(IntEnum):
@@ -19,17 +18,17 @@ class EventKind(IntEnum):
DELETE = 5 DELETE = 5
@dataclass @dataclass
class Event: class Event:
content: str = None content: str = None
public_key: str = None public_key: str = None
created_at: int = None created_at: int = None
kind: int = EventKind.TEXT_NOTE kind: int = EventKind.TEXT_NOTE
tags: List[List[str]] = field(default_factory=list) # Dataclasses require special handling when the default value is a mutable type tags: List[List[str]] = field(
default_factory=list
) # Dataclasses require special handling when the default value is a mutable type
signature: str = None signature: str = None
def __post_init__(self): def __post_init__(self):
if self.content is not None and not isinstance(self.content, str): if self.content is not None and not isinstance(self.content, str):
# DMs initialize content to None but all other kinds should pass in a str # DMs initialize content to None but all other kinds should pass in a str
@@ -38,39 +37,44 @@ class Event:
if self.created_at is None: if self.created_at is None:
self.created_at = int(time.time()) self.created_at = int(time.time())
@staticmethod @staticmethod
def serialize(public_key: str, created_at: int, kind: int, tags: List[List[str]], content: str) -> bytes: def serialize(
public_key: str, created_at: int, kind: int, tags: List[List[str]], content: str
) -> bytes:
data = [0, public_key, created_at, kind, tags, content] data = [0, public_key, created_at, kind, tags, content]
data_str = json.dumps(data, separators=(',', ':'), ensure_ascii=False) data_str = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
return data_str.encode() return data_str.encode()
@staticmethod @staticmethod
def compute_id(public_key: str, created_at: int, kind: int, tags: List[List[str]], content: str): def compute_id(
return sha256(Event.serialize(public_key, created_at, kind, tags, content)).hexdigest() public_key: str, created_at: int, kind: int, tags: List[List[str]], content: str
):
return sha256(
Event.serialize(public_key, created_at, kind, tags, content)
).hexdigest()
@property @property
def id(self) -> str: def id(self) -> str:
# Always recompute the id to reflect the up-to-date state of the Event # Always recompute the id to reflect the up-to-date state of the Event
return Event.compute_id(self.public_key, self.created_at, self.kind, self.tags, self.content) return Event.compute_id(
self.public_key, self.created_at, self.kind, self.tags, self.content
)
def add_pubkey_ref(self, pubkey: str):
"""Adds a reference to a pubkey as a 'p' tag"""
self.tags.append(["p", pubkey])
def add_pubkey_ref(self, pubkey:str): def add_event_ref(self, event_id: str):
""" Adds a reference to a pubkey as a 'p' tag """ """Adds a reference to an event_id as an 'e' tag"""
self.tags.append(['p', pubkey]) self.tags.append(["e", event_id])
def add_event_ref(self, event_id:str):
""" Adds a reference to an event_id as an 'e' tag """
self.tags.append(['e', event_id])
def verify(self) -> bool: def verify(self) -> bool:
pub_key = PublicKey(bytes.fromhex("02" + self.public_key), True) # add 02 for schnorr (bip340) pub_key = PublicKey(
return pub_key.schnorr_verify(bytes.fromhex(self.id), bytes.fromhex(self.signature), None, raw=True) bytes.fromhex("02" + self.public_key), True
) # add 02 for schnorr (bip340)
return pub_key.schnorr_verify(
bytes.fromhex(self.id), bytes.fromhex(self.signature), None, raw=True
)
def to_message(self) -> str: def to_message(self) -> str:
return json.dumps( return json.dumps(
@@ -83,20 +87,18 @@ class Event:
"kind": self.kind, "kind": self.kind,
"tags": self.tags, "tags": self.tags,
"content": self.content, "content": self.content,
"sig": self.signature "sig": self.signature,
} },
] ]
) )
@dataclass @dataclass
class EncryptedDirectMessage(Event): class EncryptedDirectMessage(Event):
recipient_pubkey: str = None recipient_pubkey: str = None
cleartext_content: str = None cleartext_content: str = None
reference_event_id: str = None reference_event_id: str = None
def __post_init__(self): def __post_init__(self):
if self.content is not None: if self.content is not None:
self.cleartext_content = self.content self.cleartext_content = self.content
@@ -115,9 +117,10 @@ class EncryptedDirectMessage(Event):
if self.reference_event_id is not None: if self.reference_event_id is not None:
self.add_event_ref(self.reference_event_id) self.add_event_ref(self.reference_event_id)
@property @property
def id(self) -> str: def id(self) -> str:
if self.content is None: if self.content is None:
raise Exception("EncryptedDirectMessage `id` is undefined until its message is encrypted and stored in the `content` field") raise Exception(
"EncryptedDirectMessage `id` is undefined until its message is encrypted and stored in the `content` field"
)
return super().id return super().id

View File

@@ -78,10 +78,8 @@ class Relay:
@property @property
def ping(self): def ping(self):
if self.connected: ping_ms = int((self.ws.last_pong_tm - self.ws.last_ping_tm) * 1000)
return int((self.ws.last_pong_tm - self.ws.last_ping_tm) * 1000) return ping_ms if self.connected and ping_ms > 0 else 0
else:
return 0
def publish(self, message: str): def publish(self, message: str):
self.queue.put(message) self.queue.put(message)