mirror of https://github.com/allinssl/allinssl
441 lines
9.3 KiB
Go
441 lines
9.3 KiB
Go
package main
|
|
|
|
import (
|
|
_ "ALLinSSL/backend/migrations"
|
|
"ALLinSSL/backend/public"
|
|
"ALLinSSL/backend/scheduler"
|
|
"ALLinSSL/backend/server"
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/joho/godotenv"
|
|
ps "github.com/mitchellh/go-ps"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"runtime"
|
|
"strconv"
|
|
"syscall"
|
|
)
|
|
|
|
var s = &scheduler.Scheduler{}
|
|
var pidPath = "data/pid"
|
|
var envPath = "data/.env"
|
|
|
|
var envVars = map[string]string{
|
|
"web": "start",
|
|
"scheduler": "start",
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Println(`请不要直接运行本程序`)
|
|
// start()
|
|
return
|
|
}
|
|
env, err := godotenv.Read(envPath)
|
|
if err == nil {
|
|
envVars = env
|
|
}
|
|
|
|
cmd := os.Args[1]
|
|
switch cmd {
|
|
case "start":
|
|
mainRun()
|
|
case "1":
|
|
fmt.Println("Starting ALLinSSL...")
|
|
if checkRun() {
|
|
_ = exec.Command("/bin/bash", "-c", fmt.Sprintf("nohup %s start > /dev/null 2>&1 &", os.Args[0])).Run()
|
|
fmt.Println("Started ALLinSSL")
|
|
return
|
|
}
|
|
fmt.Println("ALLinSSL is already running")
|
|
case "2":
|
|
fmt.Println("Stopping ALLinSSL...")
|
|
pid, err := os.ReadFile(pidPath)
|
|
if err != nil {
|
|
fmt.Println("Error reading pid file")
|
|
return
|
|
}
|
|
exec.Command("kill", "-9", string(pid)).Run()
|
|
os.Remove(pidPath)
|
|
fmt.Println("Stopped ALLinSSL")
|
|
case "3":
|
|
fmt.Println("Restarting ALLinSSL...")
|
|
pid, err := os.ReadFile(pidPath)
|
|
if err != nil {
|
|
fmt.Println("Error reading pid file")
|
|
}
|
|
exec.Command("kill", "-9", string(pid)).Run()
|
|
os.Remove(pidPath)
|
|
exec.Command("/bin/bash", "-c", fmt.Sprintf("nohup %s start > /dev/null 2>&1 &", os.Args[0])).Run()
|
|
fmt.Println("Restarted ALLinSSL")
|
|
case "4":
|
|
var secure string
|
|
if len(os.Args) > 2 {
|
|
secure = os.Args[2]
|
|
} else {
|
|
fmt.Print("请输入安全入口: ")
|
|
fmt.Scanln(&secure)
|
|
}
|
|
if len(secure) < 5 {
|
|
fmt.Println("安全入口至少需要5位")
|
|
return
|
|
}
|
|
if secure[0] != '/' {
|
|
secure = "/" + secure
|
|
}
|
|
if secure == "/login" {
|
|
fmt.Println("安全入口不能是/login")
|
|
return
|
|
}
|
|
err := public.UpdateSetting("secure", secure)
|
|
if err != nil {
|
|
fmt.Println("Error updating setting:", err)
|
|
return
|
|
}
|
|
envVars["web"] = "restart"
|
|
err = control()
|
|
fmt.Println("安全入口设置成功:", secure)
|
|
case "5":
|
|
var input string
|
|
if len(os.Args) > 2 {
|
|
input = os.Args[2]
|
|
} else {
|
|
fmt.Print("请输入用户名: ")
|
|
fmt.Scanln(&input)
|
|
}
|
|
if len(input) < 5 {
|
|
fmt.Println("用户名至少需要5位")
|
|
return
|
|
}
|
|
s, err := public.NewSqlite("data/data.db", "")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
defer s.Close()
|
|
s.TableName = "users"
|
|
_, err = s.Where("id=1", []interface{}{}).Update(map[string]interface{}{"username": input})
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
envVars["web"] = "restart"
|
|
err = control()
|
|
fmt.Println("用户名设置成功:", input)
|
|
case "6":
|
|
var input string
|
|
if len(os.Args) > 2 {
|
|
input = os.Args[2]
|
|
} else {
|
|
fmt.Print("请输入密码: ")
|
|
fmt.Scanln(&input)
|
|
}
|
|
if len(input) < 8 {
|
|
fmt.Println("密码至少需要8位")
|
|
return
|
|
}
|
|
s, err := public.NewSqlite("data/data.db", "")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
defer s.Close()
|
|
s.TableName = "users"
|
|
user, err := s.Where("id=1", []interface{}{}).Select()
|
|
if err != nil {
|
|
fmt.Println("Error selecting user:", err)
|
|
return
|
|
}
|
|
if len(user) == 0 {
|
|
fmt.Println("No user")
|
|
return
|
|
}
|
|
salt := user[0]["salt"].(string)
|
|
passwd := input + "_bt_all_in_ssl"
|
|
keyMd5 := md5.Sum([]byte(passwd))
|
|
passwdMd5 := hex.EncodeToString(keyMd5[:])
|
|
passwdMd5 += salt
|
|
keyMd5 = md5.Sum([]byte(passwdMd5))
|
|
passwdMd5 = hex.EncodeToString(keyMd5[:])
|
|
|
|
_, err = s.Where("id=1", []interface{}{}).Update(map[string]interface{}{"password": passwdMd5})
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
envVars["web"] = "restart"
|
|
err = control()
|
|
fmt.Println("密码设置成功:", input)
|
|
case "7":
|
|
var input string
|
|
if len(os.Args) > 2 {
|
|
input = os.Args[2]
|
|
} else {
|
|
fmt.Print("请输入端口号: ")
|
|
fmt.Scanln(&input)
|
|
}
|
|
port, err := strconv.Atoi(input) // 转换成整数
|
|
if err != nil {
|
|
fmt.Println("端口号必须是数字!")
|
|
return
|
|
}
|
|
if port < 1 || port > 65535 {
|
|
fmt.Println("端口号必须在 1 到 65535 之间!")
|
|
return
|
|
}
|
|
err = public.UpdateSetting("port", input)
|
|
if err != nil {
|
|
fmt.Println("Error updating setting:", err)
|
|
return
|
|
}
|
|
fmt.Println("端口号设置成功:", input)
|
|
envVars["web"] = "restart"
|
|
control()
|
|
case "8":
|
|
envVars["web"] = "stop"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("web服务已停止")
|
|
case "9":
|
|
envVars["web"] = "start"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("web服务已启动")
|
|
case "10":
|
|
envVars["web"] = "restart"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("已重启web服务")
|
|
case "11":
|
|
envVars["scheduler"] = "stop"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("后台调度服务已停止")
|
|
case "12":
|
|
envVars["scheduler"] = "start"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("后台调度服务已开启")
|
|
|
|
case "13":
|
|
envVars["scheduler"] = "restart"
|
|
if control() != nil {
|
|
return
|
|
}
|
|
fmt.Println("已重启后台调度服务")
|
|
|
|
case "14":
|
|
err := public.UpdateSetting("https", "0")
|
|
if err != nil {
|
|
fmt.Println("Error updating setting:", err)
|
|
return
|
|
}
|
|
envVars["web"] = "restart"
|
|
control()
|
|
case "15":
|
|
public.ReloadConfig()
|
|
http := "http"
|
|
if public.GetSettingIgnoreError("https") == "1" {
|
|
http = "https"
|
|
}
|
|
|
|
localIp, err := public.GetLocalIP()
|
|
if err != nil {
|
|
localIp = "0.0.0.0"
|
|
}
|
|
localAddr := fmt.Sprintf("%s://%s:%s%s", http, localIp, public.Port, public.Secure)
|
|
publicIp, err := public.GetPublicIP()
|
|
if err != nil {
|
|
publicIp = "0.0.0.0"
|
|
}
|
|
publicAddr := fmt.Sprintf("%s://%s:%s%s", http, publicIp, public.Port, public.Secure)
|
|
|
|
s, err := public.NewSqlite("data/data.db", "")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
defer s.Close()
|
|
s.TableName = "users"
|
|
user, err := s.Where("id=1", []interface{}{}).Select()
|
|
if err != nil {
|
|
fmt.Println("Error selecting user:", err)
|
|
return
|
|
}
|
|
if len(user) == 0 {
|
|
fmt.Println("No user")
|
|
return
|
|
}
|
|
username, ok := user[0]["username"].(string)
|
|
if !ok {
|
|
fmt.Println("Error getting username")
|
|
return
|
|
}
|
|
|
|
fmt.Printf(`
|
|
外网面板地址: %s
|
|
内网面板地址: %s
|
|
用户名: %s
|
|
密码: ********
|
|
`,
|
|
publicAddr, localAddr, username)
|
|
default:
|
|
fmt.Println("无效的命令")
|
|
}
|
|
}
|
|
|
|
func control() (err error) {
|
|
pidStr, err := os.ReadFile(pidPath)
|
|
if err != nil {
|
|
fmt.Println("Error reading pid file")
|
|
return
|
|
}
|
|
err = godotenv.Write(envVars, envPath)
|
|
if err != nil {
|
|
fmt.Println("Error writing to .env file")
|
|
return
|
|
}
|
|
pid, err := strconv.Atoi(string(pidStr))
|
|
if err != nil {
|
|
fmt.Println("Error converting pid to int:", err)
|
|
return
|
|
}
|
|
process, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
fmt.Println("Error finding process:", err)
|
|
return
|
|
}
|
|
err = process.Signal(syscall.SIGHUP)
|
|
if err != nil {
|
|
fmt.Println("Error sending signal:", err)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func mainRun() {
|
|
if checkRun() {
|
|
pid := os.Getpid()
|
|
os.WriteFile(pidPath, []byte(fmt.Sprintf("%d", pid)), 0644)
|
|
defer os.Remove(pidPath)
|
|
go func() {
|
|
fmt.Println("web服务正在运行...")
|
|
err := server.Run()
|
|
if err != nil {
|
|
fmt.Println("web服务在运行时遇到错误:", err)
|
|
}
|
|
fmt.Println("web服务已停止")
|
|
}()
|
|
fmt.Println("正在启动调度器...")
|
|
go s.Start()
|
|
fmt.Println("调度器启动成功")
|
|
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, syscall.SIGHUP)
|
|
for {
|
|
<-c
|
|
run()
|
|
}
|
|
} else {
|
|
fmt.Println("服务已经启动")
|
|
}
|
|
}
|
|
|
|
func checkRun() bool {
|
|
_, err := os.Stat(pidPath)
|
|
if err != nil {
|
|
return true
|
|
}
|
|
pid, err := os.ReadFile(pidPath)
|
|
if err != nil {
|
|
os.Remove(pidPath)
|
|
return true
|
|
}
|
|
pidInt, err := strconv.Atoi(string(pid))
|
|
if err != nil {
|
|
fmt.Println("Error converting pid to int")
|
|
os.Remove(pidPath)
|
|
return true
|
|
}
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
return isProcessAliveWindows(pidInt)
|
|
default:
|
|
return isProcessAliveUnix(pidInt)
|
|
}
|
|
}
|
|
|
|
// Unix/Linux/macOS 检测
|
|
func isProcessAliveUnix(pid int) bool {
|
|
proc, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
return true
|
|
}
|
|
// 发送 0 信号,不会杀死,只是检测
|
|
err = proc.Signal(syscall.Signal(0))
|
|
return err != nil
|
|
}
|
|
|
|
// Windows 检测(遍历进程表)
|
|
func isProcessAliveWindows(pid int) bool {
|
|
processList, err := ps.Processes()
|
|
if err != nil {
|
|
return true
|
|
}
|
|
for _, p := range processList {
|
|
if p.Pid() == pid {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func run() {
|
|
envVars, err := godotenv.Read(envPath)
|
|
if err != nil {
|
|
fmt.Println("Error reading .env file")
|
|
}
|
|
switch envVars["web"] {
|
|
case "start":
|
|
go func() {
|
|
fmt.Println("web服务正在运行...")
|
|
err := server.Run()
|
|
if err != nil {
|
|
fmt.Println("web服务在运行时遇到错误:", err)
|
|
return
|
|
// errchan <- err
|
|
}
|
|
fmt.Println("web服务已停止")
|
|
}()
|
|
case "stop":
|
|
public.ShutdownFunc()
|
|
fmt.Println("web服务已停止")
|
|
case "restart":
|
|
public.ShutdownFunc()
|
|
go func() {
|
|
fmt.Println("web服务正在运行...")
|
|
err := server.Run()
|
|
if err != nil {
|
|
fmt.Println("web服务在运行时遇到错误:", err)
|
|
return
|
|
}
|
|
fmt.Println("web服务已停止")
|
|
}()
|
|
}
|
|
switch envVars["scheduler"] {
|
|
case "start":
|
|
go s.Start()
|
|
case "stop":
|
|
s.Stop()
|
|
case "restart":
|
|
s.Restart()
|
|
}
|
|
}
|