Просмотр исходного кода

1,编写app-install.service服务代码;2,调整page6页面显示

niujiuru 1 неделя назад
Родитель
Сommit
137db5aa1a

+ 171 - 0
app-install.service/main.go

@@ -1 +1,172 @@
 package main
+
+import (
+	"context"
+	"errors"
+	"flag"
+	"fmt"
+	"net/http"
+	"os"
+	"rtu_linux_services/servicelib"
+	"time"
+
+	"github.com/kardianos/service"
+	"hnyfkj.com.cn/rtu/linux/baseapp"
+	"hnyfkj.com.cn/rtu/linux/utils/jsonrpc2"
+)
+
+var (
+	Version   = "0.0.0.1"
+	BuildTime = ""
+)
+
+const (
+	network    = "tcp" // http -> tcp
+	listenAddr = "127.0.0.1:7004"
+)
+
+type program struct {
+	name        string
+	core_server *jsonrpc2.RPCServer
+	http_server *http.Server
+}
+
+// Start should not block. Do the actual work async.
+func (p *program) Start(s service.Service) error {
+	logCfgFile, err := servicelib.EnsureDefaultLogConfig()
+	if err != nil {
+		return err
+	}
+
+	baseapp.InitLogger(logCfgFile)
+	baseapp.Logger.Infof("[%s] 开始运行, 程序版本: %s, 构建时间: %s", p.name, Version, BuildTime)
+
+	p.core_server, err = jsonrpc2.NewRPCServer(p.name, baseapp.Logger)
+	if err != nil {
+		return err
+	}
+
+	methods := make(jsonrpc2.MethodMap)
+
+	//////////////////////////////////////////////////////////
+	_getBuildVer := servicelib.MakeGetBuildVer(
+		Version, BuildTime)
+	methods["basic.getBuildVer"] = _getBuildVer // 获取软件版本
+	_getLogLevel := servicelib.GetLogLevel
+	methods["basic.getLogLevel"] = _getLogLevel // 获取日志级别
+	_setLogLevel := servicelib.SetLogLevel
+	methods["basic.setLogLevel"] = _setLogLevel // 设置日志级别
+	_saveLogConf := servicelib.SaveLogConf
+	methods["basic.saveLogConf"] = _saveLogConf // 保存日志设置
+	//////////////////////////////////////////////////////////
+	methods["core.package.import"] = pkgImport ///// 导入安装包
+	methods["core.package.remove"] = pkgRemove ///// 删除安装包
+	//////////////////////////////////////////////////////////
+	methods["core.app.install"] = appInstall     //安装用户应用
+	methods["core.app.uninstall"] = appUninstall //卸载当前应用
+	//////////////////////////////////////////////////////////
+	methods["core.getInstallInfo"] = getInstallInfo // 安装信息
+
+	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:    listenAddr,
+		Handler: mux,
+	}
+
+	go p.run()
+
+	return nil
+}
+
+// Do work here
+func (p *program) run() {
+	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)
+	}
+
+	baseapp.Logger.Infof("[%s] 程序退出", p.name)
+	baseapp.ExitLogger()
+	return nil
+}
+
+func main() {
+	baseapp.SetOptDirs(true, false, true, false)
+	baseapp.InitPath()
+
+	svcFlag := flag.String("service", "", "Control the yfkj-app-install service.")
+	flag.Parse()
+
+	svcConfig := &service.Config{
+		Name:        "yfkj-app-install",
+		DisplayName: "yfkj-app-install",
+		Description: "Yunfei User Application Installation And Uninstallation",
+		Option: map[string]any{
+			"Restart": "always", // 无条件重启
+		},
+	}
+
+	servicelib.WriteVersionFile(baseapp.EXEC_DIR, Version) //-> for 升级
+
+	prg := &program{
+		name: "AppInstaller",
+	}
+
+	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.IsAddrInUse(network, listenAddr) { // 查询端口占用,避免运行多份实例
+		fmt.Printf(
+			"%s.service start failed: listen addr %s already in use\n",
+			svcConfig.Name, listenAddr,
+		)
+		os.Exit(1)
+	}
+
+	if err := svc.Run(); err != nil {
+		fmt.Printf("%s.service run failed: %v\n",
+			svcConfig.Name, err)
+		os.Exit(1)
+	}
+}

+ 36 - 0
app-install.service/rpc_handler.go

@@ -1 +1,37 @@
 package main
+
+import (
+	"context"
+
+	"hnyfkj.com.cn/rtu/linux/utils/jsonrpc2"
+)
+
+// 导入用户安装包
+func pkgImport(
+	ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response {
+	return nil
+}
+
+// 删除用户安装包
+func pkgRemove(
+	ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response {
+	return nil
+}
+
+// 安装包应用安装
+func appInstall(
+	ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response {
+	return nil
+}
+
+// 卸载已安装应用
+func appUninstall(
+	ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response {
+	return nil
+}
+
+// 安装包应用信息
+func getInstallInfo(
+	ctx context.Context, req *jsonrpc2.Request) *jsonrpc2.Response {
+	return nil
+}

+ 3 - 3
readme.txt

@@ -1,7 +1,7 @@
 # 云飞科技系统服务说明:
---------------------------------------------------------------------
+--------------------------------------------------------------------------
 
-app-install.service         : Install or uninstall applications
+app-install.service         : Application installation and uninstallation
                             : 安装或卸载应用程序
 camera-capture.service      : Camera capture
                             : 相机图像采集
@@ -24,7 +24,7 @@ web-ui.service              : Web user interface
                             : 配置管理界面
 
 # 管理系统服务常用命令:
---------------------------------------------------------------------
+--------------------------------------------------------------------------
 systemctl start   <service> : 启动服务运行
 systemctl stop    <service> : 停止服务运行
 systemctl status  <service> : 查看服务状态

+ 24 - 16
web-ui.service/web/pages/page6.html

@@ -14,13 +14,21 @@
   <main class="view page-userapp">
     <div class="status-bar">
       <div class="status-item">
-        <span class="label">应用管理</span>
+        <span class="label">安装服务</span>
         <span class="value" id="avar1">--</span>
       </div>
       <div class="status-item">
-        <span class="label">用户应用</span>
+        <span class="label">当前已安装的用户应用</span>
         <span class="value" id="avar2">--</span>
       </div>
+      <div class="status-item">
+        <span class="label">用户应用运行状态</span>
+        <span class="value" id="avar3">--</span>
+      </div>
+      <div class="status-item">
+        <span class="label">用户应用进程PID</span>
+        <span class="value" id="avar4">--</span>
+      </div>
     </div>
 
     <div class="panes">
@@ -28,14 +36,12 @@
       <div class="left-pane">
         <div class="card">
           <div class="card-header">
-            <h2>应用管理</h2>
+            <h2>包管理器</h2>
             <div class="log-actions">
               <input type="file" id="userAppFile" style="display:none" accept=".tar.gz" onchange="uploadUserAppFile(this)">
-              <button class="btn" id="btn1" title="上传用户应用" onclick="onBtn1Click()">上传</button>
+              <button class="btn" id="btn1" title="上传用户应用安装包" onclick="onBtn1Click()">上传</button>
               <span style="margin:0 1px;"></span>
-              <button class="btn" id="btn2" title="安装用户应用" onclick="onBtn2Click()">安装</button>
-              <span style="margin:0 1px;"></span>
-              <button class="btn" id="btn3" title="卸载用户应用" onclick="onBtn3Click()">卸载</button>
+              <button class="btn" id="btn2" title="删除当前已上传的用户应用安装包" onclick="onBtn2Click()">移除</button>
             </div>
           </div>
           <div class="card-body">
@@ -48,11 +54,11 @@
               <span class="value" id="bvar2">--</span>
             </div>
             <div class="app-info">
-              <span class="label">上传时间:</span>
+              <span class="label">文件哈希:</span>
               <span class="value" id="bvar3">--</span>
             </div>
             <div class="app-info">
-              <span class="label">安装时间:</span>
+              <span class="label">上传时间:</span>
               <span class="value" id="bvar4">--</span>
             </div>
           </div>
@@ -61,11 +67,9 @@
           <div class="card-header">
             <h2>用户应用</h2>
             <div class="log-actions">
-              <button class="btn" id="btn4" title="启动用户应用" onclick="onBtn4Click()">启动</button>
-              <span style="margin:0 1px;"></span>
-              <button class="btn" id="btn5" title="停止用户应用" onclick="onBtn5Click()">停止</button>
+              <button class="btn" id="btn4" title="使用当前安装包安装用户应用,安装完成后自动启动,并设置为开机自启动" onclick="onBtn3Click()">安装</button>
               <span style="margin:0 1px;"></span>
-              <button class="btn" id="btn6" title="重启用户应用" onclick="onBtn6Click()">重启</button>
+              <button class="btn" id="btn5" title="卸载当前已安装的用户应用程序" onclick="onBtn4Click()">卸载</button>
             </div>
           </div>
           <div class="card-body">
@@ -78,12 +82,16 @@
               <span class="value" id="cvar2">--</span>
             </div>
             <div class="app-info">
-              <span class="label">运行状态:</span>
+              <span class="label">启动文件:</span>
               <span class="value" id="cvar3">--</span>
             </div>
+            <div class="app-info">
+              <span class="label">安装时间:</span>
+              <span class="value" id="cvar4">--</span>
+            </div>
             <div class="app-info app-desc">
               <span class="label">应用描述:</span>
-              <span class="value" id="cvar4">--</span>
+              <span class="value" id="cvar5">--</span>
             </div>
           </div>
         </div>
@@ -92,7 +100,7 @@
       <div class="right-pane">
         <div class="card log-card">
           <div class="card-header">
-            <h2>应用管理</h2>
+            <h2>安装服务</h2>
             <div class="log-actions">
               <select class="log-level-select" id="logLevel" title="当前服务日志级别" onchange="setAppInstallLogLevel()">
                 <option value="trace">trace</option>

+ 15 - 0
web-ui.service/web/static/css/page6.css

@@ -15,12 +15,14 @@
   border: 1px solid rgba(148,163,184,0.15);
   border-radius: 4px;
   flex-shrink: 0;
+  overflow: hidden;
 }
 
 .status-item {
   display: flex;
   flex-direction: column;
   gap: 4px;
+  min-width: 0;
 }
 
 .status-item .label {
@@ -30,6 +32,19 @@
 .status-item .value {
   font-size: 14px;
   font-family: ui-monospace, Consolas, monospace;
+
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.status-item:nth-child(2) {
+  flex: 0 0 150px;
+}
+
+.status-item:nth-child(3),
+.status-item:nth-child(4) {
+  flex: 0 0 120px;
 }
 
 /* 左右拆分的栏 */