Browse Source

nats ctrl

qinyan-QPDEn 2 months ago
parent
commit
0973473f3e

+ 2 - 2
package.json

@@ -35,7 +35,7 @@
     "@queenjs-modules/queentree": "^0.0.10",
     "@queenjs-modules/queentree-explorer": "^0.0.6",
     "@queenjs-modules/queentree-explorer-viewer": "^0.0.3",
-    "@queenjs/assets": "^0.0.22",
+    "@queenjs/assets": "^1.0.4",
     "@queenjs/components": "^0.0.23",
     "@queenjs/controllers": "^0.0.8",
     "@queenjs/icons": "^0.0.20",
@@ -68,7 +68,7 @@
     "lodash": "^4.17.21",
     "moment": "^2.29.4",
     "nanoid": "^4.0.2",
-    "nats.ws": "^1.15.0",
+    "nats.ws": "1.18.0",
     "proto.gl": "^1.0.0",
     "qrcode": "^1.5.3",
     "queen3d": "^0.0.80",

+ 38 - 12
src/comm/controllers/appMsgQueen5Ctrl.ts

@@ -1,23 +1,49 @@
-/**
- *
- * 当前应用queen5接受的消息处理。
- *   目前文件依赖 设计为 当前文件 依赖于modules/ediotor/controllers下的文件,这样避免share页面打包
- *   当前模块,导致nats.ws文件被引用,引发 部分手机 share页面打不开的bug
- */
-
 import { CompImageObj } from "@/modules/editor/components/CompUI/basicUI/Image2";
 import { EditorModule } from "@/modules/editor/module";
-import { AppMsgRecvController, AssetTypes } from "@queenjs/assets";
+import { AppMsgRecvController } from "@queenjs/assets";
 import { queenApi } from "queenjs";
+import { useCtx } from "../ctx";
 
 export class AppMsgQueen5Controller extends AppMsgRecvController {
   editorModule?: EditorModule;
+  title = "鲲舞";
+
+  _inited = false;
 
   get editor() {
     //使用的时候确定当前模块内容已经被设定
     return this.editorModule as EditorModule;
   }
 
+  async onReady() {
+    if (this._inited) return;
+    await super.onReady();
+
+    this._inited = true;
+    const { natsCtrl, deviceCtrl } = useCtx();
+    natsCtrl.subscribe("broad.appInsts.get", (data: any) => {
+      console.log("broad.appInsts.get->", typeof data, data);
+      if (data.guid == deviceCtrl.profile.appGuid || this.listeners.length < 1)
+        return;
+
+      const sid = data.sid;
+      const type = data.type;
+      const list = [] as any[];
+      this.listeners.forEach((lis) => {
+        if (lis.type != type) return;
+        list.push({ Id: lis.id, Type: type, Action: lis.actionName });
+      });
+      if (list.length < 1) return;
+
+      const out = {
+        Title: this.title,
+        Guid: deviceCtrl.profile.appGuid,
+        List: list,
+      };
+      natsCtrl.publish(`appInsts.get.${sid}`, JSON.stringify(out));
+    });
+  }
+
   Clear() {
     this.clearListeners();
     this.emitChange();
@@ -33,11 +59,11 @@ export class AppMsgQueen5Controller extends AppMsgRecvController {
     return file.url;
   }
 
-  //重置状态
   initAssetsListeners() {
     this.clearListeners();
+
     this.addImageListener("添加图片", async (data: any) => {
-      const { uri } = data.payload;
+      const { uri } = data.json;
       console.log("添加图片=>", uri);
 
       queenApi.showLoading("添加图片中");
@@ -49,7 +75,7 @@ export class AppMsgQueen5Controller extends AppMsgRecvController {
     });
 
     this.addImageListener("替换当前图片", async (data: any) => {
-      const { uri } = data.payload;
+      const { uri } = data.json;
       console.log("替换当前图片=>", uri);
 
       if (this.editor.controls.selectCtrl.gizmo.selectedIds.length != 1) {
@@ -71,7 +97,7 @@ export class AppMsgQueen5Controller extends AppMsgRecvController {
     });
 
     this.addListener("webpackuri", "添加3D组件", async (data: any) => {
-      const { thumbnail, link } = data.payload;
+      const { thumbnail, link } = data.json;
       // console.log("推送 url", link, thumbnail);
 
       await this.editor.actions.clickCompToDesign("Web3D", (comp) => {

+ 0 - 105
src/comm/controllers/appMsgRecvCtrl.ts

@@ -1,105 +0,0 @@
-/**
- * 负责app之间的消息的接收模块
- */
-import { nanoid } from "nanoid";
-import { Controller } from "../core/controller";
-import { useCtx } from "../ctx";
-
-export type AssetSendedCallback = (assetUri:string)=>Promise<boolean>;
-export type AssetWebpackUriSendedCallback = (uri:string, name:string, thumbnail:string)=>Promise<boolean>;
-
-export type AssetType = "empty" | "image" | "webpackuri"
-const RevcChangeEvent = "app.recv.change"
-class AssetListener {
-    id = "";
-    type = "empty" as AssetType;
-    constructor(public actionName:string, public callback: AssetSendedCallback){
-        this.id = actionName;
-    }
-    
-    toJson() {
-        return {
-            id: this.id,
-            type: this.type,
-            action: this.actionName,
-        }
-    }
-}
-
-
-export class AppMsgRecvController extends Controller {
-
-    listeners = [] as AssetListener[];
-    appGuid = "";
-
-    async onReady() {
-        const {deviceCtrl, natsCtrl} = useCtx();
-
-        this.appGuid = deviceCtrl.profile.appGuid;
-
-        natsCtrl.subscribe(`send.${this.appGuid}`, async (msg:{id:string,fromKey:string, uri:string, name?:string, thumbnail?:string})=>{
-            const listen = this.listeners.find(item=>item.id == msg.id)
-            if (!listen) return {
-                isOk: false,
-                error: "nolistener"
-            }
-            if (listen.type == "image") {
-                const callback = listen.callback as AssetSendedCallback
-                const ok = await callback(msg.uri);
-                return JSON.stringify({ isOk: ok})
-            } 
-            if (listen.type == "webpackuri" ) {
-                const callback = listen.callback as AssetWebpackUriSendedCallback
-                const ok = await callback(msg.uri, msg.name as string, msg.thumbnail as string);
-                return JSON.stringify({ isOk: ok})
-            }
-        })
-
-        natsCtrl.subscribe(`recv.actions.${this.appGuid}`, async ()=>{
-            return JSON.stringify(this.listeners.map(item=>item.toJson()))
-        })
-    }
-
-
-    //清除所有监听者
-    clearListeners() {
-        this.listeners = [];
-    }
-
-    emitChange() {
-        const {natsCtrl} = useCtx();
-        natsCtrl.publish(RevcChangeEvent, JSON.stringify({Guid: this.appGuid}))
-    }
-
-    //添加图片监听者
-    addImageListener(actionName:string, handle: AssetSendedCallback) {
-        let listen = this.listeners.find(item=>item.actionName == actionName);
-        if (listen)  {
-            listen.callback = handle;
-            return listen.id;
-        }
-        listen = new AssetListener(actionName, handle)
-        listen.type = "image";
-        this.listeners.push(listen);
-    }
-
-     //添加webpackUri听者
-     addWebpackuriListener(actionName:string, handle: AssetWebpackUriSendedCallback) {
-        let listen = this.listeners.find(item=>item.actionName == actionName);
-        if (listen)  {
-            listen.callback = handle as any;
-            return listen.id;
-        }
-        listen = new AssetListener(actionName, handle as any)
-        listen.type = "webpackuri";
-        this.listeners.push(listen);
-    }
-    
-    removeListener(id:string) {
-        let listen = this.listeners.find(item=>item.id == id);
-        if (!listen)  {
-            return;
-        }
-        this.listeners.splice(this.listeners.indexOf(listen), 1);
-    }
-}

+ 21 - 21
src/comm/controllers/cmdsvcCtrl.ts

@@ -1,25 +1,25 @@
-import { queenApi } from "queenjs";
-import { connect, StringCodec, Empty, ErrorCode } from "nats.ws";
-import { Controller } from "../core/controller";
-import { useCtx } from "../ctx";
-import { reactive } from "vue";
+// import { queenApi } from "queenjs";
+// import { connect, StringCodec, Empty, ErrorCode } from "nats.ws";
+// import { Controller } from "../core/controller";
+// import { useCtx } from "../ctx";
+// import { reactive } from "vue";
 
-export class CmdSvcController extends Controller {
+// export class CmdSvcController extends Controller {
   
-    state = reactive({
-        list: [] as {f:string,m:string}[]
-    })
+//     state = reactive({
+//         list: [] as {f:string,m:string}[]
+//     })
 
-    async onReady() {
-      const {natsCtrl} = useCtx();
-      const params = new URLSearchParams(decodeURIComponent(location.search));
-      const guid = params.get("guid");
+//     async onReady() {
+//       const {natsCtrl} = useCtx();
+//       const params = new URLSearchParams(decodeURIComponent(location.search));
+//       const guid = params.get("guid");
 
-      const state = this.state;
-      console.log("substring", `${guid}.cmdmsg`)
-      natsCtrl.subscribe(`${guid}.cmdmsg`, (msg:any)=>{
-        console.log("cmdMsg=>", msg);
-        state.list.push(msg);
-      }, {queue: "cmdsvc"})
-    }
-}
+//       const state = this.state;
+//       console.log("substring", `${guid}.cmdmsg`)
+//       natsCtrl.subscribe(`${guid}.cmdmsg`, (msg:any)=>{
+//         console.log("cmdMsg=>", msg);
+//         state.list.push(msg);
+//       }, {queue: "cmdsvc"})
+//     }
+// }

+ 127 - 109
src/comm/controllers/deviceCtrl.ts

@@ -1,9 +1,8 @@
-import {NormMsg, decodeNormMsg, encodeNormMsg} from "./entity/message";
-import { Controller } from "../core/controller";
-//@ts-ignore
 import { saveAs } from "file-saver";
+import { Base64 } from "js-base64";
+import { Controller } from "../core/controller";
+import { NormMsg, decodeNormMsg, encodeNormMsg } from "./entity/message";
 
-import {Base64 } from "js-base64"
 type UploadItem = {
   id: string;
   fpath: string;
@@ -22,7 +21,7 @@ export type FileInfo = {
 export class DeviceController extends Controller {
   ipc: any;
 
-  profile = {wsPort: "", appGuid: ""}
+  profile = { wsPort: "", appGuid: "" };
 
   isEnvOk = false;
 
@@ -34,7 +33,6 @@ export class DeviceController extends Controller {
       //@ts-ignore
       this.ipc = window.ipc;
       this.isEnvOk = true;
-
     } else {
       this.ipc = {
         emit(name: string, ...args: any[]) {
@@ -54,16 +52,16 @@ export class DeviceController extends Controller {
     this.ipc.on("OnDragEnter", function (files: string[]) {
       scope.emit("onDragEnter", files);
     });
-    this.ipc.on("downloadsucc", (fpath:string, size:number)=>{
-       scope.emit("downloadsucc", fpath, size);
-    })
+    this.ipc.on("downloadsucc", (fpath: string, size: number) => {
+      scope.emit("downloadsucc", fpath, size);
+    });
 
-    this.ipc.emit("GetSocketUri", [], (uri:string) => {
+    this.ipc.emit("GetSocketUri", [], (uri: string) => {
       let conn = new WebSocket(uri);
-      conn.onopen = (e)=>{
-        console.log("bus socket connected!!!")
-      }
-      conn.onclose =  (evt)=>{
+      conn.onopen = (e) => {
+        console.log("bus socket connected!!!");
+      };
+      conn.onclose = (evt) => {
         console.log("app bus socket conn closed", evt);
 
         setTimeout(() => {
@@ -72,30 +70,32 @@ export class DeviceController extends Controller {
       };
       conn.onmessage = function (evt) {
         if (!evt.data || evt.data == "") return;
-        
+
         try {
           const blob = evt.data as Blob;
-          blob.arrayBuffer().then(buff=>{
-            const msg = decodeNormMsg(new Uint8Array(buff))
+          blob.arrayBuffer().then((buff) => {
+            const msg = decodeNormMsg(new Uint8Array(buff));
             scope.emit("on" + msg.sub, msg);
-          })
+          });
         } catch (error) {
-          console.error(evt.data, typeof evt.data,  error);
+          console.error(evt.data, typeof evt.data, error);
         }
       };
       this._conn = conn;
     });
-
   }
 
   async onReady() {
-     if (!this.isEnvOk) return;
+    if (!this.isEnvOk) return;
 
-     this.profile = await this.GetLocalAppProfile() ||  {wsPort:"", appGuid: ""};
+    this.profile = (await this.GetLocalAppProfile()) || {
+      wsPort: "",
+      appGuid: "",
+    };
 
-     console.log("current app profile=>", this.profile);
+    console.log("current app profile=>", this.profile);
   }
-  
+
   //选择磁盘文件夹
   SelectDir(): Promise<string> {
     const sid = Date.now();
@@ -154,7 +154,7 @@ export class DeviceController extends Controller {
     const cbname = "copy" + sid;
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.on(cbname, function (ok:boolean) {
+      ipc.on(cbname, function (ok: boolean) {
         r(ok);
       });
       ipc.emit("CopyFile", [cbname, srcFile, targetFile]);
@@ -236,14 +236,18 @@ export class DeviceController extends Controller {
     return new Promise((r) => {
       const ipc = this.ipc;
       const cbname = "c" + sid;
-      ipc.emit("SelectOneFilePath", [sid, title, filters], function (ok:boolean) {
-        if (!ok) {
-          r("");
+      ipc.emit(
+        "SelectOneFilePath",
+        [sid, title, filters],
+        function (ok: boolean) {
+          if (!ok) {
+            r("");
+          }
+          ipc.on(cbname, function (dir: string) {
+            r(dir);
+          });
         }
-        ipc.on(cbname, function (dir: string) {
-          r(dir);
-        });
-      });
+      );
     });
   }
 
@@ -267,11 +271,9 @@ export class DeviceController extends Controller {
   ): Promise<boolean> {
     const sid = "d" + Date.now();
     return new Promise((r) => {
-
-        console.log(url,  "==>", fpath)
+      console.log(url, "==>", fpath);
       const cancel = this.OnMsg(sid, (data) => {
-       
-        cb && cb(data.type as any,  data);
+        cb && cb(data.type as any, data);
         if (data.type == "succ") {
           r(true);
           cancel.unbind();
@@ -298,13 +300,16 @@ export class DeviceController extends Controller {
     });
   }
 
-  Unzip(fpath:string, distDir:string, cb?: (event: "progress" | "error" | "succ", p1: NormMsg) => void) {
+  Unzip(
+    fpath: string,
+    distDir: string,
+    cb?: (event: "progress" | "error" | "succ", p1: NormMsg) => void
+  ) {
     const sid = "unzip" + Date.now();
 
     return new Promise((r) => {
-
       const cancel = this.OnMsg(sid, (data) => {
-        cb && cb(data.type as any,  data);
+        cb && cb(data.type as any, data);
         if (data.type == "succ") {
           r(true);
           cancel.unbind();
@@ -352,7 +357,7 @@ export class DeviceController extends Controller {
           1280,
           960,
         ],
-        function (ok:boolean) {
+        function (ok: boolean) {
           r(ok);
         }
       );
@@ -365,7 +370,7 @@ export class DeviceController extends Controller {
       console.error("应用socket异常");
       return;
     }
-    conn.send(encodeNormMsg({sub: subject, msg: msg}));
+    conn.send(encodeNormMsg({ sub: subject, msg: msg }));
   }
 
   OnMsg(subject: string, cb: (msg: NormMsg) => any) {
@@ -376,7 +381,7 @@ export class DeviceController extends Controller {
   UploadSync(files: UploadItem[]): Promise<UploadItem[]> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("UploadSync", [files], function (ret:any) {
+      ipc.emit("UploadSync", [files], function (ret: any) {
         r(ret);
       });
     });
@@ -387,12 +392,12 @@ export class DeviceController extends Controller {
     const sid = "u" + Date.now();
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("UploadASync", [sid, files], function (ok:boolean) {
+      ipc.emit("UploadASync", [sid, files], function (ok: boolean) {
         if (!ok) {
           r([]);
           return;
         }
-        ipc.on(sid, (items:any) => {
+        ipc.on(sid, (items: any) => {
           r(items);
         });
       });
@@ -404,66 +409,66 @@ export class DeviceController extends Controller {
     const sid = "u" + Date.now();
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("UploadDir", [sid, dir, targetDir], function (ok:any) {
+      ipc.emit("UploadDir", [sid, dir, targetDir], function (ok: any) {
         if (!ok) {
           r([]);
           return;
         }
-        ipc.on(sid, (items:any) => {
+        ipc.on(sid, (items: any) => {
           r(items);
         });
       });
     });
   }
 
-  GetFilesInDir(dir:string, filter:string): Promise<FileInfo[]>{
+  GetFilesInDir(dir: string, filter: string): Promise<FileInfo[]> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("GetFilesInDir", [ dir, filter], function (ret:any) {
+      ipc.emit("GetFilesInDir", [dir, filter], function (ret: any) {
         r(ret);
       });
     });
   }
 
-  GetSubDirNames(dir:string):Promise<string[]>{ 
+  GetSubDirNames(dir: string): Promise<string[]> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("GetSubDirNames", [ dir], function (ret:any) {
+      ipc.emit("GetSubDirNames", [dir], function (ret: any) {
         r(ret);
       });
     });
   }
 
-  RemoveFile(fpath: string) : Promise<boolean>{
+  RemoveFile(fpath: string): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("RemoveFile", [fpath], function (ok:boolean) {
+      ipc.emit("RemoveFile", [fpath], function (ok: boolean) {
         r(ok);
       });
     });
   }
 
-  GetSaveFile(title:string, filter= "图片(*.png;*.jpg)") :Promise<string> {
-    const sid = "sf"+Date.now();
+  GetSaveFile(title: string, filter = "图片(*.png;*.jpg)"): Promise<string> {
+    const sid = "sf" + Date.now();
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("GetSaveFile", [sid, title, filter], function (ok:boolean) {
-         if(ok) {
-          ipc.on(sid, (ret:any)=>{
-              r(ret);
-          })
-          return
-         }
-         r("");
+      ipc.emit("GetSaveFile", [sid, title, filter], function (ok: boolean) {
+        if (ok) {
+          ipc.on(sid, (ret: any) => {
+            r(ret);
+          });
+          return;
+        }
+        r("");
       });
     });
   }
 
-  OpenOneFile(title:string, filter= "图片(*.png;*.jpg)") :Promise<string> {
-    const sid = "sf"+Date.now();
+  OpenOneFile(title: string, filter = "图片(*.png;*.jpg)"): Promise<string> {
+    const sid = "sf" + Date.now();
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("OpenOneFile", [sid, title, filter], function (file:any) {
+      ipc.emit("OpenOneFile", [sid, title, filter], function (file: any) {
         setTimeout(() => {
           r(file);
         }, 0);
@@ -471,15 +476,14 @@ export class DeviceController extends Controller {
     });
   }
 
-  GetImageMeta(fpath:string): Promise<{Width: number, Height: number, Size:number}> {
-
-   
+  GetImageMeta(
+    fpath: string
+  ): Promise<{ Width: number; Height: number; Size: number }> {
     return new Promise((r) => {
-
       const img = new Image();
-      img.onload=()=>{
-        r({Width: img.width, Height: img.height, Size: 0})
-      }
+      img.onload = () => {
+        r({ Width: img.width, Height: img.height, Size: 0 });
+      };
       img.src = fpath;
 
       // const ipc = this.ipc;
@@ -488,66 +492,66 @@ export class DeviceController extends Controller {
       // });
     });
   }
-  
-  SetMainTitle(title :string):Promise<boolean> {
+
+  SetMainTitle(title: string): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("SetMainTitle", [title], function (ok:any) {
-         r(ok)
+      ipc.emit("SetMainTitle", [title], function (ok: any) {
+        r(ok);
       });
     });
   }
 
-  SaveFile(fpath: string, buff:any) :Promise<string>{
+  SaveFile(fpath: string, buff: any): Promise<string> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("SaveFile", [fpath, Array.from(buff)], function (err:string) {
-         r(err)
+      ipc.emit("SaveFile", [fpath, Array.from(buff)], function (err: string) {
+        r(err);
       });
     });
   }
-  
-  OpenQueen5(url: string, title:any) :Promise<boolean>{
+
+  OpenQueen5(url: string, title: any): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("OpenQueen5", [url, title], function (err:any) {
-         r(err)
+      ipc.emit("OpenQueen5", [url, title], function (err: any) {
+        r(err);
       });
     });
   }
-  OpenQueen5Play(url: string, title:any) :Promise<boolean>{
+  OpenQueen5Play(url: string, title: any): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("OpenQueen5Play", [url, title], function (err:any) {
-         r(err)
+      ipc.emit("OpenQueen5Play", [url, title], function (err: any) {
+        r(err);
       });
     });
   }
 
-  SaveBlobFile(url:string, fbase64path:string) :Promise<boolean> {
+  SaveBlobFile(url: string, fbase64path: string): Promise<boolean> {
     console.log("save blob to ", fbase64path);
 
     return new Promise((r) => {
-      const cancel = this.on("downloadsucc", (dpath:string)=>{
-        console.log("fpath=>", dpath)
-        if (fbase64path ==  Base64.encode(dpath)) {
+      const cancel = this.on("downloadsucc", (dpath: string) => {
+        console.log("fpath=>", dpath);
+        if (fbase64path == Base64.encode(dpath)) {
           cancel.unbind();
-          r(true)
+          r(true);
         }
-      })
+      });
       saveAs(url, fbase64path);
     });
   }
 
-  SaveClipboard(blob:Blob) {
-   return navigator.clipboard.write([
+  SaveClipboard(blob: Blob) {
+    return navigator.clipboard.write([
       new ClipboardItem({
-        "image/png": blob
-      })
-    ])
+        "image/png": blob,
+      }),
+    ]);
   }
 
-  GetNatsProfile(): Promise<{ apiPort: string, wsPort: string , ip:string}> {
+  GetNatsProfile(): Promise<{ apiPort: string; wsPort: string; ip: string }> {
     return new Promise((r) => {
       const ipc = this.ipc;
       ipc.emit("NatsProfile", [], function (data: any) {
@@ -556,16 +560,21 @@ export class DeviceController extends Controller {
     });
   }
 
-  GetLocalAppProfile(): Promise<{wsPort:string, appGuid:string}> {
+  GetLocalAppProfile(): Promise<{ wsPort: string; appGuid: string }> {
     return new Promise((r) => {
       const ipc = this.ipc;
       ipc.emit("LocalAppProfile", [], function (data: any) {
-        r(data || {wsPort:"", appGuid: ""});
+        r(data || { wsPort: "", appGuid: "" });
       });
     });
   }
 
-  OpenWeb(url:string, title:string, width = 1280, height = 720) :Promise<boolean>{
+  OpenWeb(
+    url: string,
+    title: string,
+    width = 1280,
+    height = 720
+  ): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
       ipc.emit("OpenWeb", [url, title, width, height], function (data: any) {
@@ -574,27 +583,36 @@ export class DeviceController extends Controller {
     });
   }
 
-  RunNativeApp(guid:string, entry:string, params:string[]) :Promise<string> {
+  RunNativeApp(guid: string, entry: string, params: string[]): Promise<string> {
     return new Promise((r) => {
       const ipc = this.ipc;
       ipc.emit("RunNativeApp", [guid, entry, params], function (err: string) {
-        console.log("xxxx", err)
+        console.log("xxxx", err);
         r(err);
       });
     });
   }
 
-  RunCmdSvcApp(guid:string, webUrl:string, entry:string, params:string[]) :Promise<string> {
+  RunCmdSvcApp(
+    guid: string,
+    webUrl: string,
+    entry: string,
+    params: string[]
+  ): Promise<string> {
     return new Promise((r) => {
       const ipc = this.ipc;
-      ipc.emit("RunCmdSvcApp", [guid, webUrl, entry, params], function (err: string) {
-        console.log("xxxx", err)
-        r(err);
-      });
+      ipc.emit(
+        "RunCmdSvcApp",
+        [guid, webUrl, entry, params],
+        function (err: string) {
+          console.log("xxxx", err);
+          r(err);
+        }
+      );
     });
   }
 
-  StopNativeApp(guid:string) :Promise<boolean> {
+  StopNativeApp(guid: string): Promise<boolean> {
     return new Promise((r) => {
       const ipc = this.ipc;
       ipc.emit("StopNativeApp", [guid], function (ok: boolean) {

+ 2 - 2
src/comm/controllers/index.ts

@@ -1,4 +1,4 @@
-import { CmdSvcController } from "./cmdsvcCtrl";
+// import { CmdSvcController } from "./cmdsvcCtrl";
 import { DeviceController } from "./deviceCtrl";
 import { NatsController } from "./natsCtrl";
 import { AppMsgSendController } from "@queenjs/assets";
@@ -8,6 +8,6 @@ export {
   AppMsgSendController,
   DeviceController,
   NatsController,
-  CmdSvcController,
+  // CmdSvcController,
   AppMsgQueen5Controller,
 };

+ 132 - 32
src/comm/controllers/natsCtrl.ts

@@ -1,36 +1,52 @@
-import { queenApi } from "queenjs";
-import { connect, StringCodec, Empty, ErrorCode } from "nats.ws";
+import { message, Modal } from "ant-design-vue";
+import { connect, Empty, StringCodec } from "nats.ws";
 import { Controller } from "../core/controller";
+import { RxValue } from "../core/rxValue";
 import { useCtx } from "../ctx";
 
+function sleep(time: number) {
+  return new Promise((r) => {
+    setTimeout(() => {
+      r(0);
+    }, time);
+  });
+}
+
 export class NatsController extends Controller {
- 
   _conn: any;
-  _isConned = false;
   _startInit = false;
+  _ui: any;
+
+  state = RxValue.create({
+    _isConned: false,
+  });
 
   async onReady() {
-      await this.initConn();
+    await this.initConn();
   }
 
   async initConn() {
     if (this._startInit) return;
     this._startInit = true;
 
-    const {deviceCtrl} = useCtx()
+    const { deviceCtrl } = useCtx();
 
+    // if (!deviceCtrl.profile.wsPort)
+    //   deviceCtrl.profile = {
+    //     wsPort: "50495",
+    //     appGuid: "spu3d",
+    //   };
     const profile = deviceCtrl.profile;
 
     if (!profile.wsPort) return;
-    
-    
-    const wsHost = `nats://localhost:${profile.wsPort}`
+
+    const wsHost = `nats://localhost:${profile.wsPort}`;
     console.log("ws host=>", wsHost);
     let ret = false;
 
     try {
       this._conn = await connect({ servers: wsHost });
-      this._isConned = !!this._conn;
+      this.state._isConned = !!this._conn;
 
       ret = true;
     } catch (error) {
@@ -40,14 +56,18 @@ export class NatsController extends Controller {
     this._startInit = false;
     return ret;
   }
-  
+
   async GetConn() {
     return this._conn;
   }
 
-  async subscribe(subject: string, callback: any, options:any = {}) {
-  
-    if (!this._isConned) {
+  async answer(
+    subject: string,
+    callback: any,
+    options: any = {},
+    respIm = true
+  ) {
+    if (!this.state._isConned) {
       console.error("建立连接失败");
       return;
     }
@@ -58,21 +78,61 @@ export class NatsController extends Controller {
     (async () => {
       for await (const m of sub) {
         const ret = sc.decode(m.data);
-        console.log(subject, "=>recieved");
+        console.log(subject, "=>recieved", typeof ret);
+        if (respIm) {
+          m.respond(sc.encode("ok"));
+        }
+
+        let resp = "";
+
         try {
-          if (ret) {
+          if ((ret && ret[0] == "[") || ret[0] == "{") {
             const msg = JSON.parse(ret);
-            const out = await callback(msg);
-            m.respond(sc.encode(out))
+            resp = await callback(msg);
+          } else {
+            resp = await callback(ret);
+          }
+        } catch (error) {
+          console.log(subject, "=>recieved json parse eror", ret);
+          console.log(error);
+        }
+        console.log(subject, "=>recieved over");
+        if (!respIm) {
+          m.respond(sc.encode(resp));
+        }
+      }
+      console.log(subject, "subscription closed");
+    })();
+    return function () {
+      sub.unsubscribe();
+    };
+  }
+
+  async subscribe(subject: string, callback: any, options: any = {}) {
+    if (!this.state._isConned) {
+      console.error("建立连接失败");
+      return;
+    }
 
+    const sc = StringCodec();
+    const sub = this._conn.subscribe(subject, options);
+
+    (async () => {
+      for await (const m of sub) {
+        const ret = sc.decode(m.data);
+        console.log(subject, "=>recieved", ret);
+        try {
+          if ((ret && ret[0] == "[") || ret[0] == "{") {
+            const msg = JSON.parse(ret);
+            callback(msg);
           } else {
-            const out = await callback(ret);
-            m.respond(sc.encode(out))
+            callback(ret);
           }
         } catch (error) {
           console.log(subject, "=>recieved json parse eror", ret);
           console.log(error);
         }
+        console.log(subject, "=>recieved over");
       }
       console.log(subject, "subscription closed");
     })();
@@ -82,13 +142,13 @@ export class NatsController extends Controller {
   }
 
   async requestApi(subject: string, data?: any, timeout?: number) {
-    if (!this._isConned) return;
+    if (!this.state._isConned) return;
 
     const ret = await this.request(subject, data, timeout);
     console.log("request api=>", ret);
 
     if (ret.error || (ret.result.ErrorNo && ret.result.ErrorNo != 200)) {
-      queenApi.messageError(ret.error || ret.result.ErrorDesc);
+      message.error(ret.error || ret.result.ErrorDesc);
       return;
     }
     try {
@@ -101,27 +161,27 @@ export class NatsController extends Controller {
       console.error(error);
     }
   }
-  
-  async publish(subject:string, value:string) {
-    
-    if (!this._isConned) {return}
+
+  async publish(subject: string, value: string) {
+    if (!this.state._isConned) {
+      return;
+    }
 
     const sc = StringCodec();
 
-    return await this._conn.publish(subject,  sc.encode(value));
+    return await this._conn.publish(subject, sc.encode(value));
   }
 
   async request(subject: string, data?: any, timeout?: number) {
-
     const ret: { error: string; result: any } = { error: "", result: null };
-    if (!this._isConned) {
+    if (!this.state._isConned) {
       console.error("建立连接失败");
       ret.error = "建立连接失败";
 
-      queenApi.showConfirm({
+      Modal.confirm({
         title: "数据请求失败",
         content: "请求数据失败,请重新启动后再试",
-        type: "danger",
+        // type: "danger",
       });
       return ret;
     }
@@ -161,9 +221,49 @@ export class NatsController extends Controller {
   }
 
   close() {
-    if (!this._isConned) {
+    if (!this.state._isConned) {
       return;
     }
     return this._conn.close();
   }
+
+  async getAppInsts(type: string) {
+    const ui = this._ui;
+    ui.showLoading("应用获取中...");
+    const instances = [] as any[];
+
+    try {
+      //等待2s获取类容 appInsts.get.sid 发送信息
+
+      const sid = Date.now();
+      const cancel = await this.subscribe("appInsts.get." + sid, (app: any) => {
+        console.log("app=?", app);
+        instances.push(app);
+      });
+      const { deviceCtrl } = useCtx();
+
+      this.publish(
+        "broad.appInsts.get",
+        JSON.stringify({
+          type: type,
+          sid: sid + "",
+          guid: deviceCtrl.profile.appGuid,
+        })
+      );
+
+      await sleep(1000);
+
+      cancel?.();
+      ui.hideLoading();
+
+      const insts = instances.filter((item: any) => {
+        return item.Guid != deviceCtrl.profile.appGuid;
+      });
+      return insts;
+    } catch (error) {
+      ui.hideLoading();
+      ui.messageError("应用获取失败");
+    }
+    return instances;
+  }
 }

+ 9 - 9
yarn.lock

@@ -1796,10 +1796,10 @@
   resolved "http://124.70.149.18:4873/@queenjs-modules%2fqueentree/-/queentree-0.0.10.tgz"
   integrity sha512-P4cIjXKgcvd8h3vVs4f1rGLNf3/Kd5G+qGiZN+idkLjiu22HU6SNmOVLUwV6PuKg+9sTPRn7FKamSHuFxXWX5g==
 
-"@queenjs/assets@^0.0.22":
-  version "0.0.22"
-  resolved "http://124.70.149.18:4873/@queenjs%2fassets/-/assets-0.0.22.tgz#32fe79422b50d9d6b328b5824ed2fcbcffdcf2ee"
-  integrity sha512-dnzz13ks5XiUsWLfqHHhdFAtVjasL3YZaeGPgcAM7mJGkByXMjA0rVE5uB0eTZeGyOurewRI16hNLx59RXw0UQ==
+"@queenjs/assets@^1.0.4":
+  version "1.0.4"
+  resolved "http://124.70.149.18:4873/@queenjs%2fassets/-/assets-1.0.4.tgz#acf1f07a5dd8e0bea2549edb6383db27cfa75389"
+  integrity sha512-0VSPDN/8VKgPp3q+tmjtnGYeBa8liPgFTS0QflLDjUv/p14mWDtrUv/X3evIIXXSL7vTq1KVDyjJwYyLLFIZzQ==
 
 "@queenjs/components@^0.0.23":
   version "0.0.23"
@@ -6388,10 +6388,10 @@ nanopop@^2.1.0:
   resolved "http://124.70.149.18:4873/nanopop/-/nanopop-2.3.0.tgz"
   integrity sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw==
 
-nats.ws@^1.15.0:
-  version "1.15.0"
-  resolved "http://124.70.149.18:4873/nats.ws/-/nats.ws-1.15.0.tgz"
-  integrity sha512-J6np4qe+rRS3y47wesYZbmKC/ez5JHR50uJ0L5yBI+8zVtQo/Nueaaos8jDTeQ2bGV0KVgH9oD1ar1XA27mVbg==
+nats.ws@1.18.0:
+  version "1.18.0"
+  resolved "http://124.70.149.18:4873/nats.ws/-/nats.ws-1.18.0.tgz#eeef911608cc3c0f0f8ff2509c8a231f40213cb5"
+  integrity sha512-5ITvGO2gd4vAVK733u494ysEOuorfygpig9pqqLapV3FuiFWp4APsZdtZ893zXCC5UclF9MYUzdiTj2cKPDxAA==
   optionalDependencies:
     nkeys.js "1.0.5"
 
@@ -6436,7 +6436,7 @@ nice-try@^1.0.4:
 
 nkeys.js@1.0.5:
   version "1.0.5"
-  resolved "http://124.70.149.18:4873/nkeys.js/-/nkeys.js-1.0.5.tgz"
+  resolved "http://124.70.149.18:4873/nkeys.js/-/nkeys.js-1.0.5.tgz#3024bde671eb33be0316ff2d5abe8b8cec960158"
   integrity sha512-u25YnRPHiGVsNzwyHnn+PT90sgAhnS8jUJ1nxmkHMFYCJ6+Ic0lv291w7uhRBpJVJ3PH2GWbYqA151lGCRrB5g==
   dependencies:
     tweetnacl "1.0.3"