### Deploying with Docker and Bash Commands Source: https://context7.com/koreader/koreader-sync-server/llms.txt Provides scripts for quick testing, production setup with volumes, building images, Docker Compose orchestration, and verification via curl. Requires Docker installed; uses persistent volumes for logs and Redis data. Inputs are command-line flags and paths; outputs container status and health check response. Limitations: Assumes pre-built image availability and manual volume creation. ```bash # Quick test deployment docker run -d -p 7200:7200 --name=kosync koreader/kosync:latest # Production deployment with persistent volumes mkdir -p ./logs/{redis,app} ./data/redis docker run -d -p 7200:7200 \ -v `pwd`/logs/app:/app/koreader-sync-server/logs \ -v `pwd`/logs/redis:/var/log/redis \ -v `pwd`/data/redis:/var/lib/redis \ --name=kosync koreader/kosync:latest # Build custom image docker build --rm=true --tag=koreader/kosync . # Docker Compose deployment docker compose up -d --build # Verify deployment curl -k -v -H "Accept: application/vnd.koreader.v1+json" \ https://localhost:7200/healthcheck ``` -------------------------------- ### Running Busted Tests for Koreader Sync Server (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt This bash script outlines the steps to run the Busted tests for the Koreader Sync Server. It involves starting a Redis server, waiting for it to become available, and then executing the Busted test runner. An example output format is also provided. ```bash # Run tests redis-server & sleep 3 busted # Output example: # ●●●●●●●●●● # 10 successes / 0 failures / 0 errors / 0 pending : 0.123456 seconds ``` -------------------------------- ### Run Koreader Sync Server using Docker Source: https://github.com/koreader/koreader-sync-server/blob/master/README.md These commands launch the Koreader Sync Server inside Docker containers. The quick test runs a transient container, while the production command mounts Redis volumes for persistent state. Additional commands show how to build a custom image and start the service with Docker Compose. ```bash docker run -d -p 7200:7200 --name=kosync koreader/kosync:latest ``` ```bash mkdir -p ./logs/{redis,app} ./data/redis\ndocker run -d -p 7200:7200 \\n -v `pwd`/logs/app:/app/koreader-sync-server/logs \\n -v `pwd`/logs/redis:/var/log/redis \\n -v `pwd`/data/redis:/var/lib/redis \\n --name=kosync koreader/kosync:latest ``` ```bash docker build --rm=true --tag=koreader/kosync . ``` ```bash docker compose up -d --build ``` -------------------------------- ### Configuring API Routes with Lua and Gin Source: https://context7.com/koreader/koreader-sync-server/llms.txt Defines versioned HTTP routes for user management, progress synchronization, and health checks using the Gin framework. Depends on the 'gin.core.routes' module and maps paths to actions in the 'syncs' controller. Supports POST, GET, and PUT methods; no explicit inputs/outputs defined beyond standard HTTP responses. Limitations include fixed version 1 without multi-version support shown. ```lua -- config/routes.lua local routes = require 'gin.core.routes' -- Define API version 1 local v1 = routes.version(1) -- User management routes v1:POST("/users/create", { controller = "syncs", action = "create_user" }) v1:GET("/users/auth", { controller = "syncs", action = "auth_user" }) -- Progress synchronization routes v1:PUT("/syncs/progress", { controller = "syncs", action = "update_progress" }) v1:GET("/syncs/progress/:document", { controller = "syncs", action = "get_progress" }) -- Health monitoring route v1:GET("/healthcheck", { controller = "syncs", action = "healthcheck" }) return routes ``` -------------------------------- ### Testing Koreader Sync Server with Busted (Lua) Source: https://context7.com/koreader/koreader-sync-server/llms.txt This Lua script demonstrates how to test the Koreader Sync Server's controller actions using the Busted testing framework. It includes setup and teardown for Redis, and tests for user creation, document progress updates, and retrieving document progress. Assumes a running Redis instance and a 'hit' function for making requests. ```lua -- spec/controllers/1/syncs_controller_spec.lua require 'spec.spec_helper' describe("SyncsController", function() before_each(function() local redis = require("redis") local client = redis.connect("127.0.0.1", 6379) client:select(2) client:flushdb() end) it("adds new user", function() local response = hit({ scheme = "https", method = "POST", path = "/users/create", body = { username = "new-user", password = "passwd123" }, }) assert.are.same(201, response.status) assert.are.same({ username = "new-user" }, response.body) end) it("should update document progress", function() -- Register user hit({ scheme = "https", method = "POST", path = "/users/create", body = { username = "user1", password = "passwd123" }, }) -- Update progress local response = hit({ scheme = "https", method = "PUT", path = "/syncs/progress", headers = { ["x-auth-user"] = "user1", ["x-auth-key"] = "passwd123", }, body = { document = "89isjkdaj9j", progress = "56", percentage = 0.32, device = "my kpw" } }) assert.are.same(200, response.status) assert.are.same("89isjkdaj9j", response.body.document) assert.truthy(response.body.timestamp) end) it("should get document progress", function() local username, userkey, doc = "user1", "passwd123", "89isjkdaj9j" -- Register and update progress hit({ scheme = "https", method = "POST", path = "/users/create", body = { username = username, password = userkey }, }) hit({ scheme = "https", method = "PUT", path = "/syncs/progress", headers = { ["x-auth-user"] = username, ["x-auth-key"] = userkey, }, body = { document = doc, progress = "56", percentage = 0.32, device = "my kpw" } }) -- Get progress local response = hit({ scheme = "https", method = "GET", path = "/syncs/progress/" .. doc, headers = { ["x-auth-user"] = username, ["x-auth-key"] = userkey, }, }) assert.are.same(200, response.status) assert.are.same({ document = doc, percentage = 0.32, progress = "56", device = "my kpw", timestamp = response.body.timestamp }, response.body) end) end) ``` -------------------------------- ### GET /users/auth Source: https://context7.com/koreader/koreader-sync-server/llms.txt Verify user credentials using header-based authentication. The API checks the provided username and authentication key against stored credentials. ```APIDOC ## GET /users/auth ### Description Verify user credentials using header-based authentication. The API checks the provided username and authentication key against stored credentials. ### Method GET ### Endpoint /users/auth ### Parameters #### Headers - **x-auth-user** (string) - Required - The username for authentication. - **x-auth-key** (string) - Required - The authentication key (MD5 hashed password). ### Response #### Success Response (200 OK) - **authorized** (string) - Indicates successful authentication ('OK'). #### Response Example ```json { "authorized": "OK" } ``` #### Error Response (401 - Unauthorized) ```json { "code": 2001, "message": "Unauthorized" } ``` ``` -------------------------------- ### GET /healthcheck Source: https://context7.com/koreader/koreader-sync-server/llms.txt Monitor service availability and health status. This endpoint provides a simple check to confirm if the server is operational. ```APIDOC ## GET /healthcheck ### Description Monitor service availability and health status. This endpoint provides a simple check to confirm if the server is operational. ### Method GET ### Endpoint /healthcheck ### Response #### Success Response (200 OK) - **state** (string) - The current state of the service ('OK' if healthy). #### Response Example ```json { "state": "OK" } ``` ``` -------------------------------- ### GET /syncs/progress/{document_hash} Source: https://context7.com/koreader/koreader-sync-server/llms.txt Retrieve the current reading progress for a specific document identified by its MD5 hash. Returns the last known reading progress data for the document. ```APIDOC ## GET /syncs/progress/{document_hash} ### Description Retrieve the current reading progress for a specific document identified by its MD5 hash. Returns the last known reading progress data for the document. ### Method GET ### Endpoint /syncs/progress/{document_hash} ### Parameters #### Path Parameters - **document_hash** (string) - Required - The MD5 hash of the document whose progress is to be retrieved. #### Headers - **x-auth-user** (string) - Required - The username for authentication. - **x-auth-key** (string) - Required - The authentication key (MD5 hashed password). ### Response #### Success Response (200 OK) - **document** (string) - The MD5 hash of the document. - **percentage** (number) - The reading progress percentage. - **progress** (string) - The specific progress marker within the document. - **device** (string) - The name of the device. - **device_id** (string) - A unique identifier for the device. - **timestamp** (integer) - The Unix timestamp when the progress was last updated. #### Response Example (with data) ```json { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345", "timestamp": 1699632145 } ``` #### Response Example (document not found) ```json {} ``` ``` -------------------------------- ### Health Check API Endpoint (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Checks the health and availability status of the Koreader Sync Server. It's a simple GET request that returns a JSON object indicating the server's state, typically 'OK' on success. ```bash # Check server health curl -k -X GET https://localhost:7200/healthcheck \ -H "Accept: application/vnd.koreader.v1+json" # Success response (200 OK) { "state": "OK" } ``` -------------------------------- ### POST /users/create Source: https://context7.com/koreader/koreader-sync-server/llms.txt Register a new user account with username and password for accessing the sync service. Passwords should be MD5 hashed on the client side. ```APIDOC ## POST /users/create ### Description Register a new user account with username and password for accessing the sync service. ### Method POST ### Endpoint /users/create ### Parameters #### Request Body - **username** (string) - Required - The desired username. - **password** (string) - Required - The MD5 hashed password. ### Request Example ```json { "username": "johndoe", "password": "5f4dcc3b5aa765d61d8327deb882cf99" } ``` ### Response #### Success Response (201 Created) - **username** (string) - The username of the newly created account. #### Response Example ```json { "username": "johndoe" } ``` #### Error Response (402 - Username already exists) ```json { "code": 2002, "message": "Username is already registered." } ``` #### Error Response (403 - Invalid fields) ```json { "code": 2003, "message": "Invalid request" } ``` ``` -------------------------------- ### Managing Redis Schema with Commands Source: https://context7.com/koreader/koreader-sync-server/llms.txt Outlines key patterns for user authentication (SET) and document progress (HSET/HGETALL) storage, with environment-specific database selection (SELECT). Uses Redis hashes for progress data including percentage, position, device info, and timestamps. Inputs are key-value pairs; outputs stored data or fields. Limitations: MD5-based document keys and fixed DB indices per environment. ```redis # User authentication key # Format: user:{username}:key # Example: SET user:johndoe:key "5f4dcc3b5aa765d61d8327deb882cf99" # Document progress hash # Format: user:{username}:document:{document_md5} # Example: HSET user:johndoe:document:0b229176d4e8db7f6d2b5a4952368d7a \ percentage "0.4523" \ progress "/body/DocFragment[20]/body/p[22]/img.0" \ device "PocketBook" \ device_id "pb-12345" \ timestamp "1699632145" # Retrieve all progress fields HGETALL user:johndoe:document:0b229176d4e8db7f6d2b5a4952368d7a # Database separation by environment # Development: DB 1 # Test: DB 2 # Production: DB 3 SELECT 3 ``` -------------------------------- ### User Management API Source: https://context7.com/koreader/koreader-sync-server/llms.txt Endpoints for managing users, including creation and authentication. ```APIDOC ## POST /users/create ### Description Creates a new user account. ### Method POST ### Endpoint /v1/users/create ### Parameters #### Request Body - **username** (string) - Required - The desired username. - **password** (string) - Required - The user's password. ### Request Example ```json { "username": "johndoe", "password": "securepassword" } ``` ### Response #### Success Response (201) - **message** (string) - Indicates successful user creation. #### Response Example ```json { "message": "User created successfully." } ``` ## GET /users/auth ### Description Authenticates a user. ### Method GET ### Endpoint /v1/users/auth ### Parameters #### Query Parameters - **username** (string) - Required - The username to authenticate. - **password** (string) - Required - The user's password. ### Response #### Success Response (200) - **token** (string) - Authentication token for the user. #### Response Example ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ``` -------------------------------- ### Create User Account API Endpoint (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Registers a new user account for the sync service. It requires a username and an MD5-hashed password. The endpoint returns the username on success or an error code for existing usernames or invalid fields. ```bash # Register a new user curl -k -X POST https://localhost:7200/users/create \ -H "Accept: application/vnd.koreader.v1+json" \ -H "Content-Type: application/json" \ -d '{ "username": "johndoe", "password": "5f4dcc3b5aa765d61d8327deb882cf99" }' # Success response (201 Created) { "username": "johndoe" } # Error response - username already exists (402) { "code": 2002, "message": "Username is already registered." } # Error response - invalid fields (403) { "code": 2003, "message": "Invalid request" } ``` -------------------------------- ### Redis Connection Management (Lua) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Initializes a Redis connection using environment-specific settings. It handles connection establishment, timeout, and database selection. This module is designed to be part of the Gin framework for use within controllers. ```lua -- db/redis.lua - Redis connection initialization local Redis = require 'gin.core.gin' local DbSettings = { production = { host = "127.0.0.1", port = 6379, database = 3, pool = 5 } } function Redis:new() local redis = require("resty.redis") local option = DbSettings[Gin.env] local red = redis:new() red:set_timeout(1000) -- 1 sec local ok, err = red:connect(option.host, option.port) if ok then red:select(option.database) return red end end -- Controller usage function SyncsController:getRedis() local redis = Redis:new() if not redis then self:raise_error(1000) -- Cannot connect to redis server else return redis end end ``` -------------------------------- ### Progress Synchronization API Source: https://context7.com/koreader/koreader-sync-server/llms.txt Endpoints for synchronizing reading progress across devices. ```APIDOC ## PUT /syncs/progress ### Description Updates the reading progress for a document. ### Method PUT ### Endpoint /v1/syncs/progress ### Parameters #### Request Body - **document** (string) - Required - MD5 hash of the document. - **percentage** (number) - Required - Reading progress percentage (0.0 to 1.0). - **progress** (string) - Optional - Current reading position within the document. - **device** (string) - Optional - Name of the device. - **device_id** (string) - Optional - Unique identifier for the device. ### Request Example ```json { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345" } ``` ### Response #### Success Response (200) - **message** (string) - Indicates successful update. #### Response Example ```json { "message": "Progress updated successfully." } ``` ## GET /syncs/progress/:document ### Description Retrieves the reading progress for a specific document. ### Method GET ### Endpoint /v1/syncs/progress/:document ### Parameters #### Path Parameters - **document** (string) - Required - MD5 hash of the document. ### Response #### Success Response (200) - **percentage** (number) - Reading progress percentage. - **progress** (string) - Current reading position within the document. - **device** (string) - Name of the device. - **device_id** (string) - Unique identifier for the device. - **timestamp** (string) - Timestamp of the last update. #### Response Example ```json { "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345", "timestamp": "1699632145" } ``` ``` -------------------------------- ### Register New User Account with Redis Source: https://context7.com/koreader/koreader-sync-server/llms.txt Creates new user accounts in Redis, preventing duplicates and validating input fields. It checks for valid username and password, then attempts to set the user's credentials in Redis, returning appropriate success or error messages. ```lua -- app/controllers/1/syncs_controller.lua function SyncsController:create_user() local redis = self:getRedis() if not is_valid_key_field(self.request.body.username) or not is_valid_field(self.request.body.password) then self:raise_error(self.error_invalid_fields) end local user_key = string.format(self.user_key, self.request.body.username) local user, err = redis:get(user_key) if user == null then ok, err = redis:set(user_key, self.request.body.password) if not ok then self:raise_error(self.error_internal) else return 201, { username = self.request.body.username } end elseif user then self:raise_error(self.error_user_exists) else self:raise_error(self.error_internal) end end ``` -------------------------------- ### Authenticate User API Endpoint (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Verifies user credentials for accessing the sync service. Authentication is performed using custom headers containing the username and MD5-hashed key. It returns an 'OK' status on successful authentication or an unauthorized error. ```bash # Authenticate with valid credentials curl -k -X GET https://localhost:7200/users/auth \ -H "Accept: application/vnd.koreader.v1+json" \ -H "x-auth-user: johndoe" \ -H "x-auth-key: 5f4dcc3b5aa765d61d8327deb882cf99" # Success response (200 OK) { "authorized": "OK" } # Error response - unauthorized (401) { "code": 2001, "message": "Unauthorized" } ``` -------------------------------- ### Traefik v3 Reverse Proxy Configuration for Koreader Sync Server (YAML) Source: https://context7.com/koreader/koreader-sync-server/llms.txt This YAML configuration demonstrates setting up Traefik v3 as a reverse proxy for the Koreader Sync Server. It specifies the service image, volume mounts for logs and data, and Traefik routing rules based on the host. The server port is configured to 17200. ```yaml # Traefik v3 example configuration services: kosync: image: koreader/kosync:latest volumes: - ./logs/app:/app/koreader-sync-server/logs - ./logs/redis:/var/log/redis - ./data/redis:/var/lib/redis labels: - traefik.enable=true - 'traefik.http.routers.kosync.rule=Host(`kosync.example.com`)' - 'traefik.http.services.kosync.loadbalancer.server.port=17200' ``` -------------------------------- ### Update Reading Progress API Endpoint (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Synchronizes the current reading progress for a specific document across devices. It requires the document's MD5 hash, reading percentage, progress marker, device name, and device ID. The endpoint returns the document hash and a timestamp on success or error messages for missing or invalid fields. ```bash # Update progress for a document curl -k -X PUT https://localhost:7200/syncs/progress \ -H "Accept: application/vnd.koreader.v1+json" \ -H "Content-Type: application/json" \ -H "x-auth-user: johndoe" \ -H "x-auth-key: 5f4dcc3b5aa765d61d8327deb882cf99" \ -d '{ "document": "0b229176d4e8db7f6d2b5a4952368d7a", "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345" }' # Success response (200 OK) { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "timestamp": 1699632145 } # Error response - missing document field (403) { "code": 2004, "message": "Field 'document' not provided." } # Error response - invalid fields (403) { "code": 2003, "message": "Invalid request" } ``` -------------------------------- ### Retrieve Reading Progress API Endpoint (Bash) Source: https://context7.com/koreader/koreader-sync-server/llms.txt Retrieves the current reading progress for a specified document identified by its MD5 hash. It requires user authentication via custom headers. The endpoint returns the document's progress details or an empty object if the document is not found. ```bash # Retrieve progress for a document curl -k -X GET https://localhost:7200/syncs/progress/0b229176d4e8db7f6d2b5a4952368d7a \ -H "Accept: application/vnd.koreader.v1+json" \ -H "x-auth-user: johndoe" \ -H "x-auth-key: 5f4dcc3b5aa765d61d8327deb882cf99" # Success response with data (200 OK) { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345", "timestamp": 1699632145 } # Response when document not found (200 OK) {} ``` -------------------------------- ### Retrieve Document Reading Progress from Redis Source: https://context7.com/koreader/koreader-sync-server/llms.txt Retrieves all progress fields for a specific document using multi-field hash retrieval from Redis. It first authorizes the user and then fetches the progress data, mapping the Redis results to a response object. ```lua -- app/controllers/1/syncs_controller.lua function SyncsController:get_progress() local redis = self:getRedis() local username = self:authorize() if not username then self:raise_error(self.error_unauthorized_user) end local doc = self.params.document if not is_valid_key_field(doc) then self:raise_error(self.error_document_field_missing) end local key = string.format(self.doc_key, username, doc) local res = {} local results, err = redis:hmget(key, self.percentage_field, self.progress_field, self.device_field, self.device_id_field, self.timestamp_field) if err then self:raise_error(self.error_internal) end if results[1] and results[1] ~= null then res.percentage = tonumber(results[1]) end if results[2] and results[2] ~= null then res.progress = results[2] end if results[3] and results[3] ~= null then res.device = results[3] end if results[4] and results[4] ~= null then res.device_id = results[4] end if results[5] and results[5] ~= null then res.timestamp = tonumber(results[5]) end if next(res) then res.document = doc end return 200, res end ``` -------------------------------- ### Configure Traefik reverse proxy for Koreader Sync Server Source: https://github.com/koreader/koreader-sync-server/blob/master/README.md Sample Traefik v3 labels to expose the Koreader Sync Server through a reverse proxy. The service runs on port 17200, allowing Traefik to handle TLS termination. ```bash kosync:\n # ...\n labels:\n - traefik.enable=true\n - 'traefik.http.routers.kosync.rule=Host(`kosync.example.com`)' - 'traefik.http.services.kosync.loadbalancer.server.port=17200' ``` -------------------------------- ### Nginx Reverse Proxy Configuration for Koreader Sync Server Source: https://context7.com/koreader/koreader-sync-server/llms.txt This Nginx configuration sets up a reverse proxy for the Koreader Sync Server, handling TLS termination. It defines an upstream server, listens on port 443 with SSL and HTTP/2, and proxies requests to the upstream while forwarding essential headers like Host, Real-IP, and Forwarded-For. ```nginx # Nginx reverse proxy example upstream kosync { server localhost:17200; } server { listen 443 ssl http2; server_name kosync.example.com; ssl_certificate /etc/letsencrypt/live/kosync.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/kosync.example.com/privkey.pem; location / { proxy_pass http://kosync; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` -------------------------------- ### PUT /syncs/progress Source: https://context7.com/koreader/koreader-sync-server/llms.txt Synchronize current reading progress for a document across devices. This endpoint updates the reading percentage, position marker, device information, and timestamp for a given document. ```APIDOC ## PUT /syncs/progress ### Description Synchronize current reading progress for a document across devices. This endpoint updates the reading percentage, position marker, device information, and timestamp for a given document. ### Method PUT ### Endpoint /syncs/progress ### Parameters #### Headers - **x-auth-user** (string) - Required - The username for authentication. - **x-auth-key** (string) - Required - The authentication key (MD5 hashed password). #### Request Body - **document** (string) - Required - The MD5 hash of the document. - **percentage** (number) - Required - The reading progress percentage (0.0 to 1.0). - **progress** (string) - Optional - The specific progress marker within the document. - **device** (string) - Required - The name of the device. - **device_id** (string) - Required - A unique identifier for the device. ### Request Example ```json { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "percentage": 0.4523, "progress": "/body/DocFragment[20]/body/p[22]/img.0", "device": "PocketBook", "device_id": "pb-12345" } ``` ### Response #### Success Response (200 OK) - **document** (string) - The MD5 hash of the document. - **timestamp** (integer) - The Unix timestamp when the progress was updated. #### Response Example ```json { "document": "0b229176d4e8db7f6d2b5a4952368d7a", "timestamp": 1699632145 } ``` #### Error Response (403 - Missing document field) ```json { "code": 2004, "message": "Field 'document' not provided." } ``` #### Error Response (403 - Invalid fields) ```json { "code": 2003, "message": "Invalid request" } ``` ``` -------------------------------- ### Store Document Reading Progress in Redis Source: https://context7.com/koreader/koreader-sync-server/llms.txt Stores document reading progress using Redis hash structures. It first authorizes the user and then updates the progress fields (percentage, progress, device, device_id, timestamp) for a given document. It handles potential errors during the process. ```lua -- app/controllers/1/syncs_controller.lua function SyncsController:update_progress() local redis = self:getRedis() local username = self:authorize() if not username then self:raise_error(self.error_unauthorized_user) end local doc = self.request.body.document if not is_valid_key_field(doc) then self:raise_error(self.error_document_field_missing) end local percentage = tonumber(self.request.body.percentage) local progress = self.request.body.progress local device = self.request.body.device local device_id = self.request.body.device_id local timestamp = os.time() if percentage and progress and device then local key = string.format(self.doc_key, username, doc) local ok, err = redis:hmset(key, { [self.percentage_field] = percentage, [self.progress_field] = progress, [self.device_field] = device, [self.device_id_field] = device_id, [self.timestamp_field] = timestamp, }) if not ok then self:raise_error(self.error_internal) end return 200, { document = doc, timestamp = timestamp, } else self:raise_error(self.error_invalid_fields) end end ``` -------------------------------- ### Verify Sync Server health endpoint Source: https://github.com/koreader/koreader-sync-server/blob/master/README.md Use this curl command to check that the sync server is reachable and returning a healthy status. The request includes the required Accept header and trusts the self‑signed certificate. ```bash curl -k -v -H "Accept: application/vnd.koreader.v1+json" https://localhost:7200/healthcheck\n# should return {"state":"OK"} ``` -------------------------------- ### Defining Errors with Lua Error Codes Source: https://context7.com/koreader/koreader-sync-server/llms.txt Centralizes error definitions mapping custom codes to HTTP status codes and messages for consistent handling. Used in controllers via 'raise_error' method to trigger responses like 401 Unauthorized. Covers connection issues, authentication, and validation errors; no external dependencies. Limitations: Static table without dynamic error generation. ```lua -- config/errors.lua local Errors = { [1000] = { status = 502, message = "Cannot connect to redis server." }, [2000] = { status = 502, message = "Unknown server error." }, [2001] = { status = 401, message = "Unauthorized" }, [2002] = { status = 402, message = "Username is already registered." }, [2003] = { status = 403, message = "Invalid request" }, [2004] = { status = 403, message = "Field 'document' not provided." }, } return Errors -- Usage in controllers self:raise_error(2001) -- Raises 401 Unauthorized error ``` -------------------------------- ### Health Monitoring API Source: https://context7.com/koreader/koreader-sync-server/llms.txt Endpoint for checking the health status of the sync server. ```APIDOC ## GET /healthcheck ### Description Checks the operational status of the KOReader Sync Server. ### Method GET ### Endpoint /v1/healthcheck ### Response #### Success Response (200) - **status** (string) - Indicates the server is running ('OK'). #### Response Example ```json { "status": "OK" } ``` ``` -------------------------------- ### Authenticate User Credentials with Redis Source: https://context7.com/koreader/koreader-sync-server/llms.txt Validates user credentials provided in request headers against authentication data stored in Redis. It checks for the presence and validity of 'x-auth-user' and 'x-auth-key' headers and compares the provided key with the one stored in Redis for the given user. ```lua -- app/controllers/1/syncs_controller.lua function SyncsController:authorize() local redis = self:getRedis() local auth_user = self.request.headers['x-auth-user'] local auth_key = self.request.headers['x-auth-key'] if is_valid_field(auth_key) and is_valid_key_field(auth_user) then local key, err = redis:get(string.format(self.user_key, auth_user)) if auth_key == key then return auth_user end end end -- Helper functions for validation local function is_valid_field(field) return type(field) == "string" and string.len(field) > 0 end local function is_valid_key_field(field) return is_valid_field(field) and not string.find(field, ":") end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.