irc: persist per-target history to files; preload last lines on switch

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-09-20 01:52:54 +03:00
parent f6d82336ca
commit 8ec5f38d07

View File

@@ -17,6 +17,7 @@ local socket = require("socket")
local socketutil = require("socketutil")
local _ = require("gettext")
local T = require("ffi/util").template
local lfs = require("libs/libkoreader-lfs")
-- Chat view based on TextViewer for scrollable text & menu buttons
local IrcChatView = TextViewer:extend{
@@ -38,6 +39,10 @@ local IrcChatView = TextViewer:extend{
_current_target = nil, -- active target ("*" for server console)
_server_label = nil,
_unread = nil, -- map target => count of unseen messages
-- History persistence
_history_dir = nil,
_history_server_dir = nil,
_history_preload_lines = 500,
}
function IrcChatView:init()
@@ -64,6 +69,8 @@ function IrcChatView:init()
self._current_target = nil
self._server_label = self._server and (self._server.name or (self._server.host .. ":" .. tostring(self._server.port or 6667))) or "IRC"
self._unread = {}
-- Init history before selecting initial buffer
self:initHistory()
-- default to server console target
self:switchTarget("*")
self:updateTitle()
@@ -72,6 +79,75 @@ function IrcChatView:init()
UIManager:nextTick(function() self:startConnection() end)
end
-- History helpers
function IrcChatView:sanitizePathPart(part)
part = part or ""
part = part:gsub("[^%w%._%-#@]+", "_")
if part == "" then part = "_" end
return part
end
function IrcChatView:getServerId()
local name = self._server and (self._server.name or "") or ""
local host = self._server and (self._server.host or "") or ""
local port = self._server and tostring(self._server.port or 6667) or "6667"
local id = string.format("%s_%s_%s", name, host, port)
return self:sanitizePathPart(id)
end
function IrcChatView:initHistory()
self._history_dir = DataStorage:getDataDir() .. "/irc_logs"
lfs.mkdir(self._history_dir)
self._history_server_dir = self._history_dir .. "/" .. self:getServerId()
lfs.mkdir(self._history_server_dir)
end
function IrcChatView:getLogPath(target)
target = target or "*"
local fname = target == "*" and "console" or self:sanitizePathPart(target)
return string.format("%s/%s.log", self._history_server_dir, fname)
end
function IrcChatView:writeHistory(target, line)
local path = self:getLogPath(target)
local f = io.open(path, "a")
if f then
f:write(line, "\n")
f:close()
end
end
function IrcChatView:readLastLines(path, max_lines)
local f = io.open(path, "r")
if not f then return nil end
local buf = {}
local count = 0
for l in f:lines() do
table.insert(buf, l)
count = count + 1
if count > max_lines then
table.remove(buf, 1)
count = count - 1
end
end
f:close()
if #buf == 0 then return nil end
return table.concat(buf, "\n")
end
function IrcChatView:preloadHistory(target)
target = target or self._current_target or "*"
if self._buffers[target] and #self._buffers[target] > 0 then return end
local path = self:getLogPath(target)
local content = self:readLastLines(path, self._history_preload_lines)
if content and #content > 0 then
self._buffers[target] = content
if target == (self._current_target or "*") and self.scroll_text_w and self.scroll_text_w.text_widget then
self.scroll_text_w.text_widget:setText(content)
end
end
end
function IrcChatView:updateTitle()
local tgt = self._current_target
local new_title
@@ -106,6 +182,8 @@ end
function IrcChatView:switchTarget(target)
if not target then return end
self:ensureBuffer(target)
-- Preload history (if any) when switching to a buffer
self:preloadHistory(target)
self._current_target = target
self:updateTitle()
if self.scroll_text_w and self.scroll_text_w.text_widget then
@@ -124,6 +202,8 @@ function IrcChatView:appendLine(line, target)
local buf = self._buffers[target]
buf = (buf and #buf > 0) and (buf .. "\n" .. prefix .. line) or (prefix .. line)
self._buffers[target] = buf
-- Persist to history
self:writeHistory(target, prefix .. line)
if target == (self._current_target or "*") then
if self.scroll_text_w and self.scroll_text_w.text_widget then
self.scroll_text_w.text_widget:setText(buf)