mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
add luci-app-kcptun
from kuoruan
This commit is contained in:
parent
a3aa73c3d1
commit
80b056613e
35
package/lean/luci-app-kcptun/Makefile
Normal file
35
package/lean/luci-app-kcptun/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
# Licensed to the public under the Apache License 2.0.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-kcptun
|
||||
PKG_VERSION:=1.4.3
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=Xingwang Liao <kuoruan@gmail.com>
|
||||
|
||||
LUCI_TITLE:=LuCI support for Kcptun
|
||||
LUCI_DEPENDS:=+jshn +wget +luci-lib-jsonc
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/kcptun
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
( . /etc/uci-defaults/40_luci-kcptun ) && rm -f /etc/uci-defaults/40_luci-kcptun
|
||||
fi
|
||||
chmod 755 $${IPKG_INSTROOT}/etc/init.d/kcptun >/dev/null 2>&1
|
||||
$${IPKG_INSTROOT}/etc/init.d/kcptun enable >/dev/null 2>&1
|
||||
exit 0
|
||||
endef
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
120
package/lean/luci-app-kcptun/luasrc/controller/kcptun.lua
Normal file
120
package/lean/luci-app-kcptun/luasrc/controller/kcptun.lua
Normal file
@ -0,0 +1,120 @@
|
||||
-- Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.controller.kcptun", package.seeall)
|
||||
|
||||
local http = require "luci.http"
|
||||
local kcp = require "luci.model.kcptun"
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/kcptun") then
|
||||
return
|
||||
end
|
||||
|
||||
entry({"admin", "services", "kcptun"},
|
||||
firstchild(), _("Kcptun Client")).dependent = false
|
||||
|
||||
entry({"admin", "services", "kcptun", "settings"},
|
||||
cbi("kcptun/settings"), _("Settings"), 1)
|
||||
|
||||
entry({"admin", "services", "kcptun", "servers"},
|
||||
arcombine(cbi("kcptun/servers"), cbi("kcptun/servers-detail")),
|
||||
_("Server Manage"), 2).leaf = true
|
||||
|
||||
entry({"admin", "services", "kcptun", "log"},
|
||||
template("kcptun/log_view"), _("Log"), 3)
|
||||
|
||||
entry({"admin", "services", "kcptun", "status"}, call("action_status"))
|
||||
|
||||
entry({"admin", "services", "kcptun", "check"}, call("action_check")).leaf = true
|
||||
|
||||
entry({"admin", "services", "kcptun", "update"}, call("action_update")).leaf = true
|
||||
|
||||
entry({"admin", "services", "kcptun", "log", "data"}, call("action_log_data"))
|
||||
|
||||
entry({"admin", "services", "kcptun", "log", "clear"}, call("action_log_clear")).leaf = true
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(content or { code = 1 })
|
||||
end
|
||||
|
||||
function action_status()
|
||||
local client_file = kcp.get_config_option("client_file")
|
||||
|
||||
http_write_json({
|
||||
client = kcp.is_running(client_file)
|
||||
})
|
||||
end
|
||||
|
||||
function action_check(type)
|
||||
local json = nil
|
||||
if type == "kcptun" then
|
||||
json = kcp.check_kcptun(http.formvalue("arch"))
|
||||
elseif type == "luci" then
|
||||
json = kcp.check_luci()
|
||||
else
|
||||
http.status(500, "Bad address")
|
||||
return
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function action_update(type)
|
||||
local json = nil
|
||||
if type == "kcptun" then
|
||||
local task = http.formvalue("task")
|
||||
if task == "extract" then
|
||||
json = kcp.extract_kcptun(http.formvalue("file"), http.formvalue("subfix"))
|
||||
elseif task == "move" then
|
||||
json = kcp.move_kcptun(http.formvalue("file"))
|
||||
else
|
||||
json = kcp.download_kcptun(http.formvalue("url"))
|
||||
end
|
||||
elseif type == "luci" then
|
||||
json = kcp.update_luci(http.formvalue("url"), http.formvalue("save"))
|
||||
else
|
||||
http.status(500, "Bad address")
|
||||
return
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function action_log_data()
|
||||
local util = require "luci.util"
|
||||
|
||||
local log_data = { }
|
||||
|
||||
local enable_logging = kcp.get_config_option("enable_logging", "0") == "1"
|
||||
|
||||
if enable_logging then
|
||||
local client_log_file = kcp.get_current_log_file("client")
|
||||
log_data.client = util.trim(
|
||||
util.exec("tail -n 50 %s 2>/dev/null | sed 'x;1!H;$!d;x'" % client_log_file))
|
||||
end
|
||||
|
||||
log_data.syslog = util.trim(
|
||||
util.exec("logread | grep kcptun | tail -n 50 | sed 'x;1!H;$!d;x'"))
|
||||
|
||||
http_write_json(log_data)
|
||||
end
|
||||
|
||||
function action_log_clear(type)
|
||||
if type and type ~= "" then
|
||||
local log_file = kcp.get_current_log_file(type)
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
if fs.access(log_file) then
|
||||
fs.writefile(log_file, "")
|
||||
else
|
||||
http.status(404, "Not found")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
http_write_json({ code = 0 })
|
||||
end
|
@ -0,0 +1,182 @@
|
||||
-- Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local dsp = require "luci.dispatcher"
|
||||
|
||||
local m, s, o
|
||||
local sid = arg[1]
|
||||
|
||||
local encrypt_methods = {
|
||||
"aes",
|
||||
"aes-128",
|
||||
"aes-192",
|
||||
"salsa20",
|
||||
"blowfish",
|
||||
"twofish",
|
||||
"cast5",
|
||||
"3des",
|
||||
"tea",
|
||||
"xtea",
|
||||
"xor",
|
||||
"none",
|
||||
}
|
||||
|
||||
local modes = {
|
||||
"normal",
|
||||
"fast",
|
||||
"fast2",
|
||||
"fast3",
|
||||
"manual",
|
||||
}
|
||||
|
||||
m = Map("kcptun", "%s - %s" % { translate("Kcptun"), translate("Edit Server") })
|
||||
m.redirect = dsp.build_url("admin/services/kcptun/servers")
|
||||
|
||||
if m.uci:get("kcptun", sid) ~= "servers" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
end
|
||||
|
||||
s = m:section(NamedSection, sid, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(Value, "alias", "%s (%s)" % { translate("Alias"), translate("optional") })
|
||||
|
||||
o = s:option(Value, "server_addr", translate("Server"))
|
||||
o.datatype = "host"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "server_port", translate("Server Port"))
|
||||
o.datatype = "port"
|
||||
o.placeholder = "29900"
|
||||
|
||||
o = s:option(Value, "listen_addr", "%s (%s)" % { translate("Local Listen Host"), translate("optional") },
|
||||
translate("Local listen host."))
|
||||
o.datatype = "host"
|
||||
o.placeholder = "0.0.0.0"
|
||||
|
||||
o = s:option(Value, "listen_port", translate("Local Port"), translate("Local Listen Port."))
|
||||
o.datatype = "port"
|
||||
o.placeholder = "12948"
|
||||
|
||||
o = s:option(Value, "key", "%s (%s)" % { translate("Key"), translate("optional") },
|
||||
translate("Pre-shared secret for client and server."))
|
||||
o.password = true
|
||||
o.placeholder = "it's a secret"
|
||||
|
||||
o = s:option(Value, "crypt", translate("crypt"), translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods) do
|
||||
o:value(v, v:upper())
|
||||
end
|
||||
o.default = "aes"
|
||||
|
||||
o = s:option(ListValue, "mode", translate("mode"), translate("Embedded Mode"))
|
||||
for _, v in ipairs(modes) do
|
||||
o:value(v, v:upper())
|
||||
end
|
||||
o.default = "fast"
|
||||
|
||||
o = s:option(Flag, "nodelay", translate("nodelay"), translate("Enable nodelay Mode."))
|
||||
o:depends("mode", "manual")
|
||||
|
||||
o = s:option(Value, "interval", translate("interval"))
|
||||
o:depends("mode", "manual")
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "50"
|
||||
|
||||
o = s:option(ListValue, "resend", translate("resend"))
|
||||
o:depends("mode", "manual")
|
||||
o:value("0", translate("Off"))
|
||||
o:value("1", translate("On"))
|
||||
o:value("2", translate("2nd ACK"))
|
||||
|
||||
o = s:option(Flag, "nc", translate("nc"))
|
||||
o:depends("mode", "manual")
|
||||
|
||||
o = s:option(Value, "mtu", "%s (%s)" % { translate("mtu"), translate("optional") },
|
||||
translate("Maximum transmission unit of UDP packets."))
|
||||
o.datatype = "range(64,9200)"
|
||||
o.placeholder = "1350"
|
||||
|
||||
o = s:option(Value, "sndwnd", "%s (%s)" % { translate("sndwnd"), translate("optional") },
|
||||
translate("Send Window Size(num of packets)."))
|
||||
o.datatype = "min(1)"
|
||||
o.default = "128"
|
||||
o.placeholder = "128"
|
||||
|
||||
o = s:option(Value, "rcvwnd", "%s (%s)" % { translate("rcvwnd"), translate("optional") },
|
||||
translate("Receive Window Size(num of packets)."))
|
||||
o.datatype = "min(1)"
|
||||
o.default = "512"
|
||||
o.placeholder = "512"
|
||||
|
||||
o = s:option(Value, "datashard", "%s (%s)" % { translate("datashard"), translate("optional") },
|
||||
translate("Reed-solomon Erasure Coding - datashard."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "10"
|
||||
|
||||
o = s:option(Value, "parityshard", "%s (%s)" % { translate("parityshard"), translate("optional") },
|
||||
translate("Reed-solomon Erasure Coding - parityshard."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "3"
|
||||
|
||||
o = s:option(Value, "dscp", "%s (%s)" % { translate("dscp"), translate("optional") }, translate("DSCP(6bit)"))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:option(Flag, "nocomp", translate("nocomp"), translate("Disable Compression?"))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "acknodelay", translate("acknodelay"))
|
||||
o.enabled = "true"
|
||||
o.disabled = "false"
|
||||
|
||||
o = s:option(Value, "conn", "%s (%s)" %{ translate("conn"), translate("optional") },
|
||||
translate("Number of UDP connections to server."))
|
||||
o.datatype = "min(1)"
|
||||
o.placeholder = "1"
|
||||
|
||||
o = s:option(Value, "autoexpire", "%s (%s)" % { translate("autoexpire"), translate("optional") },
|
||||
translate("Auto expiration time(in seconds) for a single UDP connection, 0 to disable."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "0"
|
||||
|
||||
o = s:option(Value, "scavengettl", "%s (%s)" % { translate("scavengettl"), translate("optional") },
|
||||
translate("How long an expired connection can live(in sec), -1 to disable."))
|
||||
o.datatype = "min(-1)"
|
||||
o.placeholder = "600"
|
||||
|
||||
o = s:option(Value, "sockbuf", "%s (%s)" % { translate("sockbuf"), translate("optional") },
|
||||
translate("Send/secv buffer size of udp sockets, default unit is MB."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "4"
|
||||
o.cfgvalue = function(...)
|
||||
local value = Value.cfgvalue(...)
|
||||
|
||||
if value then
|
||||
return tonumber(value) / 1024 / 1024
|
||||
end
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
local number = tonumber(value)
|
||||
if number then
|
||||
Value.write(self, section, number * 1024 * 1024)
|
||||
else
|
||||
Value.remove(self, section)
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(Value, "keepalive", "%s (%s)" % { translate("keepalive"), translate("optional") },
|
||||
translate("NAT keepalive interval to prevent your router from removing port mapping, default unit is seconds."))
|
||||
o.datatype = "uinteger"
|
||||
o.placeholder = "10"
|
||||
|
||||
o = s:option(Value, "snmpperiod", "%s (%s)" % { translate("snmpperiod"),
|
||||
translate("optional") }, translate("SNMP collect period, in seconds"))
|
||||
o.datatype = "min(1)"
|
||||
o.placeholder = "60"
|
||||
|
||||
return m
|
@ -0,0 +1,71 @@
|
||||
-- Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local dsp = require "luci.dispatcher"
|
||||
local http = require "luci.http"
|
||||
|
||||
local m, s, o
|
||||
|
||||
local function get_ip_string(ip)
|
||||
if ip and ip:find(":") then
|
||||
return "[%s]" % ip
|
||||
else
|
||||
return ip or ""
|
||||
end
|
||||
end
|
||||
|
||||
m = Map("kcptun", "%s - %s" % { translate("Kcptun"), translate("Server List") })
|
||||
|
||||
s = m:section(TypedSection, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
s.sortable = true
|
||||
s.template = "cbi/tblsection"
|
||||
s.extedit = dsp.build_url("admin/services/kcptun/servers/%s")
|
||||
function s.create(...)
|
||||
local sid = TypedSection.create(...)
|
||||
if sid then
|
||||
m.uci:save("kcptun")
|
||||
http.redirect(s.extedit % sid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "alias", translate("Alias"))
|
||||
function o.cfgvalue(self, section)
|
||||
return Value.cfgvalue(self, section) or translate("None")
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_server_address", translate("Server Address"))
|
||||
function o.cfgvalue(self, section)
|
||||
local server = m.uci:get("kcptun", section, "server_addr") or "?"
|
||||
local server_port = m.uci:get("kcptun", section, "server_port") or "29900"
|
||||
return "%s:%s" % { get_ip_string(server), server_port }
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_listen_addres", translate("Listen Address"))
|
||||
function o.cfgvalue(self, section)
|
||||
local local_host = m.uci.get("kcptun", section, "listen_addr") or "0.0.0.0"
|
||||
local local_port = m.uci.get("kcptun", section, "listen_port") or "12984"
|
||||
return "%s:%s" % { get_ip_string(local_host), local_port }
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "crypt", translate("Encrypt Method"))
|
||||
function o.cfgvalue(...)
|
||||
local v = Value.cfgvalue(...)
|
||||
return v and v:upper() or "?"
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "mode", translate("Embedded Mode"))
|
||||
function o.cfgvalue(...)
|
||||
local v = Value.cfgvalue(...)
|
||||
return v and v:upper() or "?"
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "nocomp", translate("Disable Compression"))
|
||||
function o.cfgvalue(...)
|
||||
local v = Value.cfgvalue(...)
|
||||
return v == "true" and translate("True") or translate("False")
|
||||
end
|
||||
|
||||
return m
|
@ -0,0 +1,112 @@
|
||||
-- Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local util = require "luci.util"
|
||||
local sys = require "luci.sys"
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local m, s, o
|
||||
local server_table = { }
|
||||
|
||||
local function get_ip_string(ip)
|
||||
if ip and ip:find(":") then
|
||||
return "[%s]" % ip
|
||||
else
|
||||
return ip or ""
|
||||
end
|
||||
end
|
||||
|
||||
uci:foreach("kcptun", "servers", function(s)
|
||||
if s.alias then
|
||||
server_table[s[".name"]] = s.alias
|
||||
elseif s.server_addr and s.server_port then
|
||||
server_table[s[".name"]] = "%s:%s" % { get_ip_string(s.server_addr), s.server_port }
|
||||
end
|
||||
end)
|
||||
|
||||
m = Map("kcptun", "%s - %s" % { translate("Kcptun"), translate("Settings") })
|
||||
m:append(Template("kcptun/status"))
|
||||
|
||||
s = m:section(NamedSection, "general", "general", translate("General Settings"))
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(ListValue, "server", translate("Server"))
|
||||
o:value("", translate("Disable"))
|
||||
for k, v in pairs(server_table) do
|
||||
o:value(k, v)
|
||||
end
|
||||
|
||||
o = s:option(Value, "client_file", translate("Client File"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "daemon_user", translate("Run Daemon as User"))
|
||||
for u in util.execi("cat /etc/passwd | cut -d ':' -f1") do
|
||||
o:value(u)
|
||||
end
|
||||
|
||||
o = s:option(Flag, "enable_logging", translate("Enable Logging"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "log_folder", translate("Log Folder"))
|
||||
o.datatype = "directory"
|
||||
o.placeholder = "/var/log/kcptun"
|
||||
o:depends("enable_logging", "1")
|
||||
o.formvalue = function(...)
|
||||
local v = (Value.formvalue(...) or ""):trim()
|
||||
if v ~= "" then
|
||||
v = string.gsub(v, "\\", "/")
|
||||
if v:sub(1, 1) ~= "/" then
|
||||
v = "/" .. v
|
||||
end
|
||||
|
||||
while v:sub(-1) == "/" do
|
||||
v = v:sub(1, -2)
|
||||
end
|
||||
end
|
||||
|
||||
return v
|
||||
end
|
||||
o.validate = function(self, value, section)
|
||||
if value and not fs.stat(value) then
|
||||
local res, code, msg = fs.mkdir(value)
|
||||
if not res then
|
||||
return nil, msg
|
||||
end
|
||||
end
|
||||
return Value.validate(self, value, section)
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "arch", translate("CPU Architecture"),
|
||||
translate("The ARCH for checking updates." ..
|
||||
" Note: Make sure OpenWrt/LEDE 'MIPS FPU Emulator' is enabled on MIPS/MIPSLE devices."))
|
||||
o:value("", translate("Auto"))
|
||||
o:value("i386", "x86")
|
||||
o:value("x86_64", "x86_64")
|
||||
o:value("armv5", "ARMv5")
|
||||
o:value("armv6", "ARMv6")
|
||||
o:value("armv7", "ARMv7+")
|
||||
o:value("ar71xx", "MIPS")
|
||||
o:value("ramips", "MIPSLE")
|
||||
|
||||
o = s:option(Button, "_check_kcptun", translate("Check Kcptun Update"),
|
||||
translate("Make sure that the 'Client File' dictionary has enough space."))
|
||||
o.template = "kcptun/button"
|
||||
o.inputstyle = "apply"
|
||||
o.placeholder = translate("Check Kcptun Update")
|
||||
o.btnclick = "check_update('kcptun', this);"
|
||||
o.id = "_kcptun-check_kcptun"
|
||||
|
||||
o = s:option(Flag, "save_config", translate("Save Config File"),
|
||||
translate("Save config file while upgrade LuCI."))
|
||||
|
||||
o = s:option(Button, "_check_luci", translate("Check LuCI Update"),
|
||||
translate("You may need to reload current page after update LuCI. Note that translation will not be updated."))
|
||||
o.template = "kcptun/button"
|
||||
o.inputstyle = "apply"
|
||||
o.placeholder = translate("Check LuCI Update")
|
||||
o.btnclick = "check_update('luci', this);"
|
||||
o.id = "_kcptun-check_luci"
|
||||
|
||||
return m
|
486
package/lean/luci-app-kcptun/luasrc/model/kcptun.lua
Normal file
486
package/lean/luci-app-kcptun/luasrc/model/kcptun.lua
Normal file
@ -0,0 +1,486 @@
|
||||
-- Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local util = require "luci.util"
|
||||
local i18n = require "luci.i18n"
|
||||
|
||||
module("luci.model.kcptun", package.seeall)
|
||||
|
||||
local kcptun_api = "https://api.github.com/repos/xtaci/kcptun/releases/latest"
|
||||
local luci_api = "https://api.github.com/repos/kuoruan/luci-app-kcptun/releases/latest"
|
||||
|
||||
local wget = "/usr/bin/wget"
|
||||
local wget_args = { "--no-check-certificate", "--quiet", "--timeout=10", "--tries=2" }
|
||||
local command_timeout = 40
|
||||
|
||||
local function _unpack(t, i)
|
||||
i = i or 1
|
||||
if t[i] ~= nil then
|
||||
return t[i], _unpack(t, i + 1)
|
||||
end
|
||||
end
|
||||
|
||||
local function exec(cmd, args, writer, timeout)
|
||||
local os = require "os"
|
||||
local nixio = require "nixio"
|
||||
|
||||
local fdi, fdo = nixio.pipe()
|
||||
local pid = nixio.fork()
|
||||
|
||||
if pid > 0 then
|
||||
fdo:close()
|
||||
|
||||
if writer or timeout then
|
||||
local starttime = os.time()
|
||||
while true do
|
||||
if timeout and os.difftime(os.time(), starttime) >= timeout then
|
||||
nixio.kill(pid, nixio.const.SIGTERM)
|
||||
return 1
|
||||
end
|
||||
|
||||
if writer then
|
||||
local buffer = fdi:read(2048)
|
||||
if buffer and #buffer > 0 then
|
||||
writer(buffer)
|
||||
end
|
||||
end
|
||||
|
||||
local wpid, stat, code = nixio.waitpid(pid, "nohang")
|
||||
|
||||
if wpid and stat == "exited" then
|
||||
return code
|
||||
end
|
||||
|
||||
if not writer and timeout then
|
||||
nixio.nanosleep(1)
|
||||
end
|
||||
end
|
||||
else
|
||||
local wpid, stat, code = nixio.waitpid(pid)
|
||||
return wpid and stat == "exited" and code
|
||||
end
|
||||
elseif pid == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exece(cmd, args, nil)
|
||||
nixio.stdout:close()
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_versions(ver1, comp, ver2)
|
||||
local table = table
|
||||
|
||||
local av1 = util.split(ver1, "[%.%-]", nil, true)
|
||||
local av2 = util.split(ver2, "[%.%-]", nil, true)
|
||||
|
||||
local max = table.getn(av1)
|
||||
local n2 = table.getn(av2)
|
||||
if (max < n2) then
|
||||
max = n2
|
||||
end
|
||||
|
||||
for i = 1, max, 1 do
|
||||
local s1 = av1[i] or ""
|
||||
local s2 = av2[i] or ""
|
||||
|
||||
if comp == "~=" and (s1 ~= s2) then return true end
|
||||
if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
|
||||
if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
|
||||
if (s1 ~= s2) then return false end
|
||||
end
|
||||
|
||||
return not (comp == "<" or comp == ">")
|
||||
end
|
||||
|
||||
local function auto_get_arch()
|
||||
local arch = nixio.uname().machine or ""
|
||||
|
||||
if arch == "mips" then
|
||||
if fs.access("/usr/lib/os-release") then
|
||||
arch = sys.exec("grep 'LEDE_BOARD' /usr/lib/os-release | grep -oE 'ramips|ar71xx'")
|
||||
elseif fs.access("/etc/openwrt_release") then
|
||||
arch = sys.exec("grep 'DISTRIB_TARGET' /etc/openwrt_release | grep -oE 'ramips|ar71xx'")
|
||||
end
|
||||
end
|
||||
|
||||
return util.trim(arch)
|
||||
end
|
||||
|
||||
local function get_file_info(arch)
|
||||
local file_tree = ""
|
||||
local sub_version = ""
|
||||
|
||||
if arch == "x86_64" then
|
||||
file_tree = "amd64"
|
||||
elseif arch == "ramips" then
|
||||
file_tree = "mipsle"
|
||||
elseif arch == "ar71xx" then
|
||||
file_tree = "mips"
|
||||
elseif arch:match("^i[%d]86$") then
|
||||
file_tree = "386"
|
||||
elseif arch:match("^armv[5-8]") then
|
||||
file_tree = "arm"
|
||||
sub_version = arch:match("[5-8]")
|
||||
end
|
||||
|
||||
return file_tree, sub_version
|
||||
end
|
||||
|
||||
local function get_api_json(url)
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local output = { }
|
||||
exec(wget, { "-O-", url, _unpack(wget_args) },
|
||||
function(chunk) output[#output + 1] = chunk end)
|
||||
|
||||
local json_content = util.trim(table.concat(output))
|
||||
|
||||
if json_content == "" then
|
||||
return { }
|
||||
end
|
||||
|
||||
return jsonc.parse(json_content) or { }
|
||||
end
|
||||
|
||||
function get_config_option(option, default)
|
||||
return uci:get("kcptun", "general", option) or default
|
||||
end
|
||||
|
||||
function get_current_log_file(type)
|
||||
local log_folder = get_config_option("log_folder", "/var/log/kcptun")
|
||||
return "%s/%s.%s.log" % { log_folder, type, "general" }
|
||||
end
|
||||
|
||||
function is_running(client)
|
||||
if client and client ~= "" then
|
||||
local file_name = client:match(".*/([^/]+)$") or ""
|
||||
if file_name ~= "" then
|
||||
return sys.call("pidof %s >/dev/null" % file_name) == 0
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function get_kcptun_version(file)
|
||||
if file and file ~= "" then
|
||||
if not fs.access(file, "rwx", "rx", "rx") then
|
||||
fs.chmod(file, 755)
|
||||
end
|
||||
|
||||
local info = util.trim(sys.exec("%s -v 2>/dev/null" % file))
|
||||
|
||||
if info ~= "" then
|
||||
local tb = util.split(info, "%s+", nil, true)
|
||||
return tb[1] == "kcptun" and tb[3] or ""
|
||||
end
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
function get_luci_version()
|
||||
local ipkg = require "luci.model.ipkg"
|
||||
|
||||
local package_name = "luci-app-kcptun"
|
||||
local package_info = ipkg.info(package_name) or {}
|
||||
|
||||
if next(package_info) ~= nil then
|
||||
return package_info[package_name]["Version"]
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function check_kcptun(arch)
|
||||
if not arch or arch == "" then
|
||||
arch = auto_get_arch()
|
||||
end
|
||||
|
||||
local file_tree, sub_version = get_file_info(arch)
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported. Please select manually.")
|
||||
}
|
||||
end
|
||||
|
||||
local json = get_api_json(kcptun_api)
|
||||
|
||||
if json.tag_name == nil then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Get remote version info failed.")
|
||||
}
|
||||
end
|
||||
|
||||
local remote_version = json.tag_name:match("[^v]+")
|
||||
|
||||
local client_file = get_config_option("client_file")
|
||||
|
||||
local needs_update = compare_versions(get_kcptun_version(client_file), "<", remote_version)
|
||||
local html_url, download_url
|
||||
|
||||
if needs_update then
|
||||
html_url = json.html_url
|
||||
for _, v in ipairs(json.assets) do
|
||||
if v.name and v.name:match("linux%-" .. file_tree) then
|
||||
download_url = v.browser_download_url
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if needs_update and not download_url then
|
||||
return {
|
||||
code = 1,
|
||||
version = remote_version,
|
||||
html_url = html_url,
|
||||
error = i18n.translate("New version found, but failed to get new version download url.")
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
code = 0,
|
||||
update = needs_update,
|
||||
version = remote_version,
|
||||
url = {
|
||||
html = html_url,
|
||||
download = download_url
|
||||
},
|
||||
type = file_tree .. sub_version
|
||||
}
|
||||
end
|
||||
|
||||
function check_luci()
|
||||
local json = get_api_json(luci_api)
|
||||
|
||||
if json.tag_name == nil then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Get remote version info failed.")
|
||||
}
|
||||
end
|
||||
|
||||
local remote_version = json.tag_name:match("[^v]+")
|
||||
|
||||
local needs_update = compare_versions(get_luci_version(), "<", remote_version)
|
||||
local html_url, luci_url
|
||||
local i18n_urls = { }
|
||||
|
||||
if needs_update then
|
||||
html_url = json.html_url
|
||||
for _, v in ipairs(json.assets) do
|
||||
local n = v.name
|
||||
if n then
|
||||
if n:match("luci%-app%-kcptun") then
|
||||
luci_url = v.browser_download_url
|
||||
elseif n:match("luci%-i18n%-kcptun") then
|
||||
i18n_urls[#i18n_urls + 1] = v.browser_download_url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if needs_update and not luci_url then
|
||||
return {
|
||||
code = 1,
|
||||
version = remote_version,
|
||||
html_url = html_url,
|
||||
error = i18n.translate("New version found, but failed to get new version download url.")
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
code = 0,
|
||||
update = needs_update,
|
||||
version = remote_version,
|
||||
url = {
|
||||
html = html_url,
|
||||
luci = luci_url,
|
||||
i18n = i18n_urls
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function download_kcptun(url)
|
||||
if not url or url == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Download url is required.")
|
||||
}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/kcptun_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t kcptun_download.XXXXXX"))
|
||||
|
||||
local result = exec(wget, {
|
||||
"-O", tmp_file, url, _unpack(wget_args) }, nil, command_timeout) == 0
|
||||
|
||||
if not result then
|
||||
exec("/bin/rm", { "-f", tmp_file })
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("File download failed or timed out: %s", url)
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
code = 0,
|
||||
file = tmp_file
|
||||
}
|
||||
end
|
||||
|
||||
function extract_kcptun(file, subfix)
|
||||
if not file or file == "" or not fs.access(file) then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("File path required.")
|
||||
}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t kcptun_extract.XXXXXX"))
|
||||
|
||||
local output = { }
|
||||
exec("/bin/tar", { "-C", tmp_dir, "-zxvf", file },
|
||||
function(chunk) output[#output + 1] = chunk end)
|
||||
|
||||
local files = util.split(table.concat(output))
|
||||
|
||||
exec("/bin/rm", { "-f", file })
|
||||
|
||||
local new_file = nil
|
||||
for _, f in pairs(files) do
|
||||
if f:match("client_linux_%s" % subfix) then
|
||||
new_file = tmp_dir .. "/" .. util.trim(f)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not new_file then
|
||||
for _, f in pairs(files) do
|
||||
if f:match("client_") then
|
||||
new_file = tmp_dir .. "/" .. util.trim(f)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not new_file then
|
||||
exec("/bin/rm", { "-rf", tmp_dir })
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("Can't find client in file: %s", file)
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
code = 0,
|
||||
file = new_file
|
||||
}
|
||||
end
|
||||
|
||||
function move_kcptun(file)
|
||||
if not file or file == "" or not fs.access(file) then
|
||||
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Client file is required.")
|
||||
}
|
||||
end
|
||||
|
||||
local version = get_kcptun_version(file)
|
||||
if version == "" then
|
||||
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("The client file is not suitable for current device. Please reselect ARCH.")
|
||||
}
|
||||
end
|
||||
|
||||
local client_file = get_config_option("client_file", "/var/kcptun_client")
|
||||
local client_file_bak
|
||||
|
||||
if fs.access(client_file) then
|
||||
client_file_bak = client_file .. ".bak"
|
||||
exec("/bin/mv", { "-f", client_file, client_file_bak })
|
||||
end
|
||||
|
||||
local result = exec("/bin/mv", { "-f", file, client_file }, nil, command_timeout) == 0
|
||||
|
||||
if not result or not fs.access(client_file) then
|
||||
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
|
||||
if client_file_bak then
|
||||
exec("/bin/mv", { "-f", client_file_bak, client_file })
|
||||
end
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("Can't move new file to path: %s", client_file)
|
||||
}
|
||||
end
|
||||
|
||||
exec("/bin/chmod", { "755", client_file })
|
||||
|
||||
if client_file_bak then
|
||||
exec("/bin/rm", { "-f", client_file_bak })
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/kcptun_extract.*")
|
||||
|
||||
uci:set("kcptun", "general", "client_file", client_file)
|
||||
uci:commit("kcptun")
|
||||
|
||||
return { code = 0 }
|
||||
end
|
||||
|
||||
function update_luci(url, save)
|
||||
if not url or url == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Download url is required.")
|
||||
}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/luci_kcptun.*.ipk")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t luci_kcptun.XXXXXX")) .. ".ipk"
|
||||
|
||||
local result = exec("/usr/bin/wget", {
|
||||
"-O", tmp_file, url, _unpack(wget_args) }, nil, command_timeout) == 0
|
||||
|
||||
if not result then
|
||||
exec("/bin/rm", { "-f", tmp_file })
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("File download failed or timed out: %s", url)
|
||||
}
|
||||
end
|
||||
|
||||
local opkg_args = { "--force-downgrade", "--force-reinstall" }
|
||||
|
||||
if save ~= "true" then
|
||||
opkg_args[#opkg_args + 1] = "--force-maintainer"
|
||||
end
|
||||
|
||||
result = exec("/bin/opkg", { "install", tmp_file, _unpack(opkg_args) }) == 0
|
||||
|
||||
if not result then
|
||||
exec("/bin/rm", { "-f", tmp_file })
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Package update failed.")
|
||||
}
|
||||
end
|
||||
|
||||
exec("/bin/rm", { "-f", tmp_file })
|
||||
exec("/bin/rm", { "-rf", "/tmp/luci-indexcache", "/tmp/luci-modulecache" })
|
||||
|
||||
return { code = 0 }
|
||||
end
|
19
package/lean/luci-app-kcptun/luasrc/view/kcptun/button.htm
Normal file
19
package/lean/luci-app-kcptun/luasrc/view/kcptun/button.htm
Normal file
@ -0,0 +1,19 @@
|
||||
<%#
|
||||
Copyright 2017 Hsing-wang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<%+cbi/valueheader%>
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" type="button"<%=
|
||||
attr("name", cbid) ..
|
||||
attr("id", self.id or cbid) ..
|
||||
attr("value", self.inputtitle or self.title) ..
|
||||
ifattr(self.btnclick, "onclick", self.btnclick) ..
|
||||
ifattr(self.placeholder, "placeholder")
|
||||
%> />
|
||||
<span id="<%=self.id or cbid%>-detail"></span>
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
74
package/lean/luci-app-kcptun/luasrc/view/kcptun/log_view.htm
Normal file
74
package/lean/luci-app-kcptun/luasrc/view/kcptun/log_view.htm
Normal file
@ -0,0 +1,74 @@
|
||||
<%#
|
||||
Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<% css = [[
|
||||
|
||||
#log_text {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
#log_text pre {
|
||||
word-break: break-all;
|
||||
margin: 0;
|
||||
}
|
||||
.description {
|
||||
background-color: #33ccff;
|
||||
}
|
||||
|
||||
]]
|
||||
%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<div class="cbi-map">
|
||||
<h2 name="content"><%:Kcptun%> - <%:Log Data%></h2>
|
||||
<fieldset class="cbi-section">
|
||||
<div class="cbi-section-descr">
|
||||
<input type="button" class="cbi-button" value="<%:Clear Log File%>" placeholder="<%:Clear Log File%>" onclick="return log_clear('client', this)" />
|
||||
</div>
|
||||
<fieldset class="cbi-section-node">
|
||||
<div id="log_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div>
|
||||
<div style="text-align:right"><small><%:Refresh every 5 seconds.%></small></div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
function log_clear(type, btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Processing...%>';
|
||||
|
||||
(new XHR()).get('<%=luci.dispatcher.build_url("admin/services/kcptun/log/clear")%>/' + type,
|
||||
{ token: '<%=token%>' },
|
||||
function(x, json) {
|
||||
btn.disabled = false;
|
||||
btn.value = btn.placeholder;
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
(function(doc) {
|
||||
var log_elm = doc.getElementById('log_text');
|
||||
XHR.poll(5, '<%=luci.dispatcher.build_url("admin/services/kcptun/log/data")%>', null,
|
||||
function(x, data) {
|
||||
if (log_elm && data) {
|
||||
log_elm.innerHTML = String.format(
|
||||
'<pre>%s%s%s%s</pre>',
|
||||
'<span class="description"><%:Last 50 lines of log file:%></span><br/><br/>',
|
||||
data.client || '<%:No log data.%>',
|
||||
'<br/><br/><span class="description"><%:Last 50 lines of syslog:%></span><br/><br/>',
|
||||
data.syslog || '<%:No log data.%>'
|
||||
);
|
||||
} else if (log_elm) {
|
||||
log_elm.innerHTML = '<strong><%:Error get log data.%></strong>';
|
||||
}
|
||||
}
|
||||
);
|
||||
}(document));
|
||||
//]]></script>
|
||||
|
||||
<%+footer%>
|
258
package/lean/luci-app-kcptun/luasrc/view/kcptun/status.htm
Normal file
258
package/lean/luci-app-kcptun/luasrc/view/kcptun/status.htm
Normal file
@ -0,0 +1,258 @@
|
||||
<%#
|
||||
Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<%
|
||||
local kcp = require "luci.model.kcptun"
|
||||
local dsp = require "luci.dispatcher"
|
||||
|
||||
local client_file = kcp.get_config_option("client_file")
|
||||
local client_version = kcp.get_kcptun_version(client_file)
|
||||
local luci_version = kcp.get_luci_version()
|
||||
-%>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Running Status%></legend>
|
||||
<table width="100%" cellspacing="10" id="_kcptun-status_table">
|
||||
<tr>
|
||||
<td width="33%"><%:Client Version%></td>
|
||||
<td>
|
||||
<% if client_version == "" then -%>
|
||||
<em><%:Invalid Client File.%></em>
|
||||
<% else -%>
|
||||
<%=pcdata(client_version)%>
|
||||
<%- end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td width="33%"><%:Client Status%></td><td id="_kcptun-client_status"><em><%:Collecting data...%></em></td></tr>
|
||||
<% if luci_version ~= "" then -%>
|
||||
<tr><td width="33%"><%:LuCI Version%></td><td><%=pcdata(luci_version)%></td></tr>
|
||||
<% end -%>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var client_status = document.getElementById('_kcptun-client_status');
|
||||
XHR.poll(5, '<%=dsp.build_url("admin/services/kcptun/status")%>', null,
|
||||
function(x, json) {
|
||||
if (x && x.status == 200) {
|
||||
client_status.innerHTML = json.client ? '<%:Running%>' : '<%:Not Running%>';
|
||||
}
|
||||
});
|
||||
|
||||
function add_remove_page_notice(isAdd) {
|
||||
if (isAdd) {
|
||||
window.onbeforeunload = function(e) {
|
||||
var dialogText = '<%:Update in progress. Are you sure to close window?%>';
|
||||
e.returnValue = dialogText;
|
||||
return dialogText;
|
||||
};
|
||||
} else {
|
||||
window.onbeforeunload = null;
|
||||
}
|
||||
}
|
||||
|
||||
function on_update_success(btn) {
|
||||
add_remove_page_notice(false);
|
||||
|
||||
var success = '<%:Update Success.%>';
|
||||
|
||||
if (btn) {
|
||||
btn.value = success;
|
||||
btn.placeholder = success;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
alert(success);
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function on_request_error(btn, json) {
|
||||
add_remove_page_notice(false);
|
||||
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.value = btn.placeholder;
|
||||
}
|
||||
|
||||
if (json && json.error) {
|
||||
alert(json.error);
|
||||
}
|
||||
}
|
||||
|
||||
function createVersionUrl(version, url) {
|
||||
var urlNode = '';
|
||||
if (url) {
|
||||
urlNode += '<a href="' + url + '" target="_blank">';
|
||||
}
|
||||
|
||||
urlNode += '<em style="color:red;">' + version + '</em>';
|
||||
|
||||
if (url) {
|
||||
urlNode += '</a>';
|
||||
}
|
||||
|
||||
return urlNode;
|
||||
}
|
||||
|
||||
var kcptun_info, luci_info;
|
||||
|
||||
var token_str = '<%=token%>';
|
||||
var arch_select;
|
||||
|
||||
function init_arch_select() {
|
||||
if (!arch_select) {
|
||||
arch_select = document.getElementById('cbid.kcptun.general.arch');
|
||||
|
||||
arch_select.addEventListener('change', function() {
|
||||
kcptun_info = null;
|
||||
var check_kcptun_btn = document.getElementById('_kcptun-check_kcptun');
|
||||
var text = '<%:Check Kcptun Update%>';
|
||||
check_kcptun_btn.value = text;
|
||||
check_kcptun_btn.placeholder = text;
|
||||
check_kcptun_btn.setAttribute('onclick', 'check_update(\'kcptun\', this);');
|
||||
|
||||
var detail = document.getElementById('_kcptun-check_kcptun-detail');
|
||||
detail.innerHTML = '';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function check_update(type, btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Processing...%>';
|
||||
|
||||
init_arch_select();
|
||||
add_remove_page_notice(true);
|
||||
|
||||
(new XHR()).get('<%=dsp.build_url("admin/services/kcptun/check")%>/' + type, {
|
||||
token: token_str,
|
||||
arch: arch_select ? arch_select.value : ""
|
||||
}, function(x, json) {
|
||||
if (x && x.status == 200) {
|
||||
var detailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
if (json.code == 0) {
|
||||
add_remove_page_notice(false);
|
||||
|
||||
if (json.update) {
|
||||
eval(type + '_info = json');
|
||||
|
||||
btn.disabled = false;
|
||||
btn.value = '<%:Click to Update%>';
|
||||
btn.placeholder = '<%:Click to Update%>';
|
||||
|
||||
btn.setAttribute('onclick', 'do_' + type + '_update(this);');
|
||||
|
||||
if (detailElm) {
|
||||
detailElm.innerHTML = createVersionUrl(json.version, json.url.html);
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:No Update Found%>';
|
||||
|
||||
if (detailElm) {
|
||||
detailElm.innerHTML = '';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (detailElm && json.html_url) {
|
||||
detailElm.innerHTML = createVersionUrl(json.version, json.html_url)
|
||||
}
|
||||
|
||||
on_request_error(btn, json);
|
||||
}
|
||||
} else {
|
||||
on_request_error(btn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function do_kcptun_update(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Downloading...%>';
|
||||
|
||||
add_remove_page_notice(true);
|
||||
|
||||
var kcptun_update_url = '<%=dsp.build_url("admin/services/kcptun/update/kcptun")%>';
|
||||
|
||||
(new XHR()).get(kcptun_update_url, {
|
||||
token: token_str,
|
||||
url: kcptun_info ? kcptun_info.url.download : ''
|
||||
}, function (x, json) {
|
||||
if (x && x.status == 200) {
|
||||
if (json.code == 0) {
|
||||
btn.value = '<%:Extracting...%>';
|
||||
|
||||
(new XHR()).get(kcptun_update_url, {
|
||||
token: token_str,
|
||||
task: "extract",
|
||||
file: json.file,
|
||||
subfix: kcptun_info ? kcptun_info.type : ''
|
||||
}, function (x, json) {
|
||||
if (x && x.status == 200) {
|
||||
if (json.code == 0) {
|
||||
btn.value = '<%:Moving...%>';
|
||||
|
||||
(new XHR()).get(kcptun_update_url, {
|
||||
token: token_str,
|
||||
task: "move",
|
||||
file: json.file
|
||||
}, function (x, json) {
|
||||
if (x && x.status == 200) {
|
||||
if (json.code == 0) {
|
||||
on_update_success(btn);
|
||||
} else {
|
||||
on_request_error(btn, json);
|
||||
}
|
||||
} else {
|
||||
on_request_error(btn);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
on_request_error(btn, json);
|
||||
}
|
||||
} else {
|
||||
on_request_error(btn);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
on_request_error(btn, json);
|
||||
}
|
||||
} else {
|
||||
on_request_error(btn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function do_luci_update(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Processing...%>';
|
||||
|
||||
add_remove_page_notice(true);
|
||||
|
||||
var save_config = document.getElementById('cbid.kcptun.general.save_config');
|
||||
|
||||
(new XHR()).get('<%=dsp.build_url("admin/services/kcptun/update/luci")%>', {
|
||||
token: token_str,
|
||||
url: luci_info ? luci_info.url.luci : '',
|
||||
save: save_config ? save_config.checked : false
|
||||
}, function(x, json) {
|
||||
btn.disabled = false;
|
||||
btn.value = btn.placeholder;
|
||||
if (x && x.status == 200) {
|
||||
if (json.code == 0) {
|
||||
on_update_success(btn);
|
||||
} else {
|
||||
on_request_error(btn, json);
|
||||
}
|
||||
} else {
|
||||
on_request_error(btn);
|
||||
}
|
||||
});
|
||||
}
|
||||
//]]></script>
|
346
package/lean/luci-app-kcptun/po/templates/kcptun.pot
Normal file
346
package/lean/luci-app-kcptun/po/templates/kcptun.pot
Normal file
@ -0,0 +1,346 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "2nd ACK"
|
||||
msgstr ""
|
||||
|
||||
msgid "Alias"
|
||||
msgstr ""
|
||||
|
||||
msgid "Auto"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Auto expiration time(in seconds) for a single UDP connection, 0 to disable."
|
||||
msgstr ""
|
||||
|
||||
msgid "CPU Architecture"
|
||||
msgstr ""
|
||||
|
||||
msgid "Can't determine ARCH, or ARCH not supported. Please select manually."
|
||||
msgstr ""
|
||||
|
||||
msgid "Can't find client in file: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Can't move new file to path: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check Kcptun Update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check LuCI Update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Clear Log File"
|
||||
msgstr ""
|
||||
|
||||
msgid "Click to Update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Client File"
|
||||
msgstr ""
|
||||
|
||||
msgid "Client Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Client Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Client file is required."
|
||||
msgstr ""
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr ""
|
||||
|
||||
msgid "DSCP(6bit)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable Compression"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable Compression?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download url is required."
|
||||
msgstr ""
|
||||
|
||||
msgid "Downloading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit Server"
|
||||
msgstr ""
|
||||
|
||||
msgid "Embedded Mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable Logging"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable nodelay Mode."
|
||||
msgstr ""
|
||||
|
||||
msgid "Encrypt Method"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error get log data."
|
||||
msgstr ""
|
||||
|
||||
msgid "Extracting..."
|
||||
msgstr ""
|
||||
|
||||
msgid "False"
|
||||
msgstr ""
|
||||
|
||||
msgid "File download failed or timed out: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "File path required."
|
||||
msgstr ""
|
||||
|
||||
msgid "General Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Get remote version info failed."
|
||||
msgstr ""
|
||||
|
||||
msgid "How long an expired connection can live(in sec), -1 to disable."
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid Client File."
|
||||
msgstr ""
|
||||
|
||||
msgid "Kcptun"
|
||||
msgstr ""
|
||||
|
||||
msgid "Kcptun Client"
|
||||
msgstr ""
|
||||
|
||||
msgid "Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last 50 lines of log file:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last 50 lines of syslog:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Listen Address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local Listen Host"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local Listen Port."
|
||||
msgstr ""
|
||||
|
||||
msgid "Local Port"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local listen host."
|
||||
msgstr ""
|
||||
|
||||
msgid "Log"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log Data"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log Folder"
|
||||
msgstr ""
|
||||
|
||||
msgid "LuCI Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Make sure that the 'Client File' dictionary has enough space."
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum transmission unit of UDP packets."
|
||||
msgstr ""
|
||||
|
||||
msgid "Moving..."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"NAT keepalive interval to prevent your router from removing port mapping, "
|
||||
"default unit is seconds."
|
||||
msgstr ""
|
||||
|
||||
msgid "New version found, but failed to get new version download url."
|
||||
msgstr ""
|
||||
|
||||
msgid "No Update Found"
|
||||
msgstr ""
|
||||
|
||||
msgid "No log data."
|
||||
msgstr ""
|
||||
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not Running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of UDP connections to server."
|
||||
msgstr ""
|
||||
|
||||
msgid "Off"
|
||||
msgstr ""
|
||||
|
||||
msgid "On"
|
||||
msgstr ""
|
||||
|
||||
msgid "Package update failed."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pre-shared secret for client and server."
|
||||
msgstr ""
|
||||
|
||||
msgid "Processing..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Receive Window Size(num of packets)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Reed-solomon Erasure Coding - datashard."
|
||||
msgstr ""
|
||||
|
||||
msgid "Reed-solomon Erasure Coding - parityshard."
|
||||
msgstr ""
|
||||
|
||||
msgid "Refresh every 5 seconds."
|
||||
msgstr ""
|
||||
|
||||
msgid "Run Daemon as User"
|
||||
msgstr ""
|
||||
|
||||
msgid "Running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Running Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "SNMP collect period, in seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save Config File"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save config file while upgrade LuCI."
|
||||
msgstr ""
|
||||
|
||||
msgid "Send Window Size(num of packets)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Send/secv buffer size of udp sockets, default unit is MB."
|
||||
msgstr ""
|
||||
|
||||
msgid "Server"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server Address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server List"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server Manage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Server Port"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The ARCH for checking updates. Note: Make sure OpenWrt/LEDE 'MIPS FPU "
|
||||
"Emulator' is enabled on MIPS/MIPSLE devices."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The client file is not suitable for current device. Please reselect ARCH."
|
||||
msgstr ""
|
||||
|
||||
msgid "True"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update Success."
|
||||
msgstr ""
|
||||
|
||||
msgid "Update in progress. Are you sure to close window?"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"You may need to reload current page after update LuCI. Note that translation "
|
||||
"will not be updated."
|
||||
msgstr ""
|
||||
|
||||
msgid "acknodelay"
|
||||
msgstr ""
|
||||
|
||||
msgid "autoexpire"
|
||||
msgstr ""
|
||||
|
||||
msgid "conn"
|
||||
msgstr ""
|
||||
|
||||
msgid "crypt"
|
||||
msgstr ""
|
||||
|
||||
msgid "datashard"
|
||||
msgstr ""
|
||||
|
||||
msgid "dscp"
|
||||
msgstr ""
|
||||
|
||||
msgid "interval"
|
||||
msgstr ""
|
||||
|
||||
msgid "keepalive"
|
||||
msgstr ""
|
||||
|
||||
msgid "mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "mtu"
|
||||
msgstr ""
|
||||
|
||||
msgid "nc"
|
||||
msgstr ""
|
||||
|
||||
msgid "nocomp"
|
||||
msgstr ""
|
||||
|
||||
msgid "nodelay"
|
||||
msgstr ""
|
||||
|
||||
msgid "optional"
|
||||
msgstr ""
|
||||
|
||||
msgid "parityshard"
|
||||
msgstr ""
|
||||
|
||||
msgid "rcvwnd"
|
||||
msgstr ""
|
||||
|
||||
msgid "resend"
|
||||
msgstr ""
|
||||
|
||||
msgid "scavengettl"
|
||||
msgstr ""
|
||||
|
||||
msgid "sndwnd"
|
||||
msgstr ""
|
||||
|
||||
msgid "snmpperiod"
|
||||
msgstr ""
|
||||
|
||||
msgid "sockbuf"
|
||||
msgstr ""
|
348
package/lean/luci-app-kcptun/po/zh-cn/kcptun.po
Normal file
348
package/lean/luci-app-kcptun/po/zh-cn/kcptun.po
Normal file
@ -0,0 +1,348 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "2nd ACK"
|
||||
msgstr "2次 ACK 跨越重传"
|
||||
|
||||
msgid "Alias"
|
||||
msgstr "别名"
|
||||
|
||||
msgid "Auto"
|
||||
msgstr "自动"
|
||||
|
||||
msgid ""
|
||||
"Auto expiration time(in seconds) for a single UDP connection, 0 to disable."
|
||||
msgstr "单个 UDP 连接的自动过期时间(秒),设置 0 来禁用"
|
||||
|
||||
msgid "CPU Architecture"
|
||||
msgstr "CPU 架构"
|
||||
|
||||
msgid "Can't determine ARCH, or ARCH not supported. Please select manually."
|
||||
msgstr "无法自动确定 ARCH,或者不支持该 ARCH,请手动重新选择。"
|
||||
|
||||
msgid "Can't find client in file: %s"
|
||||
msgstr "无法在文件中找到客户端:%s"
|
||||
|
||||
msgid "Can't move new file to path: %s"
|
||||
msgstr "无法移动新文件到:%s"
|
||||
|
||||
msgid "Check Kcptun Update"
|
||||
msgstr "检查 Kcptun 更新"
|
||||
|
||||
msgid "Check LuCI Update"
|
||||
msgstr "检查 LuCI 更新"
|
||||
|
||||
msgid "Clear Log File"
|
||||
msgstr "清理日志文件"
|
||||
|
||||
msgid "Click to Update"
|
||||
msgstr "点击更新"
|
||||
|
||||
msgid "Client File"
|
||||
msgstr "客户端文件"
|
||||
|
||||
msgid "Client Status"
|
||||
msgstr "客户端状态"
|
||||
|
||||
msgid "Client Version"
|
||||
msgstr "客户端版本"
|
||||
|
||||
msgid "Client file is required."
|
||||
msgstr "请指定客户端文件。"
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr "正在收集数据..."
|
||||
|
||||
msgid "DSCP(6bit)"
|
||||
msgstr "DSCP(6bit)"
|
||||
|
||||
msgid "Disable"
|
||||
msgstr "禁用"
|
||||
|
||||
msgid "Disable Compression"
|
||||
msgstr "禁用压缩"
|
||||
|
||||
msgid "Disable Compression?"
|
||||
msgstr "是否禁用压缩?"
|
||||
|
||||
msgid "Download url is required."
|
||||
msgstr "请指定下载链接。"
|
||||
|
||||
msgid "Downloading..."
|
||||
msgstr "正在下载..."
|
||||
|
||||
msgid "Edit Server"
|
||||
msgstr "编辑服务端"
|
||||
|
||||
msgid "Embedded Mode"
|
||||
msgstr "内置模式"
|
||||
|
||||
msgid "Enable Logging"
|
||||
msgstr "启用日志记录"
|
||||
|
||||
msgid "Enable nodelay Mode."
|
||||
msgstr "启用 nodelay 模式"
|
||||
|
||||
msgid "Encrypt Method"
|
||||
msgstr "加密方式"
|
||||
|
||||
msgid "Error get log data."
|
||||
msgstr "获取日志数据失败。"
|
||||
|
||||
msgid "Extracting..."
|
||||
msgstr "正在解压..."
|
||||
|
||||
msgid "False"
|
||||
msgstr "否"
|
||||
|
||||
msgid "File download failed or timed out: %s"
|
||||
msgstr "文件下载失败或超时:%s"
|
||||
|
||||
msgid "File path required."
|
||||
msgstr "请指定文件路径。"
|
||||
|
||||
msgid "General Settings"
|
||||
msgstr "基本设置"
|
||||
|
||||
msgid "Get remote version info failed."
|
||||
msgstr "获取远程版本信息失败。"
|
||||
|
||||
msgid "How long an expired connection can live(in sec), -1 to disable."
|
||||
msgstr "过期连接保留多长时间(秒),设置 -1 来禁用"
|
||||
|
||||
msgid "Invalid Client File."
|
||||
msgstr "客户端文件配置有误"
|
||||
|
||||
msgid "Kcptun"
|
||||
msgstr ""
|
||||
|
||||
msgid "Kcptun Client"
|
||||
msgstr "Kcptun 客户端"
|
||||
|
||||
msgid "Key"
|
||||
msgstr "密码"
|
||||
|
||||
msgid "Last 50 lines of log file:"
|
||||
msgstr "日志文件的最新 50 行:"
|
||||
|
||||
msgid "Last 50 lines of syslog:"
|
||||
msgstr "系统日志的最新 50 行:"
|
||||
|
||||
msgid "Listen Address"
|
||||
msgstr "监听地址"
|
||||
|
||||
msgid "Loading"
|
||||
msgstr "正在加载..."
|
||||
|
||||
msgid "Local Listen Host"
|
||||
msgstr "本地监听地址"
|
||||
|
||||
msgid "Local Listen Port."
|
||||
msgstr "本地监听端口"
|
||||
|
||||
msgid "Local Port"
|
||||
msgstr "本地端口"
|
||||
|
||||
msgid "Local listen host."
|
||||
msgstr "本地监听主机"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Log Data"
|
||||
msgstr "日志数据"
|
||||
|
||||
msgid "Log Folder"
|
||||
msgstr "日志文件夹"
|
||||
|
||||
msgid "LuCI Version"
|
||||
msgstr "LuCI 版本"
|
||||
|
||||
msgid "Make sure that the 'Client File' dictionary has enough space."
|
||||
msgstr "请确保“客户端文件”所在的文件夹具有足够的空间。"
|
||||
|
||||
msgid "Maximum transmission unit of UDP packets."
|
||||
msgstr "UDP数据包的最大传输单元"
|
||||
|
||||
msgid "Moving..."
|
||||
msgstr "正在移动..."
|
||||
|
||||
msgid ""
|
||||
"NAT keepalive interval to prevent your router from removing port mapping, "
|
||||
"default unit is seconds."
|
||||
msgstr "NAT Keepalive 包间隔时间(秒), 防止路由器删除端口映射"
|
||||
|
||||
msgid "New version found, but failed to get new version download url."
|
||||
msgstr "发现新版本,但是获取下载地址失败。"
|
||||
|
||||
msgid "No Update Found"
|
||||
msgstr "未发现更新"
|
||||
|
||||
msgid "No log data."
|
||||
msgstr "无日志数据。"
|
||||
|
||||
msgid "None"
|
||||
msgstr "无"
|
||||
|
||||
msgid "Not Running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Number of UDP connections to server."
|
||||
msgstr "到服务端的UDP连接数量"
|
||||
|
||||
msgid "Off"
|
||||
msgstr "关闭"
|
||||
|
||||
msgid "On"
|
||||
msgstr "开启"
|
||||
|
||||
msgid "Package update failed."
|
||||
msgstr "软件包升级失败。"
|
||||
|
||||
msgid "Pre-shared secret for client and server."
|
||||
msgstr "客户端和服务端的通信密码"
|
||||
|
||||
msgid "Processing..."
|
||||
msgstr "正在操作..."
|
||||
|
||||
msgid "Receive Window Size(num of packets)."
|
||||
msgstr "接收窗口大小 (数据包数量)"
|
||||
|
||||
msgid "Reed-solomon Erasure Coding - datashard."
|
||||
msgstr "前向纠错 - datashard"
|
||||
|
||||
msgid "Reed-solomon Erasure Coding - parityshard."
|
||||
msgstr "前向纠错 - parityshard"
|
||||
|
||||
msgid "Refresh every 5 seconds."
|
||||
msgstr "每 5 秒刷新。"
|
||||
|
||||
msgid "Run Daemon as User"
|
||||
msgstr "以该用户启动"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Running Status"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "SNMP collect period, in seconds"
|
||||
msgstr "SNMP采集周期(秒)"
|
||||
|
||||
msgid "Save Config File"
|
||||
msgstr "保留配置文件"
|
||||
|
||||
msgid "Save config file while upgrade LuCI."
|
||||
msgstr "在更新 LuCI 时保留配置文件"
|
||||
|
||||
msgid "Send Window Size(num of packets)."
|
||||
msgstr "发送窗口大小 (数据包数量)"
|
||||
|
||||
msgid "Send/secv buffer size of udp sockets, default unit is MB."
|
||||
msgstr "发送/接收UDP数据包的缓冲区大小(MB)"
|
||||
|
||||
msgid "Server"
|
||||
msgstr "服务端地址"
|
||||
|
||||
msgid "Server Address"
|
||||
msgstr "服务端地址"
|
||||
|
||||
msgid "Server List"
|
||||
msgstr "服务端列表"
|
||||
|
||||
msgid "Server Manage"
|
||||
msgstr "服务端管理"
|
||||
|
||||
msgid "Server Port"
|
||||
msgstr "服务端端口"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
msgid ""
|
||||
"The ARCH for checking updates. Note: Make sure OpenWrt/LEDE 'MIPS FPU "
|
||||
"Emulator' is enabled on MIPS/MIPSLE devices."
|
||||
msgstr ""
|
||||
"用于检查更新的 ARCH。注意: 在 MIPS/MIPSLE 设备上,请确保 OpenWrt/LEDE 的 "
|
||||
"'MIPS FPU Emulator' 已经启用。"
|
||||
|
||||
msgid ""
|
||||
"The client file is not suitable for current device. Please reselect ARCH."
|
||||
msgstr "客户端文件不适用于当前设备,请重新选择 ARCH。"
|
||||
|
||||
msgid "True"
|
||||
msgstr "是"
|
||||
|
||||
msgid "Update Success."
|
||||
msgstr "更新成功!"
|
||||
|
||||
msgid "Update in progress. Are you sure to close window?"
|
||||
msgstr "正在更新,确定关闭窗口?"
|
||||
|
||||
msgid ""
|
||||
"You may need to reload current page after update LuCI. Note that translation "
|
||||
"will not be updated."
|
||||
msgstr "更新 LuCI 之后你可能需要手动刷新当前页面。注意:翻译不会被更新"
|
||||
|
||||
msgid "acknodelay"
|
||||
msgstr ""
|
||||
|
||||
msgid "autoexpire"
|
||||
msgstr ""
|
||||
|
||||
msgid "conn"
|
||||
msgstr ""
|
||||
|
||||
msgid "crypt"
|
||||
msgstr ""
|
||||
|
||||
msgid "datashard"
|
||||
msgstr ""
|
||||
|
||||
msgid "dscp"
|
||||
msgstr ""
|
||||
|
||||
msgid "interval"
|
||||
msgstr ""
|
||||
|
||||
msgid "keepalive"
|
||||
msgstr ""
|
||||
|
||||
msgid "mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "mtu"
|
||||
msgstr ""
|
||||
|
||||
msgid "nc"
|
||||
msgstr ""
|
||||
|
||||
msgid "nocomp"
|
||||
msgstr ""
|
||||
|
||||
msgid "nodelay"
|
||||
msgstr ""
|
||||
|
||||
msgid "optional"
|
||||
msgstr "可选"
|
||||
|
||||
msgid "parityshard"
|
||||
msgstr ""
|
||||
|
||||
msgid "rcvwnd"
|
||||
msgstr ""
|
||||
|
||||
msgid "resend"
|
||||
msgstr ""
|
||||
|
||||
msgid "scavengettl"
|
||||
msgstr ""
|
||||
|
||||
msgid "sndwnd"
|
||||
msgstr ""
|
||||
|
||||
msgid "snmpperiod"
|
||||
msgstr ""
|
||||
|
||||
msgid "sockbuf"
|
||||
msgstr ""
|
15
package/lean/luci-app-kcptun/root/etc/config/kcptun
Normal file
15
package/lean/luci-app-kcptun/root/etc/config/kcptun
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
config general 'general'
|
||||
option server ''
|
||||
option client_file '/var/kcptun_client'
|
||||
option daemon_user 'root'
|
||||
option enable_logging '1'
|
||||
|
||||
config servers 'default'
|
||||
option server_addr ''
|
||||
option server_port '29900'
|
||||
option listen_addr '0.0.0.0'
|
||||
option listen_port '12948'
|
||||
option crypt 'aes'
|
||||
option mode 'fast'
|
||||
option nocomp 'false'
|
244
package/lean/luci-app-kcptun/root/etc/init.d/kcptun
Executable file
244
package/lean/luci-app-kcptun/root/etc/init.d/kcptun
Executable file
@ -0,0 +1,244 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# Copyright 2016-2017 Xingwang Liao <kuoruan@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
START=99
|
||||
USE_PROCD=1
|
||||
|
||||
KCPTUN=kcptun
|
||||
CONFIG_FOLDER=/var/etc/$KCPTUN
|
||||
|
||||
if [ -r /usr/share/libubox/jshn.sh ]; then
|
||||
. /usr/share/libubox/jshn.sh
|
||||
elif [ -r /lib/functions/jshn.sh ]; then
|
||||
. /lib/functions/jshn.sh
|
||||
else
|
||||
logger -p daemon.err -t "$KCPTUN" \
|
||||
"Package required: jshn."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_log() {
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
|
||||
logger -p "daemon.${level}" -t "$KCPTUN" "$msg"
|
||||
}
|
||||
|
||||
gen_client_config_file() {
|
||||
local config_file="$1"
|
||||
|
||||
json_init
|
||||
json_add_string "remoteaddr" "${server_addr}:${server_port}"
|
||||
json_add_string "localaddr" "${listen_addr}:${listen_port}"
|
||||
|
||||
add_configs() {
|
||||
local type="$1"; shift
|
||||
local k v
|
||||
|
||||
for k in "$@"; do
|
||||
v="$(eval echo "\$$k")"
|
||||
|
||||
if [ -n "$v" ]; then
|
||||
if [ "$type" = "string" ]; then
|
||||
json_add_string "$k" "$v"
|
||||
elif [ "$type" = "int" ]; then
|
||||
json_add_int "$k" "$v"
|
||||
elif [ "$type" = "boolean" ]; then
|
||||
if [ "$v" = "true" ]; then
|
||||
json_add_boolean "$k" "1"
|
||||
else
|
||||
json_add_boolean "$k" "0"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
add_configs "string" key crypt mode
|
||||
add_configs "int" conn autoexpire mtu sndwnd rcvwnd datashard parityshard dscp \
|
||||
nodelay interval resend nc sockbuf keepalive scavengettl snmpperiod
|
||||
add_configs "boolean" nocomp acknodelay
|
||||
|
||||
if [ -n "$log_file" ]; then
|
||||
json_add_string "log" "$log_file"
|
||||
fi
|
||||
|
||||
json_close_object
|
||||
|
||||
json_dump -i >"$config_file"
|
||||
}
|
||||
|
||||
setup_iptables_chain() {
|
||||
if ! ( iptables -nL "$KCPTUN" >/dev/null 2>&1 ); then
|
||||
iptables -N "$KCPTUN" 2>/dev/null
|
||||
fi
|
||||
|
||||
iptables -C OUTPUT -j "$KCPTUN" 2>/dev/null || \
|
||||
iptables -A OUTPUT -j "$KCPTUN" 2>/dev/null
|
||||
iptables -C INPUT -j "$KCPTUN" 2>/dev/null || \
|
||||
iptables -A INPUT -j "$KCPTUN" 2>/dev/null
|
||||
}
|
||||
|
||||
clear_iptables_chain() {
|
||||
iptables -F "$KCPTUN" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
add_iptables_rule() {
|
||||
local port="$1"
|
||||
local type="$2"
|
||||
|
||||
if [ "$type" = "client" ]; then
|
||||
( iptables -C "$KCPTUN" -p tcp --dport "$port" -m comment \
|
||||
--comment "$type" -j ACCEPT 2>/dev/null ) && return 0
|
||||
|
||||
iptables -A "$KCPTUN" -p tcp --dport "$port" -m comment \
|
||||
--comment "$type" -j ACCEPT 2>/dev/null
|
||||
elif [ "$type" = "server" ]; then
|
||||
( iptables -C "$KCPTUN" -p udp --dport "$port" -m comment \
|
||||
--comment "$type" -j ACCEPT 2>/dev/null ) && return 0
|
||||
|
||||
iptables -A "$KCPTUN" -p udp --dport "$port" -m comment \
|
||||
--comment "$type" -j ACCEPT 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
validate_config_section() {
|
||||
uci_validate_section "$KCPTUN" general "$1" \
|
||||
'server:uciname' \
|
||||
'client_file:string' \
|
||||
'daemon_user:string:root' \
|
||||
'enable_logging:bool:0' \
|
||||
'log_folder:directory:/var/log/kcptun'
|
||||
}
|
||||
|
||||
validate_server_section() {
|
||||
uci_validate_section "$KCPTUN" servers "$1" \
|
||||
'server_addr:host' \
|
||||
'server_port:port:29900' \
|
||||
'listen_addr:host:0.0.0.0' \
|
||||
'listen_port:port:12948' \
|
||||
'key:string' \
|
||||
'crypt:string:aes' \
|
||||
'mode:or("normal","fast","fast2","fast3","manual"):fast' \
|
||||
'conn:min(1)' \
|
||||
'autoexpire:uinteger' \
|
||||
'scavengettl:min(-1)' \
|
||||
'mtu:range(64,9200)' \
|
||||
'sndwnd:min(1)' \
|
||||
'rcvwnd:min(1)' \
|
||||
'datashard:uinteger' \
|
||||
'parityshard:uinteger' \
|
||||
'dscp:uinteger' \
|
||||
'nocomp:or("true", "false")' \
|
||||
'nodelay:bool' \
|
||||
'interval:uinteger' \
|
||||
'resend:range(0,2)' \
|
||||
'nc:bool' \
|
||||
'acknodelay:or("true", "false")' \
|
||||
'sockbuf:uinteger' \
|
||||
'keepalive:uinteger' \
|
||||
'snmpperiod:min(1)'
|
||||
}
|
||||
|
||||
validate_client_file() {
|
||||
local file="$1"
|
||||
|
||||
if [ ! -f "$file" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
[ -x "$file" ] || chmod 755 "$file"
|
||||
|
||||
( $file -v 2>/dev/null | grep -q "$KCPTUN" )
|
||||
}
|
||||
|
||||
start_kcptun_instance() {
|
||||
local section="$1"
|
||||
|
||||
if ! validate_config_section "$section" ; then
|
||||
_log "err" "Config validate failed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$server" ] || [ "$server" = "nil" ]; then
|
||||
_log "info" "No server selected, Client will stop."
|
||||
return 0
|
||||
elif ! validate_server_section "$server"; then
|
||||
_log "err" "Server config validation failed."
|
||||
return 1
|
||||
elif [ -z "$server_addr" ] || [ -z "$listen_port" ]; then
|
||||
_log "err" "Server config validation failed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$client_file" ]; then
|
||||
_log "err" "Please set client file path, or use auto download."
|
||||
return 1;
|
||||
elif ! validate_client_file "$client_file"; then
|
||||
_log "err" "Client file validation failed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
is_ipv6_address() {
|
||||
echo "$1" | grep -q ":"
|
||||
}
|
||||
|
||||
is_ipv6_address "$server_addr" && server_addr="[${server_addr}]"
|
||||
is_ipv6_address "$listen_addr" && listen_addr="[${listen_addr}]"
|
||||
|
||||
[ -d "$CONFIG_FOLDER" ] || mkdir -p "$CONFIG_FOLDER"
|
||||
|
||||
log_file=""
|
||||
if [ "$enable_logging" = "1" ]; then
|
||||
mkdir -p "$log_folder"
|
||||
chown -R "$daemon_user" "$log_folder"
|
||||
log_file="${log_folder}/client.${section}.log"
|
||||
fi
|
||||
|
||||
local config_file=${CONFIG_FOLDER}/client.${section}.json
|
||||
|
||||
if ! ( gen_client_config_file "$config_file" ); then
|
||||
_log "err" "Can't create config file".
|
||||
return 1
|
||||
fi
|
||||
|
||||
add_iptables_rule "$listen_port" "client"
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command "$client_file"
|
||||
procd_append_param command -c "$config_file"
|
||||
procd_set_param respawn
|
||||
procd_set_param user "$daemon_user"
|
||||
procd_set_param file "$config_file"
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "$KCPTUN"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
clear_iptables_chain
|
||||
setup_iptables_chain
|
||||
|
||||
config_load "$KCPTUN"
|
||||
config_foreach start_kcptun_instance "general"
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
clear_iptables_chain
|
||||
}
|
25
package/lean/luci-app-kcptun/root/etc/uci-defaults/40_luci-kcptun
Executable file
25
package/lean/luci-app-kcptun/root/etc/uci-defaults/40_luci-kcptun
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@kcptun[-1]
|
||||
add ucitrack kcptun
|
||||
set ucitrack.@kcptun[-1].init=kcptun
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
general=$(uci -q get kcptun.@general[-1])
|
||||
|
||||
if [ -z "$general" ]; then
|
||||
uci -q add kcptun general
|
||||
fi
|
||||
|
||||
if [ ."$general" != ."general" ]; then
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
rename kcptun.@general[-1]="general"
|
||||
set kcptun.general.server=""
|
||||
commit kcptun
|
||||
EOF
|
||||
fi
|
||||
|
||||
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user