mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-02 00:17:13 +00:00
feat(update): add rolling dev update channel for per-commit builds
Adds an opt-in Dev channel so panels running CI per-commit builds can self-update to the latest commit, mirroring the stable online-update flow. CI publishes/overwrites a single fixed-tag pre-release (dev-latest), force-moved to the newest main commit and marked --latest=false so releases/latest stays the stable tag. Builds stamp the short commit via -ldflags; the panel compares the running commit to the dev release commit to detect an update, and update.sh honors XUI_UPDATE_TAG to install from that tag. Linux/systemd only.
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
@@ -109,6 +110,7 @@ var defaultValueMap = map[string]string{
|
||||
"restartXrayOnClientDisable": "true",
|
||||
"xrayOutboundTestUrl": "https://www.google.com/generate_204",
|
||||
"panelOutbound": "",
|
||||
"devChannelEnable": "false",
|
||||
|
||||
// LDAP defaults
|
||||
"ldapEnable": "false",
|
||||
@@ -855,6 +857,16 @@ func (s *SettingService) SetRestartXrayOnClientDisable(value bool) error {
|
||||
return s.setBool("restartXrayOnClientDisable", value)
|
||||
}
|
||||
|
||||
// GetDevChannelEnable reports whether the panel self-update tracks the rolling
|
||||
// per-commit dev release instead of the latest stable tag.
|
||||
func (s *SettingService) GetDevChannelEnable() (bool, error) {
|
||||
return s.getBool("devChannelEnable")
|
||||
}
|
||||
|
||||
func (s *SettingService) SetDevChannelEnable(value bool) error {
|
||||
return s.setBool("devChannelEnable", value)
|
||||
}
|
||||
|
||||
// GetIpLimitEnable reports whether the IP-limit feature is available. Always
|
||||
// true since the panel enforces limits via the core's online-stats API; on an
|
||||
// older core the job falls back to access-log parsing and warns there when the
|
||||
@@ -1209,25 +1221,27 @@ func (s *SettingService) BuildSubURIBase(host string) string {
|
||||
func (s *SettingService) GetDefaultSettings(host string) (any, error) {
|
||||
type settingFunc func() (any, error)
|
||||
settings := map[string]settingFunc{
|
||||
"expireDiff": func() (any, error) { return s.GetExpireDiff() },
|
||||
"trafficDiff": func() (any, error) { return s.GetTrafficDiff() },
|
||||
"pageSize": func() (any, error) { return s.GetPageSize() },
|
||||
"defaultCert": func() (any, error) { return s.GetCertFile() },
|
||||
"defaultKey": func() (any, error) { return s.GetKeyFile() },
|
||||
"tgBotEnable": func() (any, error) { return s.GetTgbotEnabled() },
|
||||
"subThemeDir": func() (any, error) { return s.GetSubThemeDir() },
|
||||
"subEnable": func() (any, error) { return s.GetSubEnable() },
|
||||
"subJsonEnable": func() (any, error) { return s.GetSubJsonEnable() },
|
||||
"subClashEnable": func() (any, error) { return s.GetSubClashEnable() },
|
||||
"subTitle": func() (any, error) { return s.GetSubTitle() },
|
||||
"subURI": func() (any, error) { return s.GetSubURI() },
|
||||
"subJsonURI": func() (any, error) { return s.GetSubJsonURI() },
|
||||
"subClashURI": func() (any, error) { return s.GetSubClashURI() },
|
||||
"datepicker": func() (any, error) { return s.GetDatepicker() },
|
||||
"ipLimitEnable": func() (any, error) { return s.GetIpLimitEnable() },
|
||||
"accessLogEnable": func() (any, error) { return s.GetAccessLogEnable() },
|
||||
"webDomain": func() (any, error) { return s.GetWebDomain() },
|
||||
"subDomain": func() (any, error) { return s.GetSubDomain() },
|
||||
"expireDiff": func() (any, error) { return s.GetExpireDiff() },
|
||||
"trafficDiff": func() (any, error) { return s.GetTrafficDiff() },
|
||||
"pageSize": func() (any, error) { return s.GetPageSize() },
|
||||
"defaultCert": func() (any, error) { return s.GetCertFile() },
|
||||
"defaultKey": func() (any, error) { return s.GetKeyFile() },
|
||||
"tgBotEnable": func() (any, error) { return s.GetTgbotEnabled() },
|
||||
"subThemeDir": func() (any, error) { return s.GetSubThemeDir() },
|
||||
"subEnable": func() (any, error) { return s.GetSubEnable() },
|
||||
"subJsonEnable": func() (any, error) { return s.GetSubJsonEnable() },
|
||||
"subClashEnable": func() (any, error) { return s.GetSubClashEnable() },
|
||||
"subTitle": func() (any, error) { return s.GetSubTitle() },
|
||||
"subURI": func() (any, error) { return s.GetSubURI() },
|
||||
"subJsonURI": func() (any, error) { return s.GetSubJsonURI() },
|
||||
"subClashURI": func() (any, error) { return s.GetSubClashURI() },
|
||||
"datepicker": func() (any, error) { return s.GetDatepicker() },
|
||||
"ipLimitEnable": func() (any, error) { return s.GetIpLimitEnable() },
|
||||
"accessLogEnable": func() (any, error) { return s.GetAccessLogEnable() },
|
||||
"webDomain": func() (any, error) { return s.GetWebDomain() },
|
||||
"subDomain": func() (any, error) { return s.GetSubDomain() },
|
||||
"devChannelEnable": func() (any, error) { return s.GetDevChannelEnable() },
|
||||
"isDevBuild": func() (any, error) { return config.IsDevBuild(), nil },
|
||||
}
|
||||
|
||||
result := make(map[string]any)
|
||||
|
||||
Reference in New Issue
Block a user