Files
koreader/plugins/zsync.koplugin/main.lua
Hans-Werner Hilse 3066c86e38 Refactoring hardware abstraction
This is a major overhaul of the hardware abstraction layer.
A few notes:

General platform distinction happens in
  frontend/device.lua
which will delegate everything else to
  frontend/device/<platform_name>/device.lua
which should extend
  frontend/device/generic/device.lua

Screen handling is implemented in
  frontend/device/screen.lua
which includes the *functionality* to support device specifics.
Actually setting up the device specific functionality, however,
is done in the device specific setup code in the relevant
device.lua file.

The same goes for input handling.
2014-11-02 21:19:04 +01:00

314 lines
9.8 KiB
Lua

local FileManagerHistory = require("apps/filemanager/filemanagerhistory")
local FileManagerMenu = require("apps/filemanager/filemanagermenu")
local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local FileManager = require("apps/filemanager/filemanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local ButtonDialog = require("ui/widget/buttondialog")
local InfoMessage = require("ui/widget/infomessage")
local TextWidget = require("ui/widget/textwidget")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local Screen = require("device").screen
local Event = require("ui/event")
local Font = require("ui/font")
local ltn12 = require("ltn12")
local DEBUG = require("dbg")
local _ = require("gettext")
local util = require("ffi/util")
-- lfs
local ffi = require("ffi")
ffi.cdef[[
int remove(const char *);
int rmdir(const char *);
]]
local dummy = require("ffi/zeromq_h")
local ZSync = InputContainer:new{
name = "zsync",
}
function ZSync:init()
self.ui.menu:registerToMainMenu(self)
self.outbox = self.path.."/outbox"
self.server_config = self.path.."/server.cfg"
self.client_config = self.path.."/client.cfg"
end
function ZSync:addToMainMenu(tab_item_table)
table.insert(tab_item_table.plugins, {
text = _("ZSync"),
sub_item_table = {
{
text_func = function()
return not self.filemq_server
and _("Publish this document")
or _("Stop publisher")
end,
enabled_func = function()
return self.filemq_client == nil
end,
callback = function()
if not self.filemq_server then
self:publish()
else
self:unpublish()
end
end
},
{
text_func = function()
return not self.filemq_client
and _("Subscribe documents")
or _("Stop subscriber")
end,
enabled_func = function()
return self.filemq_server == nil
end,
callback = function()
if not self.filemq_client then
self:subscribe()
else
self:unsubscribe()
end
end
}
}
})
end
function ZSync:initServerZyreMQ()
local ZyreMessageQueue = require("ui/message/zyremessagequeue")
if self.zyre_messagequeue == nil then
self.server_zyre = ZyreMessageQueue:new{
header = {["FILEMQ-SERVER"] = tostring(self.fmq_port)},
}
self.server_zyre:start()
self.zyre_messagequeue = UIManager:insertZMQ(self.server_zyre)
end
end
function ZSync:initClientZyreMQ()
local ZyreMessageQueue = require("ui/message/zyremessagequeue")
if self.zyre_messagequeue == nil then
self.client_zyre = ZyreMessageQueue:new{}
self.client_zyre:start()
self.zyre_messagequeue = UIManager:insertZMQ(self.client_zyre)
end
end
function ZSync:initServerFileMQ(outboxes)
local FileMessageQueue = require("ui/message/filemessagequeue")
local filemq = ffi.load("libs/libfmq.so.1")
if self.file_messagequeue == nil then
self.filemq_server = filemq.fmq_server_new()
self.file_messagequeue = UIManager:insertZMQ(FileMessageQueue:new{
server = self.filemq_server
})
self.fmq_port = filemq.fmq_server_bind(self.filemq_server, "tcp://*:*")
filemq.fmq_server_configure(self.filemq_server, self.server_config)
filemq.fmq_server_set_anonymous(self.filemq_server, true)
end
UIManager:scheduleIn(1, function()
for _, outbox in ipairs(outboxes) do
DEBUG("publish", outbox.path, outbox.alias)
filemq.fmq_server_publish(self.filemq_server, outbox.path, outbox.alias)
end
end)
end
function ZSync:initClientFileMQ(inbox)
local FileMessageQueue = require("ui/message/filemessagequeue")
local filemq = ffi.load("libs/libfmq.so.1")
if self.file_messagequeue == nil then
self.filemq_client = filemq.fmq_client_new()
self.file_messagequeue = UIManager:insertZMQ(FileMessageQueue:new{
client = self.filemq_client
})
filemq.fmq_client_configure(self.filemq_client, self.client_config)
end
UIManager:scheduleIn(1, function()
filemq.fmq_client_set_inbox(self.filemq_client, inbox)
end)
end
local function clearDirectory(dir, rmdir)
for f in lfs.dir(dir) do
local path = dir.."/"..f
local mode = lfs.attributes(path, "mode")
if mode == "file" then
ffi.C.remove(path)
elseif mode == "directory" and f ~= "." and f ~= ".." then
clearDirectory(path, true)
end
end
if rmdir then
ffi.C.rmdir(dir)
end
end
local function mklink(path, filename)
local basename = filename:match(".*/(.*)") or filename
local linkname = path .. "/" .. basename .. ".ln"
local linkfile = io.open(linkname, "w")
if linkfile then
linkfile:write(filename .. "\n")
linkfile:close()
end
end
-- add directory directly into outboxes
function ZSync:outboxesAddDirectory(outboxes, dir)
if lfs.attributes(dir, "mode") == "directory" then
local basename = dir:match(".*/(.*)") or dir
table.insert(outboxes, {
path = dir,
alias = "/"..basename,
})
end
end
-- link file in root outbox
function ZSync:outboxAddFileLink(filename)
local mode = lfs.attributes(filename, "mode")
if mode == "file" then
mklink(self.outbox, filename)
end
end
-- copy directory content into root outbox(no recursively)
function ZSync:outboxCopyDirectory(dir)
local basename = dir:match(".*/(.*)") or dir
local newdir = self.outbox.."/"..basename
lfs.mkdir(newdir)
if pcall(lfs.dir, dir) then
for f in lfs.dir(dir) do
local filename = dir.."/"..f
if lfs.attributes(filename, "mode") == "file" then
local newfile = newdir.."/"..f
ltn12.pump.all(
ltn12.source.file(assert(io.open(filename, "rb"))),
ltn12.sink.file(assert(io.open(newfile, "wb")))
)
end
end
end
end
function ZSync:publish()
DEBUG("publish document", self.view.document.file)
lfs.mkdir(self.outbox)
clearDirectory(self.outbox)
local file = self.view.document.file
local sidecar = file:match("(.*)%.")..".sdr"
self:outboxAddFileLink(file)
self:outboxCopyDirectory(sidecar)
local outboxes = {}
table.insert(outboxes, {
path = self.outbox,
alias = "/",
})
-- init filemq first to get filemq port
self:initServerFileMQ(outboxes)
self:initServerZyreMQ()
end
function ZSync:unpublish()
DEBUG("ZSync unpublish")
clearDirectory(self.outbox)
self:stopZyreMQ()
self:stopFileMQ()
end
function ZSync:onChooseInbox(inbox)
DEBUG("choose inbox", inbox)
self.inbox = inbox
-- init zyre first for filemq endpoint
self:initClientZyreMQ()
self:initClientFileMQ(inbox)
return true
end
function ZSync:subscribe()
DEBUG("subscribe documents")
self.received = {}
local zsync = self
require("ui/downloadmgr"):new{
title = _("Choose inbox"),
onConfirm = function(inbox)
G_reader_settings:saveSetting("inbox_dir", inbox)
zsync:onChooseInbox(inbox)
end,
}:chooseDir()
end
function ZSync:unsubscribe()
DEBUG("ZSync unsubscribe")
self.received = {}
self:stopFileMQ()
self:stopZyreMQ()
end
function ZSync:onZyreEnter(id, name, header, endpoint)
local filemq = ffi.load("libs/libfmq.so.1")
if header and endpoint and header["FILEMQ-SERVER"] then
self.server_zyre_endpoint = endpoint
local port = header["FILEMQ-SERVER"]
local host = endpoint:match("(.*:)") or "*:"
local fmq_server_endpoint = host..port
DEBUG("connect filemq server at", fmq_server_endpoint)
-- wait for filemq server setup befor connecting
UIManager:scheduleIn(2, function()
filemq.fmq_client_set_resync(self.filemq_client, true)
filemq.fmq_client_subscribe(self.filemq_client, "/")
filemq.fmq_client_connect(self.filemq_client, fmq_server_endpoint)
end)
end
return true
end
function ZSync:onFileDeliver(filename, fullname)
-- sometimes several FileDelever msgs are sent from filemq
if self.received[filename] then return end
UIManager:show(InfoMessage:new{
text = _("Received file:") .. "\n" .. filename,
timeout = 1,
})
self.received[filename] = true
end
--[[
-- We assume that ZSync is running in either server mode or client mode
-- but never both. The zyre_messagequeue may be a server_zyre or client_zyre.
-- And the file_messagequeue may be a filemq_server or filemq_client.
--]]
function ZSync:stopZyreMQ()
if self.zyre_messagequeue then
self.zyre_messagequeue:stop()
UIManager:removeZMQ(self.zyre_messagequeue)
self.zyre_messagequeue = nil
self.server_zyre = nil
self.client_zyre = nil
end
end
function ZSync:stopFileMQ()
if self.file_messagequeue then
self.file_messagequeue:stop()
UIManager:removeZMQ(self.file_messagequeue)
self.file_messagequeue = nil
self.filemq_server = nil
self.filemq_client = nil
end
end
function ZSync:onCloseReader()
self:stopZyreMQ()
self:stopFileMQ()
end
return ZSync