Compare commits

..

10 Commits

Author SHA1 Message Date
Alireza Ahmadi 86379818a2 v1.3.11 2026-02-28 13:28:48 +01:00
Alireza Ahmadi 8a07d2df7e Merge pull request #1033 from alireza0/dependabot/github_actions/actions/upload-artifact-7
Bump actions/upload-artifact from 6 to 7
2026-02-28 02:03:57 +01:00
Alireza Ahmadi 7d63da8be3 Merge pull request #1032 from alireza0/dependabot/github_actions/actions/download-artifact-8
Bump actions/download-artifact from 7 to 8
2026-02-28 02:03:39 +01:00
Alireza Ahmadi 06ee9cfce2 Sing-Box v1.12.23 2026-02-28 02:02:10 +01:00
Alireza Ahmadi 13d475da20 fix crash on restart due to change #1030 2026-02-28 01:52:34 +01:00
dependabot[bot] fbf46a72b0 Bump actions/upload-artifact from 6 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 16:53:23 +00:00
dependabot[bot] 5bb15ff2c9 Bump actions/download-artifact from 7 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 16:53:18 +00:00
Alireza Ahmadi 5812d6a827 fix docker logs and db #1019 2026-02-17 21:14:37 +01:00
Seva 083f19324f Fix directory when running as administrator (#1009)
* Update install-windows.bat

* Update s-ui-windows.bat

* Update install-windows.bat

* Update build-windows.bat
2026-02-17 20:26:16 +01:00
Alireza Ahmadi dd07abf501 fix inbound delete affects on client #1008 2026-02-17 20:08:03 +01:00
18 changed files with 99 additions and 48 deletions
+2 -2
View File
@@ -23,7 +23,7 @@ jobs:
npm install npm install
npm run build npm run build
- name: Upload frontend build artifact - name: Upload frontend build artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: frontend-dist name: frontend-dist
path: frontend/dist/ path: frontend/dist/
@@ -35,7 +35,7 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
- name: Download frontend build artifact - name: Download frontend build artifact
uses: actions/download-artifact@v7 uses: actions/download-artifact@v8
with: with:
name: frontend-dist name: frontend-dist
path: frontend_dist path: frontend_dist
+1 -1
View File
@@ -102,7 +102,7 @@ jobs:
run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui
- name: Upload files to Artifacts - name: Upload files to Artifacts
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: s-ui-linux-${{ matrix.platform }} name: s-ui-linux-${{ matrix.platform }}
path: ./s-ui-linux-${{ matrix.platform }}.tar.gz path: ./s-ui-linux-${{ matrix.platform }}.tar.gz
+2 -2
View File
@@ -85,7 +85,7 @@ jobs:
zip -r "s-ui-windows-amd64.zip" s-ui-windows zip -r "s-ui-windows-amd64.zip" s-ui-windows
- name: Upload files to Artifacts - name: Upload files to Artifacts
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: s-ui-windows-amd64 name: s-ui-windows-amd64
path: ./s-ui-windows-amd64.zip path: ./s-ui-windows-amd64.zip
@@ -157,7 +157,7 @@ jobs:
zip -r "s-ui-windows-arm64.zip" s-ui-windows zip -r "s-ui-windows-arm64.zip" s-ui-windows
- name: Upload ARM64 files to Artifacts - name: Upload ARM64 files to Artifacts
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v7
with: with:
name: s-ui-windows-arm64 name: s-ui-windows-arm64
path: ./s-ui-windows-arm64.zip path: ./s-ui-windows-arm64.zip
+2 -8
View File
@@ -386,13 +386,7 @@ func (a *ApiService) DeleteToken(c *gin.Context) {
} }
func (a *ApiService) GetSingboxConfig(c *gin.Context) { func (a *ApiService) GetSingboxConfig(c *gin.Context) {
config, err := a.ConfigService.GetConfig("") rawConfig, err := a.ConfigService.GetConfig("")
if err != nil {
c.Status(400)
c.Writer.WriteString(err.Error())
return
}
rawConfig, err := json.MarshalIndent(config, "", " ")
if err != nil { if err != nil {
c.Status(400) c.Status(400)
c.Writer.WriteString(err.Error()) c.Writer.WriteString(err.Error())
@@ -400,7 +394,7 @@ func (a *ApiService) GetSingboxConfig(c *gin.Context) {
} }
c.Header("Content-Type", "application/json") c.Header("Content-Type", "application/json")
c.Header("Content-Disposition", "attachment; filename=config_"+time.Now().Format("20060102-150405")+".json") c.Header("Content-Disposition", "attachment; filename=config_"+time.Now().Format("20060102-150405")+".json")
c.Writer.Write(rawConfig) c.Writer.Write(*rawConfig)
} }
func (a *ApiService) GetCheckOutbound(c *gin.Context) { func (a *ApiService) GetCheckOutbound(c *gin.Context) {
+1 -1
View File
@@ -79,7 +79,7 @@ func (a *APP) Start() error {
return err return err
} }
err = a.configService.StartCore("") err = a.configService.StartCore()
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
+1 -1
View File
@@ -1 +1 @@
1.3.10 1.3.11
+3
View File
@@ -83,6 +83,9 @@ func (c *Core) Start(sbConfig []byte) error {
func (c *Core) Stop() error { func (c *Core) Stop() error {
c.isRunning = false c.isRunning = false
if c.instance != nil {
return nil
}
return c.instance.Close() return c.instance.Close()
} }
+1 -1
View File
@@ -13,5 +13,5 @@ func NewCheckCoreJob() *CheckCoreJob {
} }
func (s *CheckCoreJob) Run() { func (s *CheckCoreJob) Run() {
s.ConfigService.StartCore("") s.ConfigService.StartCore()
} }
+6 -2
View File
@@ -1,4 +1,8 @@
#!/bin/sh #!/bin/sh
./sui migrate DB_PATH="${SUI_DB_FOLDER:-/app/db}/s-ui.db"
./sui if [ -f "$DB_PATH" ]; then
./sui migrate
fi
exec ./sui
+2 -2
View File
@@ -10,7 +10,7 @@ require (
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/sagernet/sing v0.7.18 github.com/sagernet/sing v0.7.18
github.com/sagernet/sing-box v1.12.21 github.com/sagernet/sing-box v1.12.23
github.com/sagernet/sing-dns v0.4.6 github.com/sagernet/sing-dns v0.4.6
github.com/shirou/gopsutil/v4 v4.26.1 github.com/shirou/gopsutil/v4 v4.26.1
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
@@ -20,7 +20,7 @@ require (
) )
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.2.0 // indirect
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/akutz/memconn v0.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
+6 -2
View File
@@ -1,5 +1,9 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=
filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
@@ -217,8 +221,8 @@ github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 h1:ySqffGm82rPqI1TUPqmtHIYd12
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.7.18 h1:iZHkaru1/MoHugx3G+9S3WG4owMewKO/KvieE2Pzk4E= github.com/sagernet/sing v0.7.18 h1:iZHkaru1/MoHugx3G+9S3WG4owMewKO/KvieE2Pzk4E=
github.com/sagernet/sing v0.7.18/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.7.18/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.12.21 h1:SyTTag/f/JQmP7/1tTVlbhfKgAzB84sFhocmnwmANB8= github.com/sagernet/sing-box v1.12.23 h1:egmRGPpzMZVmc4iCl0T1wBBAZea3NTxDmi//b3sXSsQ=
github.com/sagernet/sing-box v1.12.21/go.mod h1:jjM3DQWWJSMW3U0uv3AxYRjyLnHu/SXN3A6Svex83/w= github.com/sagernet/sing-box v1.12.23/go.mod h1:jjM3DQWWJSMW3U0uv3AxYRjyLnHu/SXN3A6Svex83/w=
github.com/sagernet/sing-dns v0.4.6 h1:mjZC0o6d5sQ1sraoOBbK3G3apCbuL8wWYwu2RNu5rbM= github.com/sagernet/sing-dns v0.4.6 h1:mjZC0o6d5sQ1sraoOBbK3G3apCbuL8wWYwu2RNu5rbM=
github.com/sagernet/sing-dns v0.4.6/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8= github.com/sagernet/sing-dns v0.4.6/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
+11
View File
@@ -23,6 +23,16 @@ func InitLogger(level logging.Level) {
var backend logging.Backend var backend logging.Backend
var format logging.Formatter var format logging.Formatter
_, inContainer := os.LookupEnv("container")
if !inContainer {
if _, statErr := os.Stat("/.dockerenv"); statErr == nil {
inContainer = true
}
}
if inContainer {
backend = logging.NewLogBackend(os.Stderr, "", 0)
format = logging.MustStringFormatter(`%{time:2006/01/02 15:04:05} %{level} - %{message}`)
} else {
backend, err = logging.NewSyslogBackend("") backend, err = logging.NewSyslogBackend("")
if err != nil { if err != nil {
fmt.Println("Unable to use syslog: " + err.Error()) fmt.Println("Unable to use syslog: " + err.Error())
@@ -33,6 +43,7 @@ func InitLogger(level logging.Level) {
} else { } else {
format = logging.MustStringFormatter(`%{level} - %{message}`) format = logging.MustStringFormatter(`%{level} - %{message}`)
} }
}
backendFormatter := logging.NewBackendFormatter(backend, format) backendFormatter := logging.NewBackendFormatter(backend, format)
backendLeveled := logging.AddModuleLevel(backendFormatter) backendLeveled := logging.AddModuleLevel(backendFormatter)
+18 -6
View File
@@ -222,10 +222,16 @@ func (s *ClientService) UpdateClientsOnInboundAdd(tx *gorm.DB, initIds string, i
} }
func (s *ClientService) UpdateClientsOnInboundDelete(tx *gorm.DB, id uint, tag string) error { func (s *ClientService) UpdateClientsOnInboundDelete(tx *gorm.DB, id uint, tag string) error {
var clientIds []uint
err := tx.Raw("SELECT clients.id FROM clients, json_each(clients.inbounds) AS je WHERE je.value = ?", id).Scan(&clientIds).Error
if err != nil {
return err
}
if len(clientIds) == 0 {
return nil
}
var clients []model.Client var clients []model.Client
err := tx.Table("clients"). err = tx.Model(model.Client{}).Where("id IN ?", clientIds).Find(&clients).Error
Where("EXISTS (SELECT 1 FROM json_each(clients.inbounds) WHERE json_each.value = ?)", id).
Find(&clients).Error
if err != nil { if err != nil {
return err return err
} }
@@ -265,10 +271,16 @@ func (s *ClientService) UpdateClientsOnInboundDelete(tx *gorm.DB, id uint, tag s
func (s *ClientService) UpdateLinksByInboundChange(tx *gorm.DB, inbounds *[]model.Inbound, hostname string, oldTag string) error { func (s *ClientService) UpdateLinksByInboundChange(tx *gorm.DB, inbounds *[]model.Inbound, hostname string, oldTag string) error {
var err error var err error
for _, inbound := range *inbounds { for _, inbound := range *inbounds {
var clientIds []uint
err = tx.Raw("SELECT clients.id FROM clients, json_each(clients.inbounds) AS je WHERE je.value = ?", inbound.Id).Scan(&clientIds).Error
if err != nil {
return err
}
if len(clientIds) == 0 {
continue
}
var clients []model.Client var clients []model.Client
err = tx.Table("clients"). err = tx.Model(model.Client{}).Where("id IN ?", clientIds).Find(&clients).Error
Where("EXISTS (SELECT 1 FROM json_each(clients.inbounds) WHERE json_each.value = ?)", inbound.Id).
Find(&clients).Error
if err != nil { if err != nil {
return err return err
} }
+32 -13
View File
@@ -44,7 +44,7 @@ func NewConfigService(core *core.Core) *ConfigService {
return &ConfigService{} return &ConfigService{}
} }
func (s *ConfigService) GetConfig(data string) (*SingBoxConfig, error) { func (s *ConfigService) GetConfig(data string) (*[]byte, error) {
var err error var err error
if len(data) == 0 { if len(data) == 0 {
data, err = s.SettingService.GetConfig() data, err = s.SettingService.GetConfig()
@@ -74,22 +74,22 @@ func (s *ConfigService) GetConfig(data string) (*SingBoxConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &singboxConfig, nil rawConfig, err := json.MarshalIndent(singboxConfig, "", " ")
if err != nil {
return nil, err
}
return &rawConfig, nil
} }
func (s *ConfigService) StartCore(defaultConfig string) error { func (s *ConfigService) StartCore() error {
if corePtr.IsRunning() { if corePtr.IsRunning() {
return nil return nil
} }
singboxConfig, err := s.GetConfig(defaultConfig) rawConfig, err := s.GetConfig("")
if err != nil { if err != nil {
return err return err
} }
rawConfig, err := json.MarshalIndent(singboxConfig, "", " ") err = corePtr.Start(*rawConfig)
if err != nil {
return err
}
err = corePtr.Start(rawConfig)
if err != nil { if err != nil {
logger.Error("start sing-box err:", err.Error()) logger.Error("start sing-box err:", err.Error())
return err return err
@@ -103,15 +103,34 @@ func (s *ConfigService) RestartCore() error {
if err != nil { if err != nil {
return err return err
} }
return s.StartCore("") return s.StartCore()
} }
func (s *ConfigService) restartCoreWithConfig(config json.RawMessage) error { func (s *ConfigService) restartCoreWithConfig(config json.RawMessage) error {
err := s.StopCore() var err error
defer func() {
if err != nil {
corePtr.Stop()
logger.Error("restart sing-box err:", err.Error())
} else {
logger.Info("sing-box restarted with new config")
}
}()
if corePtr.IsRunning() {
err = corePtr.GetInstance().Close()
if err != nil { if err != nil {
return err return err
} }
return s.StartCore(string(config)) }
rawConfig, err := s.GetConfig(string(config))
if err != nil {
return err
}
err = corePtr.Start(*rawConfig)
if err != nil {
return err
}
return nil
} }
func (s *ConfigService) StopCore() error { func (s *ConfigService) StopCore() error {
@@ -144,7 +163,7 @@ func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initU
tx.Commit() tx.Commit()
// Try to start core if it is not running // Try to start core if it is not running
if !corePtr.IsRunning() { if !corePtr.IsRunning() {
s.StartCore("") s.StartCore()
} }
} else { } else {
tx.Rollback() tx.Rollback()
+2
View File
@@ -3,6 +3,8 @@ setlocal enabledelayedexpansion
echo Building S-UI for Windows... echo Building S-UI for Windows...
cd /d "%~dp0"
REM Check if Go is installed REM Check if Go is installed
go version >nul 2>&1 go version >nul 2>&1
if errorlevel 1 ( if errorlevel 1 (
+1
View File
@@ -14,6 +14,7 @@ if %errorLevel% neq 0 (
exit /b 1 exit /b 1
) )
cd /d "%~dp0"
REM Set installation directory REM Set installation directory
set "INSTALL_DIR=C:\Program Files\s-ui" set "INSTALL_DIR=C:\Program Files\s-ui"
set "SERVICE_NAME=s-ui" set "SERVICE_NAME=s-ui"
+1
View File
@@ -4,6 +4,7 @@ setlocal enabledelayedexpansion
REM S-UI Windows Control Script REM S-UI Windows Control Script
REM This script provides a menu-driven interface for managing S-UI on Windows REM This script provides a menu-driven interface for managing S-UI on Windows
cd /d "%~dp0"
set "SERVICE_NAME=s-ui" set "SERVICE_NAME=s-ui"
set "INSTALL_DIR=%SUI_HOME%" set "INSTALL_DIR=%SUI_HOME%"
if "%INSTALL_DIR%"=="" set "INSTALL_DIR=C:\Program Files\s-ui" if "%INSTALL_DIR%"=="" set "INSTALL_DIR=C:\Program Files\s-ui"