Skip to content

Commit

Permalink
Extending the work done in PR #59 from @kriptonix
Browse files Browse the repository at this point in the history
* improved relay responses in general
* NIP-01 relayResponses
* NIP-42 AUTH relayresponse
* added RelayResponseTest.php
  • Loading branch information
Sebastix committed Aug 16, 2024
1 parent bafdf35 commit 90dfa5a
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 71 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,18 @@ private key on command line.
- [x] Convert from hex to bech32-encoded keys
- [x] Event signing with Schnorr signatures (`secp256k1`)
- [x] Event validation (issue [#17](https://github.com/nostrver-se/nostr-php/issues/17))
- [ ] Support NIP-01 basic protocol flow description
- [x] Support NIP-01 basic protocol flow description
- [x] Publish events
- [x] Request events (issue [#55](https://github.com/nostrver-se/nostr-php/pull/55) credits to [kriptonix](https://github.com/kriptonix))
- [ ] Implement all types of relay responses
- [ ] EVENT - sends events requested by the client
- [ ] OK - indicate an acceptance or denial of an EVENT message
- [ ] EOSE - end of stored events
- [ ] CLOSED - subscription is ended on the server side
- [ ] NOTICE - used to send human-readable messages (like errors) to clients
- [ ] Improve handling relay responses
- [x] Implement all types of relay responses
- [x] `EVENT` - sends events requested by the client
- [x] `OK` - indicate an acceptance or denial of an EVENT message
- [x] `EOSE` - end of stored events
- [x] `CLOSED` - subscription is ended on the server side
- [x] `NOTICE` - used to send human-readable messages (like errors) to clients
- [x] Improve handling relay responses
- [ ] Support NIP-19 bech32-encoded identifiers
- [ ] Support NIP-42 authentication of clients to relays
- [ ] Support NIP-42 authentication of clients to relays => AUTH relay response
- [ ] Support NIP-45 event counts
- [ ] Support NIP-50 search capability
- [ ] Support multi-threading (async concurrency) for handling requests simultaneously
Expand All @@ -296,3 +296,4 @@ In May 2024 OpenSats granted Sebastian Hagens for further development of this li

## Contributors

See https://github.com/nostrver-se/nostr-php/graphs/contributors
21 changes: 6 additions & 15 deletions src/Relay/Relay.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,9 @@ private function setPayload(string $payload): void
}

/**
* Sends a message using WebSocket and returns a RelayResponseInterface object.
*
* @return RelayResponseInterface|RelayResponseOk|RelayResponseNotice The response object.
* @inheritDoc
*/
public function send(): RelayResponseInterface | RelayResponseOk | RelayResponseNotice
public function send(): RelayResponse
{
$this->validateUrl();

Expand All @@ -106,25 +104,18 @@ public function send(): RelayResponseInterface | RelayResponseOk | RelayResponse
$client->text($this->payload);
$response = $client->receive();
$client->disconnect();

if ($response === null) {
$response = [
'ERROR',
'Invalid response',
];
$relayResponse = RelayResponse::create($response);
} else {
$relayResponse = RelayResponse::create(json_decode($response->getContent()));
throw new \RuntimeException('Websocket client response is null');
}
$result = RelayResponse::create(json_decode($response->getContent()));
} catch (WebSocket\Exception\ClientException $e) {
$response = [
$result = [
'ERROR',
'',
false,
$e->getMessage(),
];
}

return $relayResponse;
return $result;
}
}
17 changes: 10 additions & 7 deletions src/Relay/RelaySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace swentel\nostr\Relay;

use swentel\nostr\CommandResultInterface;
use swentel\nostr\MessageInterface;
use swentel\nostr\RelayResponse\RelayResponse;
use swentel\nostr\RelaySetInterface;
use WebSocket;

Expand Down Expand Up @@ -112,7 +112,7 @@ public function isConnected(): bool
/**
* @inheritDoc
*/
public function send(): CommandResultInterface
public function send(): array
{
try {
// Send message to each relay defined in this set.
Expand All @@ -123,19 +123,22 @@ public function send(): CommandResultInterface
$client->text($payload);
$response = $client->receive();
$client->disconnect();
$response = json_decode($response->getContent());
if ($response[0] === 'NOTICE') {
throw new \RuntimeException($response[1]);
if ($response->getOpcode() === 'ping') {
continue;
}
if ($response === null) {
throw new \RuntimeException('Websocket client response is null');
}
$result[$relay->getUrl()] = RelayResponse::create(json_decode($response->getContent()));
}
} catch (WebSocket\Exception\ClientException $e) {
$response = [
$result = [
'ERROR',
'',
false,
$e->getMessage(),
];
}
return new CommandResult($response);
return $result;
}
}
4 changes: 2 additions & 2 deletions src/RelayInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function setMessage(MessageInterface $message): void;
/**
* Sends the message to the relay.
*
* @return RelayResponse
* @return RelayResponseInterface
*/
public function send(): RelayResponseInterface | RelayResponseOk | RelayResponseNotice;
public function send(): RelayResponseInterface;
}
45 changes: 37 additions & 8 deletions src/RelayResponse/RelayResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,27 @@
namespace swentel\nostr\RelayResponse;

use swentel\nostr\RelayResponseInterface;
use swentel\nostr\RelayResponse\RelayResponseOk;
use swentel\nostr\RelayResponse\RelayResponseEnum;

class RelayResponse implements RelayResponseInterface
{
public string $type;

public bool $isSuccess;

public string $message;

public function __construct(array $response)
{
$this->isSuccess = false;
if (isset($response[0])) {
$this->isSuccess = true;
$this->type = RelayResponseEnum::from($response[0])->value;
}
// Piece of legacy to support version <=1.3.3
if ($this->type === 'OK' && $response[2] === false) {
$this->isSuccess = false;
}
$this->message = !empty($response[3]) ? $response[3] : '';
}
}

/**
Expand All @@ -26,15 +35,15 @@ public function __construct(array $response)
* @param string $type The type of response to determine which object to create.
* @return object The created response object based on the type.
*/
public static function createResponse(array $response, string $type)
public static function createResponse(array $response, string $type): mixed
{
return match ($type) {
'ERROR' => new RelayResponseNotice($response),
'ERROR', 'NOTICE' => new RelayResponseNotice($response),
'EVENT' => new RelayResponseEvent($response),
'OK' => new RelayResponseOk($response),
'EOSE' => new RelayResponseEose($response),
'CLOSED' => new RelayResponseClosed($response),
'NOTICE' => new RelayResponseNotice($response),
'AUTH' => new RelayResponseAuth($response),
default => new self($response),
};
}
Expand All @@ -45,9 +54,29 @@ public static function createResponse(array $response, string $type)
* @param array $response The response data to be used for creating the object.
* @return object The created response object based on the determined type.
*/
public static function create(array $response)
public static function create(array $response): mixed
{
$type = RelayResponseEnum::from($response[0])->value;
return self::createResponse($response, $type);
}
}

/**
* Backwards compatability support for <=1.3.3 where we used the CommandResultInterface as a response.
*
* @return bool
*/
public function isSuccess(): bool
{
return $this->isSuccess;
}

/**
* Backwards compatability support for <=1.3.3 where we used the CommandResultInterface as a response.
*
* @return string
*/
public function message(): string
{
return $this->message;
}
}
16 changes: 16 additions & 0 deletions src/RelayResponse/RelayResponseAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace swentel\nostr\RelayResponse;

class RelayResponseAuth extends RelayResponse
{
public string $message;

public function __construct($response)
{
parent::__construct($response);
$this->message = $response[1];
}
}
3 changes: 2 additions & 1 deletion src/RelayResponse/RelayResponseClosed.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class RelayResponseClosed extends RelayResponse

public string $message;

public function __construct($response){
public function __construct($response)
{
parent::__construct($response);
$this->subscriptionId = $response[1];
$this->message = $response[2];
Expand Down
6 changes: 5 additions & 1 deletion src/RelayResponse/RelayResponseEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
*/
enum RelayResponseEnum: string
{
case ERROR = 'ERROR';
case EVENT = 'EVENT';
case OK = 'OK';
case EOSE = 'EOSE';
case CLOSED = 'CLOSED';
case NOTICE = 'NOTICE';
/**
* NIP-42 support - Authentication of clients to relays
* https://github.com/nostr-protocol/nips/blob/master/42.md
*/
case AUTH = 'AUTH';
}
3 changes: 2 additions & 1 deletion src/RelayResponse/RelayResponseEose.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class RelayResponseEose extends RelayResponse
{
public string $subscriptionId;

public function __construct($response){
public function __construct($response)
{
parent::__construct($response);
$this->subscriptionId = $response[1];
}
Expand Down
9 changes: 5 additions & 4 deletions src/RelayResponse/RelayResponseEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
class RelayResponseEvent extends RelayResponse
{
public string $subscriptionId;

public $event;

public function __construct($response){
public \stdClass $event;

public function __construct($response)
{
parent::__construct($response);
$this->subscriptionId = $response[1];
$this->event = $response[2];
}
}
}
5 changes: 3 additions & 2 deletions src/RelayResponse/RelayResponseNotice.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ class RelayResponseNotice extends RelayResponse
{
public string $message;

public function __construct($response){
public function __construct($response)
{
parent::__construct($response);
$this->message = $response[1];
}
}
}
7 changes: 4 additions & 3 deletions src/RelayResponse/RelayResponseOk.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
class RelayResponseOk extends RelayResponse
{
public string $eventId;

public bool $status;

public string $message;

public function __construct($response){
public function __construct($response)
{
parent::__construct($response);
$this->eventId = $response[1];
$this->status = $response[2];
$this->message = $response[3];
}
}
}
20 changes: 18 additions & 2 deletions src/RelayResponseInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,23 @@

interface RelayResponseInterface
{
public static function createResponse(array $response, string $type);
/**
* @param array $response
* @param string $type
* @return mixed
*/
public static function createResponse(array $response, string $type): mixed;

public static function create(array $response);
/**
* @param array $response
* @return mixed
*/
public static function create(array $response): mixed;

/**
* Returns whether the request was successful.
*
* @return bool
*/
public function isSuccess(): bool;
}
6 changes: 4 additions & 2 deletions src/RelaySetInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace swentel\nostr;

use swentel\nostr\Relay\CommandResult;
use swentel\nostr\Relay\Relay;

interface RelaySetInterface
Expand Down Expand Up @@ -72,7 +73,8 @@ public function isConnected(): bool;
/**
* Sends the message to all the relays in this set.
*
* @return CommandResultInterface
* @return array
* Return an array with the results of each relay.
*/
public function send(): CommandResultInterface;
public function send(): array;
}
Loading

0 comments on commit 90dfa5a

Please sign in to comment.