lx-source/main.go
2024-05-01 04:10:23 +08:00

157 lines
4.8 KiB
Go

package main
import (
"context"
"flag"
"io/fs"
"lx-source/src/env"
"lx-source/src/server"
"net/http"
"os"
"os/signal"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
"github.com/ZxwyWebSite/ztool"
"github.com/ZxwyWebSite/ztool/logs"
"github.com/gin-gonic/gin"
)
// 初始化
func init() {
ztool.Cmd_FastPrint(ztool.Str_FastConcat(`
__ __ __ ______ ______ __ __ ____ ______ ______
/ / / / / / / ____/ / __ / / / / / / __ \ / ____/ / ____/
/ / / /_/ / __ / /___ / / / / / / / / / /_/ / / / / /___
/ / \_\ \ /_/ /___ / / / / / / / / / / ___/ / / / ____/
/ /___ / / / / ____/ / / /_/ / / /_/ / / / \ / /___ / /___
/_____/ /_/ /_/ /_____/ /_____/ /_____/ /_/ \_\ /_____/ /_____/
=======================================================================
Version: `, env.Version, ` Github: https://github.com/ZxwyWebSite/lx-source
`, "\n"))
env.RunPath, _ = os.Getwd()
var confPath string
flag.StringVar(&confPath, `c`, ztool.Str_FastConcat(env.RunPath, `/data/conf.ini`), `指定配置文件路径`)
etag := flag.String(`e`, ``, `扩展启动参数`)
perm := flag.Uint(`p`, 0, `自定义文件权限(8进制前面加0)`)
flag.Parse()
if perm != nil && *perm != 0 {
ztool.Fbj_DefPerm = fs.FileMode(*perm)
fp := env.Loger.NewGroup(`FilePerm`)
// if ztool.Fbj_DefPerm > 777 {
// fp.Fatal(`请在实际权限前面加0`)
// }
fp.Info(`设置默认文件权限为 %o (%v)`, *perm, ztool.Fbj_DefPerm).Free()
}
env.Cfg.MustInit(confPath)
parseEtag(etag)
// fmt.Printf("%+v\n", env.Config)
env.Loger.NewGroup(`ServHello`).Info(`欢迎使用 LX-SOURCE 洛雪音乐自定义源`).Free()
if !env.Config.Main.Debug {
gin.SetMode(gin.ReleaseMode)
} else {
logs.Levell = logs.LevelDebu // logs.Level = 3
env.Loger.NewGroup(`DebugMode`).Debug(`已开启调试模式, 将输出更详细日志 (配置文件中 [Main].Debug 改为 false 关闭)`).Free()
}
genAuth()
if env.Config.Main.SysLev {
sl := env.Loger.NewGroup(`(beta)SysLev`)
if err := ztool.Sys_SetPriorityLev(ztool.Sys_GetPid(), ztool.Sys_PriorityHighest); err != nil {
sl.Error(`系统优先级设置失败: %v`, err)
} else {
sl.Warn(`成功设置较高优先级,此功能可能导致系统不稳定`)
}
sl.Free()
}
if env.Config.Main.Timeout != env.DefCfg.Main.Timeout {
ztool.Net_client.Timeout = time.Second * time.Duration(env.Config.Main.Timeout) // 自定义请求超时
env.Loger.NewGroup(`InitNet`).Info(`请求超时已设为 %s`, ztool.Net_client.Timeout).Free()
}
}
func main() {
defer env.Defer.Do()
// 初始化基础功能
initMain()
// 载入必要模块
env.Inits.Do()
env.Loger.NewGroup(`ServInit`).Info(`服务端启动, 监听地址 %s`, strings.Join(env.Config.Main.Listen, `|`)).Free()
loadFileLoger()
env.Defer.Add(env.Tasker.Run(env.Loger)) // wait
// 启动Http服务
listenAndServe(server.InitRouter(), env.Config.Main.Listen)
}
// 监听多端口
func listenAndServe(handler http.Handler, addrs []string) {
// 前置检测
length := len(addrs)
ss := env.Loger.NewGroup(`ServStart`)
if length == 0 {
ss.Fatal(`监听地址列表为空`)
}
// ss.Info(`服务端启动,请稍候...`)
srvlist := make(map[int]*http.Server, length) // 伪数组,便于快速删除数据
lock := new(sync.Mutex)
var failnum int32
length32 := int32(length)
// 启动服务
for i := 0; i < length; i++ {
lock.Lock()
srvlist[i] = &http.Server{Addr: addrs[i], Handler: handler}
lock.Unlock()
go func(n int) {
server := srvlist[n]
// ss.Info(`开始监听 %v`, server.Addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
ss.Error(`监听%q失败: %s`, server.Addr, err) // 监听":1011"失败: http: Server closed
fn := atomic.AddInt32(&failnum, 1)
if fn == length32 {
ss.Fatal(`所有地址监听失败,程序被迫退出`)
}
lock.Lock()
delete(srvlist, n)
lock.Unlock()
}
}(i)
}
// time.Sleep(time.Millisecond * 300)
// if len(srvlist) == 0 {
// ss.Fatal(`所有地址监听失败,程序被迫退出`)
// }
// ss.Free()
// 安全退出
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
<-quit
sc := env.Loger.NewGroup(`ServClose`)
sc.Info(`等待结束活动连接...`)
// 停止服务
var unsafenum int32
wg := new(sync.WaitGroup)
for i := range srvlist {
wg.Add(1)
go func(n int) {
server := srvlist[n]
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
if err := server.Shutdown(ctx); err != nil {
sc.Warn(`连接%q未安全退出: %s`, server.Addr, err) // 连接":1011"未安全退出: timeout
atomic.AddInt32(&unsafenum, 1)
}
cancel()
wg.Done()
}(i)
}
wg.Wait()
if unsafenum != 0 {
sc.Warn(`未安全退出 :(`)
} else {
sc.Info(`已安全退出 :)`)
}
}