mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 13:14:11 +00:00
Three Windows-specific issues addressed: 1. Orphaned xray-windows-amd64 after VS Code debugger stop. Delve's "Stop" sends TerminateProcess to the Go binary, which is uncatchable — our signal handlers never run, so xrayService.StopXray() is skipped and xray is left dangling. Spawn xray as a child of a Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE so the OS kills xray when our handle to the job is closed (which happens even on TerminateProcess). Also trap os.Interrupt in main so Ctrl+C in the terminal runs the graceful path. 2. /panel/setting/restartPanel logged "failed to send SIGHUP signal: not supported by windows" because Windows can't deliver arbitrary signals. Add a restart hook in web/global; main registers it to push SIGHUP into its own signal channel, and RestartPanel calls the hook before falling back to the (Unix-only) signal path. Same restart-loop code runs in both cases. 3. util/sys/sys_windows.go now uses windows.NewLazySystemDLL so the kernel32.dll resolve is pinned to %SystemRoot%\System32 (prevents DLL hijacking by a planted DLL next to the binary). Local filetime type replaced with windows.Filetime, and the unreliable syscall.GetLastError() fallback replaced with a type assertion on the errno captured at call time. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
71 lines
1.7 KiB
Go
71 lines
1.7 KiB
Go
// Package global provides global variables and interfaces for accessing web and subscription servers.
|
|
package global
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
_ "unsafe"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
var (
|
|
webServer WebServer
|
|
subServer SubServer
|
|
|
|
restartHookMu sync.RWMutex
|
|
restartHook func()
|
|
)
|
|
|
|
// WebServer interface defines methods for accessing the web server instance.
|
|
type WebServer interface {
|
|
GetCron() *cron.Cron // Get the cron scheduler
|
|
GetCtx() context.Context // Get the server context
|
|
GetWSHub() any // Get the WebSocket hub (using any to avoid circular dependency)
|
|
}
|
|
|
|
// SubServer interface defines methods for accessing the subscription server instance.
|
|
type SubServer interface {
|
|
GetCtx() context.Context // Get the server context
|
|
}
|
|
|
|
// SetWebServer sets the global web server instance.
|
|
func SetWebServer(s WebServer) {
|
|
webServer = s
|
|
}
|
|
|
|
// GetWebServer returns the global web server instance.
|
|
func GetWebServer() WebServer {
|
|
return webServer
|
|
}
|
|
|
|
// SetSubServer sets the global subscription server instance.
|
|
func SetSubServer(s SubServer) {
|
|
subServer = s
|
|
}
|
|
|
|
// GetSubServer returns the global subscription server instance.
|
|
func GetSubServer() SubServer {
|
|
return subServer
|
|
}
|
|
|
|
// SetRestartHook registers a callback that triggers an in-process panel
|
|
// restart. main.go sets this up to push SIGHUP into its own signal channel
|
|
// so the restart path works on Windows (where p.Signal(SIGHUP) is unsupported).
|
|
func SetRestartHook(fn func()) {
|
|
restartHookMu.Lock()
|
|
defer restartHookMu.Unlock()
|
|
restartHook = fn
|
|
}
|
|
|
|
// TriggerRestart fires the registered restart hook. Returns false if none is set.
|
|
func TriggerRestart() bool {
|
|
restartHookMu.RLock()
|
|
fn := restartHook
|
|
restartHookMu.RUnlock()
|
|
if fn == nil {
|
|
return false
|
|
}
|
|
fn()
|
|
return true
|
|
}
|