nostr 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|