### Go Project: Basic Server Setup Source: https://github.com/smhanov/zwibserve/blob/master/README.md Integrate the Zwibserve package into a Go project by creating a main.go file. This example sets up a handler for '/socket' using a SQLite database and starts the HTTP server. ```go package main import ( "log" "net/http" "github.com/smhanov/zwibserve" ) func main() { http.Handle("/socket", zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db"))) log.Printf("Running...") http.ListenAndServe(":3000", http.DefaultServeMux) } ``` -------------------------------- ### Install Apache Proxy Module (CentOS) Source: https://github.com/smhanov/zwibserve/blob/master/README.md Commands to install the Apache proxy module and configure SELinux for network connections on CentOS systems. ```bash sudo yum install mod_proxy ``` ```bash sudo /usr/sbin/setsebool -P httpd_can_network_connect 1 ``` -------------------------------- ### Load Testing Statistics Example Source: https://github.com/smhanov/zwibserve/blob/master/README.md Example output showing connection count, document length, and average, minimum, and maximum screen-to-screen times during a load test. ```text Connections=51 docLength=149360 Screen-to-screen time avg=71ms min=19ms max=958ms ``` -------------------------------- ### Implement Main Server File (main.go) Source: https://github.com/smhanov/zwibserve/blob/master/README.md Set up the main.go file to initialize the zwibserve handler with a database and start the HTTP server. Ensure the zwibserve package is imported correctly, removing the GitHub path. ```go package main import ( "log" "net/http" "zwibserve" // <-- Was github.com/smhanov/zwibserve ) func main() { http.Handle("/socket", zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db"))) log.Printf("Running...") http.ListenAndServe(":3000", http.DefaultServeMux) } ``` -------------------------------- ### Configure Apache Proxy for Zwibserve Source: https://github.com/smhanov/zwibserve/blob/master/README.md Example configuration for Apache to proxy requests to the Zwibserve collaboration service. Ensure CertFile/KeyFile are blank when using a proxy and the Zwibserve service is on a different port. ```apache SSLEngine on SSLProxyEngine On ServerName www.example.com DocumentRoot "/var/www/html" SSLCertificateFile /path/to/.crt SSLCertificateKeyFile /path/to/.key # ADD THESE LINES SSLProxyEngine on ProxyPass ws://localhost:3000/socket ProxyPassReverse ws://localhost:3000/socket ``` -------------------------------- ### Enable Management API Authentication Source: https://context7.com/smhanov/zwibserve/llms.txt Sets HTTP Basic Auth credentials for management endpoints. Without this, the management API is disabled. Example shows enabling authentication and making a management call. ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3tpassword") http.Handle("/socket", handler) // Now management calls are authenticated: // curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ // -d "method=deleteDocument&documentID=doc-abc123" // → HTTP 200 ``` -------------------------------- ### Configure Nginx Proxy for Zwibbler Source: https://github.com/smhanov/zwibserve/blob/master/README.md Nginx server block configuration to proxy requests from a specific URL path to the zwibbler service running on a different port. This setup is useful when running multiple services on the same server. ```nginx location /socket { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } ``` -------------------------------- ### Implement Custom DocumentDB Interface Source: https://context7.com/smhanov/zwibserve/llms.txt Implement this interface to plug in a custom storage backend. All methods must be safe for concurrent access. ```go type MyCustomDB struct { /* ... */ } func (db *MyCustomDB) GetDocument(docID string, mode zwibserve.CreateMode, initialData []byte) ([]byte, bool, error) { // Return existing doc, or create if mode allows. Return ErrMissing / ErrExists as appropriate. } func (db *MyCustomDB) AppendDocument(docID string, oldLength uint64, newData []byte) (uint64, error) { // Atomically append only if len(existing) == oldLength; else return ErrConflict + actual length. } func (db *MyCustomDB) SetDocumentKey(docID string, oldVersion int, key zwibserve.Key) error { /* ... */ } func (db *MyCustomDB) GetDocumentKeys(docID string) ([]zwibserve.Key, error) { /* ... */ } func (db *MyCustomDB) SetExpiration(seconds int64) { /* ... */ } func (db *MyCustomDB) DeleteDocument(docID string) error { /* ... */ } func (db *MyCustomDB) AddToken(token, docID, userID, permissions string, expSeconds int64, contents []byte) error { /* ... */ } func (db *MyCustomDB) GetToken(token string) (string, string, string, error) { /* ... */ } func (db *MyCustomDB) UpdateUser(userID, permissions string) error { /* ... */ } func (db *MyCustomDB) CheckHealth() error { /* ... */ } // Use it: handler := zwibserve.NewHandler(&MyCustomDB{}) http.Handle("/socket", handler) ``` -------------------------------- ### SQL Database Storage (MariaDB/MySQL, PostgreSQL) Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by MariaDB/MySQL or PostgreSQL. Suitable for production deployments with existing relational databases. Requires connection parameters. ```go // MariaDB / MySQL db := zwibserve.NewMariaDBConnection( "localhost:3306", // server "zwibuser", // user "zwibpass", // password "zwibbler", // database name ) // PostgreSQL db := zwibserve.NewPostgreSQLConnection( "localhost:5432", "zwibuser", "zwibpass", "zwibbler", ) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) log.Fatal(http.ListenAndServe(":3000", nil)) ``` -------------------------------- ### Create Document with Initial Content Source: https://context7.com/smhanov/zwibserve/llms.txt Pre-creates a document with initial content on the server. Returns 409 if the document already exists. Supports both string content and file uploads. ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=createDocument" \ -d "documentID=board-session-99" \ -d "contents=INITIAL_CONTENT_HERE" ``` ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -F "method=createDocument" \ -F "documentID=board-session-99" \ -F "contents=@/path/to/initial.bin" ``` -------------------------------- ### Load Testing Command Line Options Source: https://github.com/smhanov/zwibserve/blob/master/README.md Utilize command-line arguments like --test, --docid, --teachers, --students, and --verbose to perform load testing on the Zwibbler server by simulating participants. ```bash --test | Test the server at the given websocket url (eg. ws://yourserver:3000/socket) ``` ```bash --docid | The name of the whiteboard all participants connect to ``` ```bash --teachers | The number of teachers to simulate. ``` ```bash --students | The number of students to simulate. ``` ```bash --verbose | Show all actions from every student and teacher ``` -------------------------------- ### Run Stress Test Source: https://context7.com/smhanov/zwibserve/llms.txt Runs a configurable stress test simulating teacher and student clients. Outputs live latency statistics to stderr. ```go package main import "github.com/smhanov/zwibserve" func main() { zwibserve.RunStressTest(zwibserve.StressTestArgs{ Address: "ws://localhost:3000/socket", DocumentID: "stress-test-doc", NumTeachers: 5, // clients that continuously write changes NumStudents: 20, // clients that only receive changes DelayMS: 500, // avg ms between teacher writes ChangeLength: 200, // bytes per change Verbose: false, }) // Output (stderr): // Connections=25 docLength=48200 Screen-to-screen time avg=71ms min=19ms max=312ms } ``` -------------------------------- ### Configure Zwibserve with MariaDB/PostgreSQL/MySQL Source: https://github.com/smhanov/zwibserve/blob/master/README.md Modify the Database setting in zwibbler.conf to use MariaDB, PostgreSQL, or MySQL. Then, insert the appropriate DB server and credentials. ```ini Database=mariadb # Default DbServer for MariaDB and MySQL: localhost:3306 # Default DbServer for Redis: localhost:6379 DbServer= DbPassword= DbUser= ``` -------------------------------- ### Configure Zwibbler Server Port and SSL Source: https://github.com/smhanov/zwibserve/blob/master/README.md Edit the zwibbler configuration file to set the server bind address, port, and paths to SSL certificate and key files. Compression can be disabled by setting Compression=0. ```ini ServerBindAddress=0.0.0.0 ServerPort=443 CertFile= KeyFile= Compression= ``` -------------------------------- ### Configure go.mod for Local Zwibserve Module Source: https://github.com/smhanov/zwibserve/blob/master/README.md Create a go.mod file to manage dependencies and specify the local path for the zwibserve package. This ensures Go can find the zwibserve module during the build process. ```go module example.com/server go 1.14 require ( zwibserve v0.0.0 ) replace zwibserve v0.0.0 => ./zwibserve ``` -------------------------------- ### createDocument Endpoint Source: https://context7.com/smhanov/zwibserve/llms.txt Pre-creates a document with initial content on the server. Returns 409 if the document already exists. ```APIDOC ## POST /socket (createDocument) ### Description Pre-creates a document with initial content on the server. Returns 409 if the document already exists. ### Method POST ### Endpoint /socket ### Parameters #### Query Parameters - **method** (string) - Required - `createDocument` - **documentID** (string) - Required - The ID of the document to create. - **contents** (string or file) - Required - The initial content of the document. Can be a string or a file upload. ### Request Example ```bash # Create with string content curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=createDocument" \ -d "documentID=board-session-99" \ -d "contents=INITIAL_CONTENT_HERE" # Create with file upload curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -F "method=createDocument" \ -F "documentID=board-session-99" \ -F "contents=@/path/to/initial.bin" ``` ### Response #### Success Response (200) - HTTP 200 on success. #### Error Response - **409 Conflict**: If the document already exists. ``` -------------------------------- ### Configure Zwibserve with Redis Source: https://github.com/smhanov/zwibserve/blob/master/README.md Add these lines to zwibbler.conf to configure the collaboration server to use Redis for data storage. Ensure the DbServer is correctly set if not running on the default localhost:6379. ```ini # Change this to redis Database=redis # Default DbServer for Redis: localhost:6379 DbServer= DbPassword= ``` -------------------------------- ### Create a Collaboration WebSocket Handler Source: https://context7.com/smhanov/zwibserve/llms.txt Returns an http.Handler for WebSocket upgrade requests. Requires a DocumentDB implementation. Optional: enable CORS. ```go package main import ( "log" "net/http" "github.com/smhanov/zwibserve" ) func main() { db := zwibserve.NewSQLITEDB("zwibbler.db") handler := zwibserve.NewHandler(db) // Optional: enable CORS for cross-origin web clients http.Handle("/socket", handler) log.Println("Collaboration server listening on :3000") if err := http.ListenAndServe(":3000", nil); err != nil { log.Fatal(err) } } ``` -------------------------------- ### Clone Zwibserve Repository Source: https://github.com/smhanov/zwibserve/blob/master/README.md Use this command to clone the zwibserve repository into your project directory. ```bash mkdir myproject cd myproject git clone https://github.com/smhanov/zwibserve.git ``` -------------------------------- ### Configure Webhook for Session End Source: https://github.com/smhanov/zwibserve/blob/master/README.md Specify a Webhook URL to be called when all users have left a session. Refer to the API documentation for detailed configuration. ```ini # If set, this webhook will be called when all users have left a session. # See the API documents on Google Drive for details. Webhook= ``` -------------------------------- ### RunStressTest Source: https://context7.com/smhanov/zwibserve/llms.txt Runs a configurable stress test against a running collaboration server by simulating teacher clients (write) and student clients (read-only). Outputs live screen-to-screen latency statistics to stderr. ```APIDOC ## RunStressTest — Load Testing Utility Runs a configurable stress test against a running collaboration server by simulating teacher clients (write) and student clients (read-only). Outputs live screen-to-screen latency statistics to stderr. ```go package main import "github.com/smhanov/zwibserve" func main() { zwibserve.RunStressTest(zwibserve.StressTestArgs{ Address: "ws://localhost:3000/socket", DocumentID: "stress-test-doc", NumTeachers: 5, // clients that continuously write changes NumStudents: 20, // clients that only receive changes DelayMS: 500, // avg ms between teacher writes ChangeLength: 200, // bytes per change Verbose: false, }) // Output (stderr): // Connections=25 docLength=48200 Screen-to-screen time avg=71ms min=19ms max=312ms } ``` ``` -------------------------------- ### View Zwibbler Service Logs Source: https://github.com/smhanov/zwibserve/blob/master/README.md Command to view the real-time logs of the zwibbler service. ```bash sudo tail -f /var/log/zwibbler/zwibbler.log ``` -------------------------------- ### SQLite Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by an SQLite file using WAL journal mode and a shared cache. Suitable for single-server deployments. Docs can be set to expire after inactivity. ```go db := zwibserve.NewSQLITEDB("/var/lib/zwibbler/zwibbler.db") handler := zwibserve.NewHandler(db) handler.SetExpiration(86400 * 7) // expire docs after 7 days of inactivity http.Handle("/socket", handler) ``` -------------------------------- ### Configure Zwibbler MaxFiles Source: https://github.com/smhanov/zwibserve/blob/master/README.md Set MaxFiles in /etc/zwibbler.conf to leverage the increased system file handle limits. This value must be less than or equal to the OS hard limit. ```ini # Attempt to set the open file limit of the operating system to this value. # This must be less than or equal to the hard limit of the operating system. MaxFiles=100000 ``` -------------------------------- ### In-Memory Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB that stores documents in process memory. Useful for testing or short-lived scenarios where persistence is not required. Documents are lost on restart. Docs can be purged after inactivity. ```go db := zwibserve.NewMemoryDB() db.SetExpiration(3600) // purge docs not accessed for 1 hour handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) log.Fatal(http.ListenAndServe(":3000", nil)) ``` -------------------------------- ### NewHandler — Create a Collaboration WebSocket Handler Source: https://context7.com/smhanov/zwibserve/llms.txt Returns an http.Handler that accepts WebSocket upgrade requests and manages the full collaboration lifecycle. It must be given a DocumentDB implementation. This is the primary entry point for embedding zwibserve into a Go HTTP server. ```APIDOC ## NewHandler — Create a Collaboration WebSocket Handler ### Description Returns an `http.Handler` that accepts WebSocket upgrade requests and manages the full collaboration lifecycle. It must be given a `DocumentDB` implementation. This is the primary entry point for embedding zwibserve into a Go HTTP server. ### Method GET ### Endpoint /socket ### Query Parameters - **ping** (bool) - Optional - Used to check database health. ### Request Example ``` GET http://localhost:3000/socket ``` ### Response Example #### Success Response (200) - **Body**: "Zwibbler collaboration Server is running." #### Success Response (200) - **Body**: "OK" (if ping parameter is present and DB is healthy) #### Error Response (500) - **Body**: (if DB is unhealthy and ping parameter is present) ``` -------------------------------- ### Configure JWT Acceptance Source: https://github.com/smhanov/zwibserve/blob/master/README.md Set JWTKey and JWTKeyIsBase64 to enable JWT acceptance for session identifiers. This ensures only authorized individuals can write to a whiteboard. ```ini # If set, only JWT tokens will be accepted as document identifiers from the client. # The HMAC-SHA256 signature method is used. JWTKey= JWTKeyIsBase64=False ``` -------------------------------- ### DocumentDB Interface Source: https://context7.com/smhanov/zwibserve/llms.txt Implement this interface to plug in any custom storage backend. All methods must be safe for concurrent access. ```APIDOC ## DocumentDB Interface — Custom Storage Backend Implement this interface to plug in any custom storage backend. All methods must be safe for concurrent access. ```go type MyCustomDB struct { /* ... */ } func (db *MyCustomDB) GetDocument(docID string, mode zwibserve.CreateMode, initialData []byte) ([]byte, bool, error) { // Return existing doc, or create if mode allows. Return ErrMissing / ErrExists as appropriate. } func (db *MyCustomDB) AppendDocument(docID string, oldLength uint64, newData []byte) (uint64, error) { // Atomically append only if len(existing) == oldLength; else return ErrConflict + actual length. } func (db *MyCustomDB) SetDocumentKey(docID string, oldVersion int, key zwibserve.Key) error { /* ... */ } func (db *MyCustomDB) GetDocumentKeys(docID string) ([]zwibserve.Key, error) { /* ... */ } func (db *MyCustomDB) SetExpiration(seconds int64) { /* ... */ } func (db *MyCustomDB) DeleteDocument(docID string) error { /* ... */ } func (db *MyCustomDB) AddToken(token, docID, userID, permissions string, expSeconds int64, contents []byte) error { /* ... */ } func (db *MyCustomDB) GetToken(token string) (string, string, string, error) { /* ... */ } func (db *MyCustomDB) UpdateUser(userID, permissions string) error { /* ... */ } func (db *MyCustomDB) CheckHealth() error { /* ... */ } // Use it: handler := zwibserve.NewHandler(&MyCustomDB{}) http.Handle("/socket", handler) ``` ``` -------------------------------- ### NewSQLITEDB — SQLite Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by an SQLite file. Uses WAL journal mode and a shared cache for concurrency safety. This is the default storage backend and suitable for single-server deployments. ```APIDOC ## NewSQLITEDB — SQLite Document Storage ### Description Creates a `DocumentDB` backed by an SQLite file. Uses WAL journal mode and a shared cache for concurrency safety. This is the default storage backend and suitable for single-server deployments. ### Method POST (Implicit via Handler setup) ### Endpoint /socket ### Parameters #### Path Parameters - **dbPath** (string) - Required - Path to the SQLite database file. #### Request Body (Not directly applicable for handler setup, but implies configuration) ### Request Example ```go db := zwibserve.NewSQLITEDB("/var/lib/zwibbler/zwibbler.db") handler := zwibserve.NewHandler(db) handler.SetExpiration(86400 * 7) // expire docs after 7 days of inactivity http.Handle("/socket", handler) ``` ### Response (Not directly applicable for DB creation, but handler setup leads to WebSocket responses) ``` -------------------------------- ### Redis Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by Redis or Redis Cluster. Required for multiple collaboration server instances. Supports configuration for connection options. ```go import "github.com/go-redis/redis/v9" // Single Redis instance db := zwibserve.NewRedisDB(&redis.Options{ Addr: "localhost:6379", Password: "secret", DB: 0, }) // Redis Cluster clusterDB := zwibserve.NewRedisClusterDB(&redis.ClusterOptions{ Addrs: []string{ "redis-node1:6379", "redis-node2:6379", "redis-node3:6379", }, }) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) log.Fatal(http.ListenAndServe(":3000", nil)) ``` -------------------------------- ### Dump or Check Document Existence Source: https://context7.com/smhanov/zwibserve/llms.txt Retrieves the raw binary content of a document using `dumpDocument` or verifies its existence with `checkDocument`. Returns 404 if the document is not found. ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=dumpDocument" \ -d "documentID=board-session-99" \ -o saved-board.bin ``` ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=checkDocument" \ -d "documentID=board-session-99" ``` -------------------------------- ### Configure Management API Credentials Source: https://github.com/smhanov/zwibserve/blob/master/README.md Set SecretUser and SecretPassword to enable the management API for deleting and dumping documents. These credentials are used for HTTP Basic Authentication. ```ini # If set, the management API is enabled to allow deleting and dumping documents. SecretUser= SecretPassword= ``` -------------------------------- ### Add Access Token to Document Source: https://context7.com/smhanov/zwibserve/llms.txt Associates a short-lived access token with a document, user, and permissions. Clients use this token instead of the raw document ID. Requires `SetSecretUser` to be configured. ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=addToken" \ -d "token=tok_abc123xyz" \ -d "documentID=whiteboard-5" \ -d "userID=student42" \ -d "permissions=rw" \ -d "expiration=Mon, 02 Jan 2006 15:04:05 MST" ``` ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=addToken" \ -d "token=tok_readonly99" \ -d "documentID=whiteboard-5" \ -d "userID=observer1" \ -d "permissions=r" \ -d "expiration=Mon, 02 Jan 2006 15:04:05 MST" ``` -------------------------------- ### deleteDocument Endpoint Source: https://context7.com/smhanov/zwibserve/llms.txt Immediately disconnects all clients from a document and removes it from the database. Active clients receive a "does not exist" error and their connections are closed. ```APIDOC ## POST /socket (deleteDocument) ### Description Immediately disconnects all clients from a document and removes it from the database. Active clients receive a "does not exist" error and their connections are closed. ### Method POST ### Endpoint /socket ### Parameters #### Query Parameters - **method** (string) - Required - `deleteDocument` - **documentID** (string) - Required - The ID of the document to delete. ### Request Example ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=deleteDocument" \ -d "documentID=board-session-99" ``` ### Response #### Success Response (200) - HTTP 200 on success. ``` -------------------------------- ### Delete Document Source: https://context7.com/smhanov/zwibserve/llms.txt Immediately disconnects all clients from a document and removes it from the database. Active clients receive a "does not exist" error and their connections are closed. ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=deleteDocument" \ -d "documentID=board-session-99" ``` -------------------------------- ### Configure Idle Session Webhook Source: https://context7.com/smhanov/zwibserve/llms.txt Registers a URL to be called via HTTP POST approximately 10 seconds after all users leave a session. The POST body contains event and documentID. Use this to trigger long-term save logic. ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3t") handler.SetWebhookURL("https://myapp.example.com/hooks/zwibbler") http.Handle("/socket", handler) // Your webhook endpoint will receive: // POST https://myapp.example.com/hooks/zwibbler // Body: event=idle-session&documentID=board-session-99 // Authorization: Basic YWRtaW46czNjcjN0 (Basic auth with secretUser/secretPassword) ``` -------------------------------- ### Restart Zwibbler Service Source: https://github.com/smhanov/zwibserve/blob/master/README.md Command to restart the zwibbler system service after configuration changes. ```bash systemctl restart zwibbler ``` -------------------------------- ### Add CORS Middleware Source: https://context7.com/smhanov/zwibserve/llms.txt Wraps an http.Handler to add appropriate CORS headers. Use when the client is served from a different origin than the server. ```go import "net/http" handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3t") // Wrap with CORS for cross-origin management API access http.Handle("/socket", zwibserve.CORS(handler)) log.Fatal(http.ListenAndServe(":3000", nil)) ``` -------------------------------- ### Configure Zwibbler for Nginx Proxy Source: https://github.com/smhanov/zwibserve/blob/master/README.md Zwibbler configuration for use with an nginx proxy. SSL certificate and key files are not needed as nginx handles security. ```ini ServerBindAddress=0.0.0.0 ServerPort=3000 CertFile= KeyFile= ``` -------------------------------- ### Configure JWT-Based Access Control Source: https://context7.com/smhanov/zwibserve/llms.txt Enables JWT mode where clients use HMAC-SHA256-signed JWTs as document identifiers. The JWT payload contains document ID, user ID, and permissions. Requires a secret key for signing. ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) // Plain string key handler.SetJWTKey("my-hmac-secret-key", false) // Base64-encoded key handler.SetJWTKey("bXktaG1hYy1zZWNyZXQta2V5", true) http.Handle("/socket", handler) // Your app server mints tokens like: // { // "sub": "document-id-abc", // "u": "user123", // "p": "rw", // "exp": 1700000000 // } // signed with HS256 using the same key. // Clients connect passing the JWT string as the document ID. ``` -------------------------------- ### dumpDocument / checkDocument Endpoints Source: https://context7.com/smhanov/zwibserve/llms.txt Retrieves the raw binary content of a stored document (`dumpDocument`) or verifies it exists (`checkDocument`). Returns 404 if the document is not found. ```APIDOC ## POST /socket (dumpDocument / checkDocument) ### Description Retrieves the raw binary content of a stored document (`dumpDocument`) or verifies it exists (`checkDocument`). Returns 404 if the document is not found. ### Method POST ### Endpoint /socket ### Parameters #### Query Parameters - **method** (string) - Required - `dumpDocument` or `checkDocument` - **documentID** (string) - Required - The ID of the document. ### Request Example ```bash # Dump document contents curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=dumpDocument" \ -d "documentID=board-session-99" \ -o saved-board.bin # Check document existence curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=checkDocument" \ -d "documentID=board-session-99" ``` ### Response #### Success Response (200) - **dumpDocument**: Returns raw bytes of the document content. - **checkDocument**: HTTP 200 if the document exists (no body returned). #### Error Response - **404 Not Found**: If the document is not found. ``` -------------------------------- ### NewMariaDBConnection / NewPostgreSQLConnection — SQL Database Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by MariaDB/MySQL or PostgreSQL. Suitable for production deployments that already operate a relational database. ```APIDOC ## NewMariaDBConnection / NewPostgreSQLConnection — SQL Database Storage ### Description Creates a `DocumentDB` backed by MariaDB/MySQL or PostgreSQL. Suitable for production deployments that already operate a relational database. ### Method POST (Implicit via Handler setup) ### Endpoint /socket ### Parameters #### Path Parameters - **server** (string) - Required - The server address and port. - **user** (string) - Required - The database username. - **password** (string) - Required - The database password. - **database name** (string) - Required - The name of the database. ### Request Example ```go // MariaDB / MySQL db := zwibserve.NewMariaDBConnection( "localhost:3306", // server "zwibuser", // user "zwibpass", // password "zwibbler", // database name ) // PostgreSQL db := zwibserve.NewPostgreSQLConnection( "localhost:5432", "zwibuser", "zwibpass", "zwibbler", ) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) ``` ### Response (Not directly applicable for DB creation, but handler setup leads to WebSocket responses) ``` -------------------------------- ### Handler.SetCompressionAllowed Source: https://context7.com/smhanov/zwibserve/llms.txt Controls whether per-message WebSocket compression is offered to clients. Compression is enabled by default but should be disabled on Windows Server 2016 and environments where it causes issues. ```APIDOC ## Handler.SetCompressionAllowed Controls whether per-message WebSocket compression (permessage-deflate) is offered to clients. Compression is enabled by default but should be disabled on Windows Server 2016 and environments where it causes issues. ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetCompressionAllowed(false) // disable compression http.Handle("/socket", handler) ``` ``` -------------------------------- ### NewMemoryDB — In-Memory Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB that stores all documents in process memory. Useful for testing or short-lived single-server scenarios where persistence is not required. Documents are lost on restart. ```APIDOC ## NewMemoryDB — In-Memory Document Storage ### Description Creates a `DocumentDB` that stores all documents in process memory. Useful for testing or short-lived single-server scenarios where persistence is not required. Documents are lost on restart. ### Method POST (Implicit via Handler setup) ### Endpoint /socket ### Parameters (No parameters for NewMemoryDB itself) ### Request Example ```go db := zwibserve.NewMemoryDB() db.SetExpiration(3600) // purge docs not accessed for 1 hour handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) log.Fatal(http.ListenAndServe(":3000", nil)) ``` ### Response (Not directly applicable for DB creation, but handler setup leads to WebSocket responses) ``` -------------------------------- ### Handler.SetWebhookURL Source: https://context7.com/smhanov/zwibserve/llms.txt Registers a URL to be called via HTTP POST approximately 10 seconds after all users have left a session. The POST body contains event and documentID information. ```APIDOC ## Handler.SetWebhookURL(url string) ### Description Registers a URL to receive HTTP POST notifications when a session becomes idle (i.e., all users have left). The webhook is triggered approximately 10 seconds after the last user disconnects. This is useful for implementing long-term save logic on a backend server. ### Parameters - **url** (string) - The URL to send the webhook POST request to. ### Usage Example ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3t") handler.SetWebhookURL("https://myapp.example.com/hooks/zwibbler") http.Handle("/socket", handler) // The webhook endpoint will receive: // POST https://myapp.example.com/hooks/zwibbler // Body: event=idle-session&documentID=board-session-99 // Authorization: Basic YWRtaW46czNjcjN0 (Basic auth with secretUser/secretPassword) ``` ``` -------------------------------- ### Set Document Expiration Source: https://context7.com/smhanov/zwibserve/llms.txt Sets how long inactive documents are retained before automatic deletion. Use `zwibserve.NoExpiration` or -1 to disable expiry. ```go db := zwibserve.NewSQLITEDB("zwibbler.db") db.SetExpiration(86400) // delete documents inactive for 24 hours // db.SetExpiration(zwibserve.NoExpiration) // never delete (default) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) ``` -------------------------------- ### addToken Endpoint Source: https://context7.com/smhanov/zwibserve/llms.txt Associates a short-lived access token with a document, user, and permission string. Clients connect using the token instead of the raw document ID. Requires `SetSecretUser` to be configured. ```APIDOC ## POST /socket (addToken) ### Description Associates a short-lived access token with a document, user, and permission string. Clients connect using the token instead of the raw document ID. Requires `SetSecretUser` to be configured. ### Method POST ### Endpoint /socket ### Parameters #### Query Parameters - **method** (string) - Required - `addToken` - **token** (string) - Required - The token to associate. - **documentID** (string) - Required - The ID of the document. - **userID** (string) - Required - The ID of the user. - **permissions** (string) - Required - Permissions string (e.g., `rw` for read-write, `r` for read-only). - **expiration** (string) - Required - The expiration date and time of the token (e.g., `Mon, 02 Jan 2006 15:04:05 MST`). ### Request Example ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=addToken" \ -d "token=tok_abc123xyz" \ -d "documentID=whiteboard-5" \ -d "userID=student42" \ -d "permissions=rw" \ -d "expiration=Mon, 02 Jan 2006 15:04:05 MST" ``` ### Response #### Success Response (200) - No specific response body described, success indicated by HTTP 200. #### Error Response - **409 Conflict**: If the token already exists. ``` -------------------------------- ### Increase System File Handle Limit Source: https://github.com/smhanov/zwibserve/blob/master/README.md Modify /etc/security/limits.conf to increase the system's maximum number of open file handles, necessary for supporting more than 1024 connections on Linux. ```bash * hard nofile 100000 * soft nofile 100000 ``` -------------------------------- ### CORS Middleware Source: https://context7.com/smhanov/zwibserve/llms.txt A middleware wrapper that adds appropriate CORS headers to any `http.Handler`. Use this when your Zwibbler web client is served from a different origin than the collaboration server, or when you want to expose the management API cross-origin. ```APIDOC ## CORS Middleware — Cross-Origin Request Support A middleware wrapper that adds appropriate CORS headers to any `http.Handler`. Use this when your Zwibbler web client is served from a different origin than the collaboration server, or when you want to expose the management API cross-origin. ```go import "net/http" handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3t") // Wrap with CORS for cross-origin management API access http.Handle("/socket", zwibserve.CORS(handler)) log.Fatal(http.ListenAndServe(":3000", nil)) ``` ``` -------------------------------- ### NewRedisDB / NewRedisClusterDB — Redis Document Storage Source: https://context7.com/smhanov/zwibserve/llms.txt Creates a DocumentDB backed by a Redis instance or Redis Cluster. Required when running multiple collaboration server instances, since Redis provides a shared data layer across nodes. ```APIDOC ## NewRedisDB / NewRedisClusterDB — Redis Document Storage ### Description Creates a `DocumentDB` backed by a Redis instance or Redis Cluster. Required when running multiple collaboration server instances, since Redis provides a shared data layer across nodes. ### Method POST (Implicit via Handler setup) ### Endpoint /socket ### Parameters #### Path Parameters - **redis.Options** (struct) - Required for `NewRedisDB` - Options for connecting to a single Redis instance. - **redis.ClusterOptions** (struct) - Required for `NewRedisClusterDB` - Options for connecting to a Redis Cluster. ### Request Example ```go import "github.com/go-redis/redis/v9" // Single Redis instance db := zwibserve.NewRedisDB(&redis.Options{ Addr: "localhost:6379", Password: "secret", DB: 0, }) // Redis Cluster clusterDB := zwibserve.NewRedisClusterDB(&redis.ClusterOptions{ Addrs: []string{ "redis-node1:6379", "redis-node2:6379", "redis-node3:6379", }, }) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) ``` ### Response (Not directly applicable for DB creation, but handler setup leads to WebSocket responses) ``` -------------------------------- ### Configure Document Expiration Source: https://github.com/smhanov/zwibserve/blob/master/README.md Set the Expiration parameter in zwibbler.conf to define the number of seconds after a document is last accessed before it is purged. Use 'never' to disable expiration. ```ini # The number of seconds after a document is last accessed to purge unused # documents. Set to the special value "never" to disable. Expiration=never ``` -------------------------------- ### Update User Permissions Source: https://context7.com/smhanov/zwibserve/llms.txt Updates permissions for all tokens belonging to a user ID and notifies connected clients of the change. Can revoke all access by setting permissions to an empty string. ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=updateUser" \ -d "userID=student42" \ -d "permissions=r" ``` ```bash curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=updateUser" \ -d "userID=student42" \ -d "permissions=" ``` -------------------------------- ### Handler.SetJWTKey Source: https://context7.com/smhanov/zwibserve/llms.txt Enables JWT mode: only clients presenting a valid HMAC-SHA256-signed JWT as their document identifier are accepted. The JWT payload carries the document ID (`sub`), user ID (`u`), and permissions (`p`). ```APIDOC ## Handler.SetJWTKey(key string, isBase64 bool) ### Description Enables JWT mode for access control. When enabled, clients must present a valid HMAC-SHA256-signed JWT as their document identifier. The JWT payload should contain `sub` (document ID), `u` (user ID), and `p` (permissions). ### Parameters - **key** (string) - The secret key used for signing and verifying JWTs. - **isBase64** (bool) - A boolean indicating whether the provided key is Base64 encoded. ### Usage Example ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) // Using a plain string key handler.SetJWTKey("my-hmac-secret-key", false) // Using a Base64-encoded key handler.SetJWTKey("bXktaG1hYy1zZWNyZXQta2V5", true) http.Handle("/socket", handler) // Example JWT payload: // { // "sub": "document-id-abc", // "u": "user123", // "p": "rw", // "exp": 1700000000 // } ``` ``` -------------------------------- ### updateUser Endpoint Source: https://context7.com/smhanov/zwibserve/llms.txt Updates the permissions for all tokens belonging to a given user ID, and notifies any currently-connected clients with matching user IDs of the permission change in real time. ```APIDOC ## POST /socket (updateUser) ### Description Updates the permissions for all tokens belonging to a given user ID, and notifies any currently-connected clients with matching user IDs of the permission change in real time. ### Method POST ### Endpoint /socket ### Parameters #### Query Parameters - **method** (string) - Required - `updateUser` - **userID** (string) - Required - The ID of the user whose permissions are to be updated. - **permissions** (string) - Required - The new permissions string. An empty string revokes all access. ### Request Example ```bash # Revoke write access for a user (keep read permission) curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=updateUser" \ -d "userID=student42" \ -d "permissions=r" # Fully revoke all access curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ -d "method=updateUser" \ -d "userID=student42" \ -d "permissions=" ``` ### Response #### Success Response (200) - HTTP 200 on success. ``` -------------------------------- ### Disable WebSocket Compression Source: https://context7.com/smhanov/zwibserve/llms.txt Controls per-message WebSocket compression. Disable on Windows Server 2016 or if issues arise. ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetCompressionAllowed(false) // disable compression http.Handle("/socket", handler) ``` -------------------------------- ### Handler.SetSecretUser — Enable Management API Authentication Source: https://context7.com/smhanov/zwibserve/llms.txt Sets the HTTP Basic Auth credentials required to call management endpoints. Without calling this, the management API is disabled. ```APIDOC ## Handler.SetSecretUser — Enable Management API Authentication ### Description Sets the HTTP Basic Auth credentials required to call management endpoints (`addToken`, `deleteDocument`, `dumpDocument`, `createDocument`, `updateUser`). Without calling this, the management API is disabled. ### Method POST (for management endpoints) ### Endpoint /socket ### Parameters #### Path Parameters - **username** (string) - Required - The username for Basic Auth. - **password** (string) - Required - The password for Basic Auth. ### Request Example ```go handler := zwibserve.NewHandler(zwibserve.NewSQLITEDB("zwibbler.db")) handler.SetSecretUser("admin", "s3cr3tpassword") http.Handle("/socket", handler) // Example management call: // curl -u admin:s3cr3tpassword -X POST http://localhost:3000/socket \ // -d "method=deleteDocument&documentID=doc-abc123" ``` ### Response #### Success Response (200) - **Body**: (Indicates success of the management operation, e.g., "OK" or confirmation message) #### Error Response (401) - **Body**: "Unauthorized" (if credentials are invalid) ``` -------------------------------- ### DocumentDB.SetExpiration Source: https://context7.com/smhanov/zwibserve/llms.txt Sets how long (in seconds) an inactive document is retained before automatic deletion. Call `SetExpiration(zwibserve.NoExpiration)` or `SetExpiration(-1)` to disable expiry (the default). This method is available on all built-in `DocumentDB` implementations. ```APIDOC ## DocumentDB.SetExpiration — Document Lifetime Control Sets how long (in seconds) an inactive document is retained before automatic deletion. Call `SetExpiration(zwibserve.NoExpiration)` or `SetExpiration(-1)` to disable expiry (the default). This method is available on all built-in `DocumentDB` implementations. ```go db := zwibserve.NewSQLITEDB("zwibbler.db") db.SetExpiration(86400) // delete documents inactive for 24 hours // db.SetExpiration(zwibserve.NoExpiration) // never delete (default) handler := zwibserve.NewHandler(db) http.Handle("/socket", handler) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.