2

electron + go 如何从sqlite获取数据 - 轩脉刃

 1 year ago
source link: https://www.cnblogs.com/yjf512/p/17024826.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

electron + go 如何从sqlite获取数据

2023-01-04 14:51  轩脉刃  阅读(142)  评论(0)  编辑  收藏  举报

我现在的数据在sqlite中,保存在mac本地的一个文件中。用了electron+vue搭建了一个客户端。

image-20221231155037031

我大概希望是这样的逻辑,先加载本地db文件,然后再获取数据。

这里就有一个问题,我怎么获取sqlite中的数据呢?从哪里加载呢?

electron的进程分为master Process 和 renderer Process。这个事情是哪个Process来做呢?

image-20221231191651260

我觉得这里可能有好几种方案。

首先第一种,直接从RendererProcess来,这就和浏览器要直接访问本地文件的逻辑一样了。肯定可以做,不过感觉会很不安全。

第二种,就是MainProcess来读取本地文件,然后传递到Renderer来显示。这个其实是更符合electron的设计思路。因为mainProcess就是用来处理和本机的连接的。

其实还有第三种,就是启动一个本地服务器,来读取sqlite,提供接口出来给RendererProcess。然后RendererProcess就和正常的js调用接口一样,调用这个本地服务器。这个的好处就是这个本地服务器可以用其他语言来做,这里我非常希望用golang来实现。其次,这个本地服务器其实很容易修改为远端服务器。

所以我想尝试一下第三种方式来实现。

尝试eletron+go

这个方案和hade的设计思路是一致的,hade可以构建前端eletron,再构建一个后端go的二进制文件,然后eletron打包的时候把后端go的二进制文件打包进去。

那么这里就遇到第一个问题,如何在eletron中打包一个二进制文件,并且启动它呢?

如何在eletron中打包二进制文件?

找了一些资料,特别是这篇文章:

https://stackoverflow.com/questions/33152533/bundling-precompiled-binary-into-electron-app/45152204#45152204

尝试了一下,真的是可行的。

首先我用golang编译出二进制文件叫toolbox-server

然后存放的目录是resources/mac/toolbox-server:

image-20230101152617653

接着修改vue.config.js文件(这个修改的文件如果你没有使用vue来编译electron的话,你就修改package.json)

package.json增加字段:

"extraFiles": [
    {
      "from": "resources/${os}",
      "to": "Resources/bin",
      "filter": [
        "**/*"
      ]
    }
  ]

vue.config.js修改字段:

...

module.exports = defineConfig({
  ...
  pluginOptions: {
    electronBuilder: {
      builderOptions: {
        extraFiles: [
          {
            "from": "resources/${os}",
            "to": "Resources/bin",
            "filter": [
              "**/*"
            ]
          }
        ],
      }
    }
  }
})

不管是在vue.config.js还是在package.json中修改,都以为着告诉electron打包程序,我需要把resources/${os}/下的所有文件放到打包后的Resources/bin文件下。

然后在我们的electron的main.js(在我项目中是background.js)。都是代表electron的主进程。

在app的ready事件中,我注入了以下代码:

import appRootDir from 'app-root-dir';
const log = require('electron-log');
...
app.on('ready', async () => {
  if (isDevelopment && !process.env.IS_TEST) {
    // Install Vue Devtools
    try {
      await installExtension(VUEJS3_DEVTOOLS)
    } catch (e) {
      log.error('Vue Devtools failed to install:', e.toString())
    }
  }
  createWindow()

  const execPath = (!isDevelopment) ?
    joinPath(appRootDir.get(), 'bin') :
    joinPath(appRootDir.get(), 'resources', getPlatform());

  const cmd = `${joinPath(execPath, 'toolbox-server')}` + ' app start';
  log.info(cmd);

  exec(cmd, (err, stdout, stderr) => {
    if (err != null) {
      log.error('run error' + err.toString());
    }
    log.log('stdout:' + stdout.toString());
    log.error('stderr:' + stderr.toString());
  });
})

其中的log包我使用的是 electron-log。这样才能最后在编译的时候,把日志打印到

~/Library/Logs/{app_name}/ 

对于execPath我们可以再看下,这里使用了 app-root-dir 包,它对应的 appRootDir.get() 方法在运行的时候,对应的目录为:

/Applications/{app_name}.app/Contents/Resources/

其实这里我琢磨可能不用app-root-dir包也行,直接用electron的app带的各种路径方法(https://www.electronjs.org/zh/docs/latest/api/app),不过这里我没有继续尝试了。

然后使用npm run electron:build 就可以看到生成打包文件。

安装打包文件,通过应用程序-{app_name}-Content可以看到二进制的Golang文件就在这里面了。

image-20230101165147086

同时如果你在调试模式下使用 npm run electron:serve, 可以看到在electron启动的同时,这个进程也就起来了。

![image-20230101165421154](../../../Library/Application Support/typora-user-images/image-20230101165421154.png)

且端口在localhost中可用

image-20230101165441792

打包二进制文件进electron完成。

ps: 研究这个过程中,这篇(https://ld246.com/article/1547556984481)对我的帮助很大,mark下。

golang实现的http接口

剩下的就很简单了,golang写一个http接口,读取sqlite。

我使用hade框架,

image-20230101204851260

很快就可以完成类似的接口

http://127.0.0.1:8070/essay/list

image-20230101204922214

这里就没有什么好说的了。

electron的renderer调用server获取数据展示

这个也没有什么好说的了,就是基本的vue来调用http获取数据。

fetchData() {
      request({
        url: "/essay/list?page=" + this.next_page + "&size=" + this.size,
        method: "get",
      }).then((res) => {
        console.log(res);
        if (res.status === 200) {
          if (res.data.list.length === 0) {
            this.noMore = true;
            return;
          }
          for (let i= 0; i < res.data.list.length; i++) {
            this.data.push(res.data.list[i])
          }
          this.page = this.next_page;
          this.next_page = this.next_page + 1;
          this.loading = false;
        }
      });
    },

二进制打包还有一些问题

二进制打包这里还有一些问题,在打包的时候,需要配置文件,但是我目前是没有的。这个怎么办呢?

还有就是toolbox-server会生成运行时文件,都在storage里面,这个怎么办呢?

打包配置文件

首先我把配置文件也都复制到resources中。

![image-20230102125854304](../../../Library/Application Support/typora-user-images/image-20230102125854304.png)

这样vue.config.js中复制的时候也会把整个目录进行拷贝。

image-20230102130022854

接着由于我的程序运行的时候需要在toolbox-server同级目录运行,所以我修改了一下启动toolbox-server 的程序;

async function startToolboxServer() {
  const execPath = (!isDevelopment) ?
      joinPath(appRootDir.get(), 'bin', 'toolbox-server') :
      joinPath(appRootDir.get());

  const cmd = `cd ${execPath} && ${joinPath(execPath, 'toolbox-server')}` + ' app start';
  log.info(cmd);

  exec(cmd, (err, stdout, stderr) => {
    if (err != null) {
      log.error('run error' + err.toString());
    }
    log.log('stdout:' + stdout.toString());
    log.error('stderr:' + stderr.toString());
  });
}

这里主要加上了cd ${execPath} 目录。

运行日志放在应用对应的日志目录中

eletron对应的日志目录为:~/Library/Logs/{app_name}/

我们希望在这个目录下能创建一个子目录toolbox-server,把toolbox-server的运行日志放在里面。即(~/Library/Logs/toolbox/toolbox-server/)

这里就首先需要 toolbox-server 这个程序是支持修改运行日志的。

所幸hade框架是支持环境变量设置运行日志:

http://hade.funaio.cn/guide/app.html#进程运行基础配置

STORAGE_FOLDER=/Users/jianfengye/Documents/workspace/gohade/hade/teststorage ./hade app start

所以我可以通过在electron的主进程启动toolbox-server的地方设置环境变量来达到这个目的。

我修改了一下startToolboxServer 启动toolbox-server的函数

async function startToolboxServer() {
  const execPath = (!isDevelopment) ?
      joinPath(appRootDir.get(), 'bin', 'toolbox-server') :
      joinPath(appRootDir.get());

  const cmd = `cd ${execPath} && ${joinPath(execPath, 'toolbox-server')}` + ' app start';

  let logFolder = joinPath(app.getPath("logs"), "toolbox-server");
  let envVars = {...process.env}
  if (!isDevelopment) {
    envVars = { ...process.env, STORAGE_FOLDER:  logFolder}
  }

  log.info("cmd: " + cmd + ", env: " + JSON.stringify({STORAGE_FOLDER : logFolder}));

  exec(cmd, {env: envVars}, (err, stdout, stderr) => {
    if (err != null) {
      log.error('run error' + err.toString());
    }
    log.log('stdout:' + stdout.toString());
    log.error('stderr:' + stderr.toString());
  });
}

主要是在正式环境中把STORAGE_FOLDER的环境变量设置为 joinPath(app.getPath("logs"), "toolbox-server")

这里的exec是child_prcess包的函数,增加env的方法可以参考:https://nodejs.org/api/child_process.html

这里的app.getPath("logs") 是electron自带的方法,具体可以参考:https://www.electronjs.org/zh/docs/latest/api/app

于是这样设置之后,hade框架生成的strorage运行产生文件就放在了 ~/Library/Logs/toolbox 中了,完美。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK