rambo 1 year ago
parent
commit
abaf5e9168

+ 1 - 0
.gitignore

@@ -8,3 +8,4 @@ data/
 .vscode/launch.json
 public/electron/
 pnpm-lock.yaml
+build/extraResources/py/*

+ 55 - 40
electron/config/bin.js

@@ -9,19 +9,19 @@ module.exports = {
    */
   dev: {
     frontend: {
-      directory: './frontend',
-      cmd: 'npm',
-      args: ['run', 'dev'],
-      protocol: 'http://',
-      hostname: 'localhost',
+      directory: "./frontend",
+      cmd: "npm",
+      args: ["run", "dev"],
+      protocol: "http://",
+      hostname: "localhost",
       port: 8080,
-      indexPath: 'index.html'
+      indexPath: "index.html",
     },
     electron: {
-      directory: './',
-      cmd: 'electron',
-      args: ['.', '--env=local', '--color=always'],
-    }
+      directory: "./",
+      cmd: "electron",
+      args: [".", "--env=local", "--color=always"],
+    },
   },
 
   /**
@@ -30,52 +30,61 @@ module.exports = {
    */
   build: {
     frontend: {
-      directory: './frontend',
-      cmd: 'npm',
-      args: ['run', 'build'],
-    }
+      directory: "./frontend",
+      cmd: "npm",
+      args: ["run", "build"],
+    },
+    python: {
+      directory: "./python",
+      cmd: "python",
+      args: ["./setup.py", "build"],
+    },
   },
 
   /**
    * 移动资源
-   * ee-bin move 
+   * ee-bin move
    */
   move: {
     frontend_dist: {
-      dist: './frontend/dist',
-      target: './public/dist'
-    }
-  },  
+      dist: "./frontend/dist",
+      target: "./public/dist",
+    },
+    python_dist: {
+      dist: "./python/dist",
+      target: "./build/extraResources/py",
+    },
+  },
 
   /**
    * 预发布模式(prod)
    * ee-bin start
    */
   start: {
-    directory: './',
-    cmd: 'electron',
-    args: ['.', '--env=prod']
+    directory: "./",
+    cmd: "electron",
+    args: [".", "--env=prod"],
   },
 
   /**
    * 加密
-   */  
+   */
   encrypt: {
-    type: 'confusion',
+    type: "confusion",
     files: [
-      'electron/**/*.(js|json)',
-      '!electron/config/encrypt.js',
-      '!electron/config/nodemon.json',
-      '!electron/config/builder.json',
-      '!electron/config/bin.json',
+      "electron/**/*.(js|json)",
+      "!electron/config/encrypt.js",
+      "!electron/config/nodemon.json",
+      "!electron/config/builder.json",
+      "!electron/config/bin.json",
     ],
-    fileExt: ['.js'],
+    fileExt: [".js"],
     confusionOptions: {
-      compact: true,      
+      compact: true,
       stringArray: true,
-      stringArrayEncoding: ['none'],
+      stringArrayEncoding: ["none"],
       deadCodeInjection: false,
-    }
+    },
   },
 
   /**
@@ -84,14 +93,20 @@ module.exports = {
    */
   exec: {
     node_v: {
-      directory: './',
-      cmd: 'node',
-      args: ['-v'],
+      directory: "./",
+      cmd: "node",
+      args: ["-v"],
     },
     npm_v: {
-      directory: './',
-      cmd: 'npm',
-      args: ['-v'],
+      directory: "./",
+      cmd: "npm",
+      args: ["-v"],
     },
-  },   
+    python: {
+      directory: "./python",
+      cmd: ".venv/Scripts/python",
+      args: ["./main.py", "--port=7074"],
+      stdio: "inherit", // ignore
+    },
+  },
 };

+ 60 - 49
electron/config/config.default.js

@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
 
-const path = require('path');
+const path = require("path");
 
 /**
  * 默认配置
  */
 module.exports = (appInfo) => {
-
   const config = {};
 
   /**
@@ -23,7 +22,7 @@ module.exports = (appInfo) => {
    * 主窗口
    */
   config.windowsOption = {
-    title: 'EE框架',
+    title: "EE框架",
     width: 980,
     height: 650,
     minWidth: 400,
@@ -36,35 +35,35 @@ module.exports = (appInfo) => {
     },
     frame: true,
     show: false,
-    icon: path.join(appInfo.home, 'public', 'images', 'logo-32.png'),
+    icon: path.join(appInfo.home, "public", "images", "logo-32.png"),
   };
 
   /**
    * ee框架日志
-   */  
+   */
   config.logger = {
-    encoding: 'utf8',
-    level: 'INFO',
+    encoding: "utf8",
+    level: "INFO",
     outputJSON: false,
     buffer: true,
     enablePerformanceTimer: false,
-    rotator: 'day',
-    appLogName: 'ee.log',
-    coreLogName: 'ee-core.log',
-    errorLogName: 'ee-error.log' 
-  }
+    rotator: "day",
+    appLogName: "ee.log",
+    coreLogName: "ee-core.log",
+    errorLogName: "ee-error.log",
+  };
 
   /**
    * 远程模式-web地址
-   */    
+   */
   config.remoteUrl = {
     enable: false,
-    url: 'http://electron-egg.kaka996.com/'
+    url: "http://electron-egg.kaka996.com/",
   };
 
   /**
    * 内置socket服务
-   */   
+   */
   config.socketServer = {
     enable: false,
     port: 7070,
@@ -77,51 +76,49 @@ module.exports = (appInfo) => {
     cors: {
       origin: true,
     },
-    channel: 'c1'
+    channel: "c1",
   };
 
   /**
    * 内置http服务
-   */     
+   */
   config.httpServer = {
     enable: false,
     https: {
-      enable: false, 
-      key: '/public/ssl/localhost+1.key',
-      cert: '/public/ssl/localhost+1.pem'
+      enable: false,
+      key: "/public/ssl/localhost+1.key",
+      cert: "/public/ssl/localhost+1.pem",
     },
-    host: '127.0.0.1',
+    host: "127.0.0.1",
     port: 7071,
     cors: {
-      origin: "*"
+      origin: "*",
     },
     body: {
       multipart: true,
       formidable: {
-        keepExtensions: true
-      }
+        keepExtensions: true,
+      },
     },
     filterRequest: {
-      uris:  [
-        'favicon.ico'
-      ],
-      returnData: ''
-    }
+      uris: ["favicon.ico"],
+      returnData: "",
+    },
   };
 
   /**
    * 主进程
-   */     
+   */
   config.mainServer = {
-    protocol: 'file://',
-    indexPath: '/public/dist/index.html',
-  }; 
+    protocol: "file://",
+    indexPath: "/public/dist/index.html",
+  };
 
   /**
    * 硬件加速
    */
   config.hardGpu = {
-    enable: true
+    enable: true,
   };
 
   /**
@@ -137,9 +134,23 @@ module.exports = (appInfo) => {
    * jobs
    */
   config.jobs = {
-    messageLog: true
-  };  
-
+    messageLog: true,
+  };
+  /**
+   * Cross-language service
+   * 跨语言服务
+   * 例如:执行go的二进制程序,默认目录为 ./extraResources/
+   */
+  config.cross = {
+    python: {
+      enable: false,
+      name: "pyapp",
+      cmd: "./py/pyapp",
+      directory: "./py",
+      args: ["--port=7074"],
+      appExit: true,
+    },
+  };
   /**
    * 插件功能
    */
@@ -149,31 +160,31 @@ module.exports = (appInfo) => {
     },
     tray: {
       enable: true,
-      title: 'EE程序',
-      icon: '/public/images/tray.png'
+      title: "EE程序",
+      icon: "/public/images/tray.png",
     },
     security: {
       enable: true,
     },
     awaken: {
       enable: true,
-      protocol: 'ee',
-      args: []
+      protocol: "ee",
+      args: [],
     },
     autoUpdater: {
       enable: true,
-      windows: false, 
-      macOS: false, 
+      windows: false,
+      macOS: false,
       linux: false,
       options: {
-        provider: 'generic', 
-        url: 'http://kodo.qiniu.com/'
+        provider: "generic",
+        url: "http://kodo.qiniu.com/",
       },
       force: false,
-    }
+    },
   };
 
   return {
-    ...config
+    ...config,
   };
-}
+};

+ 20 - 5
electron/config/config.local.js

@@ -5,12 +5,27 @@
  */
 module.exports = (appInfo) => {
   const config = {};
-
+  /**
+   * Cross-language service
+   * 跨语言服务
+   * 如果有cmd参数,则执行该命令且需要指定 directory
+   */
+  config.cross = {
+    python: {
+      enable: false,
+      name: "pyapp",
+      cmd: "python",
+      directory: "./python",
+      args: ["./main.py", "--port=7074"],
+      stdio: "ignore",
+      appExit: true,
+    },
+  };
   /**
    * 开发者工具
    */
   config.openDevTools = {
-    mode: 'undocked'
+    mode: "undocked",
   };
 
   /**
@@ -22,10 +37,10 @@ module.exports = (appInfo) => {
    * jobs
    */
   config.jobs = {
-    messageLog: true
-  };   
+    messageLog: true,
+  };
 
   return {
-    ...config
+    ...config,
   };
 };

+ 9 - 8
electron/preload/index.js

@@ -1,14 +1,15 @@
 /*************************************************
  ** preload为预加载模块,该文件将会在程序启动时加载 **
  *************************************************/
-const Addon = require('ee-core/addon');
-
+const Addon = require("ee-core/addon");
+const Services = require("ee-core/services");
 /**
-* 预加载模块入口
-*/
+ * 预加载模块入口
+ */
 module.exports = async () => {
-
   // 示例功能模块,可选择性使用和修改
-  Addon.get('tray').create();
-  Addon.get('security').create();
-}
+  Addon.get("tray").create();
+  Addon.get("security").create();
+  // 直接调用
+  Services.get("cross").createPythonServer();
+};

+ 47 - 0
electron/service/cross.js

@@ -0,0 +1,47 @@
+"use strict";
+
+const { Service } = require("ee-core");
+const Cross = require("ee-core/cross");
+const Log = require("ee-core/log");
+const Ps = require("ee-core/ps");
+const path = require("path");
+const Is = require("ee-core/utils/is");
+
+/**
+ * cross(service层为单例)
+ * @class
+ */
+class CrossService extends Service {
+  constructor(ctx) {
+    super(ctx);
+  }
+  /**
+   * create python service
+   * In the default configuration, services can be started with applications.
+   * Developers can turn off the configuration and create it manually.
+   */
+  async createPythonServer() {
+    // method 1: Use the default Settings
+    //const entity = await Cross.run(serviceName);
+
+    // method 2: Use custom configuration
+    const serviceName = "python";
+    const opt = {
+      name: "pyapp",
+      cmd: path.join(Ps.getExtraResourcesDir(), "py", "pyapp"),
+      directory: path.join(Ps.getExtraResourcesDir(), "py"),
+      args: ["--port=7074"],
+      windowsExtname: true,
+      appExit: true,
+    };
+    const entity = await Cross.run(serviceName, opt);
+    Log.info("server name:", entity.name);
+    Log.info("server config:", entity.config);
+    Log.info("server url:", entity.getUrl());
+
+    return;
+  }
+}
+
+CrossService.toString = () => "[class CrossService]";
+module.exports = CrossService;

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
     "dev-frontend": "ee-bin dev --serve=frontend",
     "dev-electron": "ee-bin dev --serve=electron",
     "build-frontend": "ee-bin build --cmds=frontend && ee-bin move --flag=frontend_dist",
+    "build-python": "ee-bin build --cmds=python && ee-bin move --flag=python_dist",
     "start": "ee-bin start",
     "rd": "ee-bin move --flag=frontend_dist",
     "encrypt": "ee-bin encrypt",

+ 4 - 0
python/.gitignore

@@ -0,0 +1,4 @@
+**/__pycache__
+**.pyc
+.venv/*
+dist/*

+ 42 - 0
python/api.py

@@ -0,0 +1,42 @@
+from flask import Flask, request
+from flask_cors import CORS
+import json
+from jsonschema import validate, ValidationError
+import datetime
+from services.Exception import ApiException
+app = Flask(__name__)
+# 配置 CORS,允许所有来源
+CORS(app)
+
+def response(message="success", data=None, code=0):
+    return json.dumps({"message": "", "data": data, "code": code}), 200
+
+@app.errorhandler(ApiException)  # 捕捉全局异常
+def internal_error(exc:ApiException):
+    print("Internal error:",exc.msg)
+    return (
+        json.dumps({"message": str(exc.msg), "code": exc.code}, ensure_ascii=False),
+        200,
+    )
+
+
+@app.errorhandler(404)
+def page_not_found(e):
+    return (
+        json.dumps({"code": 4999, "msg": "请求出错,页面未找到"}, ensure_ascii=False),
+        404,
+    )
+
+@app.route("/", methods=["GET"])
+def index():
+    '''入口文件'''
+    name = request.args.get("name", "World")
+    return response(message="",data=f"Hello, {name}!")
+
+def Validateutils(data,schema):
+    '''数据验证'''
+    try:
+        validate(instance=data, schema=schema)
+    except ValidationError as e:
+        # 处理验证失败的逻辑
+        raise ApiException(e.message)

+ 29 - 0
python/main.py

@@ -0,0 +1,29 @@
+import argparse
+import signal
+import sys
+from api import app
+
+# argparse
+parser = argparse.ArgumentParser(description="Process some integers.")
+parser.add_argument("--port", type=int, default=7074, help="The port number.")
+args = parser.parse_args()
+
+
+# 通过信号来退出服务,否则会出现终端显示退出后,实际进程仍在运行
+# 定义信号处理函数
+def signal_handler(sig, frame):
+    print("[python] [flask] Received signal to terminate the server:", sig)
+    sys.exit(0)
+
+
+# 注册信号处理函数
+signal.signal(signal.SIGTERM, signal_handler)
+signal.signal(signal.SIGINT, signal_handler)
+
+if __name__ == "__main__":
+    # 以api方式启动服务会出现警告,请忽略
+    app.run(port=args.port,use_reloader=True)
+
+# 或许flask内置的stdio与node.js stdio有冲突,导致控制台无法显示信息。
+# 如果想要查看控制台输出,请单独启动服务 npm run dev-python
+print("python server is running at port:", args.port)

BIN
python/requirements.txt


+ 6 - 0
python/services/BaseApi.py

@@ -0,0 +1,6 @@
+class BaseApi():
+    def success(self,message=None,**msg):
+        return {'status': True, 'message': message, 'code': 0,'data':msg}
+
+    def fail(self,message,code):
+        return {'status': False,"message": message, "code": code}

+ 4 - 0
python/services/Exception.py

@@ -0,0 +1,4 @@
+class ApiException(Exception):
+    def __init__(self, msg: str,code:int=400):
+        self.msg = msg
+        self.code = code

+ 0 - 0
python/services/__init__.py


+ 25 - 0
python/setup.py

@@ -0,0 +1,25 @@
+from cx_Freeze import setup, Executable
+
+# 创建可执行文件的配置
+executableApp = Executable(
+    script="main.py",
+    target_name="pyapp",
+)
+
+# 打包的参数配置
+options = {
+    "build_exe": {
+        "build_exe": "./dist/",
+        "excludes": ["*.txt"],
+        # "include_files": ["models/RMBG"],
+        "optimize": 2,
+    }
+}
+
+setup(
+    name="pyapp",
+    version="1.0",
+    description="python app",
+    options=options,
+    executables=[executableApp]
+)