nostr 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +1 -1
- data/.tool-versions +1 -1
- data/CHANGELOG.md +32 -4
- data/README.md +4 -1
- data/adr/0003-logging-methods-vs-logger-class.md +122 -0
- data/adr/0004-default-logging-activation.md +66 -0
- data/adr/0005-logger-types.md +32 -0
- data/docs/.vitepress/config.mjs +1 -0
- data/docs/bun.lockb +0 -0
- data/docs/common-use-cases/logging-and-debugging.md +60 -0
- data/docs/core/client.md +1 -1
- data/docs/getting-started/overview.md +3 -0
- data/docs/package.json +3 -3
- data/lib/nostr/client/color_logger.rb +69 -0
- data/lib/nostr/client/logger.rb +85 -0
- data/lib/nostr/client/plain_logger.rb +69 -0
- data/lib/nostr/client.rb +32 -6
- data/lib/nostr/errors/invalid_signature_type_error.rb +1 -1
- data/lib/nostr/event.rb +1 -2
- data/lib/nostr/version.rb +1 -1
- data/lib/nostr.rb +2 -0
- data/nostr.gemspec +3 -3
- data/sig/nostr/client/color_logger.rbs +6 -0
- data/sig/nostr/client/logger.rbs +12 -0
- data/sig/nostr/client/plain_logger.rbs +6 -0
- data/sig/nostr/client.rbs +2 -0
- data/sig/vendor/event_emitter.rbs +8 -10
- metadata +18 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 707a302ca79f44bd669a84dc9086c5934bc6f753a78d90989f4d3619db5ed997
|
4
|
+
data.tar.gz: 81a83ff089c864ac5c77bc7d4b26a23755ff2573ee013f68137a79ed9351f140
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69bf9a378add76760a6955967787602e1bf6e913f22c1194fa9b8d3dc661270b038f26010bb8181378b7d21586b6d5195fe12754007551baa78531b3e4663e16
|
7
|
+
data.tar.gz: a49b8eb1acc9978a1f95be74783253d44807078fc97af2255239067c77125a7a31661514e7196f27d18c76d57805c293c54d5cc0c9427cd792c1f0e65349a796
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# Offense count: 2
|
10
10
|
# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods, CountRepeatedAttributes.
|
11
11
|
Metrics/AbcSize:
|
12
|
-
Max:
|
12
|
+
Max: 24
|
13
13
|
|
14
14
|
# Offense count: 2
|
15
15
|
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods.
|
data/.tool-versions
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
ruby 3.3.0
|
2
|
-
bun 1.
|
2
|
+
bun 1.1.3
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.1/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.7.0] 2024-04-13
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added the `Nostr::Client::Logger` class to log connection events, messages sent and received, errors, and connection
|
12
|
+
closures.
|
13
|
+
- Added the `Nostr::Client::ColorLogger` class to log events in color using ANSI escape codes.
|
14
|
+
- Added the `Nostr::Client::PlainLogger` class to log events without color coding.
|
15
|
+
- Added Architecture Decision Records (ADRs) to document the decision process for logging functionality.
|
16
|
+
- Added a new common use case document for logging and debugging.
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
|
20
|
+
- Updated the `Nostr::Client` class to use the `ColorLogger` by default for logging client interactions with relays.
|
21
|
+
- Updated the `Nostr::Client#connect` method to emit a `:send` event when sending a message.
|
22
|
+
- Updated the `Nostr::Client#on` method to pass the `relay` parameter to the `:connect` event handler.
|
23
|
+
- Updated bun to version `1.1.3` (was `1.0.30`).
|
24
|
+
- Updated the gem `json` to version `2.7` (was `2.6`).
|
25
|
+
- Updated the gem `mermaid` to version `10.9` (was `10.6`).
|
26
|
+
- Updated the gem `rubocop-rspec` to version `2.29` (was `2.27`).
|
27
|
+
- Updated the gem `steep` to version `1.7.dev3` (was `1.6`).
|
28
|
+
- Updated the gem `vitepress` to version `1.1` (was `1.0.0-rc.25`).
|
29
|
+
- Updated the gem `vitepress-plugin-mermaid` to version `2.0.16` (was `2.0.15`).
|
30
|
+
- Updated the error message in `Nostr::InvalidSignatureTypeError` to provide more detail.
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
|
34
|
+
Fixed a type-checking issue in `Nostr::Event#verify_signature` by removing a workaround after the steep gem author,
|
35
|
+
[@soutaro](https://github.com/soutaro) resolved [the problem I reported](https://github.com/soutaro/steep/issues/1079).
|
36
|
+
|
7
37
|
## [0.6.0] 2024-03-15
|
8
38
|
|
9
39
|
### Added
|
@@ -27,13 +57,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
27
57
|
- Updated the gem `rspec-rubocop` to version `2.27` (was `2.25`)
|
28
58
|
- Updated the gem `rubocop` to version `1.62` (was `1.57`)
|
29
59
|
|
30
|
-
|
60
|
+
### Fixed
|
31
61
|
|
32
62
|
- Fixed a typo in the README (`generate_keypair` -> `generate_key_pair`)
|
33
63
|
- Fixed a typo in the YARD documentation of `Nostr::Key#initialize` (`ValidationError` -> `KeyValidationError`)
|
34
|
-
|
35
|
-
### Fixed
|
36
|
-
|
37
64
|
- Fixed YARD example rendering issues in `InvalidKeyFormatError#initialize`, `InvalidKeyLengthError#initialize`,
|
38
65
|
`InvalidKeyTypeError#initialize`, `Event#initialize`, `EncryptedDirectMessage#initialize` and `Filter#to_h`
|
39
66
|
|
@@ -115,6 +142,7 @@ principles of immutability and was a major source of internal complexity as I ne
|
|
115
142
|
|
116
143
|
- Initial release
|
117
144
|
|
145
|
+
[0.7.0]: https://github.com/wilsonsilva/nostr/compare/v0.6.0...v0.7.0
|
118
146
|
[0.6.0]: https://github.com/wilsonsilva/nostr/compare/v0.5.0...v0.6.0
|
119
147
|
[0.5.0]: https://github.com/wilsonsilva/nostr/compare/v0.4.0...v0.5.0
|
120
148
|
[0.4.0]: https://github.com/wilsonsilva/nostr/compare/v0.3.0...v0.4.0
|
data/README.md
CHANGED
@@ -80,7 +80,7 @@ relay = Nostr::Relay.new(url: 'wss://nostr.wine', name: 'Wine')
|
|
80
80
|
client.connect(relay)
|
81
81
|
|
82
82
|
# Listen asynchronously for the connect event
|
83
|
-
client.on :connect do
|
83
|
+
client.on :connect do |relay|
|
84
84
|
# Send the event to the Relay
|
85
85
|
client.publish(text_note_event)
|
86
86
|
|
@@ -118,6 +118,9 @@ end
|
|
118
118
|
client.on :close do |code, reason|
|
119
119
|
# You may attempt to reconnect to the relay here
|
120
120
|
end
|
121
|
+
|
122
|
+
# This line keeps the background client from exiting immediately.
|
123
|
+
gets
|
121
124
|
```
|
122
125
|
|
123
126
|
## 📚 Documentation
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# 3. Logging methods vs logger class
|
2
|
+
|
3
|
+
Date: 2024-03-19
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Accepted
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
I'm deciding between integrating logging directly into the main class or creating a dedicated logger class.
|
12
|
+
|
13
|
+
### Option 1: Logging methods
|
14
|
+
|
15
|
+
The first approach weaves logging actions into the operational code, resulting in a tight coupling of functionality and
|
16
|
+
logging. Classes should be open for extension but closed for modification, and this strategy violates that principle.
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
class Client
|
20
|
+
def connect(relay)
|
21
|
+
execute_within_an_em_thread do
|
22
|
+
client = build_websocket_client(relay.url)
|
23
|
+
parent_to_child_channel.subscribe do |msg|
|
24
|
+
client.send(msg)
|
25
|
+
emit(:send, msg)
|
26
|
+
log_send(msg) # <------ new code
|
27
|
+
end
|
28
|
+
|
29
|
+
client.on :open do
|
30
|
+
child_to_parent_channel.push(type: :open, relay:)
|
31
|
+
log_connection_opened(relay) # <------ new code
|
32
|
+
end
|
33
|
+
|
34
|
+
client.on :message do |event|
|
35
|
+
child_to_parent_channel.push(type: :message, data: event.data)
|
36
|
+
log_message_received(event.data) # <------ new code
|
37
|
+
end
|
38
|
+
|
39
|
+
client.on :error do |event|
|
40
|
+
child_to_parent_channel.push(type: :error, message: event.message)
|
41
|
+
log_error(event.message) # <------ new code
|
42
|
+
end
|
43
|
+
|
44
|
+
client.on :close do |event|
|
45
|
+
child_to_parent_channel.push(type: :close, code: event.code, reason: event.reason)
|
46
|
+
log_connection_closed(event.code, event.reason) # <------ new code
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# ------ new code below ------
|
51
|
+
|
52
|
+
def log_send(msg)
|
53
|
+
logger.info("Message sent: #{msg}")
|
54
|
+
end
|
55
|
+
|
56
|
+
def log_connection_opened(relay)
|
57
|
+
logger.info("Connection opened to #{relay.url}")
|
58
|
+
end
|
59
|
+
|
60
|
+
def log_message_received(data)
|
61
|
+
logger.info("Message received: #{data}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_error(message)
|
65
|
+
logger.error("Error: #{message}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def log_connection_closed(code, reason)
|
69
|
+
logger.info("Connection closed with code: #{code}, reason: #{reason}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
### Option 2: Logger class
|
76
|
+
|
77
|
+
The second strategy separates logging into its own class, promoting cleaner code and adherence to the Single
|
78
|
+
Responsibility Principle. Client already exposes events that can be tapped into, so the logger class can listen to these
|
79
|
+
events and log accordingly.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class ClientLogger
|
83
|
+
def attach_to(client)
|
84
|
+
logger_instance = self
|
85
|
+
|
86
|
+
client.on(:connect) { |relay| logger_instance.on_connect(relay) }
|
87
|
+
client.on(:message) { |message| logger_instance.on_message(message) }
|
88
|
+
client.on(:send) { |message| logger_instance.on_send(message) }
|
89
|
+
client.on(:error) { |message| logger_instance.on_error(message) }
|
90
|
+
client.on(:close) { |code, reason| logger_instance.on_close(code, reason) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def on_connect(relay); end
|
94
|
+
def on_message(message); end
|
95
|
+
def on_send(message); end
|
96
|
+
def on_error(message); end
|
97
|
+
def on_close(code, reason); end
|
98
|
+
end
|
99
|
+
|
100
|
+
client = Nostr::Client.new
|
101
|
+
logger = Nostr::ClientLogger.new
|
102
|
+
logger.attach_to(client)
|
103
|
+
```
|
104
|
+
|
105
|
+
This approach decouples logging from the main class, making it easier to maintain and extend the logging system without
|
106
|
+
affecting the core logic.
|
107
|
+
|
108
|
+
## Decision
|
109
|
+
|
110
|
+
I've chosen the dedicated logger class route. This choice is driven by a desire for extensibility in the logging system.
|
111
|
+
With a separate logger, I can easily modify logging behavior—like changing formats, adjusting verbosity levels,
|
112
|
+
switching colors, or altering output destinations (files, networks, etc.) — without needing to rewrite any of the main
|
113
|
+
operational code.
|
114
|
+
|
115
|
+
## Consequences
|
116
|
+
|
117
|
+
Adopting a dedicated logger class offers greater flexibility and simplifies maintenance, making it straightforward to
|
118
|
+
adjust how and what I log independently of the core logic. This separation of concerns means that any future changes
|
119
|
+
to logging preferences or requirements can be implemented quickly and without risk to the main class's functionality.
|
120
|
+
However, it's important to manage the integration carefully to avoid introducing complexity, such as handling
|
121
|
+
dependencies and ensuring seamless communication between the main operations and the logging system.
|
122
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# 3. Default Logging Activation
|
2
|
+
|
3
|
+
Date: 2024-03-19
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Accepted
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
Logging provides visibility into the gem's behavior and helps to diagnose issues. The decision centered on whether
|
12
|
+
to enable logging by default or require manual activation.
|
13
|
+
|
14
|
+
### Option 1: On-demand Logging
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
client = Nostr::Client.new
|
18
|
+
logger = Nostr::ClientLogger.new
|
19
|
+
logger.attach_to(client)
|
20
|
+
```
|
21
|
+
|
22
|
+
#### Advantages:
|
23
|
+
|
24
|
+
- Offers users flexibility and control over logging.
|
25
|
+
- Conserves resources by logging only when needed.
|
26
|
+
|
27
|
+
#### Disadvantages:
|
28
|
+
|
29
|
+
- Potential to miss critical logs if not enabled.
|
30
|
+
- Requires users to read and understand documentation to enable logging.
|
31
|
+
- Requires users to manually activate and configure logging.
|
32
|
+
|
33
|
+
### Option 2: Automatic Logging
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
class Client
|
37
|
+
def initialize(logger: ClientLogger.new)
|
38
|
+
@logger = logger
|
39
|
+
logger&.attach_to(self)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
client = Nostr::Client.new
|
44
|
+
```
|
45
|
+
|
46
|
+
#### Advantages:
|
47
|
+
|
48
|
+
- Ensures comprehensive logging without user intervention.
|
49
|
+
- Simplifies debugging and monitoring.
|
50
|
+
- Balances logging detail with performance impact.
|
51
|
+
|
52
|
+
#### Disadvantages:
|
53
|
+
|
54
|
+
- Needs additional steps to disable logging.
|
55
|
+
|
56
|
+
## Decision
|
57
|
+
|
58
|
+
Logging will be enabled by default. Users can disable logging by passing a `nil` logger to the client:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
client = Nostr::Client.new(logger: nil)
|
62
|
+
```
|
63
|
+
|
64
|
+
## Consequences
|
65
|
+
|
66
|
+
Enabling logging by default favors ease of use and simplifies the developer's experience.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# 3. Logger Types
|
2
|
+
|
3
|
+
Date: 2024-04-01
|
4
|
+
|
5
|
+
## Status
|
6
|
+
|
7
|
+
Accepted
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
In developing the `Nostr::Client` logging mechanism, I identified a need to cater to multiple development environments
|
12
|
+
and developer preferences. The consideration was whether to implement a singular logger type or to introduce
|
13
|
+
multiple, specialized loggers. The alternatives were:
|
14
|
+
|
15
|
+
- A single `ClientLogger` providing a one-size-fits-all solution.
|
16
|
+
- Multiple logger types:
|
17
|
+
- `Nostr::Client::Logger`: The base class for logging, providing core functionalities.
|
18
|
+
- `Nostr::Client::ColorLogger`: An extension of the base logger, introducing color-coded outputs for enhanced readability in environments that support ANSI colors.
|
19
|
+
- `Nostr::Client::PlainLogger`: A variation that produces logs without color coding, suitable for environments lacking color support or for users preferring plain text.
|
20
|
+
|
21
|
+
## Decision
|
22
|
+
|
23
|
+
I decided to implement the latter option: three specific kinds of loggers (`Nostr::Client::Logger`,
|
24
|
+
`Nostr::Client::ColorLogger`, and `Nostr::Client::PlainLogger`). This approach is intended to offer flexibility and
|
25
|
+
cater to the varied preferences and requirements of our users, recognizing the diverse environments in which our
|
26
|
+
library might be used.
|
27
|
+
|
28
|
+
## Consequences
|
29
|
+
|
30
|
+
- `Developer Choice`: Developers gain the ability to select the one that best matches their needs and environmental constraints, thereby enhancing the library's usability.
|
31
|
+
- `Code Complexity`: While introducing multiple logger types increases the library's code complexity, this is offset by the significant gain in flexibility and user satisfaction.
|
32
|
+
- `Broad Compatibility`: This decision ensures that the logging mechanism is adaptable to a wide range of operational environments, enhancing the library's overall robustness and accessibility.
|
data/docs/.vitepress/config.mjs
CHANGED
@@ -78,6 +78,7 @@ export default defineConfig(withMermaid({
|
|
78
78
|
text: 'Common use cases',
|
79
79
|
collapsed: false,
|
80
80
|
items: [
|
81
|
+
{ text: 'Logging and debugging', link: '/common-use-cases/logging-and-debugging' },
|
81
82
|
{ text: 'Bech32 enc/decoding (NIP-19)', link: '/common-use-cases/bech32-encoding-and-decoding-(NIP-19)' },
|
82
83
|
{ text: 'Signing/verifying messages', link: '/common-use-cases/signing-and-verifying-messages' },
|
83
84
|
{ text: 'Signing/verifying events', link: '/common-use-cases/signing-and-verifying-events' },
|
data/docs/bun.lockb
CHANGED
Binary file
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Logging and debugging
|
2
|
+
|
3
|
+
The `Nostr::Client` class provides built-in logging functionality to help you debug and monitor client interactions with
|
4
|
+
relays. By default, the client uses the `ColorLogger`, which logs events in color. However, you can customize the
|
5
|
+
logging behavior or disable it entirely.
|
6
|
+
|
7
|
+
## Disabling logging
|
8
|
+
|
9
|
+
To instantiate a client without any logging, simply pass `logger: nil` when creating the client instance:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
client = Nostr::Client.new(logger: nil)
|
13
|
+
```
|
14
|
+
|
15
|
+
This will disable all logging for the client.
|
16
|
+
|
17
|
+
## Formatting the logging
|
18
|
+
|
19
|
+
The `Nostr::Client::Logger` class is the base class for logging functionality. It defines the following methods for
|
20
|
+
logging different events:
|
21
|
+
|
22
|
+
- `on_connect(relay)`: Logs when the client connects to a relay.
|
23
|
+
- `on_message(message)`: Logs a message received from the relay.
|
24
|
+
- `on_send(message)`: Logs a message sent to the relay.
|
25
|
+
- `on_error(message)`: Logs an error message.
|
26
|
+
- `on_close(code, reason)`: Logs when the connection with a relay is closed.
|
27
|
+
|
28
|
+
You can create your own logger by subclassing `Nostr::Client::Logger` and overriding these methods to customize the
|
29
|
+
logging format.
|
30
|
+
|
31
|
+
The `Nostr::Client::ColorLogger` is a built-in logger that logs events in color. It uses ANSI escape codes to add color
|
32
|
+
to the log output. Here's an example of how the ColorLogger formats the log messages:
|
33
|
+
|
34
|
+
- Connection: `"\u001b[32m\u001b[1mConnected to the relay\u001b[22m #{relay.name} (#{relay.url})\u001b[0m"`
|
35
|
+
- Message received: `"\u001b[32m\u001b[1m◄-\u001b[0m #{message}"`
|
36
|
+
- Message sent: `"\u001b[32m\u001b[1m-►\u001b[0m #{message}"`
|
37
|
+
- Error: `"\u001b[31m\u001b[1mError: \u001b[22m#{message}\u001b[0m"`
|
38
|
+
- Connection closed: `"\u001b[31m\u001b[1mConnection closed: \u001b[22m#{reason} (##{code})\u001b[0m"`
|
39
|
+
|
40
|
+
## Plain text logging
|
41
|
+
|
42
|
+
If you prefer plain text logging without colors, you can use the `Nostr::Client::PlainLogger`. This logger formats the
|
43
|
+
log messages in a simple, readable format without any ANSI escape codes.
|
44
|
+
|
45
|
+
To use the `PlainLogger`, pass it as the `logger` option when creating the client instance:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
client = Nostr::Client.new(logger: Nostr::Client::PlainLogger.new)
|
49
|
+
```
|
50
|
+
|
51
|
+
The `PlainLogger` formats the log messages as follows:
|
52
|
+
|
53
|
+
- Connection: `"Connected to the relay #{relay.name} (#{relay.url})"`
|
54
|
+
- Message received: `"◄- #{message}"`
|
55
|
+
- Message sent: `"-► #{message}"`
|
56
|
+
- Error: `"Error: #{message}"`
|
57
|
+
- Connection closed: `"Connection closed: #{reason} (##{code})"`
|
58
|
+
|
59
|
+
By using the appropriate logger or creating your own custom logger, you can effectively debug and monitor your Nostr
|
60
|
+
client's interactions with relays.
|
data/docs/core/client.md
CHANGED
@@ -28,7 +28,7 @@ The `:connect` event is fired when a connection with a WebSocket is opened. You
|
|
28
28
|
client = Nostr::Client.new
|
29
29
|
relay = Nostr::Relay.new(url: 'wss://relay.damus.io', name: 'Damus')
|
30
30
|
|
31
|
-
client.on :connect do
|
31
|
+
client.on :connect do |relay|
|
32
32
|
# When this block executes, you're connected to the relay
|
33
33
|
end
|
34
34
|
|
@@ -165,6 +165,9 @@ end
|
|
165
165
|
client.on :close do |code, reason|
|
166
166
|
# You may attempt to reconnect to the relay here
|
167
167
|
end
|
168
|
+
|
169
|
+
# This line keeps the background client from exiting immediately.
|
170
|
+
gets
|
168
171
|
```
|
169
172
|
|
170
173
|
Beyond what's covered here, the Nostr protocol and this gem boast a wealth of additional functionalities. For an
|
data/docs/package.json
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
"docs:preview": "vitepress preview"
|
6
6
|
},
|
7
7
|
"devDependencies": {
|
8
|
-
"mermaid": "^10.
|
9
|
-
"vitepress": "^1.
|
10
|
-
"vitepress-plugin-mermaid": "^2.0.
|
8
|
+
"mermaid": "^10.9.0",
|
9
|
+
"vitepress": "^1.1.0",
|
10
|
+
"vitepress-plugin-mermaid": "^2.0.16"
|
11
11
|
}
|
12
12
|
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures in color.
|
6
|
+
class ColorLogger < Logger
|
7
|
+
# Logs connection to a relay
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
def on_connect(relay)
|
16
|
+
puts "\u001b[32m\u001b[1mConnected to the relay\u001b[22m #{relay.name} (#{relay.url})\u001b[0m"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logs a message received from the relay
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @param [String] message The message received.
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
def on_message(message)
|
28
|
+
puts "\u001b[32m\u001b[1m◄-\u001b[0m #{message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logs a message sent to the relay
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
# @param [String] message The message sent.
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
#
|
39
|
+
def on_send(message)
|
40
|
+
puts "\u001b[32m\u001b[1m-►\u001b[0m #{message}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Logs an error message
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The error message.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_error(message)
|
52
|
+
puts "\u001b[31m\u001b[1mError: \u001b[22m#{message}\u001b[0m"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Logs a closure of connection with a relay
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# @param [String] code The closure code.
|
60
|
+
# @param [String] reason The reason for the closure.
|
61
|
+
#
|
62
|
+
# @return [void]
|
63
|
+
#
|
64
|
+
def on_close(code, reason)
|
65
|
+
puts "\u001b[31m\u001b[1mConnection closed: \u001b[22m#{reason} (##{code})\u001b[0m"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures.
|
6
|
+
class Logger
|
7
|
+
# Attaches event handlers to the specified Nostr client for logging purposes
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
#
|
11
|
+
# @example Attaching the logger to a client
|
12
|
+
# client = Nostr::Client.new
|
13
|
+
# logger = Nostr::Client::Logger.new
|
14
|
+
# logger.attach_to(client)
|
15
|
+
#
|
16
|
+
# # Now, actions like connecting, sending messages, receiving messages,
|
17
|
+
# # errors, and closing the connection will be logged to the console.
|
18
|
+
#
|
19
|
+
# @param [Nostr::Client] client The client to attach logging functionality to.
|
20
|
+
#
|
21
|
+
# @return [void]
|
22
|
+
#
|
23
|
+
def attach_to(client)
|
24
|
+
logger_instance = self
|
25
|
+
|
26
|
+
client.on(:connect) { |relay| logger_instance.on_connect(relay) }
|
27
|
+
client.on(:message) { |message| logger_instance.on_message(message) }
|
28
|
+
client.on(:send) { |message| logger_instance.on_send(message) }
|
29
|
+
client.on(:error) { |message| logger_instance.on_error(message) }
|
30
|
+
client.on(:close) { |code, reason| logger_instance.on_close(code, reason) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Logs connection to a relay
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
def on_connect(relay); end
|
42
|
+
|
43
|
+
# Logs a message received from the relay
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The message received.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_message(message); end
|
52
|
+
|
53
|
+
# Logs a message sent to the relay
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
# @param [String] message The message sent.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
#
|
61
|
+
def on_send(message); end
|
62
|
+
|
63
|
+
# Logs an error message
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
# @param [String] message The error message.
|
68
|
+
#
|
69
|
+
# @return [void]
|
70
|
+
#
|
71
|
+
def on_error(message); end
|
72
|
+
|
73
|
+
# Logs a closure of connection with a relay
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
#
|
77
|
+
# @param [String] code The closure code.
|
78
|
+
# @param [String] reason The reason for the closure.
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
#
|
82
|
+
def on_close(code, reason); end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nostr
|
4
|
+
class Client
|
5
|
+
# Logs connection events, messages sent and received, errors, and connection closures.
|
6
|
+
class PlainLogger < Logger
|
7
|
+
# Logs connection to a relay
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @param [Nostr::Relay] relay The relay the client connected to.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
def on_connect(relay)
|
16
|
+
puts "Connected to the relay #{relay.name} (#{relay.url})"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logs a message received from the relay
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# @param [String] message The message received.
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
def on_message(message)
|
28
|
+
puts "◄- #{message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Logs a message sent to the relay
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
# @param [String] message The message sent.
|
36
|
+
#
|
37
|
+
# @return [void]
|
38
|
+
#
|
39
|
+
def on_send(message)
|
40
|
+
puts "-► #{message}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Logs an error message
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
# @param [String] message The error message.
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
def on_error(message)
|
52
|
+
puts "Error: #{message}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Logs a closure of connection with a relay
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# @param [String] code The closure code.
|
60
|
+
# @param [String] reason The reason for the closure.
|
61
|
+
#
|
62
|
+
# @return [void]
|
63
|
+
#
|
64
|
+
def on_close(code, reason)
|
65
|
+
puts "Connection closed: #{reason} (##{code})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/nostr/client.rb
CHANGED
@@ -18,11 +18,19 @@ module Nostr
|
|
18
18
|
# @api public
|
19
19
|
#
|
20
20
|
# @example Instantiating a client that logs all the events it sends and receives
|
21
|
-
# client = Nostr::Client.new
|
21
|
+
# client = Nostr::Client.new
|
22
22
|
#
|
23
|
-
|
23
|
+
# @example Instantiating a client with no logging
|
24
|
+
# client = Nostr::Client.new(logger: nil)
|
25
|
+
#
|
26
|
+
# @example Instantiating a client with your own logger
|
27
|
+
# client = Nostr::Client.new(logger: YourLogger.new)
|
28
|
+
#
|
29
|
+
def initialize(logger: ColorLogger.new)
|
24
30
|
@subscriptions = {}
|
31
|
+
@logger = logger
|
25
32
|
|
33
|
+
logger&.attach_to(self)
|
26
34
|
initialize_channels
|
27
35
|
end
|
28
36
|
|
@@ -40,11 +48,11 @@ module Nostr
|
|
40
48
|
#
|
41
49
|
def connect(relay)
|
42
50
|
execute_within_an_em_thread do
|
43
|
-
client =
|
44
|
-
parent_to_child_channel.subscribe { |msg| client.send(msg) }
|
51
|
+
client = build_websocket_client(relay.url)
|
52
|
+
parent_to_child_channel.subscribe { |msg| client.send(msg) && emit(:send, msg) }
|
45
53
|
|
46
54
|
client.on :open do
|
47
|
-
child_to_parent_channel.push(type: :open)
|
55
|
+
child_to_parent_channel.push(type: :open, relay:)
|
48
56
|
end
|
49
57
|
|
50
58
|
client.on :message do |event|
|
@@ -122,6 +130,14 @@ module Nostr
|
|
122
130
|
|
123
131
|
private
|
124
132
|
|
133
|
+
# The logger that prints all the events that the client sends and receives
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
#
|
137
|
+
# @return [ClientLogger]
|
138
|
+
#
|
139
|
+
attr_reader :logger
|
140
|
+
|
125
141
|
# The subscriptions that the client has created
|
126
142
|
#
|
127
143
|
# @api private
|
@@ -167,11 +183,21 @@ module Nostr
|
|
167
183
|
@child_to_parent_channel = EventMachine::Channel.new
|
168
184
|
|
169
185
|
child_to_parent_channel.subscribe do |msg|
|
170
|
-
emit :connect
|
186
|
+
emit :connect, msg[:relay] if msg[:type] == :open
|
171
187
|
emit :message, msg[:data] if msg[:type] == :message
|
172
188
|
emit :error, msg[:message] if msg[:type] == :error
|
173
189
|
emit :close, msg[:code], msg[:reason] if msg[:type] == :close
|
174
190
|
end
|
175
191
|
end
|
192
|
+
|
193
|
+
# Builds a websocket client
|
194
|
+
#
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
# @return [Faye::WebSocket::Client]
|
198
|
+
#
|
199
|
+
def build_websocket_client(relay_url)
|
200
|
+
Faye::WebSocket::Client.new(relay_url, [], { tls: { verify_peer: false } })
|
201
|
+
end
|
176
202
|
end
|
177
203
|
end
|
data/lib/nostr/event.rb
CHANGED
@@ -203,8 +203,7 @@ module Nostr
|
|
203
203
|
def verify_signature
|
204
204
|
crypto = Crypto.new
|
205
205
|
|
206
|
-
return false if id.nil? || pubkey.nil?
|
207
|
-
return false if sig.nil? # FIXME: See https://github.com/soutaro/steep/issues/1079
|
206
|
+
return false if id.nil? || pubkey.nil? || sig.nil?
|
208
207
|
|
209
208
|
crypto.valid_sig?(id, pubkey, sig)
|
210
209
|
end
|
data/lib/nostr/version.rb
CHANGED
data/lib/nostr.rb
CHANGED
@@ -16,6 +16,8 @@ require_relative 'nostr/signature'
|
|
16
16
|
require_relative 'nostr/event'
|
17
17
|
require_relative 'nostr/events/encrypted_direct_message'
|
18
18
|
require_relative 'nostr/client'
|
19
|
+
require_relative 'nostr/client/logger'
|
20
|
+
require_relative 'nostr/client/color_logger'
|
19
21
|
require_relative 'nostr/user'
|
20
22
|
require_relative 'nostr/key'
|
21
23
|
require_relative 'nostr/private_key'
|
data/nostr.gemspec
CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_dependency 'ecdsa', '~> 1.2'
|
37
37
|
spec.add_dependency 'event_emitter', '~> 0.2'
|
38
38
|
spec.add_dependency 'faye-websocket', '~> 0.11'
|
39
|
-
spec.add_dependency 'json', '~> 2.
|
39
|
+
spec.add_dependency 'json', '~> 2.7'
|
40
40
|
|
41
41
|
spec.add_development_dependency 'bundler-audit', '~> 0.9'
|
42
42
|
spec.add_development_dependency 'dotenv', '~> 3.1'
|
@@ -54,10 +54,10 @@ Gem::Specification.new do |spec|
|
|
54
54
|
spec.add_development_dependency 'rspec', '~> 3.13'
|
55
55
|
spec.add_development_dependency 'rubocop', '~> 1.62'
|
56
56
|
spec.add_development_dependency 'rubocop-rake', '~> 0.6'
|
57
|
-
spec.add_development_dependency 'rubocop-rspec', '2.
|
57
|
+
spec.add_development_dependency 'rubocop-rspec', '2.29'
|
58
58
|
spec.add_development_dependency 'simplecov', '= 0.17'
|
59
59
|
spec.add_development_dependency 'simplecov-console', '~> 0.9'
|
60
|
-
spec.add_development_dependency 'steep', '~> 1.
|
60
|
+
spec.add_development_dependency 'steep', '~> 1.7.dev3'
|
61
61
|
spec.add_development_dependency 'typeprof', '~> 0.21'
|
62
62
|
spec.add_development_dependency 'yard', '~> 0.9'
|
63
63
|
spec.add_development_dependency 'yard-junk', '~> 0.0.9'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Nostr
|
2
|
+
class Client
|
3
|
+
class Logger
|
4
|
+
def attach_to: (Client client) -> void
|
5
|
+
def on_connect: (Relay relay) -> void
|
6
|
+
def on_message: (String message) -> void
|
7
|
+
def on_send: (String message) -> void
|
8
|
+
def on_error: (String message) -> void
|
9
|
+
def on_close: (String code, String reason) -> void
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/sig/nostr/client.rbs
CHANGED
@@ -10,11 +10,13 @@ module Nostr
|
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
+
attr_reader logger: Logger
|
13
14
|
attr_reader subscriptions: Hash[String, Subscription]
|
14
15
|
attr_reader parent_to_child_channel: EventMachine::Channel
|
15
16
|
attr_reader child_to_parent_channel: EventMachine::Channel
|
16
17
|
|
17
18
|
def execute_within_an_em_thread: { -> void } -> Thread
|
18
19
|
def initialize_channels: -> void
|
20
|
+
def build_websocket_client: (String relay_name) -> Faye::WebSocket::Client
|
19
21
|
end
|
20
22
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# Added only to satisfy the Steep requirements. Not 100% reliable.
|
2
2
|
module EventEmitter
|
3
|
-
|
4
|
-
|
5
|
-
def message: -> String
|
6
|
-
def code: -> Integer
|
7
|
-
def reason: -> String
|
8
|
-
end
|
3
|
+
def self.included: (Module) -> void
|
4
|
+
def self.apply: (untyped) -> void
|
9
5
|
|
10
|
-
def
|
6
|
+
def __events: () -> Array[untyped]
|
7
|
+
|
8
|
+
def add_listener: (Symbol | String type, ?Hash[untyped, untyped] params) { (*untyped) -> void } -> Integer
|
11
9
|
alias on add_listener
|
10
|
+
alias once add_listener
|
12
11
|
|
13
|
-
def remove_listener: (
|
14
|
-
def emit: (Symbol
|
15
|
-
def once: (Symbol `type`) -> Integer
|
12
|
+
def remove_listener: (Integer | Symbol | String id_or_type) -> void
|
13
|
+
def emit: (Symbol | String type, *untyped data) -> void
|
16
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nostr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wilson Silva
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bech32
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '2.
|
89
|
+
version: '2.7'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '2.
|
96
|
+
version: '2.7'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: bundler-audit
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -324,14 +324,14 @@ dependencies:
|
|
324
324
|
requirements:
|
325
325
|
- - '='
|
326
326
|
- !ruby/object:Gem::Version
|
327
|
-
version: '2.
|
327
|
+
version: '2.29'
|
328
328
|
type: :development
|
329
329
|
prerelease: false
|
330
330
|
version_requirements: !ruby/object:Gem::Requirement
|
331
331
|
requirements:
|
332
332
|
- - '='
|
333
333
|
- !ruby/object:Gem::Version
|
334
|
-
version: '2.
|
334
|
+
version: '2.29'
|
335
335
|
- !ruby/object:Gem::Dependency
|
336
336
|
name: simplecov
|
337
337
|
requirement: !ruby/object:Gem::Requirement
|
@@ -366,14 +366,14 @@ dependencies:
|
|
366
366
|
requirements:
|
367
367
|
- - "~>"
|
368
368
|
- !ruby/object:Gem::Version
|
369
|
-
version:
|
369
|
+
version: 1.7.dev3
|
370
370
|
type: :development
|
371
371
|
prerelease: false
|
372
372
|
version_requirements: !ruby/object:Gem::Requirement
|
373
373
|
requirements:
|
374
374
|
- - "~>"
|
375
375
|
- !ruby/object:Gem::Version
|
376
|
-
version:
|
376
|
+
version: 1.7.dev3
|
377
377
|
- !ruby/object:Gem::Dependency
|
378
378
|
name: typeprof
|
379
379
|
requirement: !ruby/object:Gem::Requirement
|
@@ -455,12 +455,16 @@ files:
|
|
455
455
|
- Steepfile
|
456
456
|
- adr/0001-record-architecture-decisions.md
|
457
457
|
- adr/0002-introduction-of-signature-class.md
|
458
|
+
- adr/0003-logging-methods-vs-logger-class.md
|
459
|
+
- adr/0004-default-logging-activation.md
|
460
|
+
- adr/0005-logger-types.md
|
458
461
|
- docs/.gitignore
|
459
462
|
- docs/.vitepress/config.mjs
|
460
463
|
- docs/README.md
|
461
464
|
- docs/api-examples.md
|
462
465
|
- docs/bun.lockb
|
463
466
|
- docs/common-use-cases/bech32-encoding-and-decoding-(NIP-19).md
|
467
|
+
- docs/common-use-cases/logging-and-debugging.md
|
464
468
|
- docs/common-use-cases/signing-and-verifying-events.md
|
465
469
|
- docs/common-use-cases/signing-and-verifying-messages.md
|
466
470
|
- docs/core/client.md
|
@@ -488,6 +492,9 @@ files:
|
|
488
492
|
- lib/nostr.rb
|
489
493
|
- lib/nostr/bech32.rb
|
490
494
|
- lib/nostr/client.rb
|
495
|
+
- lib/nostr/client/color_logger.rb
|
496
|
+
- lib/nostr/client/logger.rb
|
497
|
+
- lib/nostr/client/plain_logger.rb
|
491
498
|
- lib/nostr/client_message_type.rb
|
492
499
|
- lib/nostr/crypto.rb
|
493
500
|
- lib/nostr/errors.rb
|
@@ -520,6 +527,9 @@ files:
|
|
520
527
|
- sig/nostr.rbs
|
521
528
|
- sig/nostr/bech32.rbs
|
522
529
|
- sig/nostr/client.rbs
|
530
|
+
- sig/nostr/client/color_logger.rbs
|
531
|
+
- sig/nostr/client/logger.rbs
|
532
|
+
- sig/nostr/client/plain_logger.rbs
|
523
533
|
- sig/nostr/client_message_type.rbs
|
524
534
|
- sig/nostr/crypto.rbs
|
525
535
|
- sig/nostr/errors/error.rbs
|