mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
179 lines
5.6 KiB
Lua
179 lines
5.6 KiB
Lua
local fs = require "nixio.fs"
|
|
local nixio = require "nixio"
|
|
|
|
local OPKG_STATUS_FILE = "/usr/lib/opkg/status"
|
|
local APK_STATUS_FILE = "/lib/apk/db/installed"
|
|
local DEFAULT_VERSION = "v0.0.0"
|
|
|
|
local M = {}
|
|
|
|
M.POINTER_KEYS = {
|
|
"active_campus_id", "default_campus_id",
|
|
"active_hotspot_id", "default_hotspot_id",
|
|
}
|
|
M.LIST_KEYS = { "campus_accounts", "hotspot_profiles" }
|
|
M.SCHOOL_EXTRA_KEY = "school_extra"
|
|
|
|
function M.normalize_ap_selection(value, bssid)
|
|
local policy = tostring(value or ""):match("^%s*(.-)%s*$"):lower()
|
|
if policy == "auto" or policy == "strongest" or policy == "fixed" then
|
|
return policy
|
|
end
|
|
return tostring(bssid or ""):match("^%s*(.-)%s*$") ~= "" and "fixed" or "auto"
|
|
end
|
|
|
|
function M.is_valid_bssid(value)
|
|
local address = tostring(value or ""):match("^%s*(.-)%s*$"):lower()
|
|
if not address:match("^%x%x:%x%x:%x%x:%x%x:%x%x:%x%x$") then return false end
|
|
return address ~= "00:00:00:00:00:00" and tonumber(address:sub(1, 2), 16) % 2 == 0
|
|
end
|
|
|
|
function M.ap_selection_label(policy)
|
|
local labels = { auto = "系统自动", strongest = "连接时信号优先", fixed = "固定 BSSID" }
|
|
return labels[tostring(policy or "")] or "未知"
|
|
end
|
|
|
|
local POINTER_KEY_SET = {}
|
|
for _, key in ipairs(M.POINTER_KEYS) do
|
|
POINTER_KEY_SET[key] = true
|
|
end
|
|
|
|
local LIST_KEY_SET = {}
|
|
for _, key in ipairs(M.LIST_KEYS) do
|
|
LIST_KEY_SET[key] = true
|
|
end
|
|
|
|
-- load_defaults prefers the daemon's own schema.
|
|
--
|
|
-- Spec 02 gives Go the types, defaults, bounds and choices and leaves the page
|
|
-- its labels, so that the two cannot disagree about what a valid value is. The
|
|
-- page reports a stopped/unavailable service when schema cannot be read; it
|
|
-- never falls back to an obsolete 1.x configuration file.
|
|
local function load_defaults()
|
|
-- One pcall around both the load and the call: on a host without nixio, or
|
|
-- with the service stopped, this must fall back rather than take the page
|
|
-- down with it.
|
|
local ok, parsed = pcall(function()
|
|
return require("luci.smart_srun.bridge").defaults()
|
|
end)
|
|
if not ok or type(parsed) ~= "table" then
|
|
parsed = {}
|
|
end
|
|
if parsed.school == nil then
|
|
parsed.school = "default"
|
|
end
|
|
|
|
local defaults = {}
|
|
for key, value in pairs(parsed) do
|
|
if not POINTER_KEY_SET[key] and not LIST_KEY_SET[key] then
|
|
defaults[key] = tostring(value or "")
|
|
end
|
|
end
|
|
return defaults
|
|
end
|
|
|
|
M.SCALAR_DEFAULTS = load_defaults()
|
|
M.GLOBAL_SCALAR_KEYS = {}
|
|
for key, _ in pairs(M.SCALAR_DEFAULTS) do
|
|
M.GLOBAL_SCALAR_KEYS[#M.GLOBAL_SCALAR_KEYS + 1] = key
|
|
end
|
|
table.sort(M.GLOBAL_SCALAR_KEYS)
|
|
|
|
function M.global_scalar_key_set()
|
|
local key_set = {}
|
|
for _, key in ipairs(M.GLOBAL_SCALAR_KEYS) do
|
|
key_set[key] = true
|
|
end
|
|
return key_set
|
|
end
|
|
|
|
function M.with_file_lock(path, callback)
|
|
local oflags = nixio.open_flags("wronly", "creat")
|
|
local lock, _, msg = nixio.open(tostring(path) .. ".lock", oflags)
|
|
if not lock then
|
|
error("Open lock failed: " .. tostring(msg or "unknown"))
|
|
end
|
|
|
|
local ok, _, lock_msg = lock:lock("lock")
|
|
if not ok then
|
|
lock:close()
|
|
error("Lock failed: " .. tostring(lock_msg or "unknown"))
|
|
end
|
|
|
|
local call_ok, a, b, c = pcall(callback)
|
|
lock:lock("ulock")
|
|
lock:close()
|
|
if not call_ok then
|
|
error(a)
|
|
end
|
|
return a, b, c
|
|
end
|
|
|
|
local function normalize_version_string(raw)
|
|
local value = tostring(raw or "")
|
|
-- opkg and APK use different native RC separators; the UI uses the same
|
|
-- display version as the Go binary and the release tag.
|
|
value = value:gsub("~rc", "rc"):gsub("_rc", "rc")
|
|
local version = value:match("^v?([0-9][%w%._%-]*)%-r?%d+$") or value:match("^v?([0-9][%w%._%-]*)$")
|
|
if version and version ~= "" then
|
|
version = version:gsub("_", "-")
|
|
local base, beta = version:match("^(.+)%-beta%.?(%d+)$")
|
|
if base and beta then
|
|
version = base .. "-b" .. beta
|
|
end
|
|
return string.format("v%s", version)
|
|
end
|
|
return DEFAULT_VERSION
|
|
end
|
|
|
|
local function read_package_status()
|
|
local text = fs.readfile(OPKG_STATUS_FILE)
|
|
if text and text ~= "" then
|
|
return text
|
|
end
|
|
return fs.readfile(APK_STATUS_FILE) or ""
|
|
end
|
|
|
|
local function package_versions()
|
|
local versions = {}
|
|
local text = read_package_status() .. "\n\n"
|
|
for block in text:gmatch("(.-)\n\n") do
|
|
local package_name = block:match("\n?Package:%s*([^\r\n]+)")
|
|
or block:match("\n?P:%s*([^\r\n]+)")
|
|
or block:match("^Package:%s*([^\r\n]+)")
|
|
or block:match("^P:%s*([^\r\n]+)")
|
|
if package_name then
|
|
versions[package_name] =
|
|
block:match("\n?Version:%s*([^\r\n]+)")
|
|
or block:match("\n?V:%s*([^\r\n]+)")
|
|
or block:match("^Version:%s*([^\r\n]+)")
|
|
or block:match("^V:%s*([^\r\n]+)")
|
|
or ""
|
|
end
|
|
end
|
|
return versions
|
|
end
|
|
|
|
function M.installed_package_name()
|
|
local versions = package_versions()
|
|
if versions["luci-app-smart-srun-bundle"] then
|
|
return "luci-app-smart-srun-bundle"
|
|
end
|
|
if versions["luci-app-smart-srun"] then
|
|
return "luci-app-smart-srun"
|
|
end
|
|
return "smart-srun"
|
|
end
|
|
|
|
function M.installed_package_display_text()
|
|
local versions = package_versions()
|
|
local package_name = M.installed_package_name()
|
|
local label = package_name == "luci-app-smart-srun-bundle" and "Bundle 版"
|
|
or package_name == "luci-app-smart-srun" and "标准版"
|
|
or "CLI 版"
|
|
local version = normalize_version_string(versions[package_name] or "")
|
|
return string.format("%s %s", label, version)
|
|
end
|
|
|
|
return M
|