### 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.