update documents
This commit is contained in:
+242
@@ -0,0 +1,242 @@
|
||||
# collab-go
|
||||
|
||||
WebSocket gateway for real-time collaborative document editing. Authenticates JWT tokens and proxies collaboration traffic to `collab-core`.
|
||||
|
||||
## Overview
|
||||
|
||||
`collab-go` is a Go service that acts as the entry point for browser WebSocket connections in the Yoresee Doc collaborative editing platform. It handles:
|
||||
|
||||
- JWT token validation (HS256/384/512)
|
||||
- Document existence verification via gRPC to backend
|
||||
- Bidirectional WebSocket proxy to `collab-core` (Node.js Yjs service)
|
||||
- Health checks and graceful shutdown
|
||||
|
||||
## Connection Flow
|
||||
|
||||
```
|
||||
Browser --ws://host/ws/doc/{docId}?token={jwt}--> collab-go --> collab-core
|
||||
```
|
||||
|
||||
1. Browser connects to `/ws/doc/{docId}` with JWT in query parameter
|
||||
2. `collab-go` validates the JWT token
|
||||
3. `collab-go` calls backend gRPC `DocumentService.GetDocumentSettings()` to verify document exists
|
||||
4. On success, upgrades HTTP to WebSocket
|
||||
5. Dials `collab-core` at `{COLLAB_CORE_URL}/doc-{docId}`
|
||||
6. Proxies messages bidirectionally between browser and `collab-core`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Proto Stubs
|
||||
|
||||
`pkg/gen/` contains generated protobuf code and is gitignored. You must generate it before building:
|
||||
|
||||
```bash
|
||||
# Recommended: use parent repo script
|
||||
bash ../deploy/script/gen_proto.sh
|
||||
|
||||
# Or manual protoc
|
||||
mkdir -p pkg/gen
|
||||
protoc -I ../proto \
|
||||
--go_out=pkg/gen --go_opt=paths=source_relative \
|
||||
--go-grpc_out=pkg/gen --go-grpc_opt=paths=source_relative \
|
||||
../proto/yoresee_doc/v1/yoresee_doc.proto
|
||||
```
|
||||
|
||||
Required tools:
|
||||
- `protoc-gen-go`: `go install google.golang.org/protobuf/cmd/protoc-gen-go@latest`
|
||||
- `protoc-gen-go-grpc`: `go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest`
|
||||
|
||||
### Go
|
||||
|
||||
Go 1.24 or later.
|
||||
|
||||
## Build & Run
|
||||
|
||||
```bash
|
||||
# Build
|
||||
go build -o collab-go main.go
|
||||
|
||||
# Run
|
||||
./collab-go
|
||||
```
|
||||
|
||||
Or directly:
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
|
||||
Default port: `1234`
|
||||
|
||||
## Configuration
|
||||
|
||||
Environment variables:
|
||||
|
||||
| Variable | Default | Required | Description |
|
||||
|----------|---------|----------|-------------|
|
||||
| `ADDR` | `:1234` | No | Listen address |
|
||||
| `JWT_SECRET` | _(empty)_ | Yes | JWT signing secret. Empty = accept any parseable JWT (dev mode) |
|
||||
| `COLLAB_CORE_URL` | `ws://collab-core:1234` | No | WebSocket URL for `collab-core` |
|
||||
| `BACKEND_GRPC_ADDR` | `backend:9090` | No | gRPC address for backend service |
|
||||
| `INTERNAL_RPC_KEY` | _(empty)_ | No | Sent as `x-internal-key` gRPC metadata for internal auth |
|
||||
|
||||
### JWT Modes
|
||||
|
||||
**Production mode** (with `JWT_SECRET`):
|
||||
- Validates JWT signature using HS256/384/512
|
||||
- Token must be valid and properly signed
|
||||
|
||||
**Development mode** (empty `JWT_SECRET`):
|
||||
- Parses JWT but does not verify signature
|
||||
- Accepts any structurally valid JWT
|
||||
- Useful for local development without shared secrets
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### WebSocket
|
||||
|
||||
```
|
||||
GET /ws/doc/{docId}?token={jwt}
|
||||
```
|
||||
|
||||
- Upgrades to WebSocket on success
|
||||
- Returns `401 Unauthorized` if JWT is invalid
|
||||
- Returns `404 Not Found` if document doesn't exist
|
||||
- Returns `503 Service Unavailable` if backend gRPC is unreachable
|
||||
|
||||
### Health Probes
|
||||
|
||||
```
|
||||
GET /health
|
||||
GET /readyz
|
||||
GET /livez
|
||||
```
|
||||
|
||||
All return JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"detail": "",
|
||||
"backend": "ok"
|
||||
}
|
||||
```
|
||||
|
||||
- `/health`: Always returns `200 OK`. Includes backend status if available.
|
||||
- `/readyz`: Returns `503 Service Unavailable` during shutdown draining or if backend is unhealthy.
|
||||
- `/livez`: Always returns `200 OK`. Used for liveness checks.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
collab-go/
|
||||
├── auth/ JWT validation
|
||||
├── config/ Environment-based configuration
|
||||
├── handler/ WebSocket handler, auth + doc check + proxy
|
||||
├── health/ Health probe handlers
|
||||
├── proxy/ Bidirectional WebSocket proxy
|
||||
├── pkg/gen/ Generated protobuf stubs (gitignored)
|
||||
└── main.go Entry point
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
**auth/**
|
||||
- `Authenticator` validates JWT tokens
|
||||
- Supports HS256, HS384, HS512 signing methods
|
||||
- Falls back to unverified parsing when secret is empty
|
||||
|
||||
**config/**
|
||||
- Uses `caarlos0/env/v11` for environment variable parsing
|
||||
- All configuration via environment variables
|
||||
|
||||
**handler/**
|
||||
- `WSHandler` implements `http.Handler` for WebSocket connections
|
||||
- Validates JWT from `?token=` query parameter
|
||||
- Calls backend gRPC to verify document exists
|
||||
- Upgrades connection and delegates to proxy
|
||||
|
||||
**health/**
|
||||
- Implements Kubernetes-style health probes
|
||||
- Readiness checks backend gRPC health
|
||||
- Supports graceful shutdown draining
|
||||
|
||||
**proxy/**
|
||||
- `Proxy` manages WebSocket connection to `collab-core`
|
||||
- `ProxyWS` runs two goroutines for bidirectional message forwarding
|
||||
- Connection path: `/doc-{docId}` on `collab-core`
|
||||
|
||||
## Graceful Shutdown
|
||||
|
||||
On receiving `SIGINT` or `SIGTERM`:
|
||||
|
||||
1. Sets health checker to draining mode (readiness returns `not_ready`)
|
||||
2. Stops accepting new connections
|
||||
3. Waits up to 15 seconds for existing connections to close
|
||||
4. Exits
|
||||
|
||||
Load balancers should stop routing traffic when `/readyz` returns non-200.
|
||||
|
||||
## Docker
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
docker build -t collab-go-dev -f Dockerfile .
|
||||
docker run -p 1234:1234 --env-file .env collab-go-dev
|
||||
```
|
||||
|
||||
Runs `go run main.go` (no build cache).
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
# Build from parent directory
|
||||
docker build -t collab-go -f Dockerfile.prod ..
|
||||
```
|
||||
|
||||
Note: `Dockerfile.prod` expects build context at parent directory (`..`) because it copies:
|
||||
- `collab-go/` source
|
||||
- `proto/` for protobuf generation
|
||||
- Generates proto stubs inside the container
|
||||
|
||||
Multi-stage build:
|
||||
1. Builder stage: generates proto stubs, compiles binary
|
||||
2. Runner stage: copies binary to minimal Alpine image
|
||||
|
||||
## Integration with Collab Stack
|
||||
|
||||
`collab-go` is part of a two-service collaboration stack:
|
||||
|
||||
1. **collab-core** (Node.js): Maintains Yjs document state in memory + Redis
|
||||
2. **collab-go** (Go): WebSocket gateway, auth, proxy
|
||||
|
||||
The gateway pattern separates:
|
||||
- Authentication and authorization (Go, fast)
|
||||
- Document state management (Node.js, Yjs runtime)
|
||||
- Horizontal scaling (multiple gateway instances, single core per doc)
|
||||
|
||||
## Logging
|
||||
|
||||
All logs use prefix `collab-gateway`:
|
||||
|
||||
```
|
||||
collab-gateway listening on :1234
|
||||
collab-gateway unauthorized path=/ws/doc/abc remote=127.0.0.1:12345 err=...
|
||||
collab-gateway doc check failed docID=abc err=...
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
No tests currently exist. Verify with:
|
||||
|
||||
```bash
|
||||
go vet ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- Parent project: `../AGENTS.md`
|
||||
- Full system docs: `../../docs/README.md`
|
||||
- Chinese version: `../../docs/README_zh.md`
|
||||
Reference in New Issue
Block a user