package service import ( "encoding/base64" "os" "runtime" "s-ui/config" "s-ui/logger" "strconv" "strings" "time" "github.com/sagernet/sing-box/common/tls" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v3/net" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) type ServerService struct{} func (s *ServerService) GetStatus(request string) *map[string]interface{} { status := make(map[string]interface{}, 0) requests := strings.Split(request, ",") for _, req := range requests { switch req { case "cpu": status["cpu"] = s.GetCpuPercent() case "mem": status["mem"] = s.GetMemInfo() case "net": status["net"] = s.GetNetInfo() case "sys": status["uptime"] = s.GetUptime() status["sys"] = s.GetSystemInfo() case "sbd": status["sbd"] = s.GetSingboxInfo() } } return &status } func (s *ServerService) GetCpuPercent() float64 { percents, err := cpu.Percent(0, false) if err != nil { logger.Warning("get cpu percent failed:", err) return 0 } else { return percents[0] } } func (s *ServerService) GetUptime() uint64 { upTime, err := host.Uptime() if err != nil { logger.Warning("get uptime failed:", err) return 0 } else { return upTime } } func (s *ServerService) GetMemInfo() map[string]interface{} { info := make(map[string]interface{}, 0) memInfo, err := mem.VirtualMemory() if err != nil { logger.Warning("get virtual memory failed:", err) } else { info["current"] = memInfo.Used info["total"] = memInfo.Total } return info } func (s *ServerService) GetNetInfo() map[string]interface{} { info := make(map[string]interface{}, 0) ioStats, err := net.IOCounters(false) if err != nil { logger.Warning("get io counters failed:", err) } else if len(ioStats) > 0 { ioStat := ioStats[0] info["sent"] = ioStat.BytesSent info["recv"] = ioStat.BytesRecv info["psent"] = ioStat.PacketsSent info["precv"] = ioStat.PacketsRecv } else { logger.Warning("can not find io counters") } return info } func (s *ServerService) GetSingboxInfo() map[string]interface{} { var rtm runtime.MemStats runtime.ReadMemStats(&rtm) isRunning := corePtr.IsRunning() uptime := uint32(0) if isRunning { uptime = corePtr.GetInstance().Uptime() } return map[string]interface{}{ "running": isRunning, "stats": map[string]interface{}{ "NumGoroutine": uint32(runtime.NumGoroutine()), "Alloc": rtm.Alloc, "Uptime": uptime, }, } } func (s *ServerService) GetSystemInfo() map[string]interface{} { info := make(map[string]interface{}, 0) var rtm runtime.MemStats runtime.ReadMemStats(&rtm) info["appMem"] = rtm.Sys info["appThreads"] = uint32(runtime.NumGoroutine()) cpuInfo, err := cpu.Info() if err == nil { info["cpuType"] = cpuInfo[0].ModelName } info["cpuCount"] = runtime.NumCPU() info["hostName"], _ = os.Hostname() info["appVersion"] = config.GetVersion() ipv4 := make([]string, 0) ipv6 := make([]string, 0) // get ip address netInterfaces, _ := net.Interfaces() for i := 0; i < len(netInterfaces); i++ { if len(netInterfaces[i].Flags) > 2 && netInterfaces[i].Flags[0] == "up" && netInterfaces[i].Flags[1] != "loopback" { addrs := netInterfaces[i].Addrs for _, address := range addrs { if strings.Contains(address.Addr, ".") { ipv4 = append(ipv4, address.Addr) } else if address.Addr[0:6] != "fe80::" { ipv6 = append(ipv6, address.Addr) } } } } info["ipv4"] = ipv4 info["ipv6"] = ipv6 return info } func (s *ServerService) GetLogs(count string, level string) []string { c, _ := strconv.Atoi(count) return logger.GetLogs(c, level) } func (s *ServerService) GenKeypair(keyType string, options string) []string { if len(keyType) == 0 { return []string{"No keypair to generate"} } switch keyType { case "ech": return s.generateECHKeyPair(options) case "tls": return s.generateTLSKeyPair(options) case "reality": return s.generateRealityKeyPair() case "wireguard": return generateWireGuardKey() } return []string{"Failed to generate keypair"} } func (s *ServerService) generateECHKeyPair(options string) []string { parts := strings.Split(options, ",") configPem, keyPem, err := tls.ECHKeygenDefault(parts[0], parts[1] == "true") if err != nil { return []string{"Failed to generate ECH keypair: ", err.Error()} } return append(strings.Split(configPem, "\n"), strings.Split(keyPem, "\n")...) } func (s *ServerService) generateTLSKeyPair(serverName string) []string { privateKeyPem, publicKeyPem, err := tls.GenerateKeyPair(time.Now, serverName, time.Now().AddDate(0, 12, 0)) if err != nil { return []string{"Failed to generate TLS keypair: ", err.Error()} } return append(strings.Split(string(privateKeyPem), "\n"), strings.Split(string(publicKeyPem), "\n")...) } func (s *ServerService) generateRealityKeyPair() []string { privateKey, err := wgtypes.GeneratePrivateKey() if err != nil { return []string{"Failed to generate Reality keypair: ", err.Error()} } publicKey := privateKey.PublicKey() return []string{"PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]), "PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:])} } func generateWireGuardKey() []string { privateKey, err := wgtypes.GeneratePrivateKey() if err != nil { return []string{"Failed to generate wireguard keypair: ", err.Error()} } return []string{"PrivateKey: " + privateKey.String(), "PublicKey: " + privateKey.PublicKey().String()} }