🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.2-20251011
PKG_RELEASE:=1
LUCI_TITLE:=LuCI support for CodeServer
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+lsblk +docker +dockerd +luci-lib-taskd
define Package/luci-app-codeserver/conffiles
/etc/config/codeserver
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
+9
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
@@ -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 = "8085"
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
@@ -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
@@ -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
@@ -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
@@ -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>
@@ -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="8085"
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 %>
@@ -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>
@@ -0,0 +1,50 @@
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 "Tool"
msgstr "操作"
msgid "Console"
msgstr "控制台"
msgid "Only works in LAN"
msgstr "只在内网环境下工作。"
msgid "Execute"
msgstr "执行"
+1
View File
@@ -0,0 +1 @@
zh-cn
@@ -0,0 +1,10 @@
config main
option 'http_port' '8085'
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' ''
+91
View File
@@ -0,0 +1,91 @@
#!/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=8085
local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" \
--dns=172.17.0.1 \
-e PUID=911 -e PGID=911 \
-e DEFAULT_WORKSPACE=/config/workspace \
-p $http_port:8443 "
local tz="`uci get system.@system[0].zonename | sed 's/ /_/g'`"
[ -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
@@ -0,0 +1,11 @@
{
"luci-app-codeserver": {
"description": "Grant UCI access for luci-app-codeserver",
"read": {
"uci": [ "codeserver" ]
},
"write": {
"uci": [ "codeserver" ]
}
}
}