First commit on a late git install
This commit is contained in:
184
nostr_websocket/EXPORT_GUIDE.md
Normal file
184
nostr_websocket/EXPORT_GUIDE.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# NOSTR WebSocket Library Export Guide
|
||||
|
||||
This guide explains how to use the NOSTR WebSocket library in other C projects.
|
||||
|
||||
## Library Structure
|
||||
|
||||
The NOSTR WebSocket library consists of these key files for export:
|
||||
|
||||
### Core Files (Required)
|
||||
- `nostr_websocket_tls.h` - Header with all function declarations and constants
|
||||
- `nostr_websocket_mbedtls.c` - Main implementation using mbedTLS for SSL/TLS
|
||||
- `../cjson/cJSON.h` and `../cjson/cJSON.c` - JSON parsing (lightweight)
|
||||
|
||||
### Dependencies
|
||||
- **mbedTLS** - For SSL/TLS support (wss:// connections)
|
||||
- **Standard C libraries** - socket, networking, etc.
|
||||
|
||||
## Quick Integration
|
||||
|
||||
### 1. Copy Files to Your Project
|
||||
```bash
|
||||
# Copy the library files
|
||||
cp nostr_websocket_tls.h your_project/
|
||||
cp nostr_websocket_mbedtls.c your_project/
|
||||
cp ../cjson/cJSON.h your_project/
|
||||
cp ../cjson/cJSON.c your_project/
|
||||
```
|
||||
|
||||
### 2. Install mbedTLS Dependency
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install libmbedtls-dev
|
||||
|
||||
# Or build from source (see mbedTLS documentation)
|
||||
```
|
||||
|
||||
### 3. Compile Your Project
|
||||
```bash
|
||||
gcc -o my_nostr_app my_app.c nostr_websocket_mbedtls.c cJSON.c \
|
||||
-lmbedtls -lmbedx509 -lmbedcrypto -lm
|
||||
```
|
||||
|
||||
## Basic Usage Example
|
||||
|
||||
```c
|
||||
#include "nostr_websocket_tls.h"
|
||||
#include "cJSON.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
// Connect to relay
|
||||
nostr_ws_client_t* client = nostr_ws_connect("wss://relay.damus.io");
|
||||
if (!client) {
|
||||
printf("Failed to connect\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create subscription filter
|
||||
cJSON* filter = cJSON_CreateObject();
|
||||
cJSON* kinds = cJSON_CreateArray();
|
||||
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1)); // Text notes
|
||||
cJSON_AddItemToObject(filter, "kinds", kinds);
|
||||
cJSON_AddItemToObject(filter, "limit", cJSON_CreateNumber(10));
|
||||
|
||||
// Send REQ message
|
||||
nostr_relay_send_req(client, "my-sub", filter);
|
||||
|
||||
// Receive messages
|
||||
char buffer[8192];
|
||||
while (1) {
|
||||
int len = nostr_ws_receive(client, buffer, sizeof(buffer), 1000);
|
||||
if (len > 0) {
|
||||
printf("Received: %s\n", buffer);
|
||||
|
||||
// Parse message type
|
||||
char* msg_type;
|
||||
cJSON* parsed;
|
||||
if (nostr_parse_relay_message(buffer, &msg_type, &parsed) == 0) {
|
||||
if (strcmp(msg_type, "EOSE") == 0) {
|
||||
printf("End of subscription\n");
|
||||
free(msg_type);
|
||||
cJSON_Delete(parsed);
|
||||
break;
|
||||
}
|
||||
free(msg_type);
|
||||
cJSON_Delete(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
nostr_ws_close(client);
|
||||
cJSON_Delete(filter);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Connection Management
|
||||
- `nostr_ws_connect(url)` - Connect to relay (ws:// or wss://)
|
||||
- `nostr_ws_close(client)` - Close connection and cleanup
|
||||
- `nostr_ws_get_state(client)` - Get connection state
|
||||
|
||||
### Messaging
|
||||
- `nostr_ws_send_text(client, message)` - Send raw text message
|
||||
- `nostr_ws_receive(client, buffer, size, timeout)` - Receive message
|
||||
- `nostr_ws_ping(client)` - Send ping frame
|
||||
|
||||
### NOSTR Protocol Helpers
|
||||
- `nostr_relay_send_req(client, sub_id, filters)` - Send REQ message
|
||||
- `nostr_relay_send_event(client, event)` - Send EVENT message
|
||||
- `nostr_relay_send_close(client, sub_id)` - Send CLOSE message
|
||||
- `nostr_parse_relay_message(message, type, json)` - Parse relay message
|
||||
|
||||
### Error Handling
|
||||
- `nostr_ws_strerror(error_code)` - Get error string
|
||||
- Return codes: `NOSTR_WS_SUCCESS`, `NOSTR_WS_ERROR_*`
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Timeouts
|
||||
```c
|
||||
nostr_ws_set_timeout(client, 30000); // 30 second timeout
|
||||
```
|
||||
|
||||
### Multiple Transports
|
||||
The library supports both TCP (`ws://`) and TLS (`wss://`) automatically based on URL scheme.
|
||||
|
||||
## Cross-Platform Notes
|
||||
|
||||
### Linux/Unix
|
||||
- Works out of the box with standard development tools
|
||||
- Requires: gcc, mbedTLS development headers
|
||||
|
||||
### Potential Windows Support
|
||||
- Would need Winsock2 adaptations in transport layer
|
||||
- mbedTLS is cross-platform compatible
|
||||
|
||||
### Embedded Systems
|
||||
- Lightweight design suitable for embedded use
|
||||
- Memory usage: ~4KB per client + message buffers
|
||||
- No dynamic allocations in hot paths
|
||||
|
||||
## Library Design Benefits
|
||||
|
||||
### Modular Architecture
|
||||
- Clean separation between WebSocket protocol and NOSTR logic
|
||||
- Transport layer abstraction (easy to add new transports)
|
||||
- No global state - multiple clients supported
|
||||
|
||||
### Performance Optimized
|
||||
- Minimal memory allocations
|
||||
- Efficient SSL buffer handling
|
||||
- Fast WebSocket frame parsing
|
||||
|
||||
### Production Ready
|
||||
- Proper error handling throughout
|
||||
- Resource cleanup on all code paths
|
||||
- Thread-safe design (no shared state)
|
||||
|
||||
## Migration from Other Libraries
|
||||
|
||||
### From libwebsockets
|
||||
```c
|
||||
// Old libwebsockets code:
|
||||
// lws_client_connect_info info = {...};
|
||||
// wsi = lws_client_connect(context, &info);
|
||||
|
||||
// New NOSTR WebSocket library:
|
||||
client = nostr_ws_connect("wss://relay.example.com");
|
||||
```
|
||||
|
||||
### From raw sockets
|
||||
The library handles all WebSocket protocol details, SSL/TLS, and NOSTR message formatting automatically.
|
||||
|
||||
## Support
|
||||
|
||||
- Based on WebSocket RFC 6455
|
||||
- Implements NOSTR WebSocket conventions
|
||||
- SSL/TLS via proven mbedTLS library
|
||||
- Tested with major NOSTR relays
|
||||
|
||||
This library provides a clean, efficient way to integrate NOSTR WebSocket functionality into any C project with minimal dependencies and maximum portability.
|
||||
63
nostr_websocket/Makefile
Normal file
63
nostr_websocket/Makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
# NOSTR WebSocket Library Makefile
|
||||
# Production-ready WebSocket implementation for NOSTR protocol
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c99 -O2
|
||||
INCLUDES = -I. -I.. -I../mbedtls/include -I../mbedtls/tf-psa-crypto/include -I../mbedtls/tf-psa-crypto/drivers/builtin/include
|
||||
LIBS = -lm -L../mbedtls/library -lmbedtls -lmbedx509 -lmbedcrypto
|
||||
|
||||
# Source files
|
||||
WEBSOCKET_SOURCES = nostr_websocket_mbedtls.c ../cjson/cJSON.c
|
||||
WEBSOCKET_HEADERS = nostr_websocket_tls.h ../cjson/cJSON.h
|
||||
|
||||
# Test programs
|
||||
TEST_SOURCES = test_5_events_clean.c
|
||||
TEST_PROGRAMS = test_5_events_clean
|
||||
|
||||
# Object files
|
||||
WEBSOCKET_OBJECTS = $(WEBSOCKET_SOURCES:.c=.o)
|
||||
|
||||
.PHONY: all clean test
|
||||
|
||||
all: $(TEST_PROGRAMS)
|
||||
|
||||
# Test programs
|
||||
test_5_events_clean: test_5_events_clean.o $(WEBSOCKET_OBJECTS)
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
# Object file compilation
|
||||
%.o: %.c $(WEBSOCKET_HEADERS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
# Test target
|
||||
test: test_5_events_clean
|
||||
@echo "🧪 Running WebSocket test..."
|
||||
@echo "Press Ctrl-C to stop the test"
|
||||
./test_5_events_clean
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -f *.o $(TEST_PROGRAMS)
|
||||
rm -f ../cjson/*.o
|
||||
|
||||
# Display library info
|
||||
info:
|
||||
@echo "📚 NOSTR WebSocket Library"
|
||||
@echo "=========================="
|
||||
@echo "Core files:"
|
||||
@echo " - nostr_websocket_tls.h (header)"
|
||||
@echo " - nostr_websocket_mbedtls.c (implementation)"
|
||||
@echo " - ../cjson/cJSON.h/c (JSON support)"
|
||||
@echo ""
|
||||
@echo "Dependencies:"
|
||||
@echo " - mbedTLS (SSL/TLS support)"
|
||||
@echo " - Standard C libraries"
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make - Build test programs"
|
||||
@echo " make test - Run WebSocket test"
|
||||
@echo " make clean - Clean build artifacts"
|
||||
@echo " make info - Show this information"
|
||||
|
||||
# Help target
|
||||
help: info
|
||||
139
nostr_websocket/README.md
Normal file
139
nostr_websocket/README.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# NOSTR WebSocket Library
|
||||
|
||||
A production-ready, lightweight WebSocket client library specifically designed for the NOSTR protocol. This library provides a clean C API for connecting to NOSTR relays over both TCP (`ws://`) and TLS (`wss://`) connections.
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ **WebSocket RFC 6455 Compliant** - Full WebSocket protocol implementation
|
||||
- ✅ **SSL/TLS Support** - Secure `wss://` connections via mbedTLS
|
||||
- ✅ **NOSTR Protocol** - Built-in support for REQ, EVENT, CLOSE messages
|
||||
- ✅ **Production Ready** - Optimized performance and error handling
|
||||
- ✅ **Lightweight** - Minimal dependencies and memory footprint
|
||||
- ✅ **Cross-Platform** - Linux/Unix support, Windows adaptable
|
||||
- ✅ **Thread Safe** - No global state, multiple clients supported
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Build the Test Program
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
### 2. Run the Test
|
||||
```bash
|
||||
make test
|
||||
# or directly:
|
||||
./test_5_events_clean
|
||||
```
|
||||
|
||||
### 3. Basic Usage
|
||||
```c
|
||||
#include "nostr_websocket_tls.h"
|
||||
|
||||
// Connect to a NOSTR relay
|
||||
nostr_ws_client_t* client = nostr_ws_connect("wss://relay.damus.io");
|
||||
|
||||
// Create and send a subscription
|
||||
cJSON* filter = cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(filter, "limit", cJSON_CreateNumber(10));
|
||||
nostr_relay_send_req(client, "my-sub", filter);
|
||||
|
||||
// Receive messages
|
||||
char buffer[8192];
|
||||
int len = nostr_ws_receive(client, buffer, sizeof(buffer), 1000);
|
||||
if (len > 0) {
|
||||
printf("Received: %s\n", buffer);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
nostr_ws_close(client);
|
||||
cJSON_Delete(filter);
|
||||
```
|
||||
|
||||
## Library Structure
|
||||
|
||||
### Core Components
|
||||
- **`nostr_websocket_tls.h`** - Public API header
|
||||
- **`nostr_websocket_mbedtls.c`** - Main implementation (mbedTLS backend)
|
||||
- **`../cjson/cJSON.h/c`** - JSON parsing support
|
||||
|
||||
### Dependencies
|
||||
- **mbedTLS** - For SSL/TLS support
|
||||
- **Standard C libraries** - POSIX sockets, etc.
|
||||
|
||||
## Installation in Other Projects
|
||||
|
||||
See [`EXPORT_GUIDE.md`](EXPORT_GUIDE.md) for detailed instructions on integrating this library into your C projects.
|
||||
|
||||
## API Reference
|
||||
|
||||
### Connection Management
|
||||
```c
|
||||
nostr_ws_client_t* nostr_ws_connect(const char* url);
|
||||
int nostr_ws_close(nostr_ws_client_t* client);
|
||||
nostr_ws_state_t nostr_ws_get_state(nostr_ws_client_t* client);
|
||||
```
|
||||
|
||||
### Messaging
|
||||
```c
|
||||
int nostr_ws_send_text(nostr_ws_client_t* client, const char* message);
|
||||
int nostr_ws_receive(nostr_ws_client_t* client, char* buffer, size_t size, int timeout_ms);
|
||||
int nostr_ws_ping(nostr_ws_client_t* client);
|
||||
```
|
||||
|
||||
### NOSTR Protocol Helpers
|
||||
```c
|
||||
int nostr_relay_send_req(nostr_ws_client_t* client, const char* sub_id, cJSON* filters);
|
||||
int nostr_relay_send_event(nostr_ws_client_t* client, cJSON* event);
|
||||
int nostr_relay_send_close(nostr_ws_client_t* client, const char* sub_id);
|
||||
int nostr_parse_relay_message(const char* message, char** type, cJSON** json);
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```c
|
||||
const char* nostr_ws_strerror(int error_code);
|
||||
```
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
- **Memory Usage**: ~4KB per client + message buffers
|
||||
- **Latency**: Optimized SSL buffer handling, minimal delays
|
||||
- **Throughput**: Efficient WebSocket frame parsing
|
||||
- **Scalability**: Multiple concurrent clients supported
|
||||
|
||||
## Tested Relays
|
||||
|
||||
This library has been successfully tested with:
|
||||
- `wss://relay.damus.io`
|
||||
- `wss://nostr.mom`
|
||||
- `wss://relay.nostr.band`
|
||||
- `ws://localhost:7777` (local relays)
|
||||
|
||||
## Build Options
|
||||
|
||||
```bash
|
||||
make # Build test programs
|
||||
make test # Run WebSocket test
|
||||
make clean # Clean build artifacts
|
||||
make info # Show library information
|
||||
make help # Show help
|
||||
```
|
||||
|
||||
## Development History
|
||||
|
||||
This library evolved from the experimental WebSocket implementation in `../websocket_experiment/` and represents the production-ready, stable version suitable for integration into other projects.
|
||||
|
||||
Key improvements made during development:
|
||||
- Fixed critical WebSocket frame parsing bugs
|
||||
- Optimized SSL/TLS performance
|
||||
- Reduced memory allocations
|
||||
- Enhanced error handling
|
||||
- Added comprehensive documentation
|
||||
|
||||
## License
|
||||
|
||||
This library is part of the C NOSTR project and follows the same license terms.
|
||||
|
||||
## Contributing
|
||||
|
||||
For issues, improvements, or questions about the NOSTR WebSocket library, please refer to the main project documentation.
|
||||
1046
nostr_websocket/nostr_websocket_mbedtls.c
Normal file
1046
nostr_websocket/nostr_websocket_mbedtls.c
Normal file
File diff suppressed because it is too large
Load Diff
156
nostr_websocket/nostr_websocket_tls.h
Normal file
156
nostr_websocket/nostr_websocket_tls.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#ifndef NOSTR_WEBSOCKET_TLS_H
|
||||
#define NOSTR_WEBSOCKET_TLS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "../cjson/cJSON.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// WebSocket client state
|
||||
typedef struct nostr_ws_client nostr_ws_client_t;
|
||||
|
||||
// Connection states
|
||||
typedef enum {
|
||||
NOSTR_WS_CONNECTING = 0,
|
||||
NOSTR_WS_CONNECTED = 1,
|
||||
NOSTR_WS_CLOSING = 2,
|
||||
NOSTR_WS_CLOSED = 3,
|
||||
NOSTR_WS_ERROR = -1
|
||||
} nostr_ws_state_t;
|
||||
|
||||
// WebSocket opcodes (RFC 6455)
|
||||
typedef enum {
|
||||
WS_OPCODE_CONTINUATION = 0x0,
|
||||
WS_OPCODE_TEXT = 0x1,
|
||||
WS_OPCODE_BINARY = 0x2,
|
||||
WS_OPCODE_CLOSE = 0x8,
|
||||
WS_OPCODE_PING = 0x9,
|
||||
WS_OPCODE_PONG = 0xA
|
||||
} ws_opcode_t;
|
||||
|
||||
// Error codes
|
||||
#define NOSTR_WS_SUCCESS 0
|
||||
#define NOSTR_WS_ERROR_INVALID -1
|
||||
#define NOSTR_WS_ERROR_NETWORK -2
|
||||
#define NOSTR_WS_ERROR_PROTOCOL -3
|
||||
#define NOSTR_WS_ERROR_MEMORY -4
|
||||
#define NOSTR_WS_ERROR_TLS -5
|
||||
|
||||
// Debug control - uncomment to enable debug output
|
||||
// #define NOSTR_WS_DEBUG_ENABLED
|
||||
|
||||
// ============================================================================
|
||||
// Core WebSocket Functions (with TLS support)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Connect to a WebSocket server (supports both ws:// and wss://)
|
||||
* @param url WebSocket URL (e.g., "ws://127.0.0.1:7777" or "wss://relay.damus.io")
|
||||
* @return WebSocket client handle or NULL on error
|
||||
*/
|
||||
nostr_ws_client_t* nostr_ws_connect(const char* url);
|
||||
|
||||
/**
|
||||
* Close WebSocket connection
|
||||
* @param client WebSocket client handle
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_ws_close(nostr_ws_client_t* client);
|
||||
|
||||
/**
|
||||
* Get current connection state
|
||||
* @param client WebSocket client handle
|
||||
* @return Connection state
|
||||
*/
|
||||
nostr_ws_state_t nostr_ws_get_state(nostr_ws_client_t* client);
|
||||
|
||||
/**
|
||||
* Send text message to WebSocket server
|
||||
* @param client WebSocket client handle
|
||||
* @param message Text message to send
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_ws_send_text(nostr_ws_client_t* client, const char* message);
|
||||
|
||||
/**
|
||||
* Receive message from WebSocket server (blocking)
|
||||
* @param client WebSocket client handle
|
||||
* @param buffer Buffer to store received message
|
||||
* @param buffer_size Size of buffer
|
||||
* @param timeout_ms Timeout in milliseconds (0 = no timeout)
|
||||
* @return Number of bytes received, negative on error
|
||||
*/
|
||||
int nostr_ws_receive(nostr_ws_client_t* client, char* buffer, size_t buffer_size, int timeout_ms);
|
||||
|
||||
/**
|
||||
* Send ping frame to server
|
||||
* @param client WebSocket client handle
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_ws_ping(nostr_ws_client_t* client);
|
||||
|
||||
// ============================================================================
|
||||
// NOSTR-Specific Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Send NOSTR REQ message to relay
|
||||
* @param client WebSocket client handle
|
||||
* @param subscription_id Subscription ID
|
||||
* @param filters JSON array of filters
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_relay_send_req(nostr_ws_client_t* client, const char* subscription_id, cJSON* filters);
|
||||
|
||||
/**
|
||||
* Send NOSTR EVENT message to relay
|
||||
* @param client WebSocket client handle
|
||||
* @param event NOSTR event JSON object
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_relay_send_event(nostr_ws_client_t* client, cJSON* event);
|
||||
|
||||
/**
|
||||
* Send NOSTR CLOSE message to relay
|
||||
* @param client WebSocket client handle
|
||||
* @param subscription_id Subscription ID to close
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_relay_send_close(nostr_ws_client_t* client, const char* subscription_id);
|
||||
|
||||
/**
|
||||
* Parse received NOSTR message
|
||||
* @param message Raw message string
|
||||
* @param message_type Output: message type ("EVENT", "EOSE", "OK", "NOTICE")
|
||||
* @param parsed_json Output: parsed JSON object (caller must free)
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_parse_relay_message(const char* message, char** message_type, cJSON** parsed_json);
|
||||
|
||||
// ============================================================================
|
||||
// Utility Functions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Get error string for error code
|
||||
* @param error_code Error code from WebSocket functions
|
||||
* @return Human-readable error string
|
||||
*/
|
||||
const char* nostr_ws_strerror(int error_code);
|
||||
|
||||
/**
|
||||
* Set receive timeout for blocking operations
|
||||
* @param client WebSocket client handle
|
||||
* @param timeout_ms Timeout in milliseconds
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int nostr_ws_set_timeout(nostr_ws_client_t* client, int timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NOSTR_WEBSOCKET_TLS_H
|
||||
Reference in New Issue
Block a user