Client Message
One of the biggest strengths of the Nostr network is the almost limitless possibilities for interoperable user-facing applications. In protocol terminology these applications are often referred to as Clients. Where relays provide a data housing mechanism the clients get that data in front of users in myriad of wild and wonderful ways. Clients use WebSockets as a means to connect to relays and pass relevant data back and forth around the network. In accordance with the protocol base specification (NIP-01) there are 3 main types of messages which clients construct and pass to relays as JSON arrays. This section is concerned with the construction of these message objects using the Client Message Module.
JSON de/serialization
TODO
The ClientMessage
class easily handles the construction of the 3 main message types EVENT
, REQ
, and CLOSE
.
In the examples below we can utilize the relevant class methods event()
, req()
and close()
, respectively, to create the client message objects.
Once we have the ClientMessage
objects we can use the as_enum()
or as_json()
methods to present their content.
Note that when using as_enum()
we unlock some additional methods associated with the ClientMessageEnum
class.
These allow for logical tests to be performed to establish the type of message object being assessed (for example, is_req()
will return a bool result assessing if the object represents an REQ
message type).
# Event client message
print(" Event Client Message:")
message = ClientMessage.event(event)
print(f" - Event Message: {message.as_enum().is_event_msg()}")
print(f" - JSON: {message.as_json()}")
Note that when constructing a REQ
we want to pass through a Filter
object which will allow the relay to return data meeting a given set of criteria.
Please jump to the Filter section for more details on how to construct these objects.
# Request client message
print(" Request Client Message:")
f = Filter().id(event.id())
message = ClientMessage.req(subscription_id="ABC123", filters=[f])
print(f" - Request Message: {message.as_enum().is_req()}")
print(f" - JSON: {message.as_json()}")
# Close client message
print(" Close Client Message:")
message = ClientMessage.close("ABC123")
print(f" - Close Message: {message.as_enum().is_close()}")
print(f" - JSON: {message.as_json()}")
When presented with a client message object as either a JSON or an instance of the ClientMessageEnum
class we can parse these data using the from_json()
or from_enum()
methods, respectively.
# Parse Messages from JSON and/or Enum
print(" Parse Client Messages:")
message = ClientMessage.from_json('["REQ","ABC123",{"#p":["421a4dd67be773903f805bcb7975b4d3377893e0e09d7563b8972ee41031f551"]}]')
print(f" - ENUM: {message.as_enum()}")
f = Filter().pubkey(keys.public_key())
message = ClientMessage.from_enum(cast(ClientMessageEnum, ClientMessageEnum.REQ("ABC123", filters=[f])))
print(f" - JSON: {message.as_json()}")
The ClientMessage
class easily handles the construction of the 3 main message types EVENT
, REQ
, and CLOSE
.
In the examples below we can utilize the relevant class methods event()
, req()
and close()
, respectively, to create the client message objects.
Once we have the ClientMessage
objects we can use the asJson()
method to present their content.
// Create Event client message
console.log(" Event Client Message:");
let clientMessage = ClientMessage.event(event);
console.log(` - JSON: ${clientMessage.asJson()}`);
Note that when constructing a REQ
we want to pass through a Filter
object which will allow the relay to return data meeting a given set of criteria.
Please jump to the Filter section for more details on how to construct these objects.
// Create Request client message
console.log(" Request Client Message:");
let f = new Filter().id(event.id);
clientMessage = ClientMessage.req("ABC123", [f]);
console.log(` - JSON: ${clientMessage.asJson()}`);
// Create Close client message
console.log(" Close Client Message:");
clientMessage = ClientMessage.close("ABC123");
console.log(` - JSON: ${clientMessage.asJson()}`);
When presented with a client message object as either a JSON using the fromJson()
method.
// Parse Messages from JSON
console.log(" Parse Client Messages:");
clientMessage = ClientMessage.fromJson('["REQ","ABC123",{"#p":["421a4dd67be773903f805bcb7975b4d3377893e0e09d7563b8972ee41031f551"]}]');
console.log(` - JSON: ${clientMessage.asJson()}`);
TODO
TODO
TODO
Authorization and Count Messages
TODO
As an extension of the client messaging section of the protocol NIP-42 and NIP-45 introduce two new messaging types AUTH
and COUNT
.
The AUTH
type is designed to facilitate a method by which clients can authenticate with a given relay.
Whereas the COUNT
type offers a method for clients can request simple counts of events from relays.
These are constructed in much the same way as the earlier message examples, by using the ClientMessage
class in conjunction with the relevant methods auth()
and count()
.
As before the as_enum()
method can be used to unlock logical test methods (e.g., is_auth()
) associated with these message objects.
# Auth client message (NIP42)
print(" Auth Client Message:")
message = ClientMessage.auth(event)
print(f" - Auth Message: {message.as_enum().is_auth()}")
print(f" - JSON: {message.as_json()}")
Note that COUNT
is effectively a specific type of REQ
message therefore it utilizes the Filter
object in constructing the criteria which should be used by the relay to return the count value.
# Count client message (NIP45)
print(" Count Client Message:")
f = Filter().pubkey(keys.public_key())
message = ClientMessage.count(subscription_id="ABC123", filters=[f])
print(f" - Count Message: {message.as_enum().is_count()}")
print(f" - JSON: {message.as_json()}")
As an extension of the client messaging section of the protocol NIP-42 and NIP-45 introduce two new messaging types AUTH
and COUNT
.
The AUTH
type is designed to facilitate a method by which clients can authenticate with a given relay.
Whereas the COUNT
type offers a method for clients can request simple counts of events from relays.
These are constructed in much the same way as the earlier message examples, by using the ClientMessage
class in conjunction with the relevant methods auth()
and count()
.
// Create Auth client message (NIP42)
console.log(" Auth Client Message:");
clientMessage = ClientMessage.auth(event);
console.log(` - JSON: ${clientMessage.asJson()}`);
Note that COUNT
is effectively a specific type of REQ
message therefore it utilizes the Filter
object in constructing the criteria which should be used by the relay to return the count value.
// Create Count client message (NIP45)
console.log(" Count Client Message:");
f = new Filter().pubkey(keys.publicKey);
clientMessage = ClientMessage.count("ABC123", [f]);
console.log(` - JSON: ${clientMessage.asJson()}`);
TODO
TODO
TODO
Negentropy Messages
TODO
Finally, the ClientMessageEnum
class also opens up three additional message types NEG_OPEN()
, NEG_CLOSE()
and NEG_MSG()
.
These do not form part of the standard protocol specification but instead form part of an additional protocol Negentropy for handling set-reconciliation.
To construct these we need to first create them as instance of the ClientMessageEnum
class and then pass these into a ClientMessage
object using the from_enum()
method.
# Negative Open Message
print(" Negative Client Message (open):")
message = ClientMessage.from_enum(cast(ClientMessageEnum, ClientMessageEnum.NEG_OPEN("ABC123", filter=f, id_size=32, initial_message="<hex-msg>")))
print(f" - Negative Error Open: {message.as_enum().is_neg_open()}")
print(f" - JSON: {message.as_json()}")
# Negative Close Message
print(" Negative Client Message (close):")
message = ClientMessage.from_enum(cast(ClientMessageEnum, ClientMessageEnum.NEG_CLOSE("ABC123")))
print(f" - Negative Error Close: {message.as_enum().is_neg_close()}")
print(f" - JSON: {message.as_json()}")
# Negative Error Message
print(" Negative Client Message (message):")
enum_msg = ClientMessageEnum.NEG_MSG("ABC123", message="This is not the message you are looking for")
message = ClientMessage.from_enum(cast(ClientMessageEnum, enum_msg))
print(f" - JSON: {message.as_json()}")
print(f" - Negative Error Message: {message.as_enum().is_neg_msg()}")
Not currently available in the Javascript Bindings.
TODO
TODO
TODO