ee-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/bin/tools.js +22 -0
  4. package/config/config.default.js +179 -0
  5. package/core/index.js +13 -0
  6. package/core/lib/ee.js +220 -0
  7. package/core/lib/loader/context_loader.js +105 -0
  8. package/core/lib/loader/ee_loader.js +427 -0
  9. package/core/lib/loader/file_loader.js +262 -0
  10. package/core/lib/loader/mixin/config.js +138 -0
  11. package/core/lib/loader/mixin/controller.js +123 -0
  12. package/core/lib/loader/mixin/service.js +29 -0
  13. package/core/lib/utils/base_context_class.js +34 -0
  14. package/core/lib/utils/index.js +100 -0
  15. package/core/lib/utils/sequencify.js +59 -0
  16. package/core/lib/utils/timing.js +77 -0
  17. package/index.js +50 -0
  18. package/lib/appLoader.js +45 -0
  19. package/lib/application.js +69 -0
  20. package/lib/baseApp.js +155 -0
  21. package/lib/constant.js +30 -0
  22. package/lib/eeApp.js +306 -0
  23. package/lib/helper.js +52 -0
  24. package/lib/httpclient.js +136 -0
  25. package/lib/logger.js +47 -0
  26. package/lib/socket/io.js +22 -0
  27. package/lib/socket/ipcServer.js +112 -0
  28. package/lib/socket/socketClient.js +51 -0
  29. package/lib/socket/socketServer.js +70 -0
  30. package/lib/socket/start.js +18 -0
  31. package/lib/storage/appStorage.js +14 -0
  32. package/lib/storage/index.js +22 -0
  33. package/lib/storage/lowdbStorage.js +144 -0
  34. package/package.json +39 -0
  35. package/resource/images/loding.gif +0 -0
  36. package/resource/images/tray_logo.png +0 -0
  37. package/resource/loading.html +22 -0
  38. package/resource/view_example.html +22 -0
  39. package/tools/codeCompress.js +202 -0
  40. package/tools/replaceDist.js +71 -0
  41. package/utils/index.js +141 -0
  42. package/utils/wrap.js +38 -0
@@ -0,0 +1,69 @@
1
+ const {app} = require('electron');
2
+ const path = require('path');
3
+ const EeApp = require('./eeApp');
4
+ const debug = require('debug')('ee-core:Appliaction');
5
+
6
+ class Appliaction extends EeApp {
7
+ constructor() {
8
+
9
+ // 初始化环境变量
10
+ // const opt = this.initEnv();
11
+ const { env } = process;
12
+
13
+ let options = {
14
+ env: 'prod',
15
+ serverScope: '',
16
+ type: 'application',
17
+ baseDir: path.join(app.getAppPath(), 'electron'),
18
+ homeDir: process.cwd(),
19
+ framework: path.join(process.cwd(), 'node_modules/ee-core'),
20
+ appName: app.getName(),
21
+ userHome: app.getPath('home'),
22
+ appData: app.getPath('appData'),
23
+ appUserData: app.getPath('userData'),
24
+ logsDir: app.getPath('logs'),
25
+ appVersion: app.getVersion()
26
+ }
27
+
28
+ // argv
29
+ for (let i = 0; i < process.argv.length; i++) {
30
+ const tmpArgv = process.argv[i]
31
+ if (tmpArgv.indexOf('--env=') !== -1) {
32
+ options.env = tmpArgv.substring(6)
33
+ }
34
+ }
35
+
36
+ // normalize env
37
+
38
+ env.NODE_ENV = 'production';
39
+ env.EE_HOME = options.homeDir;
40
+ env.EE_SERVER_ENV = options.env;
41
+ env.EE_SERVER_SCOPE = options.serverScope;
42
+ env.EE_USER_HOME = options.userHome;
43
+ env.EE_APP_DATA = options.appData;
44
+ env.EE_APP_USER_DATA = options.appUserData;
45
+ env.EE_EGG_PORT = null;
46
+ env.EE_IPC_PORT = null;
47
+ env.EGG_SERVER_ENV = options.env;
48
+ debug('options:%j', options)
49
+
50
+ super(options);
51
+ this.initialize();
52
+ }
53
+
54
+ async initialize () {
55
+
56
+ await this.createPorts();
57
+
58
+ this.startSocket();
59
+ //return;
60
+
61
+ await this.ready();
62
+
63
+ await this.createElectronApp();
64
+
65
+ this.catchLog();
66
+ }
67
+ }
68
+
69
+ module.exports = Appliaction;
package/lib/baseApp.js ADDED
@@ -0,0 +1,155 @@
1
+ 'use strict';
2
+
3
+ const EeAppCore = require('../core/index').EeCore;
4
+ const EE_PATH = Symbol.for('ee#eePath');
5
+ const path = require('path');
6
+ const EE_LOADER = Symbol.for('ee#loader');
7
+ const AppLoader = require('./appLoader');
8
+ const LOGGERS = Symbol('EeApplication#loggers');
9
+ const ELoggers = require('./logger');
10
+ const HttpClient = require('./httpclient');
11
+ const HTTPCLIENT = Symbol('EeApplication#httpclient');
12
+
13
+ class BaseApp extends EeAppCore {
14
+ constructor (options = {}) {
15
+
16
+ super(options);
17
+
18
+ this.HttpClient = HttpClient;
19
+
20
+ this.loader.loadConfig();
21
+
22
+ // 缓存配置
23
+ this.getCoreDB().setItem('config', this.config);
24
+
25
+ this.loader.load();
26
+
27
+ // TODO 这个不行,要么每次new对象,要么所有地方都用同一个实例,否则会出现数据无法刷新的情况
28
+ //this.coreDB = this.getCoreDB();
29
+
30
+ this.coreLogger.info('[ee-core:baseApp] start loaded lib modules');
31
+
32
+ }
33
+
34
+ get [EE_PATH]() {
35
+ return path.join(__dirname, '..');
36
+ }
37
+
38
+ get [EE_LOADER]() {
39
+ return AppLoader;
40
+ }
41
+
42
+ /**
43
+ * loggers
44
+ * @member {Object}
45
+ * @since 1.0.0
46
+ */
47
+ get loggers() {
48
+ if (!this[LOGGERS]) {
49
+ this[LOGGERS] = ELoggers.getInstance(this.config);
50
+ }
51
+ return this[LOGGERS];
52
+ }
53
+
54
+ /**
55
+ * Get logger by name, it's equal to app.loggers['name'],
56
+ * but you can extend it with your own logical.
57
+ * @param {String} name - logger name
58
+ * @return {Logger} logger
59
+ */
60
+ getLogger(name) {
61
+ return this.loggers[name] || null;
62
+ }
63
+
64
+ /**
65
+ * application logger, log file is `$HOME/logs/ee.log`
66
+ * @member {Logger}
67
+ * @since 1.0.0
68
+ */
69
+ get logger() {
70
+ return this.getLogger('logger');
71
+ }
72
+
73
+ /**
74
+ * core logger for framework and plugins, log file is `$HOME/logs/ee-core.log`
75
+ * @member {Logger}
76
+ * @since 1.0.0
77
+ */
78
+ get coreLogger() {
79
+ return this.getLogger('coreLogger');
80
+ }
81
+
82
+ /**
83
+ * @class core存储模块
84
+ * @since 1.0.0
85
+ */
86
+ getCoreDB () {
87
+ const db = require('./storage/index').JsonDB.connection('system');
88
+ return db;
89
+ }
90
+
91
+ /**
92
+ * @class curl
93
+ * @since 1.0.0
94
+ */
95
+ curl(url, opts) {
96
+ return this.httpclient.request(url, opts);
97
+ }
98
+
99
+ /**
100
+ * HttpClient instance
101
+ * @see https://github.com/node-modules/urllib
102
+ * @member {HttpClient}
103
+ */
104
+ get httpclient() {
105
+ if (!this[HTTPCLIENT]) {
106
+ this[HTTPCLIENT] = new this.HttpClient(this);
107
+ }
108
+ return this[HTTPCLIENT];
109
+ }
110
+
111
+ /**
112
+ * 调用 egg api
113
+ */
114
+ async curlEgg (method, uri, params, timeout = 15000) {
115
+ let result = null;
116
+ try {
117
+ const port = this.config.egg.port;
118
+ const url = "http://127.0.0.1:" + port + uri;
119
+ // console.log('[ee:baseApp] [curlEgg] url:', url);
120
+ const response = await this.curl(url, {
121
+ method: method,
122
+ contentType: 'application/json',
123
+ data: params,
124
+ dataType: 'json',
125
+ timeout: timeout,
126
+ });
127
+ result = response.data;
128
+ } catch (err) {
129
+ this.logger.error('[ee:baseApp] [curlEgg] throw error:', err);
130
+ }
131
+
132
+ return result;
133
+ }
134
+
135
+ /**
136
+ * @class socket模块
137
+ * @since 1.0.0
138
+ */
139
+ get socket () {
140
+ const obj = {
141
+ ipc: {},
142
+ server: {}
143
+ }
144
+ return obj;
145
+ }
146
+
147
+ /**
148
+ * core app have been loaded
149
+ */
150
+ async ready () {
151
+ // do some things
152
+ }
153
+ }
154
+
155
+ module.exports = BaseApp;
@@ -0,0 +1,30 @@
1
+ module.exports = {
2
+ autoLaunch: {
3
+ LOGIN_SETTING_OPTIONS: {
4
+ // For Windows
5
+ args: [
6
+ '--opened-at-login=1'
7
+ ]
8
+ }
9
+ },
10
+ storageKey: {
11
+ cache: 'cache',
12
+ },
13
+ ipcChannels: {
14
+ appMessage: 'app.message',
15
+ appUpdater: 'app.updater'
16
+ },
17
+ appUpdaterStatus: {
18
+ error: -1,
19
+ available: 1,
20
+ noAvailable: 2,
21
+ downloading: 3,
22
+ downloaded: 4,
23
+ },
24
+ socketIo: {
25
+ channel: {
26
+ eggIoEe: 'c1',
27
+ eggIoFrotend: 'c2'
28
+ }
29
+ }
30
+ };
package/lib/eeApp.js ADDED
@@ -0,0 +1,306 @@
1
+ const path = require('path');
2
+ const getPort = require('get-port');
3
+ const {app, BrowserWindow, BrowserView, Menu} = require('electron');
4
+ const BaseApp = require('./baseApp');
5
+ const is = require('is-type-of');
6
+
7
+ class EeApp extends BaseApp {
8
+ constructor(options = {}) {
9
+ super(options);
10
+
11
+ this.electron = {
12
+ mainWindow: null,
13
+ tray: null
14
+ };
15
+
16
+ //this._mainWindow = null;
17
+ //this.electron.mainWindow = null;
18
+
19
+ //this.electron.tray = null;
20
+ // global.APP_TRAY = null;
21
+ //this.preferences = {};
22
+ }
23
+
24
+ /**
25
+ * 生成端口
26
+ */
27
+ async createPorts () {
28
+ const ipcPort = await getPort();
29
+ const eggPort = this.config.env === 'prod' ? await getPort() : this.config.egg.port;
30
+ this.config.egg.port = eggPort;
31
+ process.env.EE_IPC_PORT = ipcPort;
32
+ process.env.EE_EGG_PORT = eggPort;
33
+ this.coreLogger.info('[ee-core:EeApp] [createPorts] ipc port:', ipcPort);
34
+ this.coreLogger.info('[ee-core:EeApp] [createPorts] egg port:', eggPort);
35
+
36
+ // 更新db配置
37
+ this.getCoreDB().setItem('ipc_port', ipcPort);
38
+ this.getCoreDB().setItem('config', this.config);
39
+ }
40
+
41
+ /**
42
+ * 启动通信模块
43
+ */
44
+ startSocket () {
45
+ const socket = require('./socket/start');
46
+ socket(this);
47
+ }
48
+
49
+ /**
50
+ * 创建electron应用
51
+ */
52
+ async createElectronApp () {
53
+ const self = this;
54
+ await this.limitOneWindow();
55
+
56
+ app.on('second-instance', (event) => {
57
+ if (self.electron.mainWindow) {
58
+ if (self.electron.mainWindow.isMinimized()) {
59
+ self.electron.mainWindow.restore();
60
+ }
61
+ self.electron.mainWindow.focus()
62
+ }
63
+ })
64
+
65
+ app.whenReady().then(() => {
66
+ self.createWindow();
67
+ app.on('activate', function () {
68
+ if (BrowserWindow.getAllWindows().length === 0) {
69
+ self.createWindow();
70
+ }
71
+ })
72
+ })
73
+
74
+ app.on('window-all-closed', function () {
75
+ if (process.platform !== 'darwin') {
76
+ self.coreLogger.info('[Appliaction] [initialize] window-all-closed quit');
77
+ self.appQuit();
78
+ }
79
+ })
80
+ }
81
+
82
+ /**
83
+ * 创建应用主窗口
84
+ */
85
+ async createWindow () {
86
+ const winOptions = this.config.windowsOption;
87
+ this.electron.mainWindow = new BrowserWindow(winOptions);
88
+
89
+ // DevTools
90
+ if (!app.isPackaged && this.config.openDevTools) {
91
+ this.electron.mainWindow.webContents.openDevTools();
92
+ }
93
+
94
+ // 隐藏菜单
95
+ if (this.config.openAppMenu) {
96
+ Menu.setApplicationMenu(null);
97
+ }
98
+
99
+ this.loadRemoreWeb();
100
+
101
+ this.loadingView(winOptions);
102
+
103
+ await this.windowReady();
104
+
105
+ await this.loderPreload();
106
+
107
+ await this.startEggServer(this.config.egg);
108
+ }
109
+
110
+ /**
111
+ * 加载远程网址
112
+ */
113
+ loadRemoreWeb () {
114
+ const remoteConfig = this.config.remoteUrl;
115
+ if (remoteConfig.enable) {
116
+ this.loadMainUrl(remoteConfig.url);
117
+ }
118
+ }
119
+
120
+ /**
121
+ * 加载已经实现的功能
122
+ */
123
+ async loadPreference () {
124
+ const preferences = require('./preferences');
125
+ return await preferences(this);
126
+ }
127
+
128
+ /**
129
+ * 创建egg服务
130
+ */
131
+ async startEggServer (options) {
132
+ // egg服务是否开启
133
+ if (this.config.egg.enable == false) {
134
+ return;
135
+ }
136
+
137
+ this.coreLogger.info('[ee-core:EeApp] [startServer] options', options);
138
+ const protocol = 'http://';
139
+ let startRes = null;
140
+ let url = null;
141
+
142
+ if (this.config.env === 'prod') {
143
+ url = protocol + options.hostname + ':' + options.port
144
+ } else {
145
+ const developmentModeConfig = this.config.developmentMode;
146
+ const selectMode = developmentModeConfig.default;
147
+ const modeInfo = developmentModeConfig.mode[selectMode];
148
+ url = protocol + modeInfo.hostname + ':' + modeInfo.port;
149
+ }
150
+ this.coreLogger.info('[ee-core:EeApp] frontend server :', url)
151
+ startRes = await this.startEgg(options).then((res) => res, (err) => err);
152
+ this.coreLogger.info('[ee-core:EeApp] [startServer] egg startRes:', startRes)
153
+ if (startRes === 'success') {
154
+ // 是否加载远程网址
155
+ const remoteConfig = this.config.remoteUrl;
156
+ if (remoteConfig.enable) {
157
+ return;
158
+ }
159
+ this.loadMainUrl(url);
160
+ }
161
+
162
+ app.relaunch();
163
+ }
164
+
165
+ /**
166
+ * 加载loading页面
167
+ */
168
+ loadingView (winOptions) {
169
+ const remoteConfig = this.config.remoteUrl;
170
+ if (remoteConfig.enable) {
171
+ return;
172
+ }
173
+ const self = this;
174
+ const loadingBrowserView = new BrowserView();
175
+ this.electron.mainWindow.setBrowserView(loadingBrowserView);
176
+ loadingBrowserView.setBounds({
177
+ x: 0,
178
+ y: 0,
179
+ width: winOptions.width,
180
+ height: winOptions.height
181
+ });
182
+
183
+ // loading html
184
+ const loadingHtml = path.join('file://', this.config.homeDir, 'public', 'html', 'loading.html');
185
+ loadingBrowserView.webContents.loadURL(loadingHtml);
186
+ this.logger.info('loadingHtml:', loadingHtml);
187
+
188
+ this.electron.mainWindow.webContents.on('dom-ready', async (event) => {
189
+ self.electron.mainWindow.removeBrowserView(loadingBrowserView);
190
+ });
191
+ }
192
+
193
+ /**
194
+ * 加载主页面
195
+ */
196
+ loadMainUrl (url) {
197
+ this.electron.mainWindow.loadURL(url);
198
+ }
199
+
200
+ /**
201
+ * egg
202
+ */
203
+ startEgg (argv) {
204
+ const startCluster = require('egg-cluster').startCluster;
205
+
206
+ let homeDir = this.homeDir;
207
+ argv.baseDir = homeDir;
208
+ argv.framework = path.join(homeDir, 'node_modules', 'egg');
209
+
210
+ const appName = this.config.name;
211
+ argv.title = argv.title || `egg-server-${appName}`;
212
+
213
+
214
+ // normalize env
215
+ // 目前没有用到,不用修改;想要修改的话,区分打包前后的路径?
216
+ // env.HOME = HOME; // 这个home不能修改,因为自动升级功能会用到(win没有问题,mac有权限问题)
217
+ //env.NODE_ENV = 'production';
218
+
219
+ // 更新缓存配置
220
+ this.getCoreDB().setItem('config', this.config);
221
+
222
+ const ignoreKeys = [ '_', '$0', 'env', 'daemon', 'stdout', 'stderr', 'timeout', 'ignore-stderr', 'node' ];
223
+ const clusterOptions = this.stringify(argv, ignoreKeys);
224
+ const options = JSON.parse(clusterOptions);
225
+
226
+ return new Promise((resolve, reject) => {
227
+ startCluster(options, function(){
228
+ resolve('success');
229
+ });
230
+ });
231
+ }
232
+
233
+ /**
234
+ * 限制一个窗口
235
+ */
236
+ async limitOneWindow () {
237
+ const gotTheLock = app.requestSingleInstanceLock();
238
+ if (!gotTheLock) {
239
+ await this.appQuit();
240
+ }
241
+ }
242
+
243
+ /**
244
+ * electron app退出
245
+ */
246
+ async appQuit () {
247
+ await this.beforeClose();
248
+ this.electron.mainWindow.destroy();
249
+ app.quit();
250
+ }
251
+
252
+ /**
253
+ * 预加载模块
254
+ */
255
+ async loderPreload () {
256
+ let filepath = this.loader.resolveModule(path.join(this.config.baseDir, 'preload', 'index'));
257
+ if (!filepath) return;
258
+ const fileObj = this.loader.loadFile(filepath);
259
+ if (is.function(fileObj) && !is.generatorFunction(fileObj) && !is.asyncFunction(fileObj)) {
260
+ fileObj();
261
+ } else if (is.asyncFunction(fileObj)) {
262
+ await fileObj();
263
+ }
264
+ }
265
+
266
+ /**
267
+ * 序列化参数
268
+ */
269
+ stringify(obj, ignore) {
270
+ const result = {};
271
+ Object.keys(obj).forEach(key => {
272
+ if (!ignore.includes(key)) {
273
+ result[key] = obj[key];
274
+ }
275
+ });
276
+ return JSON.stringify(result);
277
+ }
278
+
279
+ /**
280
+ * 捕获异常
281
+ */
282
+ catchLog () {
283
+ const self = this;
284
+ process.on('uncaughtException', function(err) {
285
+ self.logger.error(err);
286
+ });
287
+ }
288
+
289
+ /**
290
+ * 主应用窗口已经创建
291
+ */
292
+ async windowReady () {
293
+ // do some things
294
+
295
+ }
296
+
297
+ /**
298
+ * app关闭之前
299
+ */
300
+ async beforeClose () {
301
+ // do some things
302
+
303
+ }
304
+ }
305
+
306
+ module.exports = EeApp;
package/lib/helper.js ADDED
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ const is = require('electron-is');
4
+ const { app } = require('electron');
5
+
6
+ /**
7
+ * application quit
8
+ *
9
+ * @return {undefined}
10
+ */
11
+ exports.appQuit = function () {
12
+ MAIN_WINDOW.destroy();
13
+ app.quit();
14
+ }
15
+
16
+ /**
17
+ * get Platform
18
+ *
19
+ * @return {Object}
20
+ */
21
+ exports.getPlatform = function () {
22
+ let platform = null;
23
+ let arch = null;
24
+ if (is.windows()) {
25
+ platform = 'windows';
26
+ } else if (is.macOS()) {
27
+ platform = 'macOS';
28
+ } else if (is.linux()) {
29
+ platform = 'linux';
30
+ } else {
31
+ platform = 'other';
32
+ }
33
+
34
+ if (is.x86()) {
35
+ arch = '32';
36
+ } else if (is.x64()) {
37
+ arch = '64';
38
+ } else if (process.arch == 'arm') {
39
+ arch = 'arm32';
40
+ } else if (process.arch == 'arm64') {
41
+ arch = 'arm64';
42
+ } else {
43
+ arch = 'other';
44
+ }
45
+
46
+ const platfromObj = {
47
+ platform: platform,
48
+ arch: arch
49
+ };
50
+
51
+ return platfromObj;
52
+ }