mirror of
https://github.com/kiddin9/openwrt-packages.git
synced 2025-01-09 10:27:29 +08:00
🛸 Sync 2022-07-15 01:22:56
This commit is contained in:
parent
2cdea085e6
commit
3652b84ffb
101
homebox/Makefile
Normal file
101
homebox/Makefile
Normal file
@ -0,0 +1,101 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=homebox
|
||||
PKG_VERSION:=0.0.0-dev.2020062901
|
||||
PKG_RELEASE:=11
|
||||
|
||||
PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_GIT_URL:=github.com/XGHeaven/homebox
|
||||
PKG_GIT_REF:=v$(PKG_VERSION)
|
||||
PKG_SOURCE_URL:=https://codeload.$(PKG_GIT_URL)/tar.gz/$(PKG_GIT_REF)?
|
||||
PKG_HASH:=skip
|
||||
|
||||
PKG_BUILD_DEPENDS:=golang/host homebox/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
|
||||
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/${PKG_NAME}
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=A Toolbox for Home Local Networks
|
||||
URL:=https://github.com/XGHeaven/homebox
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS)
|
||||
MENU:=1
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
A Toolbox for Home Local Networks Speed Test
|
||||
endef
|
||||
|
||||
GO_PKG_BUILD_VARS += GO111MODULE=auto
|
||||
TAR_OPTIONS:=--strip-components 1 $(TAR_OPTIONS)
|
||||
TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS)
|
||||
|
||||
define Build/Configure
|
||||
( \
|
||||
cd $(PKG_BUILD_DIR)/server; \
|
||||
$(GO_PKG_VARS) \
|
||||
go get -d -modcacherw; \
|
||||
)
|
||||
( \
|
||||
cd $(PKG_BUILD_DIR)/server; \
|
||||
GOPATH=$(PKG_BUILD_DIR)/.go_work/build \
|
||||
go install -modcacherw github.com/go-bindata/go-bindata/...@latest; \
|
||||
)
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
rm -rf $(PKG_BUILD_DIR)/build/static
|
||||
mkdir -p $(PKG_BUILD_DIR)/build
|
||||
$(CP) $(HOST_BUILD_DIR)/build/static $(PKG_BUILD_DIR)/build/
|
||||
( \
|
||||
cd $(PKG_BUILD_DIR); \
|
||||
$(GO_PKG_VARS) PATH=$(PKG_BUILD_DIR)/.go_work/build/bin:$$$$PATH \
|
||||
$(MAKE) build-server; \
|
||||
)
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin $(1)/etc/config $(1)/etc/init.d $(1)/etc/uci-defaults
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/build/server $(1)/usr/bin/homebox
|
||||
$(INSTALL_CONF) ./files/homebox.config $(1)/etc/config/homebox
|
||||
$(INSTALL_BIN) ./files/homebox.init $(1)/etc/init.d/homebox
|
||||
$(INSTALL_BIN) ./files/homebox.uci-default $(1)/etc/uci-defaults/homebox
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/homebox
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
[ -f /etc/uci-defaults/homebox ] && /etc/uci-defaults/homebox && rm -f /etc/uci-defaults/homebox
|
||||
fi
|
||||
endef
|
||||
|
||||
define Host/Configure
|
||||
cd $(HOST_BUILD_DIR)/web && rm -f package-lock.json && npm --cache-min 1440 install
|
||||
endef
|
||||
|
||||
define Host/Compile
|
||||
cd $(HOST_BUILD_DIR) && $(MAKE) build-web
|
||||
endef
|
||||
|
||||
define Host/Install
|
||||
endef
|
||||
|
||||
define Host/Clean
|
||||
rm -f $(HOST_BUILD_DIR)/build/static
|
||||
endef
|
||||
|
||||
$(eval $(call HostBuild))
|
||||
$(eval $(call BuildPackage,homebox))
|
2
homebox/files/homebox.config
Normal file
2
homebox/files/homebox.config
Normal file
@ -0,0 +1,2 @@
|
||||
config homebox
|
||||
option 'enabled' '0'
|
25
homebox/files/homebox.init
Executable file
25
homebox/files/homebox.init
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
USE_PROCD=1
|
||||
|
||||
get_config() {
|
||||
config_get_bool enabled $1 enabled 1
|
||||
config_get_bool logger $1 logger
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load homebox
|
||||
config_foreach get_config homebox
|
||||
[ $enabled != 1 ] && return 1
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /usr/bin/homebox
|
||||
[ "$logger" == 1 ] && procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "homebox"
|
||||
}
|
10
homebox/files/homebox.uci-default
Executable file
10
homebox/files/homebox.uci-default
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@homebox[-1]
|
||||
add ucitrack homebox
|
||||
set ucitrack.@homebox[-1].init=homebox
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
exit 0
|
15
luci-app-homebox/Makefile
Normal file
15
luci-app-homebox/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2016 Openwrt.org
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI support for homebox
|
||||
LUCI_DEPENDS:=+homebox
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include ../luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
24
luci-app-homebox/luasrc/controller/homebox.lua
Normal file
24
luci-app-homebox/luasrc/controller/homebox.lua
Normal file
@ -0,0 +1,24 @@
|
||||
module("luci.controller.homebox", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/homebox") then
|
||||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "homebox"}, cbi("homebox"), _("Homebox"), 20).dependent = true
|
||||
|
||||
entry({"admin", "services", "homebox_status"}, call("homebox_status"))
|
||||
end
|
||||
|
||||
function homebox_status()
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
local status = {
|
||||
running = (sys.call("pidof homebox >/dev/null") == 0),
|
||||
port = 3300
|
||||
}
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(status)
|
||||
end
|
16
luci-app-homebox/luasrc/model/cbi/homebox.lua
Normal file
16
luci-app-homebox/luasrc/model/cbi/homebox.lua
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
local m, s
|
||||
|
||||
m = Map("homebox", translate("Homebox"), translate("Homebox is a tool for local network speed testing"))
|
||||
|
||||
m:section(SimpleSection).template = "homebox_status"
|
||||
|
||||
s=m:section(TypedSection, "homebox", translate("Global Settings"))
|
||||
s.addremove=false
|
||||
s.anonymous=true
|
||||
|
||||
s:option(Flag, "enabled", translate("Enable")).rmempty=false
|
||||
|
||||
return m
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
<%+homebox_status%>
|
27
luci-app-homebox/luasrc/view/homebox_status.htm
Normal file
27
luci-app-homebox/luasrc/view/homebox_status.htm
Normal file
@ -0,0 +1,27 @@
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=url("admin/services/homebox_status")%>', null,
|
||||
function(x, st)
|
||||
{
|
||||
var tb = document.getElementById('homebox_status');
|
||||
if (st && tb)
|
||||
{
|
||||
if (st.running)
|
||||
{
|
||||
tb.innerHTML = '<br/><em style=\"color:green\"><%:The Homebox service is running.%></em>'
|
||||
+ "<br/><br/><input class=\"btn cbi-button cbi-button-apply\" type=\"button\" value=\" <%:Click to open Homebox%> \" onclick=\"window.open('http://" + window.location.hostname + ":" + st.port + "/')\"/>";
|
||||
}
|
||||
else
|
||||
{
|
||||
tb.innerHTML = '<br/><em style=\"color:red\"><%:The Homebox service is not running.%></em>';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]></script>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Homebox Status%></legend>
|
||||
<p id="homebox_status">
|
||||
<em><%:Collecting data...%></em>
|
||||
</p>
|
||||
</fieldset>
|
24
luci-app-homebox/po/zh-cn/homebox.po
Normal file
24
luci-app-homebox/po/zh-cn/homebox.po
Normal file
@ -0,0 +1,24 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Homebox"
|
||||
msgstr "Homebox"
|
||||
|
||||
msgid "Click to open Homebox"
|
||||
msgstr "点击打开Homebox"
|
||||
|
||||
msgid "Homebox is a tool for local network speed testing"
|
||||
msgstr "Homebox是一个局域网测速工具"
|
||||
|
||||
msgid "The Homebox service is running."
|
||||
msgstr "Homebox服务已启动"
|
||||
|
||||
msgid "The Homebox service is not running."
|
||||
msgstr "Homebox服务未启动"
|
||||
|
||||
msgid "Homebox Status"
|
||||
msgstr "Homebox服务状态"
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr "收集数据..."
|
||||
|
1
luci-app-homebox/po/zh_Hans
Symbolic link
1
luci-app-homebox/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
4
luci-app-homebox/root/etc/uci-defaults/50_luci-homebox
Executable file
4
luci-app-homebox/root/etc/uci-defaults/50_luci-homebox
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
16
luci-app-tasks/Makefile
Normal file
16
luci-app-tasks/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
#
|
||||
# Copyright (C) 2022 jjm2473 <jjm2473@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the MIT License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=luci for taskd
|
||||
LUCI_DEPENDS:=+luci-lib-taskd
|
||||
|
||||
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
|
||||
|
||||
include ../luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
9
luci-app-tasks/luasrc/controller/tasks/app.lua
Executable file
9
luci-app-tasks/luasrc/controller/tasks/app.lua
Executable file
@ -0,0 +1,9 @@
|
||||
|
||||
module("luci.controller.tasks.app", package.seeall)
|
||||
|
||||
|
||||
function index()
|
||||
entry({"admin", "system", "tasks"}, alias("admin", "system", "tasks", "all"), _("Tasks"), 56)
|
||||
--entry({"admin", "system", "tasks", "user"}, cbi("tasks/user"), _("User Tasks"), 1)
|
||||
entry({"admin", "system", "tasks", "all"}, form("tasks/all"))
|
||||
end
|
59
luci-app-tasks/luasrc/model/cbi/tasks/all.lua
Normal file
59
luci-app-tasks/luasrc/model/cbi/tasks/all.lua
Normal file
@ -0,0 +1,59 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local tasks = taskd.status()
|
||||
local show_log_taskid
|
||||
local m, s, o
|
||||
|
||||
local t=Template("tasks/all")
|
||||
|
||||
m = SimpleForm("taskd",
|
||||
translate("All Tasks"),
|
||||
translate("All submitted tasks, including system defined tasks"))
|
||||
m.submit=false
|
||||
m.reset=false
|
||||
|
||||
s = m:section(Table, tasks)
|
||||
s.config = "tasks"
|
||||
|
||||
o = s:option(DummyValue, "_id", translate("ID"))
|
||||
o.width="10%"
|
||||
o.cfgvalue = function(self, section)
|
||||
return section
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_status", translate("Status"))
|
||||
o.width="15%"
|
||||
o.cfgvalue = function(self, section)
|
||||
local task = tasks[section]
|
||||
return task.running and translate("Running") or (translate("Stopped:") .. " " .. task.exit_code)
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_start", translate("Start Time"))
|
||||
o.width="15%"
|
||||
o.cfgvalue = function(self, section)
|
||||
local task = tasks[section]
|
||||
return os.date("%Y/%m/%d %H:%M:%S", task.start)
|
||||
end
|
||||
-- os.date("%Y/%m/%d %H:%M:%S", 1657163212)
|
||||
|
||||
local btn_log = s:option(Button, "_log", translate("Log"))
|
||||
btn_log.inputstyle = "find"
|
||||
btn_log.write = function(self, section, value)
|
||||
t.show_log_taskid = section
|
||||
end
|
||||
|
||||
local btn_remove = s:option(Button, "_remove", translate("Remove"))
|
||||
btn_remove.inputstyle = "remove"
|
||||
btn_remove.forcewrite = true
|
||||
btn_remove.write = function(self, section, value)
|
||||
local task_id = section
|
||||
os.execute("/etc/init.d/tasks task_del "..task_id.." >/dev/null 2>&1")
|
||||
tasks[task_id] = nil
|
||||
end
|
||||
|
||||
m:append(t)
|
||||
|
||||
return m
|
28
luci-app-tasks/luasrc/view/tasks/all.htm
Normal file
28
luci-app-tasks/luasrc/view/tasks/all.htm
Normal file
@ -0,0 +1,28 @@
|
||||
<%+tasks/embed%>
|
||||
|
||||
<script>
|
||||
window.addEventListener("load", function(){
|
||||
const taskd = window.taskd;
|
||||
const logfunc = function(e) {
|
||||
taskd.show_log(this);
|
||||
return false;
|
||||
};
|
||||
const delfunc = function(e) {
|
||||
taskd.remove(this).then(()=>{
|
||||
location.reload();
|
||||
});
|
||||
return false;
|
||||
};
|
||||
const rows = document.querySelectorAll('#cbi-tasks-table tr.cbi-section-table-row');
|
||||
rows.forEach(row => {
|
||||
if (row.id) {
|
||||
const task_id = row.id.match(/cbi-tasks-(.*)/)[1];
|
||||
row.querySelector('td[data-name=_log] .cbi-button').onclick = logfunc.bind(task_id);
|
||||
row.querySelector('td[data-name=_remove] .cbi-button').onclick = delfunc.bind(task_id);
|
||||
}
|
||||
});
|
||||
<% if self.show_log_taskid then -%>
|
||||
taskd.show_log("<%=self.show_log_taskid%>");
|
||||
<%- end %>
|
||||
});
|
||||
</script>
|
29
luci-app-tasks/po/zh-cn/tasks.po
Normal file
29
luci-app-tasks/po/zh-cn/tasks.po
Normal file
@ -0,0 +1,29 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Tasks"
|
||||
msgstr "后台任务"
|
||||
|
||||
msgid "All Tasks"
|
||||
msgstr "所有任务"
|
||||
|
||||
msgid "All submitted tasks, including system defined tasks"
|
||||
msgstr "所有已提交的任务,包括系统定义的任务"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Stopped:"
|
||||
msgstr "已停止:"
|
||||
|
||||
msgid "Start Time"
|
||||
msgstr "开始时间"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
1
luci-app-tasks/po/zh_Hans
Symbolic link
1
luci-app-tasks/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
29
luci-lib-mac-vendor/Makefile
Normal file
29
luci-lib-mac-vendor/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2016 Openwrt.org
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI mac to vendor map
|
||||
LUCI_DESCRIPTION:=provide a js for mac address to vendor mapping
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
# PKG_RELEASE MUST be empty for luci.mk
|
||||
|
||||
LIB_VERSION:=1.0.2
|
||||
PKG_HASH:=skip
|
||||
|
||||
PKG_SOURCE_URL_FILE:=v$(LIB_VERSION).tar.gz
|
||||
PKG_SOURCE:=mac_vendor-$(PKG_SOURCE_URL_FILE)
|
||||
PKG_SOURCE_URL:=https://github.com/jjm2473/mac_vendor/archive/refs/tags
|
||||
|
||||
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
|
||||
|
||||
TARGET_CONFIGURE_OPTS= LIB_DIST="$(BUILD_DIR)/mac_vendor-$(LIB_VERSION)/dist" LIB_VERSION="$(LIB_VERSION)"
|
||||
TARGET_CONFIGURE_OPTS+= SED="$(SED)"
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
6
luci-lib-mac-vendor/src/Makefile
Normal file
6
luci-lib-mac-vendor/src/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
clean:
|
||||
compile:
|
||||
install:
|
||||
mkdir -p "$(DESTDIR)/www/luci-static/resources/mac_vendor"
|
||||
cp -a "$(LIB_DIST)/." "$(DESTDIR)/www/luci-static/resources/mac_vendor/"
|
||||
$(SED) 's#=PKG_VERSION"#=$(LIB_VERSION)"#g' "$(DESTDIR)/www/luci-static/resources/mac_vendor/mac_vendor.js"
|
17
luci-lib-taskd/Makefile
Normal file
17
luci-lib-taskd/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (C) 2022 jjm2473 <jjm2473@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the MIT License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Task library
|
||||
LUCI_DEPENDS:=+luci-lib-xterm +taskd
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
|
||||
|
||||
include ../luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
107
luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.css
Normal file
107
luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.css
Normal file
@ -0,0 +1,107 @@
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#tasks_detail_container {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #0008;
|
||||
}
|
||||
#tasks_dialog {
|
||||
position: absolute;
|
||||
width: 770px;
|
||||
max-height: 100%;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #000;
|
||||
|
||||
border-radius: 10px;
|
||||
box-shadow: 2px 2px 6px #000a;
|
||||
padding: 20px;
|
||||
|
||||
color: white;
|
||||
}
|
||||
.dialog-title-bar {
|
||||
margin-top: -10px;
|
||||
margin-right: -10px;
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
.dialog-title-bar .dialog-title {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dialog-content {
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
margin-right: -10px;
|
||||
}
|
||||
.dialog-icons {
|
||||
align-self: center;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.dialog-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: white;
|
||||
color: black;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
margin-left: 10px;
|
||||
line-height: 1;
|
||||
font-family: sans-serif;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dialog-icon.dialog-icon-min {
|
||||
background-color: darkorange;
|
||||
}
|
||||
.dialog-icon.dialog-icon-close {
|
||||
background-color: #ff5f56;
|
||||
}
|
||||
.dialog-icons:hover .dialog-icon.dialog-icon-min:before {
|
||||
content: "_";
|
||||
}
|
||||
.dialog-icons:hover .dialog-icon.dialog-icon-close:before {
|
||||
content: "X";
|
||||
}
|
||||
|
||||
.tasks_stopped .dialog-icon.dialog-icon-close {
|
||||
background-color: #27c840;
|
||||
}
|
||||
.tasks_stopped #tasks_dialog {
|
||||
padding: 19px;
|
||||
border: 1px #27c840 solid;
|
||||
|
||||
animation: border-blink 1s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.tasks_failed #tasks_dialog {
|
||||
border-color: #ff0000;
|
||||
}
|
||||
|
||||
.tasks_failed .dialog-icon.dialog-icon-close {
|
||||
background-color: #ff0000;
|
||||
}
|
||||
|
||||
@keyframes border-blink { 50% { border-color:#fff ; } }
|
198
luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js
Normal file
198
luci-lib-taskd/htdocs/luci-static/resources/tasks/tasks.js
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
(function(){
|
||||
const taskd={};
|
||||
const $gettext = function(str) {
|
||||
return taskd.i18n[str] || str;
|
||||
};
|
||||
const request = function(url, method, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.open(method || 'GET', url, true);
|
||||
|
||||
oReq.onload = function (oEvent) {
|
||||
resolve(oReq.responseText);
|
||||
};
|
||||
if (method=='POST') {
|
||||
oReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
}
|
||||
oReq.send(data || method=='POST'?"token="+taskd.csrfToken:null);
|
||||
});
|
||||
};
|
||||
const getBin = function(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.open("GET", url, true);
|
||||
oReq.responseType = "arraybuffer";
|
||||
|
||||
oReq.onload = function (oEvent) {
|
||||
resolve({status: oReq.status, buffer: new Uint8Array(oReq.response)});
|
||||
};
|
||||
|
||||
oReq.send(null);
|
||||
});
|
||||
};
|
||||
const getTaskDetail = function(task_id) {
|
||||
return request("/cgi-bin/luci/admin/system/tasks/status?task_id="+task_id).then(data=>JSON.parse(data));
|
||||
};
|
||||
const create_dialog = function(cfg) {
|
||||
const container = document.createElement('div');
|
||||
container.id = "tasks_detail_container";
|
||||
container.innerHTML = taskd.dialog_template;
|
||||
|
||||
document.body.appendChild(container);
|
||||
const title_view = container.querySelector(".dialog-title-bar .dialog-title");
|
||||
title_view.innerText = cfg.title;
|
||||
|
||||
const term = new Terminal({convertEol: cfg.convertEol||false});
|
||||
if (cfg.nohide) {
|
||||
container.querySelector(".dialog-icon-min").hidden = true;
|
||||
} else {
|
||||
container.querySelector(".dialog-icon-min").onclick = function(){
|
||||
container.hidden=true;
|
||||
term.dispose();
|
||||
document.body.removeChild(container);
|
||||
cfg.onhide && cfg.onhide();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
term.open(document.getElementById("tasks_xterm_log"));
|
||||
|
||||
return {term,container};
|
||||
};
|
||||
const show_log_txt = function(title, content, onclose) {
|
||||
const dialog = create_dialog({title, convertEol:true, onhine:onclose});
|
||||
const container = dialog.container;
|
||||
const term = dialog.term;
|
||||
container.querySelector(".dialog-icon-close").hidden = true;
|
||||
term.write(content);
|
||||
};
|
||||
const show_log = function(task_id, nohide) {
|
||||
let showing = true;
|
||||
let running = true;
|
||||
const dialog = create_dialog({title:task_id, nohide, onhide:function(){showing=false;}});
|
||||
const container = dialog.container;
|
||||
const term = dialog.term;
|
||||
|
||||
const title_view = container.querySelector(".dialog-title-bar .dialog-title");
|
||||
container.querySelector(".dialog-icon-close").onclick = function(){
|
||||
if (!running || confirm($gettext("Stop running task?"))) {
|
||||
running=false;
|
||||
showing=false;
|
||||
del_task(task_id).then(()=>{
|
||||
location.href = location.href;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const checkTask = function() {
|
||||
return getTaskDetail(task_id).then(data=>{
|
||||
if (!running) {
|
||||
return false;
|
||||
}
|
||||
running = data.running;
|
||||
let title = task_id;
|
||||
if (!data.running && data.stop) {
|
||||
title += " (" + (data.exit_code?$gettext("Failed at:"):$gettext("Finished at:")) + " " + new Date(data.stop * 1000).toLocaleString() + ")";
|
||||
}
|
||||
title += " > " + (data.command || '');
|
||||
title_view.title = title;
|
||||
title_view.innerText = title;
|
||||
if (!data.running) {
|
||||
container.classList.add('tasks_stopped')
|
||||
if (data.exit_code) {
|
||||
container.classList.add('tasks_failed')
|
||||
}
|
||||
}
|
||||
return data.running;
|
||||
});
|
||||
};
|
||||
let logoffset = 0;
|
||||
const pulllog = function() {
|
||||
getBin("/cgi-bin/luci/admin/system/tasks/log?task_id="+task_id+"&offset="+logoffset).then(function(res){
|
||||
if (!showing) {
|
||||
return false;
|
||||
}
|
||||
switch(res.status){
|
||||
case 205:
|
||||
term.reset();
|
||||
logoffset = 0;
|
||||
return running;
|
||||
break;
|
||||
case 204:
|
||||
return running && checkTask();
|
||||
break;
|
||||
case 200:
|
||||
logoffset += res.buffer.byteLength;
|
||||
term.write(res.buffer);
|
||||
return running;
|
||||
break;
|
||||
}
|
||||
}).then(again => {
|
||||
if (again) {
|
||||
setTimeout(pulllog, 0);
|
||||
}
|
||||
});
|
||||
};
|
||||
checkTask().then(pulllog);
|
||||
};
|
||||
const del_task = function(task_id) {
|
||||
return request("/cgi-bin/luci/admin/system/tasks/stop?task_id="+task_id, "POST");
|
||||
};
|
||||
taskd.show_log = show_log;
|
||||
taskd.remove = del_task;
|
||||
taskd.show_log_txt = show_log_txt;
|
||||
window.taskd=taskd;
|
||||
})();
|
||||
|
||||
(function(){
|
||||
// compat
|
||||
if (typeof(window.findParent) !== 'function') {
|
||||
const elem = function(e) {
|
||||
return (e != null && typeof(e) == 'object' && 'nodeType' in e);
|
||||
};
|
||||
const matches = function(node, selector) {
|
||||
var m = elem(node) ? node.matches || node.msMatchesSelector : null;
|
||||
return m ? m.call(node, selector) : false;
|
||||
};
|
||||
window.findParent = function (node, selector) {
|
||||
if (elem(node) && node.closest)
|
||||
return node.closest(selector);
|
||||
|
||||
while (elem(node))
|
||||
if (matches(node, selector))
|
||||
return node;
|
||||
else
|
||||
node = node.parentNode;
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
if (typeof(window.cbi_submit) !== 'function') {
|
||||
const makeHidden = function(name) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = name;
|
||||
return input;
|
||||
};
|
||||
window.cbi_submit = function(elem, name, value, action) {
|
||||
var form = elem.form || findParent(elem, 'form');
|
||||
|
||||
if (!form)
|
||||
return false;
|
||||
|
||||
if (action)
|
||||
form.action = action;
|
||||
|
||||
if (name) {
|
||||
var hidden = form.querySelector('input[type="hidden"][name="%s"]'.format(name)) ||
|
||||
makeHidden(name);
|
||||
|
||||
hidden.value = value || '1';
|
||||
form.appendChild(hidden);
|
||||
}
|
||||
|
||||
form.submit();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
})();
|
91
luci-lib-taskd/luasrc/controller/tasks-lib.lua
Executable file
91
luci-lib-taskd/luasrc/controller/tasks-lib.lua
Executable file
@ -0,0 +1,91 @@
|
||||
|
||||
module("luci.controller.tasks-lib", package.seeall)
|
||||
|
||||
|
||||
function index()
|
||||
entry({"admin", "system", "tasks", "status"}, call("tasks_status")).dependent=false
|
||||
entry({"admin", "system", "tasks", "log"}, call("tasks_log")).dependent=false
|
||||
entry({"admin", "system", "tasks", "stop"}, post("tasks_stop")).dependent=false
|
||||
end
|
||||
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
local ltn12 = require "luci.ltn12"
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
|
||||
function tasks_status()
|
||||
local data = taskd.status(luci.http.formvalue("task_id"))
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(data)
|
||||
end
|
||||
|
||||
function tasks_log()
|
||||
local task_id = luci.http.formvalue("task_id")
|
||||
local offset = luci.http.formvalue("offset")
|
||||
offset = offset and tonumber(offset) or 0
|
||||
local logpath = "/var/log/tasks/"..task_id..".log"
|
||||
local i
|
||||
local logfd = io.open(logpath, "rb")
|
||||
if logfd == nil then
|
||||
luci.http.status(404)
|
||||
luci.http.write("log not found")
|
||||
return
|
||||
end
|
||||
|
||||
local size = logfd:seek("end")
|
||||
|
||||
if size < offset then
|
||||
luci.http.status(205, "Reset Content")
|
||||
luci.http.write("reset offset")
|
||||
return
|
||||
end
|
||||
|
||||
i = 0
|
||||
while (i<200)
|
||||
do
|
||||
if size > offset then
|
||||
break
|
||||
end
|
||||
nixio.nanosleep(0, 10000000) -- sleep 10ms
|
||||
size = logfd:seek("end")
|
||||
i = i+1
|
||||
end
|
||||
if i == 200 then
|
||||
logfd:close()
|
||||
luci.http.status(204)
|
||||
luci.http.prepare_content("application/octet-stream")
|
||||
return
|
||||
end
|
||||
logfd:seek("set", offset)
|
||||
|
||||
local write_log = function()
|
||||
local buffer = logfd:read(4096)
|
||||
if buffer and #buffer > 0 then
|
||||
return buffer
|
||||
else
|
||||
logfd:close()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/octet-stream")
|
||||
|
||||
if logfd then
|
||||
ltn12.pump.all(write_log, luci.http.write)
|
||||
end
|
||||
end
|
||||
|
||||
function tasks_stop()
|
||||
local sys = require("luci.sys")
|
||||
local task_id = luci.http.formvalue("task_id") or ""
|
||||
if task_id == "" then
|
||||
luci.http.status(400)
|
||||
luci.http.write("task_id is empty")
|
||||
return
|
||||
end
|
||||
if sys.call("/etc/init.d/tasks task_del "..task_id.." >/dev/null 2>&1") ~= 0 then
|
||||
nixio.nanosleep(2, 10000000)
|
||||
end
|
||||
luci.http.status(204)
|
||||
end
|
96
luci-lib-taskd/luasrc/model/tasks.lua
Normal file
96
luci-lib-taskd/luasrc/model/tasks.lua
Normal file
@ -0,0 +1,96 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local taskd = {}
|
||||
|
||||
local function output(data)
|
||||
local ret={}
|
||||
ret.running=data.running
|
||||
if not data.running then
|
||||
ret.exit_code=data.exit_code
|
||||
end
|
||||
ret.command=data["command"] and data["command"][4] or '#'
|
||||
if data["data"] then
|
||||
ret.start=tonumber(data["data"]["start"])
|
||||
if not data.running and data["data"]["stop"] then
|
||||
ret.stop=tonumber(data["data"]["stop"])
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
taskd.status = function (task_id)
|
||||
task_id = task_id or ""
|
||||
local data = util.trim(util.exec("/etc/init.d/tasks task_status "..task_id.." 2>/dev/null")) or ""
|
||||
if data ~= "" then
|
||||
data = jsonc.parse(data)
|
||||
if task_id ~= "" and not data.running and data["data"] then
|
||||
data["data"]["stop"] = util.trim(util.exec("/etc/init.d/tasks task_stop_at "..task_id.." 2>/dev/null")) or ""
|
||||
end
|
||||
else
|
||||
if task_id == "" then
|
||||
data = {}
|
||||
else
|
||||
data = {running=false, exit_code=255}
|
||||
end
|
||||
end
|
||||
if task_id ~= "" then
|
||||
return output(data)
|
||||
end
|
||||
local ary={}
|
||||
for k, v in pairs(data) do
|
||||
ary[k] = output(v)
|
||||
end
|
||||
return ary
|
||||
end
|
||||
|
||||
taskd.docker_map = function(config, task_id, script_path, title, desc)
|
||||
require("luci.cbi")
|
||||
require("luci.http")
|
||||
require("luci.sys")
|
||||
local translate = require("luci.i18n").translate
|
||||
local m
|
||||
m = luci.cbi.Map(config, title, desc)
|
||||
m.template = "tasks/docker"
|
||||
-- hide default buttons
|
||||
m.pageaction = false
|
||||
-- we want hook 'on_after_apply' works, 'apply_on_parse' can be true (rollback) or false (no rollback),
|
||||
-- but 'apply_on_parse' must be true for luci 17.01 and below
|
||||
m.apply_on_parse = true
|
||||
m.script_path = script_path
|
||||
m.task_id = task_id
|
||||
m.auto_show_task = true
|
||||
m.on_before_apply = function(self)
|
||||
if self.uci.rollback then
|
||||
-- luci 18.06+ has 'rollback' function
|
||||
-- rollback dialog will show because 'apply_on_parse' is true,
|
||||
-- hide rollback dialog by hook 'apply' function
|
||||
local apply = self.uci.apply
|
||||
self.uci.apply = function(uci, rollback)
|
||||
apply(uci, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
m.on_after_apply = function(self)
|
||||
local cmd
|
||||
local action = luci.http.formvalue("cbi.apply") or "null"
|
||||
if "upgrade" == action or "install" == action
|
||||
or "start" == action or "stop" == action or "restart" == action or "rm" == action then
|
||||
cmd = string.format("\"%s\" %s", script_path, action)
|
||||
end
|
||||
if cmd then
|
||||
if luci.sys.call("/etc/init.d/tasks task_add " .. task_id .. " '" .. cmd .. "' >/dev/null 2>&1") ~= 0 then
|
||||
self.task_start_failed = true
|
||||
self.message = translate("Config saved, but apply failed")
|
||||
end
|
||||
else
|
||||
self.message = translate("Unknown command: ") .. action
|
||||
end
|
||||
if self.message then
|
||||
self.auto_show_task = false
|
||||
end
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
return taskd
|
56
luci-lib-taskd/luasrc/view/tasks/docker.htm
Normal file
56
luci-lib-taskd/luasrc/view/tasks/docker.htm
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
<% if self.task_start_failed then %>
|
||||
<div class="alert-message warning"><%:Another task running, try again later.%> <a href="javascript:void(taskd.show_log('<%=self.task_id%>'))"><%:Click here to check running task%></a></div>
|
||||
<% end %>
|
||||
|
||||
<%+cbi/map%>
|
||||
<%
|
||||
local task_running = false
|
||||
local taskd = require "luci.model.tasks"
|
||||
local status = taskd.status(self.task_id)
|
||||
task_running = status.running
|
||||
-%>
|
||||
<div class="cbi-page-actions control-group">
|
||||
<%
|
||||
if not task_running then
|
||||
%>
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec(self.script_path.." status"))
|
||||
local container_install = (string.len(container_status) > 0)
|
||||
local container_running = container_status == "running"
|
||||
if container_install then
|
||||
-%>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Upgrade%>/<%:Apply%>" onclick="cbi_submit(this, 'cbi.apply', 'upgrade')" />
|
||||
<%
|
||||
if container_running then
|
||||
-%>
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Stop%>" onclick="cbi_submit(this, 'cbi.apply', 'stop')" />
|
||||
|
||||
<input class="btn cbi-button cbi-button-reload" type="button" value="<%:Restart%>" onclick="cbi_submit(this, 'cbi.apply', 'restart')" />
|
||||
<% else %>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Start%>" onclick="cbi_submit(this, 'cbi.apply', 'start')" />
|
||||
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Remove%>" onclick="cbi_submit(this, 'cbi.apply', 'rm')" />
|
||||
<% end
|
||||
else %>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Install%>" onclick="cbi_submit(this, 'cbi.apply', 'install')" />
|
||||
<% end
|
||||
else
|
||||
%>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Task Running%>…" onclick="taskd.show_log('<%=self.task_id%>')" />
|
||||
<%
|
||||
end
|
||||
%>
|
||||
</div>
|
||||
|
||||
<%+tasks/embed%>
|
||||
<%
|
||||
if self.auto_show_task and task_running then
|
||||
-%>
|
||||
<script>
|
||||
taskd.show_log("<%=self.task_id%>");
|
||||
</script>
|
||||
<%
|
||||
end
|
||||
%>
|
31
luci-lib-taskd/luasrc/view/tasks/embed.htm
Normal file
31
luci-lib-taskd/luasrc/view/tasks/embed.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<%+xterm/embed%>
|
||||
<link rel="stylesheet" href="<%=resource%>/tasks/tasks.css<%# ?v=PKG_VERSION %>">
|
||||
<script src="<%=resource%>/tasks/tasks.js<%# ?v=PKG_VERSION %>"></script>
|
||||
<%
|
||||
local i18n = {}
|
||||
local function tr(str)
|
||||
i18n[str]=translate(str)
|
||||
end
|
||||
tr("Stop running task?")
|
||||
tr("Stopped at:")
|
||||
tr("Finished at:")
|
||||
tr("Failed at:")
|
||||
-%>
|
||||
<script>
|
||||
window.taskd.csrfToken="<%=token%>";
|
||||
window.taskd.i18n=<% luci.http.write_json(i18n) %>;
|
||||
window.taskd.dialog_template=`
|
||||
<div id="tasks_dialog">
|
||||
<div class="dialog-title-bar">
|
||||
<span class="dialog-title" id="tasks_id"></span>
|
||||
<span class="dialog-icons">
|
||||
<span class="dialog-icon dialog-icon-close" title="<%:Stop and Remove%>"></span>
|
||||
<span class="dialog-icon dialog-icon-min" title="<%:Hide%>"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="dialog-content">
|
||||
<div id="tasks_xterm_log"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
</script>
|
15
luci-lib-taskd/src/Makefile
Normal file
15
luci-lib-taskd/src/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
clean:
|
||||
compile:
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_NAME:=luci-lib-dummy
|
||||
INCLUDE_DIR:=./dummy
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
install:
|
||||
mkdir -p "$(DESTDIR)$(LUCI_LIBRARYDIR)/i18n"
|
||||
$(foreach lang,$(LUCI_LANGUAGES),$(foreach po,$(wildcard ${CURDIR}/po/$(lang)/*.po), \
|
||||
po2lmo $(po) \
|
||||
$(DESTDIR)$(LUCI_LIBRARYDIR)/i18n/$(basename $(notdir $(po))).$(lang).lmo;))
|
2
luci-lib-taskd/src/dummy/package.mk
Normal file
2
luci-lib-taskd/src/dummy/package.mk
Normal file
@ -0,0 +1,2 @@
|
||||
define BuildPackage
|
||||
endef
|
32
luci-lib-taskd/src/po/zh-cn/lib-tasks.po
Normal file
32
luci-lib-taskd/src/po/zh-cn/lib-tasks.po
Normal file
@ -0,0 +1,32 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Stop running task?"
|
||||
msgstr "删除运行中的任务?"
|
||||
|
||||
msgid "Finished at:"
|
||||
msgstr "完成于:"
|
||||
|
||||
msgid "Failed at:"
|
||||
msgstr "失败于:"
|
||||
|
||||
msgid "Stop and Remove"
|
||||
msgstr "停止并删除"
|
||||
|
||||
msgid "Hide"
|
||||
msgstr "隐藏"
|
||||
|
||||
msgid "Config saved, but apply failed"
|
||||
msgstr "配置已保存,但应用失败"
|
||||
|
||||
msgid "Unknown command: "
|
||||
msgstr "未知命令:"
|
||||
|
||||
msgid "Another task running, try again later."
|
||||
msgstr "已有后台任务运行中,请稍后重试。"
|
||||
|
||||
msgid "Click here to check running task"
|
||||
msgstr "点此查看运行中的任务"
|
||||
|
||||
msgid "Task Running"
|
||||
msgstr "任务执行中"
|
19
luci-lib-xterm/Makefile
Normal file
19
luci-lib-xterm/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2017-2019, The xterm.js authors (MIT License)
|
||||
# Copyright (c) 2014-2017, SourceLair, Private Company (www.sourcelair.com) (MIT License)
|
||||
# Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
#
|
||||
# This is free software, licensed under the MIT License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Xterm.js library
|
||||
LUCI_DEPENDS:=
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
180
luci-lib-xterm/htdocs/luci-static/resources/xterm/xterm.css
Normal file
180
luci-lib-xterm/htdocs/luci-static/resources/xterm/xterm.css
Normal file
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer,
|
||||
.xterm .xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.xterm-screen .xterm-decoration-container .xterm-decoration {
|
||||
z-index: 6;
|
||||
position: absolute;
|
||||
}
|
File diff suppressed because one or more lines are too long
3
luci-lib-xterm/luasrc/view/xterm/embed.htm
Normal file
3
luci-lib-xterm/luasrc/view/xterm/embed.htm
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
<link rel="stylesheet" href="<%=resource%>/xterm/xterm.css<%# ?v=PKG_VERSION %>">
|
||||
<script src="<%=resource%>/xterm/xterm.js<%# ?v=PKG_VERSION %>"></script>
|
41
taskd/Makefile
Normal file
41
taskd/Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright (C) 2022 jjm2473 <jjm2473@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the MIT License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
PKG_NAME:=taskd
|
||||
PKG_VERSION:=1.0.2
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=Simple Task Manager
|
||||
DEPENDS:=+procd +script-utils +coreutils-stty
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
Simple Task Manager based on procd
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/usr/libexec
|
||||
$(INSTALL_BIN) ./files/tasks.init $(1)/etc/init.d/tasks
|
||||
$(INSTALL_BIN) ./files/taskd.sh $(1)/usr/libexec/taskd
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
16
taskd/files/taskd.sh
Executable file
16
taskd/files/taskd.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
TASK_ID="$1"
|
||||
TASK_CMD="$2"
|
||||
|
||||
exec </dev/null >>"/var/log/tasks/$TASK_ID.log" 2>&1
|
||||
|
||||
export HOME=/root
|
||||
export TERM=xterm-256color
|
||||
|
||||
exec script -efqc 'onexit() {
|
||||
/etc/init.d/tasks _task_onstop '"$TASK_ID"'
|
||||
}
|
||||
trap onexit EXIT;
|
||||
stty cols 80 rows 24;
|
||||
'"$TASK_CMD" /dev/null
|
133
taskd/files/tasks.init
Executable file
133
taskd/files/tasks.init
Executable file
@ -0,0 +1,133 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2022 jjm2473@gmail.com
|
||||
|
||||
USE_PROCD=1
|
||||
START=49
|
||||
|
||||
extra_command "task_add" "<task_id> <task_cmd> [<time_wait>] Add and run a task, time_wait is wait time before auto delete stopped task, in seconds, -1 means forever"
|
||||
extra_command "task_del" "<task_id> Stop and delete task"
|
||||
extra_command "task_status" "[<task_id>] Dump task status, dump all tasks if no task_id specified"
|
||||
extra_command "task_stop_at" "<task_id> Get stop time"
|
||||
extra_command "task_gc" "Auto delete exipred (stopped and after timw_wait) tasks"
|
||||
extra_command "_task_onstop" "<task_id> Update stop time, for internal usage"
|
||||
|
||||
_task_add() {
|
||||
local task_id="${1}"
|
||||
local task_cmd="${2}"
|
||||
local time_wait="${3}"
|
||||
> "/var/log/tasks/$task_id.log"
|
||||
procd_open_instance "$task_id"
|
||||
procd_set_param data start=`date +'%s'` time_wait="$time_wait"
|
||||
procd_set_param command sh -c "exec /usr/libexec/taskd '$task_id' \"\$0\"" "$task_cmd"
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
task_add() {
|
||||
local task_id="${1}"
|
||||
local task_cmd="${2}"
|
||||
local time_wait="${3}"
|
||||
[ -z "$task_id" -o -z "$task_cmd" ] && return 127
|
||||
|
||||
if service_running "$task_id"; then
|
||||
echo "already running" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! mkdir -p /var/log/tasks; then
|
||||
echo "create /var/log/tasks failed!" >&2
|
||||
return 1
|
||||
fi
|
||||
rc_procd _task_add "$task_id" "$task_cmd" "$time_wait"
|
||||
return 0
|
||||
}
|
||||
|
||||
_task_del() {
|
||||
local service="${1}"
|
||||
local task_id="${2}"
|
||||
procd_kill "$service" "$task_id"
|
||||
> "/var/log/tasks/$task_id.log"
|
||||
rm -f "/var/log/tasks/$task_id.log"
|
||||
}
|
||||
|
||||
task_del() {
|
||||
local task_id="${1}"
|
||||
[ -z "$task_id" ] && return 127
|
||||
procd_lock
|
||||
_task_del "$(basename ${basescript:-$initscript})" "$task_id"
|
||||
if [ "$(_task_status "$task_id" | jsonfilter -e '$.running' 2>/dev/null)" = "true" ]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
_task_status() {
|
||||
local service="$(basename ${basescript:-$initscript})"
|
||||
local instance="$1"
|
||||
local data
|
||||
|
||||
json_init
|
||||
[ -n "$service" ] && json_add_string name "$service"
|
||||
|
||||
data=$(_procd_ubus_call list | jsonfilter -e '@["'"$service"'"]')
|
||||
[ -z "$data" ] && return 1
|
||||
|
||||
data=$(echo "$data" | jsonfilter -e '$.instances')
|
||||
if [ -z "$data" ]; then
|
||||
if [ -z "$instance" ]; then
|
||||
echo "{}"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$instance" ]; then
|
||||
echo "$data"
|
||||
else
|
||||
instance="\"$instance\""
|
||||
echo "$data" | jsonfilter -e '$['"$instance"']'
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
task_status() {
|
||||
local task_id="${1}"
|
||||
_task_status "$task_id"
|
||||
}
|
||||
|
||||
task_stop_at() {
|
||||
local task_id="${1}"
|
||||
[ -z "$task_id" ] && return 127
|
||||
date +'%s' -r "/var/log/tasks/$task_id.log"
|
||||
}
|
||||
|
||||
task_gc() {
|
||||
local service="$(basename ${basescript:-$initscript})"
|
||||
local task_id instance time_wait
|
||||
local data
|
||||
|
||||
json_init
|
||||
[ -n "$service" ] && json_add_string name "$service"
|
||||
|
||||
data=$(_procd_ubus_call list | jsonfilter -e '@["'"$service"'"]')
|
||||
[ -z "$data" ] && return 1
|
||||
|
||||
data=$(echo "$data" | jsonfilter -e '$.instances')
|
||||
[ -z "$data" ] && return 1
|
||||
|
||||
procd_lock
|
||||
|
||||
ls /var/log/tasks/ | sed 's/.log$//g' | while read task_id; do
|
||||
instance=$(echo "$data" | jsonfilter -e '$["'"$task_id"'"]')
|
||||
[ "$(echo "$instance" | jsonfilter -e '$.running')" = "false" ] || continue
|
||||
time_wait=$(echo "$instance" | jsonfilter -e '$.data.time_wait')
|
||||
[ "$time_wait" = "-1" ] && continue
|
||||
[ $(($(date +'%s' -r "/var/log/tasks/$task_id.log") + ${time_wait:-0})) -lt `date +'%s'` ] && _task_del "$service" "$task_id"
|
||||
done
|
||||
}
|
||||
|
||||
_task_onstop() {
|
||||
local task_id="${1}"
|
||||
[ -z "$task_id" ] && return 127
|
||||
touch "/var/log/tasks/$task_id.log"
|
||||
}
|
Loading…
Reference in New Issue
Block a user