mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-27 14:52:52 +08:00
🐤 Sync 2026-04-19 08:30:38
This commit is contained in:
1 parent
746d64b361
commit
a9b3f7579c
14 files changed
+327
-42
No files matched your search
@@ -0,0 +1,17 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=1.0.0-20240101
|
||||
PKG_RELEASE:=1
|
||||
|
||||
LUCI_TITLE:=LuCI support for Hermes
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+docker +dockerd +luci-lib-taskd
|
||||
|
||||
define Package/luci-app-hermes/conffiles
|
||||
/etc/config/hermes
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -0,0 +1,6 @@
|
||||
module("luci.controller.hermes", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "services", "hermes"}, alias("admin", "services", "hermes", "config"), _("Hermes"), 30).dependent = true
|
||||
entry({"admin", "services", "hermes", "config"}, cbi("hermes"))
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
]]--
|
||||
|
||||
local taskd = require "luci.model.tasks"
|
||||
local hermes_model = require "luci.model.hermes"
|
||||
local m, s, o
|
||||
|
||||
m = taskd.docker_map("hermes", "hermes", "/usr/libexec/istorec/hermes.sh",
|
||||
translate("Hermes"),
|
||||
translate("The self-improving AI agent that runs on your server. Layered memory that accumulates across sessions, a cron scheduler that fires while you're offline, and a skills system that saves reusable procedures automatically.")
|
||||
.. translate("Official website:") .. ' <a href=\"https://get-hermes.ai/\" target=\"_blank\">https://get-hermes.ai/</a>')
|
||||
|
||||
s = m:section(SimpleSection, translate("Service Status"), translate("Hermes status:"))
|
||||
s:append(Template("hermes/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, "port", translate("Port") .. "<b>*</b>")
|
||||
o.default = "8787"
|
||||
o.datatype = "port"
|
||||
|
||||
local blocks = hermes_model.blocks()
|
||||
|
||||
o = s:option(Value, "data_path", translate("Data path") .. "<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
local data_paths, data_default = hermes_model.find_paths(blocks, "data")
|
||||
for _, val in pairs(data_paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = data_default
|
||||
|
||||
o = s:option(Value, "workspace_path", translate("Workspace path") .. "<b>*</b>")
|
||||
o.rmempty = false
|
||||
o.datatype = "string"
|
||||
local ws_paths, ws_default = hermes_model.find_paths(blocks, "workspace")
|
||||
for _, val in pairs(ws_paths) do
|
||||
o:value(val, val)
|
||||
end
|
||||
o.default = ws_default
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,38 @@
|
||||
local util = require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local hermes = {}
|
||||
|
||||
hermes.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)
|
||||
if obj and obj["blockdevices"] then
|
||||
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
|
||||
end
|
||||
return vals
|
||||
end
|
||||
|
||||
hermes.find_paths = function(blocks, subdir)
|
||||
local configs = {}
|
||||
local default_path = ''
|
||||
for _, mountpoint in pairs(blocks) do
|
||||
table.insert(configs, mountpoint .. "/hermes/" .. subdir)
|
||||
end
|
||||
if #configs > 0 then
|
||||
default_path = configs[1]
|
||||
end
|
||||
return configs, default_path
|
||||
end
|
||||
|
||||
return hermes
|
||||
@@ -0,0 +1,30 @@
|
||||
<%
|
||||
local util = require "luci.util"
|
||||
local container_status = util.trim(util.exec("/usr/libexec/istorec/hermes.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"><%:Hermes is running%></button>
|
||||
<% else %>
|
||||
<button class="cbi-button cbi-button-negative" disabled="true"><%:Hermes is not running%></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
if container_running then
|
||||
local port = util.trim(util.exec("/usr/libexec/istorec/hermes.sh port"))
|
||||
if port == "" then
|
||||
port = "8787"
|
||||
end
|
||||
-%>
|
||||
<div class="cbi-value cbi-value-last">
|
||||
<label class="cbi-value-title"> </label>
|
||||
<div class="cbi-value-field">
|
||||
<input type="button" class="btn cbi-button cbi-button-apply" name="start" value="<%:Open Hermes%>" onclick="window.open('http://'+location.hostname+':<%=port%>/', '_blank')">
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -0,0 +1,44 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Official website:"
|
||||
msgstr "官方网站:"
|
||||
|
||||
msgid "Hermes"
|
||||
msgstr "Hermes 消息服务"
|
||||
|
||||
msgid "The self-improving AI agent that runs on your server. Layered memory that accumulates across sessions, a cron scheduler that fires while you're offline, and a skills system that saves reusable procedures automatically."
|
||||
msgstr "运行在您的服务器上的自我改进型人工智能代理。它采用跨会话累积的分层内存、在您离线时运行的定时任务调度程序,以及自动保存可重用程序的技能系统。"
|
||||
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
msgid "Data path"
|
||||
msgstr "数据路径"
|
||||
|
||||
msgid "Workspace path"
|
||||
msgstr "工作目录路径"
|
||||
|
||||
msgid "Service Status"
|
||||
msgstr "服务状态"
|
||||
|
||||
msgid "Hermes status:"
|
||||
msgstr "Hermes 状态信息如下:"
|
||||
|
||||
msgid "Setup"
|
||||
msgstr "安装配置"
|
||||
|
||||
msgid "The following parameters will only take effect during installation or upgrade:"
|
||||
msgstr "以下参数只在安装或者升级时才会生效:"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Hermes is running"
|
||||
msgstr "Hermes 运行中"
|
||||
|
||||
msgid "Hermes is not running"
|
||||
msgstr "Hermes 未运行"
|
||||
|
||||
msgid "Open Hermes"
|
||||
msgstr "打开 Hermes"
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
zh-cn
|
||||
@@ -0,0 +1,4 @@
|
||||
config main
|
||||
option 'port' '8787'
|
||||
option 'data_path' ''
|
||||
option 'workspace_path' ''
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
|
||||
ACTION=${1}
|
||||
shift 1
|
||||
|
||||
do_install() {
|
||||
local port=$(uci get hermes.@main[0].port 2>/dev/null | tr -d '\n\r')
|
||||
local data=$(uci get hermes.@main[0].data_path 2>/dev/null | tr -d '\n\r')
|
||||
local workspace=$(uci get hermes.@main[0].workspace_path 2>/dev/null | tr -d '\n\r')
|
||||
|
||||
local image_name="linkease/hermes:latest"
|
||||
echo "docker pull ${image_name}"
|
||||
docker pull ${image_name}
|
||||
docker rm -f hermes
|
||||
|
||||
[ -z "$port" ] && port=8787
|
||||
|
||||
local cmd="docker run --restart=unless-stopped -d"
|
||||
|
||||
[ -n "$data" ] && cmd="$cmd -v \"$data:/data/.hermes\""
|
||||
[ -n "$workspace" ] && cmd="$cmd -v \"$workspace:/workspace\""
|
||||
|
||||
cmd="$cmd -p $port:8787"
|
||||
|
||||
local tz=$(uci get system.@system[0].zonename 2>/dev/null | sed 's/ /_/g')
|
||||
[ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
|
||||
|
||||
cmd="$cmd --name hermes \"$image_name\""
|
||||
|
||||
echo "$cmd"
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 sub-command"
|
||||
echo "where sub-command is one of:"
|
||||
echo " install Install the hermes"
|
||||
echo " upgrade Upgrade the hermes"
|
||||
echo " rm/start/stop/restart Remove/Start/Stop/Restart the hermes"
|
||||
echo " status Hermes status"
|
||||
echo " port Hermes port"
|
||||
}
|
||||
|
||||
case ${ACTION} in
|
||||
"install")
|
||||
do_install
|
||||
;;
|
||||
"upgrade")
|
||||
do_install
|
||||
;;
|
||||
"rm")
|
||||
docker rm -f hermes
|
||||
;;
|
||||
"start" | "stop" | "restart")
|
||||
docker ${ACTION} hermes
|
||||
;;
|
||||
"status")
|
||||
docker ps --all -f 'name=^/hermes$' --format '{{.State}}'
|
||||
;;
|
||||
"port")
|
||||
docker ps --all -f 'name=^/hermes$' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*->8787/tcp' | sed 's/0.0.0.0:\([0-9]*\)->.*/\1/'
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-hermes": {
|
||||
"description": "Grant UCI access for luci-app-hermes",
|
||||
"read": {
|
||||
"uci": [ "hermes" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "hermes" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.4.15
|
||||
PKG_RELEASE:=81
|
||||
PKG_RELEASE:=82
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -48,15 +48,23 @@ o.default = ""
|
||||
o:depends("console_auth", true)
|
||||
|
||||
---- Console Port
|
||||
o = s:option(Value, "console_port", translate("Console Port"), translate(
|
||||
"In the browser input routing IP plus port access, such as:192.168.1.1:1188"))
|
||||
o.default = "1188"
|
||||
o = s:option(Value, "console_port", translate("Console Port"), translate("In the browser input routing IP plus port access, such as:192.168.1.1:1188"))
|
||||
o.datatype = "port"
|
||||
o.default = 1188
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
o = s:option(Flag, "bind_local", translate("Haproxy Port") .. " " .. translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
|
||||
o.default = "0"
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
o = s:option(ListValue, "balancingStrategy", translate("Balancing Strategy"))
|
||||
o:value("roundrobin", "roundRobin")
|
||||
o:value("random", "random")
|
||||
o:value("leastconn", "leastConn")
|
||||
o:value("source", "source")
|
||||
o.default = "roundrobin"
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
---- Health Check Type
|
||||
o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
|
||||
o.default = "passwall_logic"
|
||||
@@ -77,9 +85,12 @@ o.description = translate("The URL used to detect the connection status.")
|
||||
o:depends("health_check_type", "passwall_logic")
|
||||
|
||||
---- Health Check Inter
|
||||
o = s:option(Value, "health_check_inter", translate("Health Check Inter"), translate("Units:seconds"))
|
||||
o.default = "60"
|
||||
o = s:option(Value, "health_check_inter", translate("Health Check Inter"))
|
||||
o.datatype = "min(20)"
|
||||
o.default = 60
|
||||
o:depends("balancing_enable", true)
|
||||
o.description = translate("Units:seconds") .. " ( ≥ 20s )<br>" ..
|
||||
translate("Note: Frequent health checks increase CPU usage; an interval ≥ 60 seconds is recommended.")
|
||||
|
||||
o = s:option(DummyValue, "health_check_tips", " ")
|
||||
o.rawhtml = true
|
||||
@@ -89,11 +100,10 @@ end
|
||||
o:depends("health_check_type", "passwall_logic")
|
||||
|
||||
-- [[ Balancing Settings ]]--
|
||||
s = m:section(TypedSection, "haproxy_config", translate("Node List"),
|
||||
"<font color='red'>" ..
|
||||
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") ..
|
||||
"\n" .. translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") ..
|
||||
"</font>")
|
||||
s = m:section(TypedSection, "haproxy_config", translate("Node List"))
|
||||
s.description = "<font color='red'>" ..
|
||||
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") .. "<br>" ..
|
||||
translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") .. "</font>"
|
||||
s.template = "cbi/tblsection"
|
||||
s.sortable = true
|
||||
s.anonymous = true
|
||||
@@ -148,7 +158,7 @@ o.rmempty = false
|
||||
|
||||
---- Node Weight
|
||||
o = s:option(Value, "lbweight", translate("Node Weight"))
|
||||
o.datatype = "uinteger"
|
||||
o.datatype = "min(1)"
|
||||
o.default = 5
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
@@ -970,6 +970,9 @@ msgstr "内置实现"
|
||||
msgid "Health Check Inter"
|
||||
msgstr "健康检查节点间隔时间"
|
||||
|
||||
msgid "Note: Frequent health checks increase CPU usage; an interval ≥ 60 seconds is recommended."
|
||||
msgstr "注意:检测过于频繁会增加 CPU 负载,建议间隔 ≥60 秒。"
|
||||
|
||||
msgid "When the URL test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."
|
||||
msgstr "当使用 URL 测试时,负载均衡节点将转换成 Socks 节点。下面的节点列表自定义时必须为 Socks 节点,否则健康检查将无效。"
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ local haproxy_dns = var["-dns"] or "119.29.29.29:53,223.5.5.5:53"
|
||||
|
||||
local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1"
|
||||
local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp"
|
||||
local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "10"
|
||||
local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "20"
|
||||
local balancingStrategy = uci:get(appname, "@global_haproxy[0]", "balancingStrategy") or "roundrobin"
|
||||
local console_port = uci:get(appname, "@global_haproxy[0]", "console_port")
|
||||
local bind_local = uci:get(appname, "@global_haproxy[0]", "bind_local") or "0"
|
||||
local bind_address = "0.0.0.0"
|
||||
@@ -40,35 +41,37 @@ local f_out = io.open(haproxy_file, "a")
|
||||
local haproxy_config = [[
|
||||
global
|
||||
daemon
|
||||
log 127.0.0.1 local2
|
||||
maxconn 60000
|
||||
stats socket {{path}}/haproxy.sock
|
||||
log 127.0.0.1 local2
|
||||
maxconn 60000
|
||||
stats socket {{path}}/haproxy.sock
|
||||
nbthread {{nbthread}}
|
||||
external-check
|
||||
insecure-fork-wanted
|
||||
spread-checks 50
|
||||
tune.max-checks-per-thread 5
|
||||
|
||||
defaults
|
||||
mode tcp
|
||||
log global
|
||||
option tcplog
|
||||
option dontlognull
|
||||
mode tcp
|
||||
log global
|
||||
option tcplog
|
||||
option dontlognull
|
||||
option http-server-close
|
||||
#option forwardfor except 127.0.0.0/8
|
||||
option redispatch
|
||||
retries 2
|
||||
timeout http-request 10s
|
||||
timeout queue 1m
|
||||
timeout connect 10s
|
||||
timeout client 1m
|
||||
timeout server 1m
|
||||
#option forwardfor except 127.0.0.0/8
|
||||
option redispatch
|
||||
retries 2
|
||||
timeout http-request 10s
|
||||
timeout queue 1m
|
||||
timeout connect 10s
|
||||
timeout client 1m
|
||||
timeout server 1m
|
||||
timeout http-keep-alive 10s
|
||||
timeout check 10s
|
||||
maxconn 3000
|
||||
|
||||
timeout check 10s
|
||||
maxconn 3000
|
||||
|
||||
resolvers mydns
|
||||
resolve_retries 1
|
||||
timeout resolve 5s
|
||||
hold valid 600s
|
||||
resolve_retries 1
|
||||
timeout resolve 5s
|
||||
hold valid 600s
|
||||
{{dns}}
|
||||
]]
|
||||
|
||||
@@ -99,10 +102,12 @@ uci:foreach(appname, "haproxy_config", function(t)
|
||||
local lbss = t.lbss
|
||||
local listen_port = tonumber(t.haproxy_port) or 0
|
||||
local server_node = uci:get_all(appname, lbss)
|
||||
if server_node and server_node.address and server_node.port then
|
||||
server_remark = server_node.address .. ":" .. server_node.port
|
||||
local hop = (health_check_type == "passwall_logic") and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil
|
||||
hop = hop and hop:gsub(":", "-") or nil
|
||||
if server_node and server_node.address and (server_node.port or hop) then
|
||||
server_remark = server_node.address .. ":" .. (server_node.port or hop)
|
||||
server_address = server_node.address
|
||||
server_port = server_node.port
|
||||
server_port = server_node.port or hop
|
||||
t.origin_address = server_address
|
||||
t.origin_port = server_port
|
||||
if health_check_type == "passwall_logic" then
|
||||
@@ -145,6 +150,10 @@ uci:foreach(appname, "haproxy_config", function(t)
|
||||
end
|
||||
end)
|
||||
|
||||
local inter = tonumber((health_check_inter or "20"):match("^%d+"))
|
||||
inter = (inter and inter >= 20) and inter or 20
|
||||
local inter_arg = "inter " .. inter .. "s fastinter " .. inter / 2 .. "s downinter " .. inter * 1.5 .. "s"
|
||||
|
||||
local sortTable = {}
|
||||
for i in pairs(listens) do
|
||||
if i ~= nil then
|
||||
@@ -160,8 +169,8 @@ for i, port in pairs(sortTable) do
|
||||
listen %s
|
||||
bind %s:%s
|
||||
mode tcp
|
||||
balance roundrobin
|
||||
]], port, bind_address, port))
|
||||
balance %s
|
||||
]], port, bind_address, port, balancingStrategy))
|
||||
|
||||
if health_check_type == "passwall_logic" then
|
||||
f_out:write(string.format([[
|
||||
@@ -182,7 +191,7 @@ listen %s
|
||||
count_B = count_B + 1
|
||||
end
|
||||
local server = o.server_address .. ":" .. o.server_port
|
||||
local server_conf = "server {{remark}} {{server}} weight {{weight}} {{resolvers}} check inter {{inter}} rise 1 fall 3 {{backup}}"
|
||||
local server_conf = "server {{remark}} {{server}} weight {{weight}} {{resolvers}} check {{inter_arg}} rise 2 fall 2 {{backup}}"
|
||||
server_conf = server_conf:gsub("{{remark}}", remark)
|
||||
server_conf = server_conf:gsub("{{server}}", server)
|
||||
server_conf = server_conf:gsub("{{weight}}", o.lbweight)
|
||||
@@ -191,10 +200,10 @@ listen %s
|
||||
resolvers = ""
|
||||
end
|
||||
server_conf = server_conf:gsub("{{resolvers}}", resolvers)
|
||||
server_conf = server_conf:gsub("{{inter}}", tonumber(health_check_inter) .. "s")
|
||||
server_conf = server_conf:gsub("{{inter_arg}}", inter_arg)
|
||||
server_conf = server_conf:gsub("{{backup}}", tostring(o.backup) == "1" and "backup" or "")
|
||||
|
||||
f_out:write(" " .. server_conf .. "\n")
|
||||
f_out:write(" " .. api.trim(server_conf) .. "\n")
|
||||
|
||||
if o.export ~= "0" then
|
||||
sys.call(string.format(". /usr/share/passwall/utils.sh ; add_ip2route %s %s", o.origin_address, o.export))
|
||||
|
||||
Reference in new issue
Block a user