# @ultra-node/electron-engine

> electron 项目开发基础库，便于直接开发业务逻辑

Latest version **0.1.20** (published 2023-03-21) · LGPL 2.1 license · 0 weekly downloads

## Install

```sh
npm install @ultra-node/electron-engine
pnpm add @ultra-node/electron-engine
yarn add @ultra-node/electron-engine
bun add @ultra-node/electron-engine
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.1.20 |
| Published | 2023-03-21 |
| First published | 2023-01-11 |
| Weekly downloads | 0 |
| License | LGPL 2.1 |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 3 |
| Unpacked size | 867.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | zz |
| Maintainers | zzlink |

## Links

- npm: https://www.npmjs.com/package/@ultra-node/electron-engine
- npm.io page: https://npm.io/package/@ultra-node/electron-engine

## Dependencies (3)

- [axios](https://npm.io/package/axios.md) ^1.2.2
- [mousetrap](https://npm.io/package/mousetrap.md) ^1.6.5
- [@electron/remote](https://npm.io/package/@electron/remote.md) ^2.0.9

## Recent versions

- 0.1.20 (latest) — 2023-03-21
- 0.1.19 — 2023-03-17
- 0.1.18 — 2023-03-16
- 0.1.17 — 2023-03-16
- 0.1.16 — 2023-03-15
- 0.1.15 — 2023-03-15
- 0.1.14 — 2023-03-14
- 0.1.13 — 2023-03-14
- 0.1.12 — 2023-03-14
- 0.1.11 — 2023-03-14
- 0.1.10 — 2023-03-14
- 0.1.9 — 2023-03-14
- 0.1.8 — 2023-03-14
- 0.1.6 — 2023-03-13
- 0.1.5 — 2023-03-13
- … 4 more at https://npm.io/package/@ultra-node/electron-engine/versions

## README

electron 项目开发基础库，便于直接开发业务逻辑



[toc]



### 1. 引擎初始化

#### 1.1 主进程初始化引擎

​		在electron主进程入口(main.ts 或 background.ts) 入增加如下代码：

```typescript
import { initEngine } from '@electron-engine/engine.main'
initEngine()
```



​		完整主程序入口文件如下:

```typescript
import { app } from 'electron'
import { initEngine } from '@electron-engine/engine.main'
import windows from './core/windows/main'

initEngine()

app.on('ready', async () => {
  windows.LoginWindow.createWindow()
})
```

##### 1.1.1 参数说明

```typescript
export interface IEngineConfig {
    logger?: ILoggerConfig
    httpServer?: IHttpServerConfig
    rcElectron?: IRCElectronConfig
    appConfig?: IAppConfigConfig
    notification?: INotificationConfig
    shortcut?: IShortcutConfig
    appTray?: IAppTrayConfig
}
```



#### 1.2 渲染进程初始化引擎

​		在窗体preload.js文件中增加如下代码：

```typescript
require('@electron-engine/engine.renderer')
```

### 2. Http请求

#### 2.1 业务的http请求基类

```typescript
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
import HttpRequestBase from '@ultra-node/electron-engine/http-request/HttpRequestBase'
import { IResult } from '@ultra-node/electron-engine/types'
import { EErrorCode } from '@/types'

interface IServerData {
  data: any
  errCode: string
  errMsg: string
  flag: boolean
}
export default class ApiBase extends HttpRequestBase {
  constructor(apiConfig?: AxiosRequestConfig) {
    const config: AxiosRequestConfig = {
      timeout: 1000 * 15, // 15秒
      baseURL: ''
    }
    !!apiConfig && Object.assign(config, apiConfig)
    super(config)
    super.intercepReqeust({
      onBeforeRequest: this.onBeforeRequest,
      onRequestError: this.onRequestError
    })
    super.intercepResponse({
      onAfterResponse: this.onAfterResponse,
      onResponseError: this.onResponseError
    })
  }

  private onBeforeRequest(config: AxiosRequestConfig<any>): AxiosRequestConfig<any> {
    return config
  }

  private onRequestError(error: AxiosError): any {
    const code = error.message === 'canceled' ? EErrorCode.Canceled : error.response?.status
    const result: IResult = {
      isOK: false,
      data: {},
      code,
      msg: error.message
    }
    return Promise.resolve({ data: result })
  }
  /**
   * 将服务端返回格式转化成应用封装格式
   * @param result 服务原始响应数据
   * @returns 应用所需要的响应数据格式
   */
  private onAfterResponse(result: AxiosResponse<any, any>): AxiosResponse<any, any> {
    const serverData = result.data as IServerData
    const appData: IResult = {
      isOK: serverData.flag,
      data: serverData.data,
      code: serverData.flag ? 0 : serverData.errCode, // 将server的成功码统一转换成 0，为和应用其它模块保持一致
      msg: serverData.errMsg
    }
    result.data = appData
    return result
  }

  private onResponseError(error: AxiosError): any {
    const code = error.message === 'canceled' ? EErrorCode.Canceled : error.response?.status
    const msg = error.code === 'ERR_NETWORK' ? '当前网络不可用，请检查网络设置' : error.message?.includes('timeout of') ? '加载超时' : error.message
    const result: IResult = {
      isOK: false,
      data: {},
      code,
      msg
    }
    return Promise.resolve({ data: result })
  }
}
```

#### 2.2 具体业务请求类

```typescript
import ApiBase from './ApiBase'

export default class LoginApi extends ApiBase {
  public login(name: string, pwd: string) {
    return this.postForm('/login', { name, pwd })
  }
}
```

### 3. 窗体管理

#### 3.1 主进程使用的窗体对象

```typescript
import MainWindow from '@ultra-node/electron-engine/window/MainWindow'

export default class LoginWindow extends MainWindow {
  devUrl = (process.env.WEBPACK_DEV_SERVER_URL as string) + '/login.html'
  prodUrl = 'app://./login.html'
  windowOptions: Electron.BrowserWindowConstructorOptions = {
    width: 508,
    height: 611,
    minWidth: 508,
    minHeight: 611,
    maxWidth: 508,
    maxHeight: 611,
    frame: false,
    webPreferences: {
      preload: path.join(__dirname, '/preload-login.js'),
      nodeIntegration: true,
      contextIsolation: false
    }
  }
  constructor() {
    super(EWindowName.LoginWindow)
  }
}
```

#### 3.2 渲染进程使用的窗体对象

```typescript
import RendererWindow from '@ultra-node/electron-engine/window/RendererWindow'
import { EWindowName } from '..'

export default class LoginWindow extends RendererWindow {
  constructor() {
    super(EWindowName.LoginWindow)
  }
}
```

### 4. Ipc 通讯封装

#### 4.1 渲染进程调用主进程，同步返回结果

- 主进程中：

  ```typescript
  import { listenFromRendererSync } from '@ultra-node/electron-engine/ipc/ipc.main'
  
  listenFromRendererSync('event-name', (event: any, param: string) => {
    return 'result'
  })
  ```

- 渲染进程中：

  ```typescript
  import { sendToMainSync } from '@ultra-node/electron-engine/ipc/ipc.renderer'
  
  const result = sendToMainSync('event-name','我是参数')
  ```

#### 4.2 渲染进程调用主进程，异步返回结果 

- 主进程中：

  ```typescript
  import { listenFromRendererAsync } from '@ultra-node/electron-engine/ipc/ipc.main'
  
  listenFromRendererAsync('event-name', (event: any, param: string) => {
    return await OtherMethod()
  })
  ```

- 渲染进程中：

  ```typescript
  import { sendToMainAsync } from '@ultra-node/electron-engine/ipc/ipc.renderer'
  
  const result = await sendToMainAsync('event-name','我是参数')
  ```

#### 4.3 渲染进程调用主进程，无返回结果 

- 主进程中：

  ```typescript
  import { listenFromRendererVoid } from '@ultra-node/electron-engine/ipc/ipc.main'
  
  listenFromRendererVoid('event-name', (event: any, param: string) => {
    OtherMethod()
  })
  ```

- 渲染进程中：

  ```typescript
  import { sendToMainVoid } from '@ultra-node/electron-engine/ipc/ipc.renderer'
  
  sendToMainVoid('event-name','我是参数')
  ```

#### 4.4 主进程调用渲染进程

- 主进程中：

  ```typescript
  import { sendToRendererVoid } from '@ultra-node/electron-engine/ipc/ipc.main'
  
  sendToRendererVoid(webcontents, 'event-name','我是参数')
  ```

- 渲染进程中：

  ```typescript
  import { listenFromMainVoid } from '@ultra-node/electron-engine/ipc/ipc.renderer'
  
  listenFromMainVoid('event-name', (event: any, param: string) => {
    OtherMethod()
  })
  ```

### 5. 日志

#### 5.1 日志初始化

​		在做engine初始化时，可以添加日志相关参数

```typescript
	initEngine({
        logger:{
            filePath: 'full path'
        }
    })

// export interface ILoggerConfig {
//   fileLevel?: TLoggerLevel
//   fileMaxSize?: number
//   filePath?: string
//   fileFormat?: string
// }
```

#### 5.2 主进程使用日志输出

```typescript
import logger from '@ultra-node/electron-engine/logger/logger.main'
logger.info('i am from main process')
```

#### 5.3 渲染进程使用日志输出

```typescript
import logger from '@ultra-node/electron-engine/logger/logger.renderer'
logger.info('i am from renderer process')
logger.debug('i am from renderer process')
logger.error('i am from renderer process')
```

### 6. 快捷键管理

#### 6.1 系统快捷键

​		只要软件存活，无轮是否被焦点，都可以监听到

```typescript
import { listenSysShortcut, registerSysShortcut } from '@ultra-node/electron-engine/shortcut/shortcut.renderer'

// 注册
registerSysShortcut('shortcut-name','shift+j')
// 监听
listenSysShortcut('shortcut-name',()=>{
    console.log('shortcut-name pressed')
})
```

#### 6.2 应用快捷键

​		软件存活，且处于被焦点状态时，才可以收到监听

```typescript
import { listenAppShortcut, registerAppShortcut } from '@ultra-node/electron-engine/shortcut/shortcut.renderer'

// 注册
registerAppShortcut('shortcut-name','shift+j')
// 监听
listenAppShortcut('shortcut-name',()=>{
    console.log('shortcut-name pressed')
})
```

### 7. 应用协议

​		注册应用唤醒协议，可以将协议格式放到浏览器中进行唤醒app, 生成的协议格式为： protocol://

- 主进程中注册协议

  ```typescript
  import { registerProtocol, unregisterProtocol } from '@ultra-node/electron-engine/protocol/protocol.main'
  
  registerProtocol('rcbw')
  ```

- 主进程中监听协议唤起

  ```typescript
  import { listenProtocol } from '@ultra-node/electron-engine/protocol/protocol.main'
  
  listenProtocol('rcbw',(url: string)=> {
      console.log('用户用这个url唤醒的App', url)
  })
  ```

### 8. 应用托盘图标

```typescript
import initAppTray, { IAppTrayOptions } from '@ultra-node/electron-engine/tray/tray.main'

// 鼠标事件
const onMouseClick = () => {
    // 鼠标点击图标
}
// 右键菜单
const contextMenuItems: MenuItemConstructorOptions[] = [
    {
        label: '退出',
        role: 'quit',
        click: () => {
            app.quit()
        }
    }
]
// 基本信息
const trayOptions: IAppTrayOptions = {
    iconPath: PathUtil.resolvePath('extraResources/icons/32x32.png'),
    toolTip: 'appName',
    contextMenuItems,
    onClick: onMouseClick
}
// 初始化托盘
initAppTray(trayOptions)
```

### 9. 系统通知

- 主进程初始化

  ```typescript
  initEngine({
      notification:{
          appId: 'appId',
          init: true
      }
  })
  ```

- 渲染进程发起

  ```typescript
  import { showNotification } from '@ultra-node/electron-engine/notification/notification.renderer'
  
  showNotification({
      title:'',
      body:''
  })
  ```

### 10. shell 功能

#### 10.1 打开文件夹，并选中文件

```typescript
import { showItemInFolder } from '@ultra-node/electron-engine/shell'

showItemInFolder('/data/a.txt')
```

### 11. Dictionary 字典类封装

```typescript
import { Dictionary } from '@ultra-node/electron-engine/dictionary'

const dict = new Dictionary()
dict.set('key', 'value')
dict.get('key')
```

### 12. 本地 Http 服务器

​		使用 express 在主进程搭建的 http 服务，用于资源代理，也可用于第三方应用调用此应用

#### 12.1 服务初始化

```typescript
// 初始化
initEngine({
    httpServer:{
        init: true,
        defaultControll: true // 是否开启默认处理器
    }
})
```

#### 12.2 使用

```typescript
import { startServer } from '@ultra-node/electron-engine/http-server/httpServer.main'

const localhost = await startServer([])
// localhost: http://localhost:8088
```

#### 12.3 默认处理器

localhost/local/path/filename?url=remote_address

处理机制：当在 local/path 有 filename 资源时，直接返回，否则会从url下载完后返回，并将资源放到 local/path/filename 处

#### 12.4 增加自定义处理

```typescript
import { ControllerBase } from '@ultra-node/electron-engine/http-server'

class MyController extends ControllerBase{
  public method: 'get' | 'post' = 'get'
  public routePath: string = '/pic/*'
  public handler(req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>, rsp: Response<any, Record<string, any>>): void {
    throw new Error('Method not implemented.')
  }
}

await startServer([new MyController()])
```

### 13. app-config: 应用配置 

​		数据会存到本地文件，每次操作都是io, 因此存储仅用于存储简单的软件配置信息

#### 13.1 初始化配置

```typescript
initEngine({
    appConfig:{
      init: boolean // 是否开启此功能
      fileDir?: string // 文件目录
      fileName?: string // 文件名
      fileExt?: string // 文件后缀
      encryptionKey?: string // 加密字符串
      default?: T // 默认数据格式
    }
})
```

#### 13.2 使用

```typescript
import { appConfig } from '@ultra-node/electron-engine/app-config/appConfig.renderer'

appConfig.set('key','value')
appConfig.get('key')
```

### 14. app-session: 应用全局缓存

​		使用主进程存储数据，使用ipc做桥梁，因此此session可用于不同窗体间数据共享，适合全局性变量，但不适合存储业务大量数据

```typescript
import { appSession } from '@ultra-node/electron-engine/app-session/appSession.renderer'

appSession.set('key','value')
appSession.get('key')
```

### 15. rc-electron 融云 imsdk PC端解决方案

​		开启后，融云 IM 将直接使用协议栈功能，代替websocket通过socket进行通讯

```typescript
initEngine({
    rcElectron: {
        init: true // 开启功能
    }
})
```

### 16. utils: 工具类

#### 16.1 快捷键打开 userdata 目录

```typescript
import { useOpenUserData } from '@ultra-node/electron-engine/utils/appShortcutUtil'

useOpenUserData()
```

#### 16.2 获取绝对路径

​		自动适配开发、生产环境

```typescript
import { resolvePath } from '@ultra-node/electron-engine/utils/pathUril'

resolvePath('/extraResources/icon')
```

#### 16.3 获取当前文件寄宿的窗体名称

```typescript
import { getHostWindowName } from '@ultra-node/electron-engine/utils/windowUtil'

const currentWindowName = getHostWindowName()
```

---
_Source: https://npm.io/package/@ultra-node/electron-engine · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
