Commit 4074ed8d authored by WorldTeacher's avatar WorldTeacher
Browse files

feat(networking): connection switch

parent 9db73fed
Loading
Loading
Loading
Loading
+187 −14
Original line number Diff line number Diff line
@@ -119,13 +119,33 @@ function Settings:configureDisplayName(parent)
    input_dialog:onShowKeyboard()
end

---Settings:configureServerUrl.
function Settings:configureServerUrl(parent)
---Settings:_applyEffectiveServerUrl.
-- Recomputes the runtime effective URL on `parent` after any of the URL /
-- SSID / toggle settings change, and reinitialises the API client.
local function _applyEffectiveServerUrl(parent)
    if type(parent.resolveServerUrl) == "function" then
        parent.server_url = parent:resolveServerUrl()
    end
    if parent.api and parent.server_url and parent.server_url ~= "" then
        parent.api:init(parent.server_url, parent.username, parent.password, parent.db)
    end
end

-- Local helpers for the chained Server URL flow.
-- The flow is a single multi-step wizard:
--   step 1: Local URL          (always)
--   step 2: Home Network SSID  (only when auto-switch is enabled)
--   step 3: Remote URL         (always)
-- Each step has Back / Cancel / Next (or Save on the final step). Values
-- are committed at the very end so cancelling at any step is non-destructive.

local function _showRemoteUrlStep(self, parent, draft)
    local input_dialog
    input_dialog = InputDialog:new{
        title = _("Booklore Server URL"),
        input = parent.server_url,
        input_hint = "http://192.168.1.100:6060",
        title = _("Booklore Remote URL"),
        input = draft.remote_url,
        input_hint = "https://booklore.example.com",
        description = _("Address used when not on the home network. Leave empty if you don't need remote access."),
        buttons = {
            {
                {
@@ -134,23 +154,104 @@ function Settings:configureServerUrl(parent)
                        UIManager:close(input_dialog)
                    end,
                },
                {
                    text = _("Back"),
                    callback = function()
                        draft.remote_url = input_dialog:getInputText() or ""
                        UIManager:close(input_dialog)
                        if parent.auto_network_switch_enabled then
                            self:_showHomeSsidStep(parent, draft)
                        else
                            self:_showLocalUrlStep(parent, draft)
                        end
                    end,
                },
                {
                    text = _("Save"),
                    is_enter_default = true,
                    callback = function()
                        parent.server_url = input_dialog:getInputText():gsub("/$", "")
                        parent.settings:saveSetting("server_url", parent.server_url)
                        local local_url  = (draft.local_url or ""):gsub("/$", "")
                        local remote_url = (input_dialog:getInputText() or ""):gsub("/$", "")
                        local ssid       = draft.home_ssid or ""
                        ssid = ssid:gsub("^%s+", ""):gsub("%s+$", "")

                        parent.local_server_url  = local_url
                        parent.remote_server_url = remote_url
                        parent.home_network_ssid = ssid

                        parent.settings:saveSetting("local_server_url",  local_url)
                        parent.settings:saveSetting("remote_server_url", remote_url)
                        parent.settings:saveSetting("home_network_ssid", ssid)
                        -- Keep the legacy single-URL key in sync with the
                        -- local URL so older readers of `server_url` still
                        -- get a sane value.
                        parent.settings:saveSetting("server_url", local_url)
                        parent.settings:flush()

                        if parent.api then
                            parent.api:init(parent.server_url, parent.username, parent.password, parent.db)
                        _applyEffectiveServerUrl(parent)

                        UIManager:close(input_dialog)
                        UIManager:show(InfoMessage:new{
                            text = _("Server URLs saved"),
                            timeout = 2,
                        })
                    end,
                },
            },
        },
    }
    UIManager:show(input_dialog)
    input_dialog:onShowKeyboard()
end

function Settings:_showHomeSsidStep(parent, draft)
    local self_ref = self
    local input_dialog
    input_dialog = InputDialog:new{
        title = _("Home Network Name (SSID)"),
        input = draft.home_ssid,
        input_hint = _("e.g. MyHomeWiFi"),
        description = _("WiFi name where the local URL is reachable. Tap 'Use current network' to auto-fill from the currently connected WiFi."),
        buttons = {
            {
                {
                    text = _("Cancel"),
                    callback = function()
                        UIManager:close(input_dialog)
                    end,
                },
                {
                    text = _("Use current network"),
                    callback = function()
                        local ssid
                        if parent and type(parent.getCurrentNetworkSSID) == "function" then
                            ssid = parent:getCurrentNetworkSSID()
                        end
                        if not ssid or ssid == "" then
                            UIManager:show(InfoMessage:new{
                            text = _("Server URL saved"),
                            timeout = 1,
                                text = _("Could not detect current network. Make sure WiFi is connected."),
                                timeout = 3,
                            })
                            return
                        end
                        input_dialog:setInputText(ssid)
                    end,
                },
                {
                    text = _("Back"),
                    callback = function()
                        draft.home_ssid = input_dialog:getInputText() or ""
                        UIManager:close(input_dialog)
                        self_ref:_showLocalUrlStep(parent, draft)
                    end,
                },
                {
                    text = _("Next"),
                    is_enter_default = true,
                    callback = function()
                        draft.home_ssid = input_dialog:getInputText() or ""
                        UIManager:close(input_dialog)
                        _showRemoteUrlStep(self_ref, parent, draft)
                    end,
                },
            },
@@ -160,6 +261,55 @@ function Settings:configureServerUrl(parent)
    input_dialog:onShowKeyboard()
end

function Settings:_showLocalUrlStep(parent, draft)
    local self_ref = self
    local input_dialog
    input_dialog = InputDialog:new{
        title = _("Booklore Local URL"),
        input = draft.local_url,
        input_hint = "http://192.168.1.100:6060",
        description = _("Address used when on the home network."),
        buttons = {
            {
                {
                    text = _("Cancel"),
                    callback = function()
                        UIManager:close(input_dialog)
                    end,
                },
                {
                    text = _("Next"),
                    is_enter_default = true,
                    callback = function()
                        draft.local_url = input_dialog:getInputText() or ""
                        UIManager:close(input_dialog)
                        if parent.auto_network_switch_enabled then
                            self_ref:_showHomeSsidStep(parent, draft)
                        else
                            _showRemoteUrlStep(self_ref, parent, draft)
                        end
                    end,
                },
            },
        },
    }
    UIManager:show(input_dialog)
    input_dialog:onShowKeyboard()
end

---Settings:configureServerUrl.
-- Single chained wizard for both Server URLs (and the home WiFi SSID when
-- automatic network switching is enabled). Drafted values are only
-- persisted on the final Save, so cancelling at any step is safe.
function Settings:configureServerUrl(parent)
    local draft = {
        local_url  = parent.local_server_url  or parent.server_url or "",
        remote_url = parent.remote_server_url or "",
        home_ssid  = parent.home_network_ssid or "",
    }
    self:_showLocalUrlStep(parent, draft)
end

-- Chained dialog: Username → Next → Password → Save
---Settings:configureConnection.
function Settings:configureConnection(parent)
@@ -610,8 +760,8 @@ function Settings:buildAuthMenu(parent)
        text = _("Connection Setup"),
        sub_item_table = {
            {
                text = _("Server URL"),
                help_text = _("The URL of your Booklore server (e.g., http://192.168.1.100:6060). This is where reading sessions will be synced."),
                text = _("Server URLs"),
                help_text = _("Set the Local URL (e.g., http://192.168.1.100:6060) and the Remote URL of your Booklore server. When automatic network switching is enabled the home WiFi name is captured here too."),
                keep_menu_open = true,
                callback = function()
                    self:configureServerUrl(parent)
@@ -643,6 +793,26 @@ function Settings:buildAuthMenu(parent)
                    parent:testConnection()
                end,
            },
            {
                text = _("Automatic network switching"),
                help_text = _("When enabled the plugin uses the Local URL while connected to the configured home WiFi and the Remote URL otherwise. When disabled the Local URL is preferred (Remote is used as a fallback if Local is empty)."),
                checked_func = function()
                    return parent.auto_network_switch_enabled
                end,
                callback = function()
                    parent.auto_network_switch_enabled = not parent.auto_network_switch_enabled
                    parent.settings:saveSetting("auto_network_switch_enabled", parent.auto_network_switch_enabled)
                    parent.settings:flush()
                    _applyEffectiveServerUrl(parent)
                    UIManager:show(InfoMessage:new{
                        text = parent.auto_network_switch_enabled
                            and _("Automatic network switching enabled")
                            or  _("Automatic network switching disabled"),
                        timeout = 2,
                    })
                end,
                keep_menu_open = true,
            },
        },
    }
end
@@ -912,6 +1082,9 @@ function Settings:exportSettings(parent)
        sync_delay_after_connect_seconds = parent.sync_delay_after_connect_seconds,
        force_push_session_on_suspend = parent.force_push_session_on_suspend,
        connect_network_on_suspend    = parent.connect_network_on_suspend,
        auto_network_switch_enabled   = parent.auto_network_switch_enabled,
        -- home_network_ssid and remote_server_url intentionally excluded
        -- (treated as user-environment / sensitive deployment data).
        sync_mode                     = parent.sync_mode,
        manual_sync_only              = parent.manual_sync_only,
        rating_sync_enabled           = parent.rating_sync_enabled,
+166 −16

File changed.

Preview size limit exceeded, changes collapsed.

+15 −9
Original line number Diff line number Diff line
+++
title = "Connection Setup"
description = "Configure your BookLore server URL and login credentials."
description = "Configure local/remote server URLs and login credentials."
weight = 1
+++

@@ -14,9 +14,13 @@ Connection settings are found at:

---

## Server URL
## Server URLs

Tap **Server URL** to enter the address of your BookLore server.
Tap **Server URLs** to configure:

- **Local URL**: used on your home network.
- **Remote URL**: used away from home when automatic network switching is enabled.
- **Home SSID**: the WiFi name treated as your home network.

**Format:** `http://<host>:<port>` or `https://<host>`

@@ -24,11 +28,11 @@ Tap **Server URL** to enter the address of your BookLore server.

```
http://192.168.1.100:6060
http://booklore.local:6060
https://booklore.example.com
http://your-url.local:6060
https://domain.example.com
```

Trailing slashes are not required. The plugin will strip them automatically.
Trailing slashes are not required. The plugin strips them automatically.

> Enter only the base URL - do not append `/api` or any path. The plugin handles all API routing internally.

@@ -71,14 +75,16 @@ In most setups, the KOReader account and BookLore account are the same user. You
## Test Connection

Tap **Test Connection** to verify that:
1. The server is reachable at the configured URL.
2. The KOReader credentials are accepted.
1. The selected connection target is correct (**Local**, **Remote**, or fallback).
2. The server is reachable at the effective URL.
3. The KOReader credentials are accepted.

The button is only enabled once a server URL and username have been entered.
The button is enabled once a server URL is configured.

A successful test shows:

```
Connection type: Local
KOReader: Success
BookLore: Success
by-hash endpoint: ok
+17 −3
Original line number Diff line number Diff line
@@ -120,10 +120,24 @@ This advanced clear dialog removes **synced history records** only. Pending queu

## Clear Cache

Removes all entries from the `book_cache` table. The entry is greyed out when the cache is already empty.
Removes entries from the `book_cache` table along with all tables that reference it via foreign keys. The entry is greyed out when the cache is already empty.

The cache stores the mapping between each local file and its BookLore book ID, along with the file fingerprint and metadata such as title, author, and ISBN. Clearing it does not affect pending sessions, ratings, annotations, or bookmarks.
The following tables are cleared together (they would otherwise leave dangling foreign-key references):

The cache rebuilds automatically: the next time you open a book, the plugin recalculates its fingerprint, queries the server, and repopulates the cache entry.
- `book_cache` (rows not still referenced by pending queues)
- `synced_annotations`
- `synced_bookmarks`
- `rating_sync_history`
- `book_metadata`

> **Important:** This is a broad clear. Synced annotation/bookmark history, rating sync history, and stored book metadata are all removed.

What is **not** affected:

- Pending queues: `pending_sessions`, `pending_annotations`, `pending_ratings`, `pending_bookmarks`, `pending_koreader_progress`
- `book_cache` rows still referenced by any pending queue (these are kept to preserve queued sync data)
- `historical_sessions`

The cache rebuilds automatically: the next time you open a book, the plugin recalculates its fingerprint, queries the server, and repopulates the cache entry. Synced history tables repopulate as future sync activity occurs.

> Use this after reorganising your library (for example, after moving many files to different folders) to force the plugin to rebuild all file-path-to-book mappings cleanly. No confirmation dialog is shown - the cache is cleared immediately.
+5 −5
Original line number Diff line number Diff line
@@ -35,10 +35,10 @@ This guide helps you:

Open **Tools → BookLore Sync → Sync Behavior** and choose one mode:

- **Automatic (sync on suspend + WiFi)**
  - Queues session/progress on suspend and attempts sync on suspend/resume.
  - Suspend/resume background sync runs only when network is already connected.
  - Manual actions (for example **Sync Pending Now**) can auto-enable/connect WiFi when needed.
- **Automatic (sync on suspend when connected)**
  - Queues session/progress on suspend and attempts sync on suspend/resume **only when WiFi is already connected**.
  - Suspend/resume background sync does **not** enable WiFi; if disconnected, data stays queued for the next trigger.
  - Manual actions (for example **Sync Pending Now**) can still auto-enable/connect WiFi when invoked explicitly.

- **Manual only (cache everything)**
  - Always queues data locally.
@@ -53,7 +53,7 @@ Open **Tools → BookLore Sync → Sync Behavior → Networking**.
  - Increase on slower devices/networks.

- **Run until connect**
  - Disables plugin-side timeout and waits until WiFi connects (or network stack times out).
  - Disables plugin-side timeout and waits until WiFi connects (or KOReader/network stack times out).
  - Useful when fixed timeout is too short.

- **Sync delay after connect**
Loading