package main import ( "context" "encoding/json" "errors" "flag" "fmt" "net/http" "os" "strconv" "time" "rtu_linux_services/servicelib" "github.com/kardianos/service" "hnyfkj.com.cn/rtu/linux/baseapp" "hnyfkj.com.cn/rtu/linux/netmgrd" "hnyfkj.com.cn/rtu/linux/utils/jsonrpc2" ) var ( Version = "0.0.0.1" BuildTime = "" ListenPort = "7000" ) type program struct { name string core_server *jsonrpc2.RPCServer http_server *http.Server done chan struct{} } // Start should not block. Do the actual work async. func (p *program) Start(s service.Service) error { baseapp.InitPath() logCfgFile, err := servicelib.EnsureDefaultLogConfig() if err != nil { return err } baseapp.InitLogger(logCfgFile) baseapp.Logger.Infof("App Version: %s, Build Time: %s", Version, BuildTime) if !netmgrd.ModemInit() { return errors.New("modem init failed") } netmgrd.SetTimeSyncEnabled(false) // 关闭时间同步, 由"timesyncd.service"完成 netmgrd.ModuleInit() p.core_server, err = jsonrpc2.NewRPCServer(p.name, baseapp.Logger) if err != nil { return err } methods := make(jsonrpc2.MethodMap) //////////////////////////////////////////////////////////// methods["basic.getBuildVer"] = p.getBuildVer /// 获取软件版本 methods["basic.getLogLevel"] = p.getLogLevel /// 获取日志级别 methods["basic.setLogLevel"] = p.setLogLevel /// 设置日志级别 methods["basic.saveLogConf"] = p.saveLogConf /// 保存日志设置 //////////////////////////////////////////////////////////// methods["core.getModemInfo"] = p.getModemInfo // IMEI、ICCID methods["core.getNetStatus"] = p.getNetStatus // 联网状态信息 //////////////////////////////////////////////////////////// err = p.core_server.RegisterMethods(methods) if err != nil { return err } mux := http.NewServeMux() mux.Handle("/rpc", p.core_server) p.http_server = &http.Server{ Addr: "127.0.0.1:" + ListenPort, Handler: mux, } p.done = make(chan struct{}) go p.run() return nil } // Do work here func (p *program) run() { defer close(p.done) baseapp.Logger.Infof( "[%s] http server starting on %s...", p.name, p.http_server.Addr, ) err := p.http_server.ListenAndServe() // 同步阻塞 if err != nil && !errors.Is(err, http.ErrServerClosed) { baseapp.Logger.Errorf("[%s] start http server error: %v", p.name, err) return } } // Stop should not block. Return with a few seconds. func (p *program) Stop(s service.Service) error { if p.core_server != nil { p.core_server.Stop() } if p.http_server != nil { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _ = p.http_server.Shutdown(ctx) } if p.done != nil { <-p.done } netmgrd.ModemExit() baseapp.ExitLogger() return nil } func (p *program) getBuildVer(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { result := map[string]string{ "version": Version, "build_time": BuildTime, } return jsonrpc2.BuildResponse(req, result, nil) } func (p *program) getLogLevel(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { level, _ := baseapp.GetLogLevel() result := map[string]string{ "log_level": level, } return jsonrpc2.BuildResponse(req, result, nil) } func (p *program) setLogLevel(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { var params map[string]string if err := json.Unmarshal(req.Params, ¶ms); err != nil { return jsonrpc2.BuildError(req, jsonrpc2.ErrInvalidParams, err.Error()) } level, ok := params["log_level"] if !ok || level == "" { return jsonrpc2.BuildError(req, jsonrpc2.ErrInvalidParams, "missing or empty 'log_level' parameter") } err := baseapp.UpdateLogLevel(level) if err != nil { return jsonrpc2.BuildError(req, jsonrpc2.ErrInternal, err.Error()) } return jsonrpc2.BuildResponse(req, "success", nil) } func (p *program) saveLogConf(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { err := baseapp.SaveLogConfig() if err != nil { return jsonrpc2.BuildError(req, jsonrpc2.ErrInternal, err.Error()) } return jsonrpc2.BuildResponse(req, "success", nil) } func (p *program) getModemInfo(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { result := map[string]string{ "imei": netmgrd.GetIMEI(), "iccid": netmgrd.GetSimICCID(), "rssi": netmgrd.GetRSSI(), } return jsonrpc2.BuildResponse(req, result, nil) } func (p *program) getNetStatus(ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response { result := map[string]string{ "net_available": strconv.FormatBool(netmgrd.IsInetAvailable()), "net_type": netmgrd.GetCurrentNetType().String(), } return jsonrpc2.BuildResponse(req, result, nil) } func main() { svcFlag := flag.String("service", "", "Control the system service.") flag.Parse() svcConfig := &service.Config{ Name: "yfkj-networkd", DisplayName: "yfkj-networkd", Description: "Network connectivity management", Option: map[string]any{ "Restart": "always", // 无条件重启 }, } prg := &program{ name: "NetworkManager", } svc, err := service.New(prg, svcConfig) if err != nil { fmt.Printf("%s.service creation failed: %v\n", svcConfig.Name, err) os.Exit(1) } if len(*svcFlag) != 0 { err := service.Control(svc, *svcFlag) if err != nil { fmt.Printf("%v\n Valid actions: %q\n", err, service.ControlAction) } os.Exit(0) } if servicelib.IsPortInUse(ListenPort) { // 查询端口占用,避免运行多份实例 fmt.Printf( "%s.service start failed: listen port %s already in use\n", svcConfig.Name, ListenPort, ) os.Exit(1) } if err := svc.Run(); err != nil { fmt.Printf("%s.service run failed: %v\n", svcConfig.Name, err) os.Exit(1) } }