Relay Message

The backbone of the Nostr network is built on relays rather than application specific centralized databases. 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 5 main types of messages which relays construct as JSON arrays. This section is concerned with the construction of these message objects using the Relay Message Module.

JSON de/serialization

Rust
use nostr_sdk::prelude::*;

pub fn relay_message() -> Result<()> {
    // Deserialize from json
    let json = r#"["EVENT", "random_string", {"id":"70b10f70c1318967eddf12527799411b1a9780ad9c43858f5e5fcd45486a13a5","pubkey":"379e863e8357163b5bce5d2688dc4f1dcc2d505222fb8d74db600f30535dfdfe","created_at":1612809991,"kind":1,"tags":[],"content":"test","sig":"273a9cd5d11455590f4359500bccb7a89428262b96b3ea87a756b770964472f8c3e87f5d5e64d8d2e859a71462a3f477b554565c4f2f326cb01dd7620db71502"}]"#;
    let msg = RelayMessage::from_json(json)?;

    // Serialize as json
    let json = msg.as_json();
    println!("{json}");

    Ok(())
}
Python

The RelayMessage class easily handles the construction of the 5 main message types EVENT, OK, EOSE (end of stored events), CLOSED and NOTICE. In the examples below we can utilize the relevant class methods event(), ok(), eose(), closed() and notice(), respectively, to create the relay message objects.

Once we have the RelayMessage 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 RelayMessageEnum class. These allow for logical tests to be performed to establish the type of message object being assessed (for example, is_ok() will return a bool result assessing if the object represents an OK message type).

# Create Event relay message
print("  Event Relay Message:")
message = RelayMessage.event("subscription_ID_abc123", event)
print(f"     - Event Message: {message.as_enum().is_event_msg()}")
print(f"     - JSON: {message.as_json()}")
# Create event acceptance relay message
print("  Event Acceptance Relay Message:")
message = RelayMessage.ok(event.id(), False, "You have no power here, Gandalf The Grey")
print(f"     - Event Acceptance Message: {message.as_enum().is_ok()}")
print(f"     - JSON: {message.as_json()}")
# Create End of Stored Events relay message
print("  End of Stored Events Relay Message:")
message = RelayMessage.eose("subscription_ID_abc123")
print(f"     - End of Stored Events Message: {message.as_enum().is_end_of_stored_events()}")
print(f"     - JSON: {message.as_json()}")
# Create Closed relay message
print("  Closed Relay Message:")
message = RelayMessage.closed("subscription_ID_abc123", "So long and thanks for all the fish")
print(f"     - Closed Message: {message.as_enum().is_closed()}")
print(f"     - JSON: {message.as_json()}")
# Create Notice relay message
print("  Notice Relay Message:")
message = RelayMessage.notice("You have been served")
print(f"     - Notice Message: {message.as_enum().is_notice()}")
print(f"     - JSON: {message.as_json()}")

When presented with a relay message object as either a JSON or an instance of the RelayMessageEnum class we can parse these data using the from_json() or from_enum() methods, respectively.

# Parse Messages from JSON and/or Enum
print("  Parse Relay Messages:")
message = RelayMessage.from_json('["NOTICE","You have been served"]')
print(f"     - ENUM: {message.as_enum()}")
message = RelayMessage.from_enum(cast(RelayMessageEnum, RelayMessageEnum.NOTICE("You have been served")))
print(f"     - JSON: {message.as_json()}")
JavaScript

The RelayMessage class easily handles the construction of the 5 main message types EVENT, OK, EOSE (end of stored events), CLOSED and NOTICE. In the examples below we can utilize the relevant class methods event(), ok(), eose(), closed() and notice(), respectively, to create the relay message objects.

Once we have the RelayMessage objects we can use the asJson() method to present their content.

console.log("  Event Relay Message:");
let relayMessage = RelayMessage.event("subscription_ID_abc123", event);
console.log(`     - JSON: ${relayMessage.asJson()}`);
console.log("  Event Acceptance Relay Message:");
relayMessage = RelayMessage.ok(event.id, false, "You have no power here, Gandalf The Grey");
console.log(`     - JSON: ${relayMessage.asJson()}`);
console.log("  End of Stored Events Relay Message:");
relayMessage = RelayMessage.eose("subscription_ID_abc123");
console.log(`     - JSON: ${relayMessage.asJson()}`);
console.log("  Closed Relay Message:");
relayMessage = RelayMessage.closed("subscription_ID_abc123", "So long and thanks for all the fish");
console.log(`     - JSON: ${relayMessage.asJson()}`);
console.log("  Notice Relay Message:");
relayMessage = RelayMessage.notice("You have been served");
console.log(`     - JSON: ${relayMessage.asJson()}`);

When presented with a relay message object as either a JSON we can parse these data using the fromJson() method.

console.log("  Parse Relay Message:");
relayMessage = RelayMessage.fromJson('["NOTICE","You have been served"]');
console.log(`     - JSON: ${relayMessage.asJson()}`);
Kotlin

TODO

Swift

TODO

Flutter

TODO

Authorization and Count Messages

Rust

TODO

Python

As an extension of the relay 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 relays to provide simple counts of events to clients (upon request). These are constructed in much the same way as the earlier message examples, by using the RelayMessage 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.

# Create Authorization relay message (NIP42)
print("  Auth Relay Message:")
message = RelayMessage.auth("I Challenge You To A Duel! (or some other challenge string)")
print(f"     - Auth Message: {message.as_enum().is_auth()}")
print(f"     - JSON: {message.as_json()}")
# Create Count relay message (NIP45)
print("  Count Relay Message:")
message = RelayMessage.count("subscription_ID_abc123", 42)
print(f"     - Count Message: {message.as_enum().is_count()}")
print(f"     - JSON: {message.as_json()}")
JavaScript

As an extension of the relay 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 relays to provide simple counts of events to clients (upon request). These are constructed in much the same way as the earlier message examples, by using the RelayMessage class in conjunction with the relevant methods auth() and count().

console.log("  Auth Relay Message:");
relayMessage = RelayMessage.auth("I Challenge You To A Duel! (or some other challenge string)");
console.log(`     - JSON: ${relayMessage.asJson()}`);
console.log("  Count Relay Message:");
relayMessage = RelayMessage.count("subscription_ID_abc123", 42);
console.log(`     - JSON: ${relayMessage.asJson()}`);
Kotlin

TODO

Swift

TODO

Flutter

TODO

Error Messages

Rust

TODO

Python

Finally, the RelayMessageEnum class also opens up two additional message types NEG_ERR() and NEG_CODE(). These do not form part of the standard protocol specification but do have specific uses when it comes to providing methods by which error messaging (or error codes) can be handled by relays. To construct these we need to first create them as instance of the RelayMessageEnum class and then pass these into a RelayMessage object using the from_enum() method.

# Negative Error Code
print("  Negative Relay Message (code):")
relay_message_neg = RelayMessageEnum.NEG_ERR("subscription_ID_abc123", "404")
message = RelayMessage.from_enum(cast(RelayMessageEnum, relay_message_neg))
print(f"     - Negative Error Code: {message.as_enum().is_neg_err()}")
print(f"     - JSON: {message.as_json()}")
# Negative Error Message
print("  Negative Relay Message (message):")
relay_message_neg = RelayMessageEnum.NEG_MSG("subscription_ID_abc123", "This is not the message you are looking for")
message = RelayMessage.from_enum(cast(RelayMessageEnum, relay_message_neg))
print(f"     - Negative Error Message: {message.as_enum().is_neg_msg()}")
print(f"     - JSON: {message.as_json()}")
JavaScript

Not available currently with JavaScript bindings.

Kotlin

TODO

Swift

TODO

Flutter

TODO