This NIP solves the problem of sharing and distributing binary content over NOSTR networks such as media - images, short videos, music, or in general any files up to a certain size
Key Takeaways
-------------
* Builds on NIP-94
* Defines how binary content (images, media, files) is managed by NOSTR network
* Defines new commands at the protocol level ("FILE","RETRIEVE")
* Uses the binary messages in the websocket connection
* **url is optional** - This item can be still filled with a link to an external server. This may help during the transition period when the client is uploading the file to third party servers for relays that don't support this NIP.
* **field "nip97"** appears only when event is sent from the relay to a client. This field is added by the relay to indicate, that event also contains a binary content. The value is always `true`. This also indicates, that binary content can be received by the command `RETRIEVE` (see below). *This field SHOULD NOT be set by a client *`*`
* **field "file_url"** (optional) appears only when event is sent from the relay to a client. Its presence indicates, that the binary content can be downloaded at a given URL which is set as a value of this field. If this field is missing, then the binary connent cannot be downloaded using the http protocol, and the only way to retrieve the content is by using the command `RETRIEVE`. This field, cannot appear without the field `"nip97":true`. The client must not assume that given url is permanent and canonical. The relay can generate urls dynamically for the clients (each client can receive a different URL for the same event) *This field SHOULT NOT be set by a client*`*`
`*` - *It is allowed to publish events with these fields by using the command*`FILE`*(see below) . The relay should remove these fields during the processing of the event. It is not allowed for the command* `EVENT`* as it is currently undefined, how the relay is handling these new fields.*
**NOTE** - when copying events from one relay to another, the service must check for the presence of a field `"nip97":true`. If such a fields exists on the event, it must be posted using the `FILE` command with its binary content. (see below)
The client MUST notify the relay that it is about to send a binary file. This is just implemented by the new 'FILE' command. The command "allocates" the binary channel of the websocket connection for file transfer. This will allow this binary channel to be used for other purposes in the future.
The relay MUST always respond with a NIP-20 response to both the command and the binary message.
Response to the command `FILE` is `OK`, with status `true` - which signals that relay is ready to accept a binary message as binary content of the file. The text part of the response is just informational for debugging purpose.
If the relay respons with status `false`, or the response is not `OK` message, the client MUST NOT send any binary message. The text part of the response contains explanation of the error (similar to NIP-20)
The relay must also respond once it receives the binary message if it was correctly announced using the `FILE` command. The response is also `OK`, with status `true` for success or `false` for failure.
This proposal doesn't define response for binary messages sent without the announcement
### Special error messages
*`max_size: <size in bytes>` - this error message informs that file is too big.
*`invalid: file mismatch` - received binary content doesn't match to announced metadata in the associated event
### Rules for state control
1. The relay SHOULD NOT accept any binary message without prior anouncement.
2. The relay SHOULD publish event after successful binary transfer.
3. The relay MUST NOT publish an event with incomplette binary transfer.
4. If a `FILE` command is sent after another `FILE` without sending a binary message between them, the previous operation is cancelled and the associated event MUST NOT be published.
5. If a client sends `FILE` command and then closes the connection without sending a binary message, the operation is canceled and event MUST NOT be published.
6. If the connection is closed during reading a binary message (continuation frames), the operation is canceled and event MUST NOT be published.
7. If the received binary message is corrupted (hash or size doesn't match), the relay MUST NOT publish the event and signal this to the client using appropriate response.
8. Relay is free to choose not to accept binary content for any reason. For example, Relay may test submitted images for explicit or copyrighted content and reject such content.
8. responds with failure state if the checks fail (on text channel) - done
9. responds with success state otherwise (on text channel), stores the binary content and publishes the event
Download
--------
The `RETRIEVE` command is used to download the binary file from the relay
**Protocol flow**
```
client: ["RETRIEVE","<event-id>"]
relay: ["OK","<event-id>", true, ""]
relay: <binarymessage>
```
**NOTE** the binary content is referenced by the event's id (not by the file hash).
If the binary file does not exist, the response looks like this
```
client: ["RETRIEVE","<event-id>"]
relay: ["OK","<event-id>", false, "missing: not found"]
```
In this case, the relay MUST NOT generate a binary message
**NOTE**: It may indeed happen that binary content is unavailable even though there is an event for it. The client must be prepared for this eventuality. For example, the event might have been incorrectly published, or the relay database may have been corrupted, or the content might been deleted for copyrighted or explicit content.
If the relay caches files, for example, on CDN servers, it can announce availablity of the contnet using the "file_url" field inserted directly to the event
* **max_file_size** - maximum size of binary content in bytes. This value can be greater than the value **max_message_size**. This value is mandatory for the relay supporting this NIP. The relay MUST NOT assume that **max_message_size** defines maximum size of a fragment as there are many websocket clients that are unable to control size of fragments from their API. This includes all majority browsers.