电子标签部署
# 简介
终极方案是,在Win部署一套完整的标签项目;BS模式部署;
Linux只是CS模式下的备用方案;
# Docker方案部署
# 脚本
Dockerfile
FROM node:10.14-alpine
RUN apk --update add tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& apk del tzdata
RUN apk add --update --no-cache make gcc g++ \
curl bash tree vim git openssh build-base \
libffi-dev openssl-dev bzip2-dev zlib-dev readline-dev sqlite-dev \
linux-headers \
&& rm -r /usr/share/man \
&& rm -r /var/cache/apk/*
# 换成样式生产执行文件后,可以不用安装python3及相关依赖;
ENV PYTHONUNBUFFERED=1
# Install python3 & pip3
RUN apk add --no-cache python python-dev
rm -r /root/.cache
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN npm i --registry=https://registry.npm.taobao.org --production
# RUN npm i --registry=https://registry.npm.taobao.org
COPY . .
EXPOSE 7082
CMD npm run docker
# CMD npm run dev
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
兼容树莓派修改基容器:【最后完整方案是:直接用树莓派部署
,用浏览器访问操作管理】
FROM arm32v7/node:10.18.0-alpine3.11
#xxx
# Install python3 & pip3
RUN apk add --no-cache python python-dev python3 python3-dev python3-setuptools \
linux-headers build-base ca-certificates && \
python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools && \
pip3 install --no-cache Pillow numpy PyCRC qrcode argparse && \
if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi && \
rm -r /root/.cache
RUN pip3 install --no-cache -Iv numpy==1.17.1
RUN pip3 install --no-cache -Iv PyCRC==1.21
RUN pip3 install --no-cache -Iv qrcode==6.1
RUN pip3 install --no-cache argparse
RUN pip3 install --no-cache -Iv Pillow==6.1.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
build.sh
#!/bin/bash
# 使用说明:
# 启动脚本:sudo bash ./docker/build.sh
sudo docker build -t etag -f docker/Dockerfile .
2
3
4
5
docker-compose.yml
version: '2.2'
services:
redis:
image: redis:5-alpine
volumes:
- /srv/etag/redis/data:/data
network_mode: host
restart: always
mysql:
image: mysql:5.7.6
network_mode: host
restart: always
etag:
depends_on:
- redis
- mysql
image: etag
network_mode: host
volumes:
- /srv/etag/config/config.json:/usr/src/app/database/config.json
- /srv/etag/config/config.prod.js:/usr/src/app/config/config.prod.js
- /srv/etag/logs:/usr/src/app/logs
- /srv/etag/public:/usr/src/app/public
restart: always
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
install.sh
#!/bin/bash
# 使用说明:
# 启动脚本:sudo bash ./docker/start.sh
sudo mkdir -p /srv/etag/config/
sudo mkdir -p /srv/etag/mysql/
sudo cp -r ./docker/config/ /srv/etag/
sudo cp -r ./docker/mysql/init/ /srv/etag/mysql/
sudo docker-compose -p etag-compose -f docker/docker-compose.yml stop
sudo docker-compose -p etag-compose -f docker/docker-compose.yml rm
sudo docker-compose -p etag-compose -f docker/docker-compose.yml up -d
2
3
4
5
6
7
8
9
10
11
12
start.sh
#!/bin/bash
# 使用说明:
# 启动脚本:sudo bash ./docker/start.sh
sudo docker-compose -p etag-compose -f docker/docker-compose.yml restart
2
3
4
5
stop.sh
#!/bin/bash
# 使用说明:
# 启动脚本:sudo bash ./docker/stop.sh
sudo docker-compose -p etag-compose -f docker/docker-compose.yml stop
2
3
4
5
# 各平台处理
# Linux环境
启动及管理
sudo bash ./docker/build.sh // 可以配合阿里云镜像加速打镜像;
sudo bash ./docker/install.sh
#sudo bash ./docker/start.sh
#sudo bash ./docker/stop.sh
2
3
4
# Win环境
1: 考虑过直接在win环境下测试,发送udp在win不兼容,要设置当 exclusive
被设为 true
时,该句柄将不会被共享,不能端口公用;由于这个问题就不能充分使用cluster模式;目前的方案还是设置cluster为一个进程;
2: 发现有部分Win系统不能安装Docker,最后的方案调整为在Win安装Ubuntu虚拟机;虚拟机(Virtual Machine)指通过软件 (opens new window)模拟的具有完整硬件 (opens new window)系统功能的、运行在一个完全隔离 (opens new window)环境中的完整计算机系统 (opens new window)。并设置网络模式为host模式,确保udp,tcp可以被同一网段下的标签识别到;
# Pkg方案部署
先用pkg把项目做成可执行程序,再用electron包装成安装程序,再生成安装图标,做成BS架构的桌面程序;
选择pkg4.3.8版本,最新版本对应的node版本处理socket.io有问题;最后选择降级版本处理;pkgv4.3.8对应node v8 8.11.3版本;
# 配置
config.prod.js
const logDir = 'pkg'
config.rundir = process.cwd() + '/run'
config.logger = {
dir: path.join(process.cwd(), 'logs', logDir),
// level: 'INFO',
// consoleLevel: 'NONE'
level: 'DEBUG',
consoleLevel: 'DEBUG'
}
config.static = {
prefix: '',
dir: [process.cwd() + '/public', process.cwd() + '/public/web']
}
2
3
4
5
6
7
8
9
10
11
12
13
package.json
"bin": "pkg.js",
"pkg": {
"scripts": [
"./app/**/*.js",
"./config/**/*.js",
"./lib/**/*.js",
"./agent.js",
"./app.js"
],
"assets": [
"./app/public/**/*",
"./public/",
"./node_modules/**/*",
"./lib//**/*"
]
},
"scripts": {
"build": "pkg . -t node8-win-x64 --out-path ./pkg -d",
"build:linux": "pkg . -t node8-linux-x64 --out-path ./pkg",
"build:mac": "pkg . -t node8-mac-x64 --out-path ./pkg -d",
"docker": "egg-scripts start --title=egg-server-etag --sticky",
"start": "egg-scripts start --daemon --title=egg-server-etag --sticky",
"stop": "egg-scripts stop --title=egg-server-etag",
"dev": "egg-bin dev --sticky --port 7082",
"debug": "egg-bin debug",
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 要点:
# 动态config
内部读取外部的配置信息:ip及数据库相关
方式一:config.prod.js启动读取外部conf.json配置;
方式二:利用configWillLoad周期来做,利用周期读取外部config.js,然后替换config/config.prod.js内容;
const conf = fs.readFileSync(path.join('./config/conf.json'), 'utf8')
const { ip,
dbUsr, dbPwd, dbName, dbHost, dbPort,
redisHost, redisPort, redisPwd
} = JSON.parse(conf)
const commonRed = {
host: redisHost || '127.0.0.1',
port: redisPort || 6379,
password: redisPwd || null
}
2
3
4
5
6
7
8
9
10
11
configWillLoad() {
let customConfig = require(process.cwd() + '/config.js');
this.app.config.sequelize.host = customConfig.dbHost;
}
2
3
4
# C++模块的依赖处理
按照提示有两种方案;
Error: [egg-core] load file: C:\snapshot\etag-adm\agent.js, error: Cannot find module'./build/Release/crc16'
1) If you want to compile the package/file into executable, please pay attention to compilation warnings and specify a literal in 'require' call.
2) If you don't want to compile the package/file into executable and want to 'require' it from filesystem (likely plugin), specify an absolute path in 'require' call using process.cwd() or process.execPath.
2
3
目前用的是第二种方案;方便调试测试用;
let CRC16
if (process.env.NODE_ENV === 'production') {
CRC16 = require(process.cwd() + '/build/Release/crc16.node')
} else {
CRC16 = require('crc16')
}
2
3
4
5
6
# 启动测试,确认exe是否成功
etag.bat
记得用脚本知道哪个参数;
@echo off
rem echo "start etag workers with 1 test"
start cmd /k "etag.exe start --title=egg-server-etag --sticky --workers=1"
2
3
# 各平台处理
# Linux环境
pkg.js
'use strict'
const fs = require('fs')
const rootDir = '/snapshot/'
const baseDir = rootDir + fs.readdirSync(rootDir)[0]
const startIndex = process.argv.indexOf('start')
if (startIndex > -1) {
process.argv = [].concat(
process.argv.slice(0, startIndex + 1),
baseDir,
process.argv.slice(startIndex + 1)
)
}
//console.log(process.argv)
require('./node_modules/egg-scripts/bin/egg-scripts.js')
2
3
4
5
6
7
8
9
10
11
12
13
14
# Win环境
const rootDir = 'c:\\snapshot\\' //跟程序放的盘符有关;
const baseDir = rootDir + fs.readdirSync(rootDir)[0]
2
最后 process.argv
为: 主要是配置这个:'c:\snapshot\etag-adm',
[ 'C:\\samy\\code\\etag-cloud\\etag-adm\\pkg\\etag.exe',
'C:\\snapshot\\etag-adm\\pkg.js',
'start',
'c:\\snapshot\\etag-adm',
'--title=egg-server-etag',
'--sticky',
'--workers=1' ]
2
3
4
5
6
7
# Electron包装
把exe安装文件,打包成eletron安装程序,安装后就是启动了后台服务器及设置桌面,用户点击桌面图标即可进入程序;以及后面方便升级安装程序;
# 要点
# 用Electron启动etag.exe文件
exeFile启动,并指定cwd
# 监听是否完全启动
监听是否完全启动,再加载etag.exe中的后台管理界面
方式一:定时请求成功判断,再移除定时器;方式二:多进程通讯;
function startWebServer () {
let prc = execFile(webServer, ['start', '--sticky', '--workers=1'], { cwd: `${process.cwd()}/server`, maxBuffer: 50 * 1000 * 1024 })
//xxxxx
}
function createWindow () {
//xxxxx
const interval = setInterval(function (){
http.get(indexUrl, function (res) {
if (res.statusCode === 200) {
mainWindow.loadURL(indexUrl)
clearInterval(interval)
}
}).on("error", function (err){})
}, 2000)
}
app.on('ready', function () {
setupLogger()
startWebServer()
createWindow()
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 自动化脚本(gulp+jenkins)
模拟的步骤
- 把后端项目打包成etag.exe文件;
- 拷贝etag.exe和public/web的后台管理到etag-install项目server目录下;
- 再etag-install目录下打包不同平台win32/64安装程序;
etag-adm/package.json
, etag-install/package.json
的调整;
"build": "npx pkg . -t node10-win-x64 --out-path ./pkg/x64",
"build_64": "cd node_modules/crc16 & node-gyp clean configure build --verbose --arch=x64 & cd ../../ & pkg . -t node10-win-x64 --out-path ./pkg/x64",
"build_32": "cd node_modules/crc16 & node-gyp clean configure build --verbose --arch=ia32 & cd ../../ & pkg . -t node10-win-x86 --out-path ./pkg/ia32",
"build_32": "npm run del && electron-builder -w --ia32",
"build_64": "npm run del && electron-builder -w --x64",
2
3
4
5
6
gulp实现:
var gulp = require('gulp');
var exec = require('child_process').exec;
var path = require('path');
var del = require('del');
var fs = require('fs-extra');
var root = path.join(__dirname, '../');
var etag_adm = path.join(root, 'etag-adm');
var etag_web = path.join(root, 'etag-adm/web');
var etag_install = __dirname;
var server_dir = path.join(root, '/etag-install/server');
var binary = [
{
source: etag_adm,
target: server_dir,
file: 'node_modules/crc16/build/Release/crc16.node',
targetFile: "build/Release/crc16.node",
}
];
function runCMD(cmd) {
return new Promise(function (resolve, reject) {
exec(cmd, function (err, stdout, stderr) {
if (err) {
reject(err);
}
console.log(stdout);
resolve(stdout);
});
});
}
function writeConfig() {//通过jenkins动态设置host的地址;
// let args = {};
// for (let i = 3; i < process.argv.length; i++) {
// let a = process.argv[i].split('=');
// if (a[0] == '--host') {
// args.host = a[1];
// }
// }
let config = {
"ip": "192.168.11.158",
"dbUsr": "",
"dbPwd": "",
"dbName": "etag",
"dbHost": "127.0.0.1",
"dbPort": "3306",
"redisHost": "127.0.0.1",
"redisPort": "6379",
"redisPwd": null
}
// if (args.host) {
// config.HOST = `http://${args.host}`;
// }
let file = `${server_dir}/config/conf.json`;
fs.ensureFileSync(file);
fs.writeFileSync(file, JSON.stringify(config));
}
gulp.task('etag_web', function () {
process.chdir(etag_web);
// let args = {};
// for (let i = 3; i < process.argv.length; i++) {
// let a = process.argv[i].split('=');
// if (a[0] == '--host') {
// args.host = a[1];
// }
// }
del.sync(['dist/**', `${etag_adm}/public/web/*`], {force: true});
// return runCMD(`npm run build ${args.host}`)
return runCMD(`npm run build`)
.then(() => {
return gulp.src(`${etag_adm}/public/web/*`)
.pipe(gulp.dest(`${etag_install}/server/public/web`));
});
});
gulp.task('etag_adm:build_32', function () {
console.log('build etag_adm --ia32');
process.chdir(etag_adm);
return runCMD('npm run build_32');
});
gulp.task('etag_adm:build_64', function () {
console.log('build etag_adm --x64');
process.chdir(etag_adm);
return runCMD('npm run build_64');
});
gulp.task('copy_binary:64', function () {
console.log('copy binary 64');
del.sync('./server/node_modules');
binary.forEach(item => {
let sourceFile = path.join(item.source, item.file);
let targetFile = path.dirname(path.join(item.target, item.targetFile));
gulp.src([sourceFile])
.pipe(gulp.dest(targetFile));
});
writeConfig();
var etag_adm_binary = path.join(etag_adm, '/pkg/x64/etag.exe');
return gulp.src([etag_adm_binary])
.pipe(gulp.dest(server_dir));
});
gulp.task('copy_binary:32', function () {
console.log('copy binary 32');
del.sync('./server/node_modules');
binary.forEach(item => {
let sourceFile = path.join(item.source, item.file);
let targetFile = path.dirname(path.join(item.target, item.targetFile));
gulp.src([sourceFile])
.pipe(gulp.dest(targetFile));
});
writeConfig();
var etag_adm_binary = path.join(etag_adm, '/pkg/ia32/etag.exe');
return gulp.src([etag_adm_binary])
.pipe(gulp.dest(server_dir));
});
gulp.task('etag_install:build_32', function () {
process.chdir(etag_install);
return runCMD('npm run build_32')
.then(() => {
return gulp.src(['build/win_ia32/*', '!win_ia32-unpacked'])
.pipe(gulp.dest('./output/win_ia32'));
});
});
gulp.task('etag_install:build_64', function () {
process.chdir(etag_install);
// del.sync(['build/*', '!build', '!build/icons', '../output/x64/*'] , {force: true})
return runCMD('npm run build_64')
.then(() => {
return gulp.src(['build/win_x64/*', '!win-x64-unpacked'])
.pipe(gulp.dest('./output/win_x64'));
});
});
gulp.task('build:build_32', gulp.series('etag_adm:build_32', 'copy_binary:32', 'etag_install:build_32'));
gulp.task('build:build_64', gulp.series('etag_adm:build_64', 'copy_binary:64', 'etag_install:build_64'));
gulp.task('build', gulp.series('etag_web', 'build:build_32', 'build:build_64'));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
jenkins直接配置执行etag_install.bat
即可;
自动化打包示例;
echo off
cd etag-adm/web
call npm i
call npm run build
REM mkdir ..\..\etag-adm\public\web
REM xcopy /s/y dist\* ..\..\etag-adm\public\web\
xcopy /s/y ..\public\web\* ..\..\etag-install\server\public\web\
cd ../..
cd etag-adm
call npm i
call npm run build_64
xcopy /s/y \pkg\x64\etag.exe ..\etag-install\server\
mkdir ..\etag-install\server\node_modules\crc16\build\Release
xcopy /s/y node_modules\crc16\build\Release\crc16.node ..\etag-install\server\build\Release\
cd ..
cd etag-install
call npm i
call npm run build_64
xcopy /s/y .\build\win_x64\latest.yml .\output\win_x64\
xcopy /s/y .\build\win_x64\*.*.exe .\output\win_x64\
xcopy /s/y .\build\win_x64\*.*.exe.blockmap .\output\win_x64\
xcopy /s/y .\build\win_x64\builder-effective-config.yaml .\output\win_x64\
cd ..
cd etag-adm
call npm i
call npm run build_32
xcopy /s/y \pkg\ia32\etag.exe ..\etag-install\server\
mkdir ..\etag-install\server\node_modules\crc16\build\Release
xcopy /s/y node_modules\crc16\build\Release\crc16.node ..\etag-install\server\build\Release\
cd ..
cd etag-install
call npm i
call npm run build_32
xcopy /s/y .\build\win_ia32\latest.yml .\output\win_ia32\
xcopy /s/y .\build\win_ia32\*.*.exe .\output\win_ia32\
xcopy /s/y .\build\win_ia32\*.*.exe.blockmap .\output\win_ia32\
xcopy /s/y .\build\win_ia32\builder-effective-config.yaml .\output\win_ia32\
cd ..
pause
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 数据库初始化
bat脚本处理;数据表及初始化帐号;
init.sql
通过sexualize-cli迁移出来的数据;表结构及默认管理员帐号数据;
SET NAMES utf8mb4;
-- set character_set_server=utf8mb4;
-- set collation_server=utf8mb4_unicode_ci;
-- DROP DATABASE if exists etag;
CREATE DATABASE IF NOT EXISTS etag CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SHOW DATABASEs;
USE etag;
SELECT @@character_set_database, @@collation_database;
-- xxxxx
2
3
4
5
6
7
8
9
init.bat
@echo off
chcp 65001
set MYSQL_BIN="C:\Program Files\MySQL\MySQL Server 5.7\bin\"
set HOST=xx
set USR=xx
set PWD=xx
set NAME=xx
echo ###正在创建及初始化数据库###
:begin
%MYSQL_BIN%mysql -h%HOST% -u%USR% -p%PWD% < init.sql
echo ###创建及初始化数据库完毕###
PAUSE
exit
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 处理异步多进程
1:Linux/Mac生产模式下,控制队列数量为路由器的数量,可通过host来控制创建;放在agent.js处理,确保一个;
2:因要部署在Win, 对udp 句柄有限制,不能共享,目前方案控制workers=1;后期待解决,获取替换到Linux/树莓派环境下部署,但是要确保统一局网;
# 问题
# 由于项目涉及到通过python脚本生产标签样式,有安装python环境及依赖,不方便跨平台处理,尤其是安装Pillow依赖库时,有部分平台不兼容;
最后的调整方案是,直接把生产样式包的脚本打包成可执行程序,js直接调用执行命令,生成可执行文件即可;
.\stylegen.exe -sn 22 -u 22 -o 22 -l 22 -n 22 -qr 22 --out test.bin
再外部执行时,指定子进程的cwd处理;execSync(cmd, {cwd: styleGenDir})
function genStyle (data) {
const dir = 'public/adm/products/style'
fse.ensureDirSync(dir)
//xxxxx
let cmd
if (os.platform() === 'win32') {
const styleGenDir = './stylegen'
cmd = `stylegen.exe ${para} --out ${styleWin}`
execSync(cmd, {cwd: styleGenDir})
} else {
cmd = `python3 ${script} ${para} -sf ${styleJson} --out ${style}`
execSync(cmd)
}
// console.log(cmd)
return /.*?public\/(.*)/.exec(style)[1]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
在Mac打包vue的dist文件前端界面在Win不兼容,导致不能动态显示设备在线状态
解决方案是,直接在Win也编译前端界面项目;
资源处理
config.static = {
prefix: '',
dir: [process.cwd() + '/public', process.cwd() + '/public/web']
}
2
3
4
# 文件上传在Win的兼容处理,中间件处理;
路径兼容win平台路径;用path.join(); 路径上避免处理不兼容的路径设置;
// const file = middleware.file(public/uploads/${module}
)
const name = path.basename(file.filepath)
const size = await ctx.helper.fileSize(file.filepath)
const buf = fse.readFileSync(file.filepath)
const md5Str = md5(buf)
const dirNew = path.join(dir, name.replace(/(.*\/)*([^.]+).*/ig, '$2'))
fse.ensureDirSync(dirNew)
const dest = path.join(dirNew, file.filename)
fse.moveSync(file.filepath, dest)
file.filepath = dest // 绝对路径
file.name = file.filename // 存储名字
file.destination = /.*?public(.*)/.exec(dirNew)[1] // 相对文件夹
file.url = /.*?public(.*)/.exec(dest)[1] // 相对文件路径
file.size = size
file.md5 = md5Str
file.format = path.extname(file.filepath).replace(/^./, '')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 移除掉Node.js 性能平台监控
注意: Node.js 性能平台 (alinode) 目前仅支持 macOS 和 Linux,不支持 Windows。
报错 ERROR 16276 nodejs.ENOENTError: spawn D:\samy\etag\node_modules\commandx\get_processes_count ENOENT
配置
exports.alinode = {
enable: process.platform !== 'win32',
package: 'egg-alinode'
}
config.alinode = {
appid: 'xx',
secret: 'xx',
agentidMode: 'IP'
}
2
3
4
5
6
7
8
9
10
# 设置win系统的防火墙,关闭或者设置为通知模式或者指定电子标签程序开放
因使用udp监听标签上报功能,涉及到端口通讯。需要开发防火墙功能;要不然监听不到标签上报的数据;
# 版本升级后,pubic文件夹覆盖掉,加载外部配置及前端界面设置
应用数据信息,因考虑放在外部文件夹;os.homedir()
处理;
config.default.js
'use strict'
const os = require('os')
const path = require('path')
const fse = require('fs-extra')
const isWin = process.platform === 'win32'
function loadConf(){
const confPath = path.join(process.cwd(), 'config', 'conf.json')
const webPath = path.join(process.cwd(), 'public', 'web')
let conf = require(confPath)
if (isWin) {
const homeDir = path.join(os.homedir(), '.etag-install')
const homeConfDir = path.join(homeDir, 'config')
fse.ensureDirSync(homeConfDir)
global.homeDir = homeDir
const homeConfPath = path.join(homeConfDir, 'conf.json')
const homeWebPath = path.join(homeDir, 'public', 'web')
if (!fse.existsSync(homeConfPath)) {
fse.copySync(confPath, homeConfPath)
}
if (!fse.existsSync(homeWebPath)) {
fse.copySync(webPath, homeWebPath)
}
conf = require(homeConfPath)
}
return conf
}
module.exports = appInfo => {
const config = exports = {}
config.middleware = ['errorHandle']
let conf = loadConf()
const {ip, filesDir,
dbUsr, dbPwd, dbName, dbHost, dbPort,
redisHost, redisPort, redisPwd
} = conf
config.static = {
prefix: '',
dir: [isWin? `${global.homeDir}/public`:`${process.cwd()}/public`]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
对应还要处理的,文件上传的路径及生成样式的路径修改;
//app/router/product.js
let filePath = `./public/uploads/${module}`
if (process.platform === 'win32') {
filePath = `${global.homeDir}/${filePath}`
}
const file = middleware.file(filePath)
//app/model/product.js
function genStyle (data) {
let dir = 'public/adm/products/style'
if (process.platform === 'win32') {
dir = `${global.homeDir}/${dir}`
}
fse.ensureDirSync(dir)
const script = './lib/python/stylegen.py'
const style = `./${dir}/${data._id}.bin`
const styleWin = `${dir}/${data._id}.bin`
const styleJson = `./lib/python/style.json`
const para = `-sn ${data.name} -u ${data.unit} -o ${data.origin} -l ${data.level} -n ${data.code} -qr ${data.code}` // -im yu.jpg
let cmd
if (process.platform === 'win32') {
const styleGenDir = './stylegen'
cmd = `stylegen.exe ${para} --out ${styleWin}`
execSync(cmd, {cwd: styleGenDir})
} else {
cmd = `python3 ${script} ${para} -sf ${styleJson} --out ${style}`
execSync(cmd)
}
console.log(cmd)
return /.*?public\/(.*)/.exec(style)[1]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 兼容树莓派系统,替换了crc16库为crc16纯js库,因crc16库不兼容arm系统架构,编译部署不了
修改后,便于自动化脚本,可以做简化出了,不用每次打包重新编译crc库及拷贝crc16库的操作;