Merge pull request #43 from linkease/penpot

Penpot
This commit is contained in:
Janson
2022-11-18 17:22:45 +08:00
committed by GitHub
45 changed files with 1736 additions and 4 deletions

View File

@@ -48,7 +48,7 @@ for _, val in pairs(paths) do
end
o.default = default_path
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file/?path=/root/mnt' target='_blank'>/mnt</a>")
o.datatype = "string"
return m

View File

@@ -0,0 +1,18 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-20221114
PKG_RELEASE:=
LUCI_TITLE:=LuCI support for CodeServer
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+docker +luci-lib-taskd
define Package/luci-app-codeserver/conffiles
/etc/config/codeserver
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,9 @@
module("luci.controller.codeserver", package.seeall)
function index()
entry({"admin", "services", "codeserver"}, alias("admin", "services", "codeserver", "config"), _("CodeServer"), 30).dependent = true
entry({"admin", "services", "codeserver", "config"}, cbi("codeserver/config"), _("Config"), 10).leaf = true
entry({"admin", "services", "codeserver", "tool"}, form("codeserver/tool"), _("Tool"), 30).leaf = true
entry({"admin", "services", "codeserver", "console"}, form("codeserver/console"), _("Console"), 50).leaf = true
end

View File

@@ -0,0 +1,64 @@
--[[
LuCI - Lua Configuration Interface
]]--
local taskd = require "luci.model.tasks"
local codeserver_model = require "luci.model.codeserver"
local m, s, o
m = taskd.docker_map("codeserver", "codeserver", "/usr/libexec/istorec/codeserver.sh",
translate("CodeServer"),
translate("CodeServer is a web version of VSCode.")
.. translate("Official website:") .. ' <a href=\"https://coder.com/\" target=\"_blank\">https://coder.com/</a>')
s = m:section(SimpleSection, translate("Service Status"), translate("CodeServer status:"))
s:append(Template("codeserver/status"))
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
s.addremove=false
s.anonymous=true
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
o.default = "8082"
o.datatype = "string"
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("lscr.io/linuxserver/code-server:latest", "lscr.io/linuxserver/code-server:latest")
o:value("lscr.io/linuxserver/code-server:4.8.3", "lscr.io/linuxserver/code-server:4.8.3")
o.default = "lscr.io/linuxserver/code-server:latest"
local blocks = codeserver_model.blocks()
local home = codeserver_model.home()
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
local paths, default_path = codeserver_model.find_paths(blocks, home, "Configs")
for _, val in pairs(paths) do
o:value(val, val)
end
o.default = default_path
o = s:option(Value, "env_password", "PASSWORD")
o.password = true
o.datatype = "string"
o = s:option(Value, "env_hashed_password", "HASHED_PASSWORD")
o.datatype = "string"
o.password = true
o = s:option(Value, "env_sudo_password", "SUDO_PASSWORD")
o.password = true
o.datatype = "string"
o = s:option(Value, "env_sudo_password_hash", "SUDO_PASSWORD_HASH")
o.password = true
o.datatype = "string"
o = s:option(Value, "env_proxy_domain", "PROXY_DOMAIN")
o.datatype = "string"
return m

View File

@@ -0,0 +1,110 @@
--[[
LuCI - Lua Configuration Interface
]]--
require "luci.util"
local docker = require "luci.model.docker"
local dk = docker.new()
local container_name = "codeserver"
local m, s, o
local images, networks, container_info, res
res = dk.containers:inspect({name = container_name})
if res.code < 300 then
container_info = res.body
else
return
end
m=SimpleForm("Console", "", translate("Only works in LAN"))
m.submit = false
m.reset = false
local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil
local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil
if cmd_docker and cmd_ttyd and container_info.State.Status == "running" then
local cmd = "/bin/bash"
local uid
s = m:section(SimpleSection)
o = s:option(Value, "command", translate("Command"))
o:value("/bin/sh", "/bin/sh")
o:value("/bin/ash", "/bin/ash")
o:value("/bin/bash", "/bin/bash")
o.default = "/bin/bash"
o.forcewrite = true
o.write = function(self, section, value)
cmd = value
end
o = s:option(Value, "uid", translate("UID"))
o.forcewrite = true
o.write = function(self, section, value)
uid = value
end
o = s:option(Button, "connect")
o.render = function(self, section, scope)
self.inputstyle = "add"
self.title = " "
self.inputtitle = translate("Connect")
Button.render(self, section, scope)
end
o.write = function(self, section)
local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil
local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil
if not cmd_docker or not cmd_ttyd or cmd_docker:match("^%s+$") or cmd_ttyd:match("^%s+$")then
return
end
local pid = luci.util.trim(luci.util.exec("netstat -lnpt | grep :7682 | grep ttyd | tr -s ' ' | cut -d ' ' -f7 | cut -d'/' -f1"))
if pid and pid ~= "" then
luci.util.exec("kill -9 " .. pid)
end
local hosts
local uci = require "luci.model.uci".cursor()
local remote = uci:get_bool("dockerd", "globals", "remote_endpoint") or false
local host = nil
local port = nil
local socket = nil
if remote then
host = uci:get("dockerd", "globals", "remote_host") or nil
port = uci:get("dockerd", "globals", "remote_port") or nil
else
socket = uci:get("dockerd", "globals", "socket_path") or "/var/run/docker.sock"
end
if remote and host and port then
hosts = host .. ':'.. port
elseif socket then
hosts = socket
else
return
end
if uid and uid ~= "" then
uid = "-u " .. uid
else
uid = ""
end
local start_cmd = string.format('%s -d 2 --once -p 7682 %s -H "unix://%s" exec -it %s %s %s&', cmd_ttyd, cmd_docker, hosts, uid, container_name, cmd)
os.execute(start_cmd)
o = s:option(DummyValue, "console")
o.container_id = container_id
o.template = "codeserver/console"
end
end
return m

View File

@@ -0,0 +1,56 @@
--[[
LuCI - Lua Configuration Interface
]]--
local http = require 'luci.http'
m=SimpleForm("Tools")
m.submit = false
m.reset = false
s = m:section(SimpleSection)
o = s:option(Value, "action", translate("Action").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("git-config", "git-config")
o.default = "git-config"
local data = {}
o = s:option(Value, "username", "user.name")
o.datatype = "string"
o.placeholder = "username"
o:depends("action", "git-config")
o = s:option(Value, "email", "user.email")
o.datatype = "string"
o.placeholder = "email@address"
o:depends("action", "git-config")
local t=Template("codeserver/tool")
m:append(t)
local btn_do = s:option(Button, "_do")
btn_do.render = function(self, section, scope)
self.inputstyle = "add"
self.title = " "
self.inputtitle = translate("Execute")
Button.render(self, section, scope)
end
btn_do.write = function(self, section, value)
local action = m:get(section, "action")
if action == "git-config" then
local user = m:get(section, "username")
local email = m:get(section, "email")
if user ~= nil and email ~= nil then
local cmd = string.format("/usr/libexec/istorec/codeserver.sh %s %s %s", action, user, email)
cmd = "/etc/init.d/tasks task_add codeserver " .. luci.util.shellquote(cmd) .. " >/dev/null 2>&1"
os.execute(cmd)
t.show_log_taskid = "codeserver"
end
end
end
return m

View File

@@ -0,0 +1,54 @@
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local codeserver = {}
codeserver.blocks = function()
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
local vals = {}
if f then
local ret = f:read("*all")
f:close()
local obj = jsonc.parse(ret)
for _, val in pairs(obj["blockdevices"]) do
local fsize = val["fssize"]
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
-- fsize > 1G
vals[#vals+1] = val["mountpoint"]
end
end
end
return vals
end
codeserver.home = function()
local uci = require "luci.model.uci".cursor()
local home_dirs = {}
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public")
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
return home_dirs
end
codeserver.find_paths = function(blocks, home_dirs, path_name)
local default_path = ''
local configs = {}
default_path = home_dirs[path_name] .. "/CodeServer"
if #blocks == 0 then
table.insert(configs, default_path)
else
for _, val in pairs(blocks) do
table.insert(configs, val .. "/" .. path_name .. "/CodeServer")
end
local without_conf_dir = "/root/" .. path_name .. "/CodeServer"
if default_path == without_conf_dir then
default_path = configs[1]
end
end
return configs, default_path
end
return codeserver

View File

@@ -0,0 +1,10 @@
<div class="cbi-map">
<iframe id="terminal" style="width: 100%; min-height: 600px; border: none; border-radius: 3px;"></iframe>
</div>
<script type="text/javascript">
const el = document.querySelectorAll(".cbi-value")
for (let i = 0; i < el.length; i++) {
el[i].style.display = "none";
}
document.getElementById("terminal").src = "http://" + window.location.hostname + ":7682";
</script>

View File

@@ -0,0 +1,31 @@
<%
local util = require "luci.util"
local container_status = util.trim(util.exec("/usr/libexec/istorec/codeserver.sh status"))
local container_install = (string.len(container_status) > 0)
local container_running = container_status == "running"
-%>
<div class="cbi-value">
<label class="cbi-value-title"><%:Status%></label>
<div class="cbi-value-field">
<% if container_running then %>
<button class="cbi-button cbi-button-success" disabled="true"><%:CodeServer is running%></button>
<% else %>
<button class="cbi-button cbi-button-negative" disabled="true"><%:CodeServer is not running%></button>
<% end %>
</div>
</div>
<%
if container_running then
local port=util.trim(util.exec("/usr/libexec/istorec/codeserver.sh port"))
if port == "" then
port="8443"
end
-%>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">&nbsp;</label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open CodeServer%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
</div>
</div>
<% end %>

View File

@@ -0,0 +1,11 @@
<%+tasks/embed%>
<script>
window.addEventListener("load", function(){
const taskd = window.taskd;
<% if self.show_log_taskid then -%>
taskd.show_log("<%=self.show_log_taskid%>");
<%- end %>
});
</script>

View File

@@ -0,0 +1,45 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "CodeServer is a web version of VSCode."
msgstr "CodeServer 就一个在线版本的 VSCode可以在线开发。"
msgid "Config path"
msgstr "配置文件路径"
msgid "HTTP Port"
msgstr "HTTP 端口"
msgid "Service Status"
msgstr "服务状态"
msgid "CodeServer status:"
msgstr "CodeServer 的状态信息如下:"
msgid "Setup"
msgstr "安装配置"
msgid "The following parameters will only take effect during installation or upgrade:"
msgstr "以下参数只在安装或者升级时才会生效:"
msgid "Status"
msgstr "状态"
msgid "CodeServer is running"
msgstr "CodeServer 运行中"
msgid "CodeServer is not running"
msgstr "CodeServer 未运行"
msgid "Open CodeServer"
msgstr "打开 CodeServer"
msgid "Console"
msgstr "控制台"
msgid "Only works in LAN"
msgstr "只在内网环境下工作。"

View File

@@ -0,0 +1,10 @@
config main
option 'http_port' '8082'
option 'image_name' 'lscr.io/linuxserver/code-server:latest'
option 'config_path' ''
option 'env_password' ''
option 'env_hashed_password' ''
option 'env_sudo_password' ''
option 'env_sudo_password_hash' ''
option 'env_proxy_domain' ''

View File

@@ -0,0 +1,90 @@
#!/bin/sh
# Author Xiaobao(xiaobao@linkease.com)
ACTION=${1}
shift 1
do_install() {
local http_port=`uci get codeserver.@main[0].http_port 2>/dev/null`
local image_name=`uci get codeserver.@main[0].image_name 2>/dev/null`
local config=`uci get codeserver.@main[0].config_path 2>/dev/null`
local env_password=`uci get codeserver.@main[0].env_password 2>/dev/null`
local env_hashed_password=`uci get codeserver.@main[0].env_hashed_password 2>/dev/null`
local env_sudo_password=`uci get codeserver.@main[0].env_sudo_password 2>/dev/null`
local env_sudo_password_hash=`uci get codeserver.@main[0].env_sudo_password_hash 2>/dev/null`
local env_proxy_domain=`uci get codeserver.@main[0].env_proxy_domain 2>/dev/null`
[ -z "$image_name" ] && image_name="lscr.io/linuxserver/code-server:latest"
echo "docker pull ${image_name}"
docker pull ${image_name}
docker rm -f codeserver
if [ -z "$config" ]; then
echo "config path is empty!"
exit 1
fi
[ -z "$http_port" ] && http_port=8082
local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" \
--dns=172.17.0.1 \
-e DEFAULT_WORKSPACE=/config/workspace \
-p $http_port:8443 "
local tz="`cat /tmp/TZ`"
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
[ -z "$env_password" ] || cmd="$cmd -e \"PASSWORD=$env_password\""
[ -z "$env_hashed_password" ] || cmd="$cmd -e \"HASHED_PASSWORD=$env_hashed_password\""
[ -z "$env_sudo_password" ] || cmd="$cmd -e \"SUDO_PASSWORD=$env_sudo_password\""
[ -z "$env_sudo_password_hash" ] || cmd="$cmd -e \"SUDO_PASSWORD_HASH=$env_sudo_password_hash\""
[ -z "$env_proxy_domain" ] || cmd="$cmd -e \"PROXY_DOMAIN=$env_proxy_domain\""
cmd="$cmd -v /mnt:/mnt"
mountpoint -q /mnt && cmd="$cmd:rslave"
cmd="$cmd --name codeserver \"$image_name\""
echo "$cmd"
eval "$cmd"
}
usage() {
echo "usage: $0 sub-command"
echo "where sub-command is one of:"
echo " install Install the codeserver"
echo " upgrade Upgrade the codeserver"
echo " rm/start/stop/restart Remove/Start/Stop/Restart the codeserver"
echo " status CodeServer status"
echo " port CodeServer port"
}
case ${ACTION} in
"install")
do_install
;;
"upgrade")
do_install
;;
"rm")
docker rm -f codeserver
;;
"start" | "stop" | "restart")
docker ${ACTION} codeserver
;;
"status")
docker ps --all -f 'name=codeserver' --format '{{.State}}'
;;
"port")
docker ps --all -f 'name=codeserver' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
;;
"git-config")
docker exec codeserver git config --global user.name "${1}"
docker exec codeserver git config --global user.email "${2}"
echo "git config --global user.name ${1}"
echo "git config --global user.email ${2}"
;;
*)
usage
exit 1
;;
esac

View File

@@ -48,7 +48,7 @@ for _, val in pairs(paths) do
end
o.default = default_path
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file/?path=/root/mnt' target='_blank'>/mnt</a>")
o.datatype = "string"
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))

View File

@@ -0,0 +1,18 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-20221114
PKG_RELEASE:=
LUCI_TITLE:=LuCI support for Emby
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+docker +luci-lib-taskd
define Package/luci-app-emby/conffiles
/etc/config/emby
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,7 @@
module("luci.controller.gogs", package.seeall)
function index()
entry({"admin", "services", "gogs"}, alias("admin", "services", "gogs", "config"), _("Gogs"), 30).dependent = true
entry({"admin", "services", "gogs", "config"}, cbi("gogs"))
end

View File

@@ -0,0 +1,51 @@
--[[
LuCI - Lua Configuration Interface
]]--
local taskd = require "luci.model.tasks"
local gogs_model = require "luci.model.gogs"
local m, s, o
m = taskd.docker_map("gogs", "gogs", "/usr/libexec/istorec/gogs.sh",
translate("Gogs"),
translate("Gogs is a painless self-hosted Git service.")
.. translate("Official website:") .. ' <a href=\"https://gogs.io/\" target=\"_blank\">https://gogs.io/</a>')
s = m:section(SimpleSection, translate("Service Status"), translate("Gogs status:"))
s:append(Template("gogs/status"))
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
s.addremove=false
s.anonymous=true
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
o.default = "3001"
o.datatype = "string"
o.rmempty = false
o = s:option(Value, "ssh_port", translate("SSH Port").."<b>*</b>")
o.default = "3022"
o.datatype = "string"
o.rmempty = false
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("gogs/gogs:latest", "gogs/gogs:latest")
o:value("gogs/gogs:0.12", "gogs/gogs:0.12")
o.default = "gogs/gogs:latest"
local blocks = gogs_model.blocks()
local home = gogs_model.home()
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
local paths, default_path = gogs_model.find_paths(blocks, home, "Configs")
for _, val in pairs(paths) do
o:value(val, val)
end
o.default = default_path
return m

View File

@@ -0,0 +1,54 @@
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local gogs = {}
gogs.blocks = function()
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
local vals = {}
if f then
local ret = f:read("*all")
f:close()
local obj = jsonc.parse(ret)
for _, val in pairs(obj["blockdevices"]) do
local fsize = val["fssize"]
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
-- fsize > 1G
vals[#vals+1] = val["mountpoint"]
end
end
end
return vals
end
gogs.home = function()
local uci = require "luci.model.uci".cursor()
local home_dirs = {}
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public")
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
return home_dirs
end
gogs.find_paths = function(blocks, home_dirs, path_name)
local default_path = ''
local configs = {}
default_path = home_dirs[path_name] .. "/Gogs"
if #blocks == 0 then
table.insert(configs, default_path)
else
for _, val in pairs(blocks) do
table.insert(configs, val .. "/" .. path_name .. "/Gogs")
end
local without_conf_dir = "/root/" .. path_name .. "/Gogs"
if default_path == without_conf_dir then
default_path = configs[1]
end
end
return configs, default_path
end
return gogs

View File

@@ -0,0 +1,31 @@
<%
local util = require "luci.util"
local container_status = util.trim(util.exec("/usr/libexec/istorec/gogs.sh status"))
local container_install = (string.len(container_status) > 0)
local container_running = container_status == "running"
-%>
<div class="cbi-value">
<label class="cbi-value-title"><%:Status%></label>
<div class="cbi-value-field">
<% if container_running then %>
<button class="cbi-button cbi-button-success" disabled="true"><%:Gogs is running%></button>
<% else %>
<button class="cbi-button cbi-button-negative" disabled="true"><%:Gogs is not running%></button>
<% end %>
</div>
</div>
<%
if container_running then
local port=util.trim(util.exec("/usr/libexec/istorec/gogs.sh port"))
if port == "" then
port="3001"
end
-%>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">&nbsp;</label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open Gogs%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
</div>
</div>
<% end %>

View File

@@ -0,0 +1,42 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "Gogs is a painless self-hosted Git service."
msgstr "Gogs 是一个轻松易用的 Git 服务。"
msgid "Config path"
msgstr "配置文件路径"
msgid "HTTP Port"
msgstr "HTTP 端口"
msgid "SSH Port"
msgstr "SSH 端口"
msgid "Service Status"
msgstr "服务状态"
msgid "Gogs status:"
msgstr "Gogs 的状态信息如下:"
msgid "Setup"
msgstr "安装配置"
msgid "The following parameters will only take effect during installation or upgrade:"
msgstr "以下参数只在安装或者升级时才会生效:"
msgid "Status"
msgstr "状态"
msgid "Gogs is running"
msgstr "Gogs 运行中"
msgid "Gogs is not running"
msgstr "Gogs 未运行"
msgid "Open Gogs"
msgstr "打开 Gogs"

View File

@@ -0,0 +1,6 @@
config main
option 'http_port' '3001'
option 'ssh_port' '3022'
option 'image_name' 'gogs/gogs:latest'
option 'config_path' ''

View File

@@ -0,0 +1,80 @@
#!/bin/sh
# Author Xiaobao(xiaobao@linkease.com)
ACTION=${1}
shift 1
do_install() {
local http_port=`uci get gogs.@main[0].http_port 2>/dev/null`
local ssh_port=`uci get gogs.@main[0].ssh_port 2>/dev/null`
local image_name=`uci get gogs.@main[0].image_name 2>/dev/null`
local config=`uci get gogs.@main[0].config_path 2>/dev/null`
[ -z "$image_name" ] && image_name="gogs/gogs:latest"
echo "docker pull ${image_name}"
docker pull ${image_name}
docker rm -f gogs
if [ -z "$config" ]; then
echo "config path is empty!"
exit 1
fi
if [ -z "$http_port" ]; then
http_port=3001
fi
if [ -z "$ssh_port" ]; then
ssh_port=3022
fi
local cmd="docker run --restart=unless-stopped -d -v \"$config:/data\" \
--dns=172.17.0.1 \
-p $http_port:3000 \
-p $ssh_port:22 "
local tz="`cat /tmp/TZ`"
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
cmd="$cmd -v /mnt:/mnt"
mountpoint -q /mnt && cmd="$cmd:rslave"
cmd="$cmd --name gogs \"$image_name\""
echo "$cmd"
eval "$cmd"
}
usage() {
echo "usage: $0 sub-command"
echo "where sub-command is one of:"
echo " install Install the gogs"
echo " upgrade Upgrade the gogs"
echo " rm/start/stop/restart Remove/Start/Stop/Restart the gogs"
echo " status Gogs status"
echo " port Gogs port"
}
case ${ACTION} in
"install")
do_install
;;
"upgrade")
do_install
;;
"rm")
docker rm -f gogs
;;
"start" | "stop" | "restart")
docker ${ACTION} gogs
;;
"status")
docker ps --all -f 'name=gogs' --format '{{.State}}'
;;
"port")
local http_port=`uci get gogs.@main[0].http_port 2>/dev/null`
echo $http_port
;;
*)
usage
exit 1
;;
esac

View File

@@ -40,7 +40,7 @@ for _, val in pairs(paths) do
end
o.default = default_path
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file/?path=/root/mnt' target='_blank'>/mnt</a>")
o.datatype = "string"
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))

View File

@@ -0,0 +1,18 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-20221114
PKG_RELEASE:=
LUCI_TITLE:=LuCI support for Penpot
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+docker +luci-lib-taskd docker-compose
define Package/luci-app-penpot/conffiles
/etc/config/penpot
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,8 @@
module("luci.controller.penpot", package.seeall)
function index()
entry({"admin", "services", "penpot"}, alias("admin", "services", "penpot", "config"), _("Penpot"), 30).dependent = true
entry({"admin", "services", "penpot", "config"}, cbi("penpot/config"), _("Config"), 10).leaf = true
entry({"admin", "services", "penpot", "tool"}, form("penpot/tool"), _("Tool"), 30).leaf = true
end

View File

@@ -0,0 +1,63 @@
--[[
LuCI - Lua Configuration Interface
]]--
local taskd = require "luci.model.tasks"
local penpot_model = require "luci.model.penpot"
local m, s, o
m = taskd.docker_map("penpot", "penpot", "/usr/libexec/istorec/penpot.sh",
translate("Penpot"),
translate("Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.")
.. translate("Official website:") .. ' <a href=\"https://penpot.app/\" target=\"_blank\">https://penpot.app/</a>')
s = m:section(SimpleSection, translate("Service Status"), translate("Penpot status:"))
s:append(Template("penpot/status"))
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
s.addremove=false
s.anonymous=true
o = s:option(Value, "http_port", translate("HTTP Port").."<b>*</b>")
o.default = "9001"
o.datatype = "string"
local blocks = penpot_model.blocks()
local home = penpot_model.home()
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>", translate("Manually edit template at") .. " <a href='/cgi-bin/luci/admin/services/linkease/file/?path=/root/usr/share/penpot' target='_blank'>/root/usr/share/penpot</a>")
o.rmempty = false
o.datatype = "string"
local paths, default_path = penpot_model.find_paths(blocks, home, "Configs")
for _, val in pairs(paths) do
o:value(val, val)
end
o.default = default_path
o = s:option(Value, "public_uri", "PUBLIC_URI")
o.datatype = "string"
o = s:option(Value, "redis_uri", "REDIS_URI")
o.datatype = "string"
o = s:option(Value, "db_uri", "DB_URI")
o.datatype = "string"
o = s:option(Value, "db_name", "DB_NAME")
o.datatype = "string"
o = s:option(Value, "db_username", "DB_USERNAME")
o.datatype = "string"
o = s:option(Value, "db_password", "DB_PASSWORD")
o.password = true
o.datatype = "string"
o = s:option(Value, "smtp_default_from", "SMTP_DEFAULT_FROM")
o.datatype = "string"
o = s:option(Value, "smtp_default_reply_to", "SMTP_DEFAULT_REPLY_TO")
o.datatype = "string"
return m

View File

@@ -0,0 +1,62 @@
--[[
LuCI - Lua Configuration Interface
]]--
local http = require 'luci.http'
m=SimpleForm("Tools")
m.submit = false
m.reset = false
s = m:section(SimpleSection)
o = s:option(Value, "action", translate("Action").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("create-user", "create-user")
o.default = "create-user"
local data = {}
o = s:option(Value, "email", "Email")
o.datatype = "string"
o.placeholder = "email@address"
o:depends("action", "create-user")
o = s:option(Value, "password", "Password")
o.password = true
o.datatype = "string"
o:depends("action", "create-user")
o = s:option(Value, "fullname", "Your Full Name")
o.datatype = "string"
o.placeholder = "Full Name"
o:depends("action", "create-user")
local t=Template("penpot/tool")
m:append(t)
local btn_do = s:option(Button, "_do")
btn_do.render = function(self, section, scope)
self.inputstyle = "add"
self.title = " "
self.inputtitle = translate("Execute")
Button.render(self, section, scope)
end
btn_do.write = function(self, section, value)
local action = m:get(section, "action")
if action == "create-user" then
local email = m:get(section, "email")
local password = m:get(section, "password")
local fullname = m:get(section, "fullname")
if email ~= nil and password ~= nil and fullname ~= nil then
local cmd = string.format("/usr/libexec/istorec/penpot.sh %s %s %s %s", action, email, password, fullname)
cmd = "/etc/init.d/tasks task_add penpot " .. luci.util.shellquote(cmd) .. " >/dev/null 2>&1"
os.execute(cmd)
t.show_log_taskid = "penpot"
end
end
end
return m

View File

@@ -0,0 +1,54 @@
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local penpot = {}
penpot.blocks = function()
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
local vals = {}
if f then
local ret = f:read("*all")
f:close()
local obj = jsonc.parse(ret)
for _, val in pairs(obj["blockdevices"]) do
local fsize = val["fssize"]
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
-- fsize > 1G
vals[#vals+1] = val["mountpoint"]
end
end
end
return vals
end
penpot.home = function()
local uci = require "luci.model.uci".cursor()
local home_dirs = {}
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public")
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
return home_dirs
end
penpot.find_paths = function(blocks, home_dirs, path_name)
local default_path = ''
local configs = {}
default_path = home_dirs[path_name] .. "/Penpot"
if #blocks == 0 then
table.insert(configs, default_path)
else
for _, val in pairs(blocks) do
table.insert(configs, val .. "/" .. path_name .. "/Penpot")
end
local without_conf_dir = "/root/" .. path_name .. "/Penpot"
if default_path == without_conf_dir then
default_path = configs[1]
end
end
return configs, default_path
end
return penpot

View File

@@ -0,0 +1,31 @@
<%
local util = require "luci.util"
local container_status = util.trim(util.exec("/usr/libexec/istorec/penpot.sh status"))
local container_install = (string.len(container_status) > 0)
local container_running = container_status == "running"
-%>
<div class="cbi-value">
<label class="cbi-value-title"><%:Status%></label>
<div class="cbi-value-field">
<% if container_running then %>
<button class="cbi-button cbi-button-success" disabled="true"><%:Penpot is running%></button>
<% else %>
<button class="cbi-button cbi-button-negative" disabled="true"><%:Penpot is not running%></button>
<% end %>
</div>
</div>
<%
if container_running then
local port=util.trim(util.exec("/usr/libexec/istorec/penpot.sh port"))
if port == "" then
port="9001"
end
-%>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">&nbsp;</label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open Penpot%>" onclick="window.open('http://'+location.hostname+':<%=port%>', '_blank')">
</div>
</div>
<% end %>

View File

@@ -0,0 +1,11 @@
<%+tasks/embed%>
<script>
window.addEventListener("load", function(){
const taskd = window.taskd;
<% if self.show_log_taskid then -%>
taskd.show_log("<%=self.show_log_taskid%>");
<%- end %>
});
</script>

View File

@@ -0,0 +1,44 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "Penpot is the first Open Source design and prototyping platform meant for cross-domain teams."
msgstr "Penpot 是第一个开源的便于团队协作的在线设计平台。"
msgid "Config path"
msgstr "配置文件路径"
msgid "HTTP Port"
msgstr "HTTP 端口"
msgid "Service Status"
msgstr "服务状态"
msgid "Penpot status:"
msgstr "Penpot 的状态信息如下:"
msgid "Setup"
msgstr "安装配置"
msgid "The following parameters will only take effect during installation or upgrade:"
msgstr "以下参数只在安装或者升级时才会生效:"
msgid "Status"
msgstr "状态"
msgid "Penpot is running"
msgstr "Penpot 运行中"
msgid "Penpot is not running"
msgstr "Penpot 未运行"
msgid "Open Penpot"
msgstr "打开 Penpot"
msgid "Console"
msgstr "控制台"
msgid "Manually edit template at"
msgstr "可以手动手改配置文件的模板,路径在:"

View File

@@ -0,0 +1,12 @@
config main
option 'http_port' '9001'
option 'config_path' ''
option 'public_uri' 'http://localhost:9001'
option 'redis_uri' 'redis://penpot-redis/0'
option 'db_uri' 'postgresql://penpot-postgres/penpot'
option 'db_name' 'penpot'
option 'db_username' 'penpot'
option 'db_password' 'penpot'
option 'smtp_default_from' 'no-reply@example.com'
option 'smtp_default_reply_to' 'no-reply@example.com'

View File

@@ -0,0 +1,77 @@
#!/bin/sh
# Author Xiaobao(xiaobao@linkease.com)
ACTION=${1}
shift 1
do_install() {
local config=`uci get penpot.@main[0].config_path 2>/dev/null`
if [ -z "$config" ]; then
echo "config path is empty!"
exit 1
fi
mkdir -p $config
lua /usr/libexec/istorec/penpot_template.lua penpot /usr/share/penpot/config.template.env $config/config.env
RET=$?
if [ ! "$RET" = "0" ]; then
echo "convert config.env failed"
exit 1
fi
lua /usr/libexec/istorec/penpot_template.lua penpot /usr/share/penpot/docker-compose.template.yaml $config/docker-compose.yaml
RET=$?
if [ ! "$RET" = "0" ]; then
echo "convert config.env failed"
exit 1
fi
cd $config
docker-compose down
docker-compose up -d
echo "Wait 120 to intialize"
sleep 120
echo "Now you should create a user manually"
}
usage() {
echo "usage: $0 sub-command"
echo "where sub-command is one of:"
echo " install Install the penpot"
echo " upgrade Upgrade the penpot"
echo " rm/start/stop/restart Remove/Start/Stop/Restart the penpot"
echo " status Penpot status"
echo " port Penpot port"
}
case ${ACTION} in
"install")
do_install
;;
"upgrade")
do_install
;;
"rm")
local config=`uci get penpot.@main[0].config_path 2>/dev/null`
cd $config && docker-compose down
;;
"start" | "stop" | "restart")
local config=`uci get penpot.@main[0].config_path 2>/dev/null`
cd $config && docker-compose ${ACTION}
;;
"status")
docker ps --all -f 'name=penpot_penpot-frontend_1' --format '{{.State}}'
;;
"port")
http_port=`uci get penpot.@main[0].http_port 2>/dev/null`
echo $http_port
;;
"create-user")
echo docker exec -ti penpot_penpot-backend_1 ./manage.sh create-profile -u "${1}" -p "${2}" -n "${3}"
docker exec -ti penpot_penpot-backend_1 ./manage.sh create-profile -u "${1}" -p "${2}" -n "${3}"
;;
*)
usage
exit 1
;;
esac

View File

@@ -0,0 +1,96 @@
local util = require "luci.util"
local tparser = require "luci.template.parser"
local uci = require "luci.model.uci"
local nixio = require "nixio"
local tostring, pairs, loadstring = tostring, pairs, loadstring
local setmetatable, loadfile = setmetatable, loadfile
local getfenv, setfenv, rawget = getfenv, setfenv, rawget
local assert, type, error = assert, type, error
local default_ctx = {tostring = tostring}
local from_string = function(template)
return Template(default_ctx, nil, template)
end
local from_file = function(template_file)
return Template(default_ctx, template_file)
end
-- Template class
Template = util.class()
-- Constructor - Reads and compiles the template on-demand
function Template.__init__(self, viewns, name, template)
if name then
self.name = name
else
self.name = "[string]"
end
-- Create a new namespace for this template
self.viewns = viewns
-- Compile template
local err
local sourcefile
if name then
sourcefile = name
self.template, _, err = tparser.parse(sourcefile)
else
sourcefile = "[string]"
self.template, _, err = tparser.parse_string(template)
end
-- If we have no valid template throw error, otherwise cache the template
if not self.template then
error("Failed to load template '" .. self.name .. "'.\n" ..
"Error while parsing template '" .. sourcefile .. "':\n" ..
(err or "Unknown syntax error"))
end
end
-- Renders a template
function Template.render(self, scope)
-- Put our predefined objects in the scope of the template
setfenv(self.template, setmetatable({}, {__index =
function(tbl, key)
return rawget(tbl, key) or self.viewns[key] or scope[key]
end}))
-- Now finally render the thing
local stat, err = util.copcall(self.template)
if not stat then
error("Failed to execute template '" .. self.name .. "'.\n" ..
"A runtime error occurred: " .. tostring(err or "(nil)"))
end
end
if #arg == 3 then
local cur = uci.cursor()
local configs = {}
cur:foreach(arg[1], "main", function(s)
for k, v in pairs(s) do
configs[k] = v
end
end)
if not nixio.fs.access(arg[2]) then
print(arg[2] .. " not found")
os.exit(10)
end
local target = io.open(arg[3], "w")
if not target then
print(arg[3] .. " can not write")
end
configs.write = function(data)
target:write(data)
end
from_file(arg[2]):render(configs)
target:close()
else
print("penpot_template.lua [appname] [template-in] [template-out]")
end

View File

@@ -0,0 +1,96 @@
## Should be set to the public domain where penpot is going to be served.
##
## NOTE: If you are going to serve it under different domain than
## 'localhost' without HTTPS, consider setting the
## `disable-secure-session-cookies' flag on the 'PENPOT_FLAGS'
## setting.
PENPOT_PUBLIC_URI=<%=public_uri%>
## Feature flags.
PENPOT_FLAGS=enable-registration enable-login disable-email-verification disable-secure-session-cookies
## Temporal workaround because of bad builtin default
PENPOT_HTTP_SERVER_HOST=0.0.0.0
## Standard database connection parameters (only postgresql is supported):
PENPOT_DATABASE_URI=<%=db_uri%>
PENPOT_DATABASE_USERNAME=<%=db_username%>
PENPOT_DATABASE_PASSWORD=<%=db_password%>
## Redis is used for the websockets notifications.
PENPOT_REDIS_URI=<%=redis_uri%>
## By default, files uploaded by users are stored in local
## filesystem. But it can be configured to store in AWS S3.
PENPOT_ASSETS_STORAGE_BACKEND=assets-fs
PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets
## Telemetry. When enabled, a periodical process will send anonymous
## data about this instance. Telemetry data will enable us to learn on
## how the application is used, based on real scenarios. If you want
## to help us, please leave it enabled.
PENPOT_TELEMETRY_ENABLED=true
## Email sending configuration. By default, emails are printed in the
## console, but for production usage is recommended to setup a real
## SMTP provider. Emails are used to confirm user registrations.
PENPOT_SMTP_DEFAULT_FROM=<%=smtp_default_from%>
PENPOT_SMTP_DEFAULT_REPLY_TO=<%=smtp_default_reply_to%>
# PENPOT_SMTP_HOST=
# PENPOT_SMTP_PORT=
# PENPOT_SMTP_USERNAME=
# PENPOT_SMTP_PASSWORD=
# PENPOT_SMTP_TLS=true
# PENPOT_SMTP_SSL=false
## Comma separated list of allowed domains to register. Empty to allow
## all.
# PENPOT_REGISTRATION_DOMAIN_WHITELIST=""
## Authentication providers
## Google
# PENPOT_GOOGLE_CLIENT_ID=
# PENPOT_GOOGLE_CLIENT_SECRET=
## GitHub
# PENPOT_GITHUB_CLIENT_ID=
# PENPOT_GITHUB_CLIENT_SECRET=
## GitLab
# PENPOT_GITLAB_BASE_URI=https://gitlab.com
# PENPOT_GITLAB_CLIENT_ID=
# PENPOT_GITLAB_CLIENT_SECRET=
## OpenID Connect (since 1.5.0)
# PENPOT_OIDC_BASE_URI=
# PENPOT_OIDC_CLIENT_ID=
# PENPOT_OIDC_CLIENT_SECRET=
## LDAP
##
## NOTE: to enable ldap, you will need to put 'enable-login-with-ldap'
## on the 'PENPOT_FLAGS' environment variable.
# PENPOT_LDAP_HOST=ldap
# PENPOT_LDAP_PORT=10389
# PENPOT_LDAP_SSL=false
# PENPOT_LDAP_STARTTLS=false
# PENPOT_LDAP_BASE_DN=ou=people,dc=planetexpress,dc=com
# PENPOT_LDAP_BIND_DN=cn=admin,dc=planetexpress,dc=com
# PENPOT_LDAP_BIND_PASSWORD=GoodNewsEveryone
# PENPOT_LDAP_ATTRS_USERNAME=uid
# PENPOT_LDAP_ATTRS_EMAIL=mail
# PENPOT_LDAP_ATTRS_FULLNAME=cn

View File

@@ -0,0 +1,73 @@
---
version: "3.5"
networks:
penpot:
services:
penpot-frontend:
image: "penpotapp/frontend:latest"
ports:
- <%=http_port%>:80
volumes:
- <%=config_path%>/data/asserts:/opt/data
env_file:
- config.env
depends_on:
- penpot-backend
- penpot-exporter
networks:
- penpot
penpot-backend:
image: "penpotapp/backend:latest"
volumes:
- <%=config_path%>/data/asserts:/opt/data
depends_on:
- penpot-postgres
- penpot-redis
env_file:
- config.env
networks:
- penpot
penpot-exporter:
image: "penpotapp/exporter:latest"
env_file:
- config.env
environment:
# Don't touch it; this uses internal docker network to
# communicate with the frontend.
- PENPOT_PUBLIC_URI=http://penpot-frontend
networks:
- penpot
penpot-postgres:
image: "postgres:14"
restart: always
stop_signal: SIGINT
environment:
- POSTGRES_INITDB_ARGS=--data-checksums
- POSTGRES_DB=<%=db_name%>
- POSTGRES_USER=<%=db_username%>
- POSTGRES_PASSWORD=<%=db_password%>
volumes:
- <%=config_path%>/data/postgres:/var/lib/postgresql/data
networks:
- penpot
penpot-redis:
image: redis:7
restart: always
networks:
- penpot

View File

@@ -50,7 +50,7 @@ for _, val in pairs(paths) do
end
o.default = default_path
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file#/?path=/root/mnt' target='_blank'>/mnt</a>")
o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " <a href='/cgi-bin/luci/admin/services/linkease/file/?path=/root/mnt' target='_blank'>/mnt</a>")
o.datatype = "string"
o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space"))

View File

@@ -0,0 +1,18 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-20221114
PKG_RELEASE:=
LUCI_TITLE:=LuCI support for UnifiController
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+docker +luci-lib-taskd
define Package/luci-app-unifi/conffiles
/etc/config/unifi
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,7 @@
module("luci.controller.unifi", package.seeall)
function index()
entry({"admin", "services", "unifi"}, alias("admin", "services", "unifi", "config"), _("UnifiController"), 30).dependent = true
entry({"admin", "services", "unifi", "config"}, cbi("unifi"))
end

View File

@@ -0,0 +1,49 @@
--[[
LuCI - Lua Configuration Interface
]]--
local taskd = require "luci.model.tasks"
local unifi_model = require "luci.model.unifi"
local m, s, o
m = taskd.docker_map("unifi", "unifi", "/usr/libexec/istorec/unifi.sh",
translate("UnifiController"),
translate("UnifiController ubnt.")
.. translate("Official website:") .. ' <a href=\"https://www.ui.com/\" target=\"_blank\">https://www.ui.com/</a>')
s = m:section(SimpleSection, translate("Service Status"), translate("UnifiController status:"))
s:append(Template("unifi/status"))
s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:"))
s.addremove=false
s.anonymous=true
o = s:option(Flag, "hostnet", translate("Host network"), translate("UnifiController running in host network, for DLNA application, port is always 8096 if enabled"))
o.default = 0
o.rmempty = false
o = s:option(Value, "http_port", translate("HTTPS Port").."<b>*</b>")
o.default = "8083"
o.datatype = "string"
o:depends("hostnet", 0)
o = s:option(Value, "image_name", translate("Image").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
o:value("lscr.io/linuxserver/unifi-controller:latest", "lscr.io/linuxserver/unifi-controller:latest")
o.default = "lscr.io/linuxserver/unifi-controller:latest"
local blocks = unifi_model.blocks()
local home = unifi_model.home()
o = s:option(Value, "config_path", translate("Config path").."<b>*</b>")
o.rmempty = false
o.datatype = "string"
local paths, default_path = unifi_model.find_paths(blocks, home, "Configs")
for _, val in pairs(paths) do
o:value(val, val)
end
o.default = default_path
return m

View File

@@ -0,0 +1,53 @@
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local unifi = {}
unifi.blocks = function()
local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r")
local vals = {}
if f then
local ret = f:read("*all")
f:close()
local obj = jsonc.parse(ret)
for _, val in pairs(obj["blockdevices"]) do
local fsize = val["fssize"]
if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then
-- fsize > 1G
vals[#vals+1] = val["mountpoint"]
end
end
end
return vals
end
unifi.home = function()
local uci = require "luci.model.uci".cursor()
local home_dirs = {}
home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root")
home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs")
home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches")
return home_dirs
end
unifi.find_paths = function(blocks, home_dirs, path_name)
local default_path = ''
local configs = {}
default_path = home_dirs[path_name] .. "/UnifiController"
if #blocks == 0 then
table.insert(configs, default_path)
else
for _, val in pairs(blocks) do
table.insert(configs, val .. "/" .. path_name .. "/UnifiController")
end
local without_conf_dir = "/root/" .. path_name .. "/UnifiController"
if default_path == without_conf_dir then
default_path = configs[1]
end
end
return configs, default_path
end
return unifi

View File

@@ -0,0 +1,31 @@
<%
local util = require "luci.util"
local container_status = util.trim(util.exec("/usr/libexec/istorec/unifi.sh status"))
local container_install = (string.len(container_status) > 0)
local container_running = container_status == "running"
-%>
<div class="cbi-value">
<label class="cbi-value-title"><%:Status%></label>
<div class="cbi-value-field">
<% if container_running then %>
<button class="cbi-button cbi-button-success" disabled="true"><%:UnifiController is running%></button>
<% else %>
<button class="cbi-button cbi-button-negative" disabled="true"><%:UnifiController is not running%></button>
<% end %>
</div>
</div>
<%
if container_running then
local port=util.trim(util.exec("/usr/libexec/istorec/unifi.sh port"))
if port == "" then
port="8083"
end
-%>
<div class="cbi-value cbi-value-last">
<label class="cbi-value-title">&nbsp;</label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open UnifiController%>" onclick="window.open('https://'+location.hostname+':<%=port%>', '_blank')">
</div>
</div>
<% end %>

View File

@@ -0,0 +1,41 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "UnifiController ubnt."
msgstr "Ubnt AC 控制器。"
msgid "Config path"
msgstr "配置文件路径"
msgid "HTTPS Port"
msgstr "HTTPS 端口"
msgid "Service Status"
msgstr "服务状态"
msgid "UnifiController status:"
msgstr "UnifiController 的状态信息如下:"
msgid "Setup"
msgstr "安装配置"
msgid "The following parameters will only take effect during installation or upgrade:"
msgstr "以下参数只在安装或者升级时才会生效:"
msgid "Status"
msgstr "状态"
msgid "UnifiController is running"
msgstr "UnifiController 运行中"
msgid "UnifiController is not running"
msgstr "UnifiController 未运行"
msgid "Open UnifiController"
msgstr "打开 UnifiController"
msgid "Not required, all disk is mounted in"
msgstr "可不填,所有硬盘都在"

View File

@@ -0,0 +1,6 @@
config main
option 'hostnet' '0'
option 'http_port' '8083'
option 'image_name' 'lscr.io/linuxserver/unifi-controller:latest'
option 'config_path' ''

View File

@@ -0,0 +1,85 @@
#!/bin/sh
# Author Xiaobao(xiaobao@linkease.com)
ACTION=${1}
shift 1
do_install() {
local hostnet=`uci get unifi.@main[0].hostnet 2>/dev/null`
local http_port=`uci get unifi.@main[0].http_port 2>/dev/null`
local image_name=`uci get unifi.@main[0].image_name 2>/dev/null`
local config=`uci get unifi.@main[0].config_path 2>/dev/null`
[ -z "$image_name" ] && image_name="lscr.io/linuxserver/unifi-controller:latest"
echo "docker pull ${image_name}"
docker pull ${image_name}
docker rm -f unifi
if [ -z "$config" ]; then
echo "config path is empty!"
exit 1
fi
[ -z "$http_port" ] && http_port=8083
local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" "
if [ "$hostnet" = 1 ]; then
cmd="$cmd\
--dns=127.0.0.1 \
--network=host "
else
cmd="$cmd\
--dns=172.17.0.1 \
-p 3478:3478/udp \
-p 10001:10001/udp \
-p 8080:8080 \
-p $http_port:8443 "
fi
local tz="`cat /tmp/TZ`"
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
cmd="$cmd -v /mnt:/mnt"
mountpoint -q /mnt && cmd="$cmd:rslave"
cmd="$cmd --name unifi \"$image_name\""
echo "$cmd"
eval "$cmd"
}
usage() {
echo "usage: $0 sub-command"
echo "where sub-command is one of:"
echo " install Install the unifi"
echo " upgrade Upgrade the unifi"
echo " rm/start/stop/restart Remove/Start/Stop/Restart the unifi"
echo " status UnifiController status"
echo " port UnifiController port"
}
case ${ACTION} in
"install")
do_install
;;
"upgrade")
do_install
;;
"rm")
docker rm -f unifi
;;
"start" | "stop" | "restart")
docker ${ACTION} unifi
;;
"status")
docker ps --all -f 'name=unifi' --format '{{.State}}'
;;
"port")
http_port=`uci get unifi.@main[0].http_port 2>/dev/null`
echo $http_port
;;
*)
usage
exit 1
;;
esac