aaden-cli 1.6.109-rc.0 → 1.6.109
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.
- package/AadenDeploy/Utils/enableNgrok.sh +21 -19
- package/AadenDeploy/Utils/fixCronJob.sh +5 -4
- package/AadenDeploy/aadensetup.sh +217 -163
- package/AadenDeploy/checkDeviceId.sh +104 -0
- package/AadenDeploy/setDeviceId.sh +130 -0
- package/README.md +2 -1
- package/dist/index.js +28 -7
- package/dist/patch/202608190700removeGitDoUpdateCron.sh +39 -0
- package/index.js +27 -6
- package/package.json +2 -2
- package/patch/202608190700removeGitDoUpdateCron.sh +39 -0
- package/dist/patch/202304051415FixDatevMemory.sh +0 -19
- package/patch/202304051415FixDatevMemory.sh +0 -19
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
# 和 aaden-cli 其他地方一样用 -S 喂密码:aaden 没有免密 sudo、又没有终端时(被装机脚本或 set-device-id 调用)裸 sudo 会直接失败
|
|
3
|
+
sudoS() { echo "Innerken322." | sudo -S -p '' "$@"; }
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
sudoS npm config set prefix /usr/local
|
|
4
6
|
cd || exit
|
|
5
|
-
|
|
7
|
+
sudoS rm -rf ngrok
|
|
6
8
|
axel -n 8 "https://aaden-storage.s3.eu-central-1.amazonaws.com/ngrok"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
sudoS cp -f ngrok /etc/aaden/ngrok
|
|
10
|
+
sudoS chmod +x /etc/aaden/ngrok
|
|
9
11
|
|
|
10
12
|
DeviceId=$(cat /var/www/html/Resource/config/config.ini | grep -e DeviceId | cut -d = -f 2 | grep '[1-9]*' | sed 's/"//g')
|
|
11
13
|
aaden-cli update-ngrok-config $DeviceId
|
|
12
14
|
|
|
13
15
|
ServiceFileName=/etc/systemd/system/aaden-ngrok-v3.service
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
sudoS touch $ServiceFileName
|
|
18
|
+
sudoS chmod 777 $ServiceFileName
|
|
17
19
|
echo -e "
|
|
18
20
|
[Unit]
|
|
19
21
|
Description=Ngrok Service v3 For Aaden
|
|
@@ -29,24 +31,24 @@ ExecStart=/etc/aaden/ngrok -config=/etc/aaden/ngrok-config.yml start-all --log=/
|
|
|
29
31
|
[Install]
|
|
30
32
|
WantedBy=multi-user.target
|
|
31
33
|
" >$ServiceFileName
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
sudoS rm /etc/systemd/system/aaden-ngrok.service
|
|
35
|
+
sudoS rm /etc/systemd/system/aaden-ngrok-2.service
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
sudoS systemctl daemon-reload
|
|
38
|
+
sudoS systemctl start aaden-ngrok-v3.service
|
|
39
|
+
sudoS systemctl enable aaden-ngrok-v3.service
|
|
40
|
+
sudoS systemctl stop aaden-ngrok.service
|
|
41
|
+
sudoS systemctl stop aaden-ngrok-2.service
|
|
42
|
+
sudoS systemctl disable aaden-ngrok.service
|
|
43
|
+
sudoS systemctl disable aaden-ngrok-2.service
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
sudoS service aaden-ngrok-v3 restart
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
ServiceFileName=/etc/avahi/services/aaden.service
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
sudoS touch $ServiceFileName
|
|
51
|
+
sudoS chmod 777 $ServiceFileName
|
|
50
52
|
echo -e "
|
|
51
53
|
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
|
52
54
|
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
|
@@ -59,7 +61,7 @@ echo -e "
|
|
|
59
61
|
</service-group>
|
|
60
62
|
" >$ServiceFileName
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
sudoS service avahi-daemon restart
|
|
63
65
|
|
|
64
66
|
echo "ngrok 修复脚本执行完毕。请直接检查ngrok是否正常开启。如果开启,请无视这里的任何报错。"
|
|
65
67
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
# 和 aaden-cli 其他地方一样用 -S 喂密码:aaden 没有免密 sudo、又没有终端时(被装机脚本或 set-device-id 调用)裸 sudo 会直接失败
|
|
3
|
+
sudoS() { echo "Innerken322." | sudo -S -p '' "$@"; }
|
|
2
4
|
echo 'Cronjob Before Aaden'
|
|
3
5
|
echo "Innerken322." | sudo -S crontab -l -u aaden
|
|
4
6
|
echo 'Cronjob Before Root'
|
|
@@ -15,11 +17,10 @@ echo "* * * * * curl --location --request GET 'http://localhost/PHP/BackendData.
|
|
|
15
17
|
echo "* * * * * curl --location --request GET 'http://localhost/PHP/BackendData.php?op=autoSendMonthSummary'" >>conf
|
|
16
18
|
echo "* * * * * curl --location --request GET 'http://localhost/PHP/ZBon.php?op=autoAddCombinedRecord'" >>conf
|
|
17
19
|
echo "3 * * * * curl --location --request GET 'http://localhost/PHP/writeDETax2024.php'" >>conf
|
|
18
|
-
|
|
19
|
-
echo "@reboot sleep 60 && curl --location -X POST 'http://localhost/PHP/UpdateSelf.php?op=doUpdate'" >>conf
|
|
20
|
+
# 不再写 git doUpdate(59 4 / @reboot):git 通道 2026-08 已停用,后端 doUpdate 直接跳过,后端更新改走 root 的 auto-upgrade → light-update
|
|
20
21
|
echo "*/5 * * * * /usr/local/bin/aaden-cli do-log" >>conf
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
sudoS crontab -u aaden -r
|
|
23
|
+
sudoS crontab -u aaden conf
|
|
23
24
|
echo "Innerken322." | sudo -S rm -f conf
|
|
24
25
|
crontab -l -u aaden
|
|
25
26
|
echo "END Aaden Deploy CONFIG"
|
|
@@ -1,180 +1,234 @@
|
|
|
1
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Aaden 收银机装机:全新的 Ubuntu(或 WSL)→ 可以交付的收银机。
|
|
3
|
+
# aaden-cli install <设备号> (或在 AadenDeploy 目录下 ./aadensetup.sh <设备号>)
|
|
4
|
+
#
|
|
5
|
+
# - 设备号最先问并查云端(checkDeviceId.sh),撞号在装任何东西之前拦下来
|
|
6
|
+
# - 每一步记下退出码和耗时;关键步骤失败就停下;最后做一遍自检,连同每一步的结果作为「出厂安装」事件上报云端
|
|
7
|
+
# - 全部输出另存一份到 /var/log/aaden-setup.log
|
|
8
|
+
# - 可以重跑:数据库已经初始化过就跳过,配置、主机名、/etc/hosts、定时任务都是覆盖写,不会重复追加
|
|
9
|
+
export PATH="/usr/local/bin:$PATH"
|
|
10
|
+
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
+
PW='Innerken322.'
|
|
12
|
+
LOG=/var/log/aaden-setup.log
|
|
13
|
+
WEB=/var/www/html
|
|
14
|
+
BACKEND_SRC=/etc/aaden/updateFiles/backendFiles
|
|
15
|
+
|
|
16
|
+
# 和 aaden-cli 其他地方一样用 -S 从 stdin 喂密码。不能再往 sudoS 的命令里重定向 stdin(密码会被当成内容),
|
|
17
|
+
# 需要重定向时写成 sudoS sh -c '… < 文件'
|
|
18
|
+
sudoS() { echo "$PW" | sudo -S -p '' "$@"; }
|
|
19
|
+
is_wsl() { grep -qi microsoft /proc/version 2>/dev/null; }
|
|
20
|
+
|
|
21
|
+
banner() {
|
|
22
|
+
echo ""
|
|
2
23
|
echo "#######################################################################"
|
|
3
|
-
echo
|
|
24
|
+
echo "# $*"
|
|
4
25
|
echo "#######################################################################"
|
|
5
26
|
}
|
|
6
27
|
|
|
7
|
-
|
|
8
|
-
echo "#######################################################################"
|
|
9
|
-
echo "# Start to configurate aaden! #"
|
|
10
|
-
echo "# V 1.0.0 #"
|
|
11
|
-
echo "#######################################################################"
|
|
12
|
-
echo ""
|
|
13
|
-
sudo add-apt-repository ppa:ondrej/php -y
|
|
28
|
+
banner "Aaden 收银机装机"
|
|
14
29
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
echoWithWait "Installing Lamp...."
|
|
22
|
-
sudo snap install axel
|
|
23
|
-
|
|
24
|
-
sudo apt install apache2 -y
|
|
25
|
-
sudo apt install net-tools -y
|
|
26
|
-
sudo apt install software-properties-common apt-transport-https -y
|
|
27
|
-
echoWithWait "Install PHP7.4"
|
|
28
|
-
|
|
29
|
-
sudo apt install mysql-server -y
|
|
30
|
-
sudo apt install aptitude -y
|
|
31
|
-
sudo apt install curl -y
|
|
32
|
-
sudo aptitude -y install expect
|
|
33
|
-
sudo apt install default-jdk -y
|
|
34
|
-
sudo apt install php7.4 php7.4-common libapache2-mod-php7.4 php7.4-cli -y
|
|
35
|
-
sudo apt install php7.4-xml -y
|
|
36
|
-
sudo apt install php7.4-curl php7.4-mysql php7.4-gd php7.4-zip php7.4-intl php7.4-common php7.4-mbstring -y
|
|
37
|
-
sudo update-alternatives --set php /usr/bin/php7.4
|
|
38
|
-
sudo update-alternatives --set phar /usr/bin/phar7.4
|
|
39
|
-
sudo update-alternatives --set phar.phar /usr/bin/phar.phar7.4
|
|
40
|
-
|
|
41
|
-
sudo systemctl restart apache2
|
|
42
|
-
|
|
43
|
-
echoWithWait "Install Complate"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
sudo apt -y install vim apt-transport-https wget software-properties-common
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
echoWithWait "Install Docker Requirment"
|
|
50
|
-
sudo apt-get install -y \
|
|
51
|
-
apt-transport-https \
|
|
52
|
-
ca-certificates \
|
|
53
|
-
curl \
|
|
54
|
-
gnupg-agent \
|
|
55
|
-
software-properties-common
|
|
56
|
-
|
|
57
|
-
sudo apt update -y
|
|
58
|
-
sudo apt-get install ttyload -y
|
|
59
|
-
|
|
60
|
-
echoWithWait "Deploying ssh"
|
|
61
|
-
|
|
62
|
-
sudo apt-get install openssh-server -y
|
|
63
|
-
|
|
64
|
-
echoWithWait "Installing Pip for python3"
|
|
65
|
-
sudo apt-get install python3-pip -y
|
|
66
|
-
|
|
67
|
-
echoWithWait "Get Requests library for python3"
|
|
68
|
-
python3 -m pip install requests
|
|
69
|
-
|
|
70
|
-
sudo apt-get install unzip -y
|
|
71
|
-
curl -sS https://getcomposer.org/installer -o composer-setup.php
|
|
72
|
-
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
|
73
|
-
sudo composer self-update
|
|
74
|
-
composer -v
|
|
75
|
-
|
|
76
|
-
sudo chmod +x files/getFile.sh
|
|
77
|
-
sudo chmod 777 -R .
|
|
78
|
-
|
|
79
|
-
cd files/ || exit
|
|
80
|
-
./getFile.sh
|
|
81
|
-
cd ..
|
|
82
|
-
|
|
83
|
-
echoWithWait "Configing MYSQL SECURE, only for remote root disable no, else follow it and set to yes, please set the root password as defaultPassword"
|
|
84
|
-
|
|
85
|
-
sudo chmod +x scureSql.sh
|
|
86
|
-
sudo /bin/bash scureSql.sh 'Innerken322.'
|
|
87
|
-
|
|
88
|
-
echoWithWait "Configing Mysql"
|
|
89
|
-
cd /etc/aaden/updateFiles || exit
|
|
90
|
-
|
|
91
|
-
sudo mysql -uroot < backendFiles/new.sql
|
|
92
|
-
|
|
93
|
-
echoWithWait "Uploading PHP Files"
|
|
94
|
-
sudo mv backendFiles/* /var/www/html/
|
|
95
|
-
sudo service apache2 restart
|
|
96
|
-
sudo chown -hR www-data:www-data /var/www/html
|
|
97
|
-
|
|
98
|
-
sudo chmod -R 777 /var/www/html/Resource
|
|
99
|
-
sudo chmod +x /var/www/html/crontab.sh
|
|
100
|
-
|
|
101
|
-
# give excute permission to migrations
|
|
102
|
-
sudo chmod +x /var/www/html/PHP/vendor/bin/phinx
|
|
103
|
-
sudo chmod +x /var/www/html/PHP/vendor/robmorgan/phinx/bin/phinx
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
echoWithWait "Skip App Install"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
echoWithWait "Add Cronjob"
|
|
112
|
-
sudo touch conf
|
|
113
|
-
sudo chmod 777 conf
|
|
114
|
-
echo "* * * * * wget -O /dev/null http://localhost/PHP/AccessLog.php?op=reportStatus" >>conf
|
|
115
|
-
echo "* * * * * /var/www/html/crontab.sh > /dev/null" >>conf
|
|
116
|
-
crontab conf && sudo rm -f conf
|
|
117
|
-
crontab -l
|
|
118
|
-
|
|
119
|
-
echoWithWait "Finishing Install"
|
|
120
|
-
|
|
121
|
-
if [ -z "$1" ]; then
|
|
122
|
-
read -p 'DeviceId: ' DeviceId
|
|
123
|
-
else
|
|
124
|
-
DeviceId=$1
|
|
30
|
+
# ---------------------------------------------------------------- 设备号(最先问,先查撞号)
|
|
31
|
+
DEVICE_ID="$1"
|
|
32
|
+
if [ -z "$DEVICE_ID" ]; then
|
|
33
|
+
read -r -p '设备号: ' DEVICE_ID
|
|
125
34
|
fi
|
|
35
|
+
bash "$DIR/checkDeviceId.sh" "$DEVICE_ID" || exit 1
|
|
36
|
+
DEVICE_ID=$((10#$DEVICE_ID))
|
|
37
|
+
export AADEN_SKIP_DEVICE_CHECK=1 # 后面 set-device-id 不再问第二遍
|
|
38
|
+
|
|
39
|
+
# sudo 凭据先缓存上并一直续着:装机要十几分钟,中途调的 aaden-cli 子命令里还有裸 sudo
|
|
40
|
+
sudoS -v 2>/dev/null || sudo -v || exit 1
|
|
41
|
+
(while kill -0 $$ 2>/dev/null; do sudoS -v 2>/dev/null; sleep 50; done) &
|
|
42
|
+
KEEPALIVE=$!
|
|
43
|
+
trap 'kill $KEEPALIVE 2>/dev/null' EXIT
|
|
44
|
+
|
|
45
|
+
sudoS touch "$LOG" && sudoS chmod 666 "$LOG"
|
|
46
|
+
exec > >(tee -a "$LOG") 2>&1
|
|
47
|
+
echo "$(date '+%F %T') 开始装机,设备号 $DEVICE_ID"
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------- 步骤记录与上报
|
|
50
|
+
STEPS=""
|
|
51
|
+
step() { # step <名字> <命令…>:输出照常打到屏幕,记下退出码和耗时
|
|
52
|
+
local name=$1 start=$SECONDS code
|
|
53
|
+
shift
|
|
54
|
+
banner "$name"
|
|
55
|
+
"$@"
|
|
56
|
+
code=$?
|
|
57
|
+
STEPS="$STEPS $name=$code/$((SECONDS - start))s"
|
|
58
|
+
[ "$code" = 0 ] || echo "✗ $name 失败(退出码 $code),详细输出见 $LOG"
|
|
59
|
+
return "$code"
|
|
60
|
+
}
|
|
126
61
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
sudo usermod -a -G lp aaden
|
|
138
|
-
sudo usermod -a -G lp www-data
|
|
139
|
-
sudo usermod -a -G root aaden
|
|
140
|
-
sudo usermod -a -G root www-data
|
|
141
|
-
sudo usermod -a -G adm aaden
|
|
142
|
-
sudo usermod -a -G sudo aaden
|
|
143
|
-
|
|
144
|
-
echoWithWait "RUN MIGRATION"
|
|
145
|
-
# run migrations
|
|
146
|
-
cd /var/www/html/PHP || exit
|
|
147
|
-
vendor/bin/phinx migrate
|
|
62
|
+
report() { # report <result> <附加内容>:「出厂安装」事件,在云端设备事件里能看到每一步和自检结果
|
|
63
|
+
local content="出厂安装 [${STEPS# }]$2 result:$1"
|
|
64
|
+
python3 - "$DEVICE_ID" "$content" "$(aaden-cli --version 2>/dev/null | tail -n 1)" <<'PY' || echo "(上报云端失败)"
|
|
65
|
+
import json, sys, urllib.request
|
|
66
|
+
device_id, content, version = sys.argv[1:4]
|
|
67
|
+
body = json.dumps({"deviceId": device_id, "content": content, "type": "系统生成", "operator": "aaden-cli v" + version}).encode()
|
|
68
|
+
urllib.request.urlopen(urllib.request.Request("https://cloud-v2.aaden.io/deviceLog/createEvent", body, {"Content-Type": "application/json"}), timeout=10)
|
|
69
|
+
PY
|
|
70
|
+
}
|
|
148
71
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
aaden-cli fix-ngrok
|
|
72
|
+
must() { # 关键步骤:失败就上报并停下,后面的步骤都依赖它
|
|
73
|
+
step "$@" && return 0
|
|
74
|
+
report 1 " 中止于 $1"
|
|
75
|
+
banner "装机中止:$1 失败。修好之后重新运行同一条命令即可,已经完成的部分会跳过或覆盖。日志:$LOG"
|
|
76
|
+
exit 1
|
|
77
|
+
}
|
|
156
78
|
|
|
79
|
+
# ---------------------------------------------------------------- 1. 系统软件
|
|
80
|
+
install_packages() {
|
|
81
|
+
local apt="env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold"
|
|
82
|
+
# 上次装到一半断掉(断电、断网、包脚本失败)留下的半配置状态先收拾掉,否则后面的 apt 全部报错
|
|
83
|
+
sudoS env DEBIAN_FRONTEND=noninteractive dpkg --configure -a
|
|
84
|
+
command -v add-apt-repository >/dev/null || sudoS $apt install software-properties-common || return 1
|
|
85
|
+
# Ubuntu 22.04 起官方源没有 PHP 7.4
|
|
86
|
+
sudoS add-apt-repository -y ppa:ondrej/php || return 1
|
|
87
|
+
sudoS apt-get update || return 1
|
|
88
|
+
sudoS $apt install \
|
|
89
|
+
apache2 mysql-server \
|
|
90
|
+
php7.4 php7.4-common php7.4-cli libapache2-mod-php7.4 \
|
|
91
|
+
php7.4-xml php7.4-curl php7.4-mysql php7.4-gd php7.4-zip php7.4-intl php7.4-mbstring \
|
|
92
|
+
default-jdk openssh-server \
|
|
93
|
+
curl wget unzip axel expect vim net-tools ttyload ca-certificates apt-transport-https \
|
|
94
|
+
python3-requests || return 1
|
|
95
|
+
# 装了别的 PHP 版本时,命令行默认的 php 也指向 7.4
|
|
96
|
+
sudoS update-alternatives --set php /usr/bin/php7.4
|
|
97
|
+
sudoS update-alternatives --set phar /usr/bin/phar7.4 2>/dev/null
|
|
98
|
+
sudoS update-alternatives --set phar.phar /usr/bin/phar.phar7.4 2>/dev/null
|
|
99
|
+
sudoS systemctl restart apache2 2>/dev/null || sudoS service apache2 restart
|
|
100
|
+
}
|
|
101
|
+
must apt install_packages
|
|
157
102
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
103
|
+
# ---------------------------------------------------------------- 2. 后端代码
|
|
104
|
+
download_backend() {
|
|
105
|
+
bash "$DIR/files/getFile.sh" && [ -f "$BACKEND_SRC/package.json" ]
|
|
106
|
+
}
|
|
107
|
+
must download download_backend
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------- 3. 数据库
|
|
110
|
+
setup_database() {
|
|
111
|
+
# 先确保 MySQL 在跑(没有 systemd 的 WSL 不会自动起),否则下面的判断会把已有的库当成没有
|
|
112
|
+
sudoS service mysql start 2>/dev/null
|
|
113
|
+
# 没有 systemd 时 socket 目录可能是 700,aaden 跑数据库迁移会连不上(SQLSTATE 2002 Permission denied)
|
|
114
|
+
sudoS chmod 755 /var/run/mysqld 2>/dev/null
|
|
115
|
+
if sudoS mysql -uroot -e 'USE aaden' 2>/dev/null || sudoS test -d /var/lib/mysql/aaden; then
|
|
116
|
+
echo "数据库 aaden 已存在,跳过初始化(重跑装机不会覆盖门店数据)"
|
|
117
|
+
return 0
|
|
118
|
+
fi
|
|
119
|
+
sudoS bash "$DIR/scureSql.sh" "$PW"
|
|
120
|
+
sudoS sh -c "mysql -uroot < '$BACKEND_SRC/new.sql'" && sudoS mysql -uroot -e 'USE aaden'
|
|
121
|
+
}
|
|
122
|
+
must db setup_database
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------- 4. 部署后端
|
|
125
|
+
deploy_backend() {
|
|
126
|
+
# cp 而不是 mv:重跑时目标目录已存在,mv 会失败
|
|
127
|
+
sudoS cp -a "$BACKEND_SRC/." "$WEB/" || return 1
|
|
128
|
+
sudoS rm -rf "$BACKEND_SRC"
|
|
129
|
+
sudoS chown -hR www-data:www-data "$WEB"
|
|
130
|
+
sudoS chmod -R 777 "$WEB/Resource"
|
|
131
|
+
sudoS chmod +x "$WEB/crontab.sh" "$WEB/PHP/vendor/bin/phinx" "$WEB/PHP/vendor/robmorgan/phinx/bin/phinx"
|
|
132
|
+
sudoS systemctl restart apache2 2>/dev/null || sudoS service apache2 restart
|
|
133
|
+
sleep 2
|
|
134
|
+
curl -fsS -m 10 http://localhost/package.json | grep '"version"'
|
|
135
|
+
}
|
|
136
|
+
must deploy deploy_backend
|
|
164
137
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
echo "# Install TeamViewer #"
|
|
168
|
-
echo "# V 1.0.0 #"
|
|
169
|
-
echo "#######################################################################"
|
|
170
|
-
echo ""
|
|
138
|
+
# ---------------------------------------------------------------- 5. 设备号:配置、主机名、ngrok、上报
|
|
139
|
+
must device aaden-cli set-device-id "$DEVICE_ID"
|
|
171
140
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
sudo apt -y install ./teamviewer_amd64.deb
|
|
141
|
+
# ---------------------------------------------------------------- 6. 数据库迁移
|
|
142
|
+
must migrate sh -c "cd '$WEB/PHP' && vendor/bin/phinx migrate"
|
|
175
143
|
|
|
176
|
-
|
|
144
|
+
# ---------------------------------------------------------------- 7. 系统配置(失败不中止,最后的自检会标出来)
|
|
145
|
+
add_groups() {
|
|
146
|
+
# 打印机(lp)、读日志(adm)、aaden 能 sudo;www-data 要能访问 USB 打印机
|
|
147
|
+
sudoS usermod -a -G lp,root,adm,sudo aaden && sudoS usermod -a -G lp,root www-data
|
|
148
|
+
}
|
|
149
|
+
step groups add_groups
|
|
150
|
+
step patch aaden-cli patch
|
|
151
|
+
# 日结物化守护进程:每日数据库备份和 DSFinV-K 日结物化都靠它
|
|
152
|
+
step gdpdu aaden-cli auto-write-gdpdu
|
|
153
|
+
# aaden 和 root 的定时任务整份覆盖写(do-log 上报、每日自动更新等)
|
|
154
|
+
step cron aaden-cli fix-cronjob
|
|
155
|
+
# 升级 aaden-cli、跑补丁、后端 light-update、同步 AppCenter 前端
|
|
156
|
+
step upgrade aaden-cli upgrade
|
|
157
|
+
|
|
158
|
+
if ! is_wsl; then
|
|
159
|
+
install_teamviewer() {
|
|
160
|
+
local deb
|
|
161
|
+
deb=$(mktemp --suffix=.deb)
|
|
162
|
+
wget -q -O "$deb" https://download.teamviewer.com/download/linux/teamviewer_amd64.deb \
|
|
163
|
+
&& sudoS env DEBIAN_FRONTEND=noninteractive apt-get -y install "$deb"
|
|
164
|
+
local code=$?
|
|
165
|
+
rm -f "$deb"
|
|
166
|
+
wget -q -O "$HOME/background.png" https://aaden.online/AadenOS/background.png
|
|
167
|
+
return $code
|
|
168
|
+
}
|
|
169
|
+
step teamviewer install_teamviewer
|
|
170
|
+
fi
|
|
177
171
|
|
|
172
|
+
# ---------------------------------------------------------------- 8. 自检
|
|
173
|
+
banner "自检"
|
|
174
|
+
CHECKS=""
|
|
175
|
+
BAD=""
|
|
176
|
+
check() { # check <key> <说明> <命令…>
|
|
177
|
+
local key=$1 label=$2
|
|
178
|
+
shift 2
|
|
179
|
+
if "$@" >/dev/null 2>&1; then
|
|
180
|
+
CHECKS="$CHECKS $key=ok"
|
|
181
|
+
echo " ✓ $label"
|
|
182
|
+
else
|
|
183
|
+
CHECKS="$CHECKS $key=FAIL"
|
|
184
|
+
BAD="$BAD $label"
|
|
185
|
+
echo " ✗ $label"
|
|
186
|
+
fi
|
|
187
|
+
}
|
|
188
|
+
NGROK_HOST="ik$(printf '%04d' "$DEVICE_ID").ngrok.aaden.io"
|
|
178
189
|
|
|
190
|
+
check_cloud() {
|
|
191
|
+
aaden-cli do-log >/dev/null 2>&1
|
|
192
|
+
curl -fsS -m 15 "https://cloud-v2.aaden.io/deviceLog/install-check/$DEVICE_ID" \
|
|
193
|
+
| python3 -c 'import json,sys; m = json.load(sys.stdin).get("lastReportMinutesAgo"); sys.exit(0 if m is not None and m <= 10 else 1)'
|
|
194
|
+
}
|
|
195
|
+
check_ngrok() { # 隧道刚起来时要等几秒
|
|
196
|
+
local i
|
|
197
|
+
for i in 1 2 3 4 5 6; do
|
|
198
|
+
curl -fsS -m 10 "https://$NGROK_HOST/package.json" | grep -q '"version"' && return 0
|
|
199
|
+
sleep 10
|
|
200
|
+
done
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
203
|
+
check_gdpdu() {
|
|
204
|
+
systemctl is-active --quiet aaden-gdpdu.service 2>/dev/null \
|
|
205
|
+
|| pgrep -f 'autoWriteGdpdu\.php' >/dev/null \
|
|
206
|
+
|| [ -f /etc/cron.d/aaden-gdpdu ]
|
|
207
|
+
}
|
|
208
|
+
check_cron() {
|
|
209
|
+
crontab -l 2>/dev/null | grep -q 'do-log' && sudoS crontab -l -u root 2>/dev/null | grep -q 'auto-upgrade'
|
|
210
|
+
}
|
|
179
211
|
|
|
212
|
+
check_id() {
|
|
213
|
+
[ "$(awk -F= '/^\[/ { s = $0 } s ~ /^\[Device\]/ && $1 ~ /^[ \t]*DeviceId[ \t]*$/ { gsub(/[ \t"\r]/, "", $2); print $2; exit }' "$WEB/Resource/config/config.ini")" = "$DEVICE_ID" ]
|
|
214
|
+
}
|
|
180
215
|
|
|
216
|
+
check backend "后端在跑(http://localhost/package.json)" sh -c 'curl -fsS -m 10 http://localhost/package.json | grep -q version'
|
|
217
|
+
check id "设备号写入配置($DEVICE_ID)" check_id
|
|
218
|
+
check cloud "云端收到本机上报(ERP 门店列表「机器」列显示就绪)" check_cloud
|
|
219
|
+
check ngrok "远程访问 https://$NGROK_HOST" check_ngrok
|
|
220
|
+
check gdpdu "日结守护进程 aaden-gdpdu(没有它就没有每日备份)" check_gdpdu
|
|
221
|
+
check cron "定时任务(上报、每日自动更新)" check_cron
|
|
222
|
+
|
|
223
|
+
FAILED_STEPS=$(echo "$STEPS" | tr ' ' '\n' | grep -v '=0/' | cut -d= -f1 | tr '\n' ' ')
|
|
224
|
+
if [ -z "$BAD" ] && [ -z "${FAILED_STEPS// /}" ]; then
|
|
225
|
+
report 0 " [自检${CHECKS}]"
|
|
226
|
+
banner "装机完成,设备号 $DEVICE_ID,可以交付"
|
|
227
|
+
exit 0
|
|
228
|
+
fi
|
|
229
|
+
report 1 " [自检${CHECKS}]"
|
|
230
|
+
banner "装机跑完了,但有问题要处理"
|
|
231
|
+
[ -n "${FAILED_STEPS// /}" ] && echo "失败的步骤:$FAILED_STEPS"
|
|
232
|
+
[ -n "$BAD" ] && echo "没通过的自检:$BAD"
|
|
233
|
+
echo "处理完可以重新运行同一条命令。日志:$LOG"
|
|
234
|
+
exit 1
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# 装机前检查设备号:这个号在 ERP 是哪家店、是不是已经有收银机在用。拦住输错号、用了别家号的「撞号」——
|
|
3
|
+
# 同一个号装两台机器,云端的上报、备份、报表、远程连接(ngrok ik 号)会互相覆盖。
|
|
4
|
+
#
|
|
5
|
+
# 退出码 0 = 继续装;1 = 号不对或装机同事取消。
|
|
6
|
+
# 连不上云端只警告、不挡安装(现场网络常常不好)。确实要跳过检查:AADEN_SKIP_DEVICE_CHECK=1
|
|
7
|
+
DeviceId="$1"
|
|
8
|
+
CLOUD="${AADEN_CLOUD_URL:-https://cloud-v2.aaden.io}"
|
|
9
|
+
|
|
10
|
+
[ -n "$AADEN_SKIP_DEVICE_CHECK" ] && { echo "跳过设备号检查(AADEN_SKIP_DEVICE_CHECK)"; exit 0; }
|
|
11
|
+
if ! [[ "$DeviceId" =~ ^[0-9]+$ ]]; then
|
|
12
|
+
echo "设备号必须是数字:'$DeviceId'"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# 提问走 /dev/tty:脚本的标准输入可能被管道占着。没有终端(自动化装机)时 ask 返回空串
|
|
17
|
+
HAVE_TTY=""
|
|
18
|
+
{ exec 3</dev/tty; } 2>/dev/null && HAVE_TTY=1
|
|
19
|
+
ask() {
|
|
20
|
+
local answer=""
|
|
21
|
+
[ -n "$HAVE_TTY" ] && read -r -p "$1" answer <&3 2>/dev/tty
|
|
22
|
+
echo "$answer"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
URL="$CLOUD/deviceLog/install-check/$DeviceId"
|
|
26
|
+
JSON=$(curl -fsS -m 15 "$URL" 2>/dev/null || wget -qO- -T 15 "$URL" 2>/dev/null)
|
|
27
|
+
|
|
28
|
+
# 第一行是结论(OK / IN_USE / NO_STORE / ERROR),后面是给装机同事看的说明
|
|
29
|
+
REPORT=$(python3 - "$JSON" <<'PY'
|
|
30
|
+
import json, sys
|
|
31
|
+
try:
|
|
32
|
+
d = json.loads(sys.argv[1])
|
|
33
|
+
store, machine = d.get("store"), d.get("machine")
|
|
34
|
+
except Exception:
|
|
35
|
+
print("ERROR")
|
|
36
|
+
sys.exit()
|
|
37
|
+
|
|
38
|
+
status = {"AwaitingInstallation": "等待安装", "Installed": "已安装", "Closed": "已关停", "StopService": "停止服务"}
|
|
39
|
+
|
|
40
|
+
def when(v):
|
|
41
|
+
return v[:16].replace("T", " ") if v else "—"
|
|
42
|
+
|
|
43
|
+
def ago(minutes):
|
|
44
|
+
if minutes is None:
|
|
45
|
+
return "—"
|
|
46
|
+
if minutes < 60:
|
|
47
|
+
return f"{max(minutes, 1)} 分钟前"
|
|
48
|
+
if minutes < 24 * 60:
|
|
49
|
+
return f"{round(minutes / 60)} 小时前"
|
|
50
|
+
return f"{round(minutes / 60 / 24)} 天前"
|
|
51
|
+
|
|
52
|
+
if not store:
|
|
53
|
+
print("NO_STORE")
|
|
54
|
+
sys.exit()
|
|
55
|
+
|
|
56
|
+
parts = [p for p in (store.get("displayCode"), store.get("city"), status.get(store.get("status"), store.get("status"))) if p]
|
|
57
|
+
store_line = f"ERP 门店「{store.get('name') or '—'}」({','.join(parts)})"
|
|
58
|
+
|
|
59
|
+
if machine:
|
|
60
|
+
print("IN_USE")
|
|
61
|
+
print(f" 收银机里的餐厅名:{machine.get('posName') or '—'}")
|
|
62
|
+
print(f" 第一次上报 {when(machine.get('firstReportAt'))},最近上报 {ago(d.get('lastReportMinutesAgo'))}")
|
|
63
|
+
print(f" {store_line}")
|
|
64
|
+
else:
|
|
65
|
+
print("OK")
|
|
66
|
+
print(f" {store_line}")
|
|
67
|
+
print(" 云端还没收到过这个号的收银机上报")
|
|
68
|
+
PY
|
|
69
|
+
)
|
|
70
|
+
VERDICT=$(echo "$REPORT" | head -n 1)
|
|
71
|
+
DETAIL=$(echo "$REPORT" | tail -n +2)
|
|
72
|
+
|
|
73
|
+
echo ""
|
|
74
|
+
echo "#######################################################################"
|
|
75
|
+
echo "检查设备号 $DeviceId"
|
|
76
|
+
case "$VERDICT" in
|
|
77
|
+
OK)
|
|
78
|
+
echo "$DETAIL"
|
|
79
|
+
# 没有终端可问(自动化装机)时号也没人用,直接继续
|
|
80
|
+
if [ -n "$HAVE_TTY" ]; then
|
|
81
|
+
answer=$(ask "是这家店吗?[y/N] ")
|
|
82
|
+
[[ "$answer" =~ ^[yY] ]] || { echo "已取消。"; exit 1; }
|
|
83
|
+
fi
|
|
84
|
+
;;
|
|
85
|
+
IN_USE)
|
|
86
|
+
echo "⚠ 这个号已经有收银机在用:"
|
|
87
|
+
echo "$DETAIL"
|
|
88
|
+
echo "同一个号装两台机器,云端的上报、备份、报表、远程连接会互相覆盖。"
|
|
89
|
+
echo "只有给这家店换机或重装才应该继续,而且旧机器要先关掉。"
|
|
90
|
+
answer=$(ask "确认继续请再输入一遍设备号(直接回车取消):")
|
|
91
|
+
[ "$answer" = "$DeviceId" ] || { echo "已取消。"; exit 1; }
|
|
92
|
+
;;
|
|
93
|
+
NO_STORE)
|
|
94
|
+
echo "✗ ERP 里没有编号 $DeviceId 的门店:先在 ERP 建档,或者检查设备号有没有输错。"
|
|
95
|
+
echo " 确实要装:AADEN_SKIP_DEVICE_CHECK=1 再跑一次"
|
|
96
|
+
exit 1
|
|
97
|
+
;;
|
|
98
|
+
*)
|
|
99
|
+
echo "⚠ 连不上云端($CLOUD),没法检查设备号有没有撞号,继续安装。"
|
|
100
|
+
sleep 3
|
|
101
|
+
;;
|
|
102
|
+
esac
|
|
103
|
+
echo "#######################################################################"
|
|
104
|
+
exit 0
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# 设定本机设备号(= ERP 门店编号)。全新装机(aadensetup.sh)和镜像克隆来的机器改号都走这一个入口:
|
|
3
|
+
# aaden-cli set-device-id <号>
|
|
4
|
+
#
|
|
5
|
+
# 1. 先查云端:这个号是 ERP 里哪家店、是不是已经有收银机在用(checkDeviceId.sh),拦住撞号
|
|
6
|
+
# 2. 写配置:没有 config.ini 时让后端 AutoSetup.php 按默认配置生成;已有时只改 [Device] 段和 config.json,其余配置原样保留
|
|
7
|
+
# 3. 主机名 aadenXXXX,/etc/hosts 里只留一行(以前每次装机都往里追加一行)
|
|
8
|
+
# 4. ngrok 隧道 ikXXXX / SSH 端口 10000+号,重启隧道;第一次装时下载 ngrok 并装成服务
|
|
9
|
+
# 5. 马上上报一次,云端 ERP 门店列表的「机器」列随即显示就绪
|
|
10
|
+
#
|
|
11
|
+
# 退出码:0 成功;1 号不对或取消;2 写配置失败
|
|
12
|
+
export PATH="/usr/local/bin:$PATH"
|
|
13
|
+
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
14
|
+
CONFIG_DIR=/var/www/html/Resource/config
|
|
15
|
+
CONFIG_INI=$CONFIG_DIR/config.ini
|
|
16
|
+
CONFIG_JSON=$CONFIG_DIR/config.json
|
|
17
|
+
|
|
18
|
+
# 和 aaden-cli 其他地方一样用 -S 从 stdin 喂密码(aaden 不一定有免密 sudo)。
|
|
19
|
+
# 注意:不能再往 sudoS 的命令里用管道喂内容——stdin 已经被密码占了,内容一律先写临时文件再 sudoS cp。
|
|
20
|
+
sudoS() { echo "Innerken322." | sudo -S -p '' "$@"; }
|
|
21
|
+
# 先把 sudo 凭据缓存上:后面调的 aaden-cli 子命令(fix-ngrok 等)里还有裸 sudo
|
|
22
|
+
sudoS -v 2>/dev/null
|
|
23
|
+
|
|
24
|
+
NEW_ID="$1"
|
|
25
|
+
if [ -z "$NEW_ID" ]; then
|
|
26
|
+
read -r -p '设备号: ' NEW_ID
|
|
27
|
+
fi
|
|
28
|
+
NEW_ID=$(printf '%s' "$NEW_ID" | tr -d '[:space:]')
|
|
29
|
+
if ! [[ "$NEW_ID" =~ ^[0-9]+$ ]]; then
|
|
30
|
+
echo "设备号必须是数字:'$NEW_ID'"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
NEW_ID=$((10#$NEW_ID)) # 去掉前导零,和云端、ERP 编号一致
|
|
34
|
+
NAME="IK$(printf '%04d' "$NEW_ID")"
|
|
35
|
+
HOST="aaden$(printf '%04d' "$NEW_ID")" # 和 ngrok 的 ik 号一样补到 4 位:aaden0001、aaden1958
|
|
36
|
+
|
|
37
|
+
ini_device_id() {
|
|
38
|
+
[ -f "$CONFIG_INI" ] || return
|
|
39
|
+
awk -F= '/^\[/ { s = $0 } s ~ /^\[Device\]/ && $1 ~ /^[ \t]*DeviceId[ \t]*$/ { gsub(/[ \t"\r]/, "", $2); print $2; exit }' "$CONFIG_INI"
|
|
40
|
+
}
|
|
41
|
+
OLD_ID=$(ini_device_id)
|
|
42
|
+
|
|
43
|
+
if [ "$OLD_ID" = "$NEW_ID" ]; then
|
|
44
|
+
echo "本机已经是设备号 $NEW_ID,只重新应用主机名、ngrok 并上报"
|
|
45
|
+
else
|
|
46
|
+
[ -n "$OLD_ID" ] && echo "本机原设备号:$OLD_ID → 改成 $NEW_ID"
|
|
47
|
+
bash "$DIR/checkDeviceId.sh" "$NEW_ID" || exit 1
|
|
48
|
+
|
|
49
|
+
# 已经启用 TSE 的机器改号:TSE 记录会挂到新号上。正常流程是先改号,再「清空数据、启用 TSE」
|
|
50
|
+
if [ -n "$OLD_ID" ] && grep -qiE '^[ \t]*TseEnabled[ \t]*=[ \t]*"?(true|1)"?[ \t]*$' "$CONFIG_INI"; then
|
|
51
|
+
echo "⚠ 本机已经启用 TSE(原设备号 $OLD_ID)。正常应该先改号,再清空数据、启用 TSE。"
|
|
52
|
+
answer=""
|
|
53
|
+
{ exec 3</dev/tty; } 2>/dev/null && read -r -p "确定要改号请输入 yes:" answer <&3 2>/dev/tty
|
|
54
|
+
[ "$answer" = "yes" ] || { echo "已取消。"; exit 1; }
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------- 配置
|
|
59
|
+
if [ ! -f "$CONFIG_INI" ]; then
|
|
60
|
+
# 全新装机:后端按默认配置生成 config.ini / config.json(以 www-data 写,权限和以前一样)
|
|
61
|
+
curl -fsS -m 30 "http://localhost/PHP/AutoSetup.php?DeviceId=$NEW_ID" >/dev/null \
|
|
62
|
+
|| { echo "调用 AutoSetup.php 失败(Apache/PHP 还没起来?)"; exit 2; }
|
|
63
|
+
elif [ "$OLD_ID" != "$NEW_ID" ]; then
|
|
64
|
+
TMP=$(mktemp)
|
|
65
|
+
awk -v id="$NEW_ID" -v name="$NAME" '
|
|
66
|
+
function fill() {
|
|
67
|
+
if (!doneId) print "DeviceId = \"" id "\""
|
|
68
|
+
if (!doneName) print "DeviceName = \"" name "\""
|
|
69
|
+
}
|
|
70
|
+
/^\[/ {
|
|
71
|
+
if (inDev) fill()
|
|
72
|
+
inDev = ($0 ~ /^\[Device\][ \t\r]*$/)
|
|
73
|
+
if (inDev) seen = 1
|
|
74
|
+
print; next
|
|
75
|
+
}
|
|
76
|
+
inDev && /^[ \t]*DeviceId[ \t]*=/ { print "DeviceId = \"" id "\""; doneId = 1; next }
|
|
77
|
+
inDev && /^[ \t]*DeviceName[ \t]*=/ { print "DeviceName = \"" name "\""; doneName = 1; next }
|
|
78
|
+
{ print }
|
|
79
|
+
END {
|
|
80
|
+
if (inDev) fill()
|
|
81
|
+
if (!seen) { print "[Device]"; print "DeviceId = \"" id "\""; print "DeviceName = \"" name "\"" }
|
|
82
|
+
}' "$CONFIG_INI" >"$TMP"
|
|
83
|
+
# cp 覆盖内容、保留原文件的属主和权限
|
|
84
|
+
sudoS cp "$TMP" "$CONFIG_INI" || { rm -f "$TMP"; echo "写 $CONFIG_INI 失败"; exit 2; }
|
|
85
|
+
printf '{"DeviceId":"%s","DeviceName":"%s"}' "$NEW_ID" "$NAME" >"$TMP"
|
|
86
|
+
sudoS cp "$TMP" "$CONFIG_JSON"
|
|
87
|
+
rm -f "$TMP"
|
|
88
|
+
fi
|
|
89
|
+
if [ "$(ini_device_id)" != "$NEW_ID" ]; then
|
|
90
|
+
echo "写完配置后读到的设备号是「$(ini_device_id)」,不是 $NEW_ID"
|
|
91
|
+
exit 2
|
|
92
|
+
fi
|
|
93
|
+
echo "配置已写入:$CONFIG_INI → DeviceId = $NEW_ID"
|
|
94
|
+
|
|
95
|
+
# ---------------------------------------------------------------- 主机名
|
|
96
|
+
# 先写 /etc/hosts 再改主机名,否则改完的那一刻 sudo 会报 unable to resolve host
|
|
97
|
+
TMP=$(mktemp)
|
|
98
|
+
grep -vE '[[:space:]]aaden[0-9]+[[:space:]]*$' /etc/hosts >"$TMP"
|
|
99
|
+
echo "127.0.1.1 $HOST" >>"$TMP"
|
|
100
|
+
sudoS cp "$TMP" /etc/hosts
|
|
101
|
+
rm -f "$TMP"
|
|
102
|
+
# WSL 没有 systemd 时 hostnamectl 不可用,退回直接写 /etc/hostname
|
|
103
|
+
if ! sudoS hostnamectl set-hostname "$HOST" 2>/dev/null; then
|
|
104
|
+
TMP=$(mktemp)
|
|
105
|
+
echo "$HOST" >"$TMP"
|
|
106
|
+
sudoS cp "$TMP" /etc/hostname && sudoS hostname "$HOST"
|
|
107
|
+
rm -f "$TMP"
|
|
108
|
+
fi
|
|
109
|
+
echo "主机名:$HOST"
|
|
110
|
+
|
|
111
|
+
# ---------------------------------------------------------------- ngrok
|
|
112
|
+
aaden-cli update-ngrok-config "$NEW_ID" >/dev/null
|
|
113
|
+
if [ -f /etc/systemd/system/aaden-ngrok-v3.service ] && [ -x /etc/aaden/ngrok ]; then
|
|
114
|
+
sudoS systemctl restart aaden-ngrok-v3 2>/dev/null || sudoS service aaden-ngrok-v3 restart
|
|
115
|
+
else
|
|
116
|
+
aaden-cli fix-ngrok # 第一次:下载 ngrok、装 systemd 服务
|
|
117
|
+
fi
|
|
118
|
+
echo "ngrok:ik$(printf '%04d' "$NEW_ID").ngrok.aaden.io,SSH 端口 $((10000 + NEW_ID))"
|
|
119
|
+
|
|
120
|
+
# ---------------------------------------------------------------- 上报
|
|
121
|
+
# do-log 连不上云端时退出码也是 0,所以回头问云端确认收到了没有
|
|
122
|
+
aaden-cli do-log >/dev/null 2>&1
|
|
123
|
+
MINUTES=$(curl -fsS -m 15 "${AADEN_CLOUD_URL:-https://cloud-v2.aaden.io}/deviceLog/install-check/$NEW_ID" 2>/dev/null \
|
|
124
|
+
| python3 -c 'import json, sys; m = json.load(sys.stdin).get("lastReportMinutesAgo"); print("" if m is None else m)' 2>/dev/null)
|
|
125
|
+
if [ -n "$MINUTES" ] && [ "$MINUTES" -le 5 ]; then
|
|
126
|
+
echo "云端已收到本机上报,ERP 门店列表的「机器」列显示就绪"
|
|
127
|
+
else
|
|
128
|
+
echo "⚠ 云端还没收到本机上报(网络不通?)。联网后每 5 分钟会自动上报一次"
|
|
129
|
+
fi
|
|
130
|
+
exit 0
|
package/README.md
CHANGED
|
@@ -28,7 +28,8 @@ Options:
|
|
|
28
28
|
|
|
29
29
|
Commands:
|
|
30
30
|
update [channel]
|
|
31
|
-
install [options] <deviceId> [channel]
|
|
31
|
+
install [options] <deviceId> [channel] 装机(= AadenDeploy/aadensetup.sh):撞号检查、装软件、部署后端、设备号、自检并上报
|
|
32
|
+
set-device-id [deviceId] 设定本机设备号:撞号检查、config.ini、主机名、ngrok、立即上报(镜像克隆的机器改号也用它)
|
|
32
33
|
setup-wifi
|
|
33
34
|
upgrade
|
|
34
35
|
where
|
package/dist/index.js
CHANGED
|
@@ -18729,7 +18729,7 @@ module.exports = JSON.parse('{"name":"axios","version":"0.19.2","description":"P
|
|
|
18729
18729
|
/***/ ((module) => {
|
|
18730
18730
|
|
|
18731
18731
|
"use strict";
|
|
18732
|
-
module.exports =
|
|
18732
|
+
module.exports = {"i8":"1.6.109"};
|
|
18733
18733
|
|
|
18734
18734
|
/***/ })
|
|
18735
18735
|
|
|
@@ -18843,6 +18843,8 @@ program.command('rollback').action(rollback)
|
|
|
18843
18843
|
program
|
|
18844
18844
|
.command('install <deviceId>')
|
|
18845
18845
|
.action(install)
|
|
18846
|
+
// 设定本机设备号(= ERP 门店编号):撞号检查 + config.ini + 主机名 + ngrok + 立即上报。装机和镜像克隆来的机器改号都用它
|
|
18847
|
+
program.command('set-device-id [deviceId]').action(setDeviceId)
|
|
18846
18848
|
program.command('remove-all-data').action(removeAllData)
|
|
18847
18849
|
program.command('mount-tse').action(remountTSE)
|
|
18848
18850
|
program.command('upgrade').action(upgrade) // auto execute.
|
|
@@ -19110,12 +19112,13 @@ async function updateNgrokConfig(deviceId) {
|
|
|
19110
19112
|
console.log('Start to config Ngrok service')
|
|
19111
19113
|
console.log('开始配置' + deviceId + '设备的Ngrok服务')
|
|
19112
19114
|
|
|
19115
|
+
// 和其他地方一样用 -S 喂密码:aaden 没有免密 sudo、又没有终端时(set-device-id 被脚本调用)裸 sudo 会直接失败
|
|
19113
19116
|
const command = [
|
|
19114
19117
|
'cd /etc',
|
|
19115
|
-
'sudo mkdir -p aaden',
|
|
19118
|
+
'echo "Innerken322." | sudo -S -p \'\' mkdir -p aaden',
|
|
19116
19119
|
'cd aaden',
|
|
19117
|
-
'sudo touch ngrok-config.yml',
|
|
19118
|
-
'sudo chmod 777 ngrok-config.yml',
|
|
19120
|
+
'echo "Innerken322." | sudo -S -p \'\' touch ngrok-config.yml',
|
|
19121
|
+
'echo "Innerken322." | sudo -S -p \'\' chmod 777 ngrok-config.yml',
|
|
19119
19122
|
`echo "
|
|
19120
19123
|
server_addr: ngrok.aaden.io:4443
|
|
19121
19124
|
trust_host_root_certs: true
|
|
@@ -19527,11 +19530,29 @@ async function install(deviceId) {
|
|
|
19527
19530
|
'cd AadenDeploy',
|
|
19528
19531
|
`./aadensetup.sh ${deviceId} ${channel}` + (installApp ? ' b' : '')
|
|
19529
19532
|
]
|
|
19530
|
-
|
|
19533
|
+
// 「出厂安装」事件由 aadensetup.sh 自己在最后上报(带每一步的结果和自检),这里不再重复记
|
|
19534
|
+
const {code} = await cli.executeInShell(command, program.debug)
|
|
19535
|
+
process.exitCode = code
|
|
19531
19536
|
} else {
|
|
19532
19537
|
console.log('Device Id is invalid.')
|
|
19533
19538
|
}
|
|
19534
|
-
|
|
19539
|
+
}
|
|
19540
|
+
|
|
19541
|
+
async function setDeviceId(deviceId) {
|
|
19542
|
+
const oldId = getMyDeviceId()
|
|
19543
|
+
const command = [
|
|
19544
|
+
...getPrivilegeCMD('AadenDeploy/setDeviceId.sh'),
|
|
19545
|
+
'cd AadenDeploy',
|
|
19546
|
+
`./setDeviceId.sh ${deviceId && deviceId !== 'notset' ? deviceId : ''}`
|
|
19547
|
+
]
|
|
19548
|
+
const {code} = await cli.executeInShell(command, program.debug)
|
|
19549
|
+
// aadensetup.sh 按退出码判断这一步成没成
|
|
19550
|
+
process.exitCode = code
|
|
19551
|
+
if (code !== 0) {
|
|
19552
|
+
return
|
|
19553
|
+
}
|
|
19554
|
+
const newId = getMyDeviceId()
|
|
19555
|
+
await logAction(String(oldId) === String(newId) ? `重新应用设备号 ${newId}` : `设定设备号 ${oldId === -1 ? '(无)' : oldId} → ${newId}`)
|
|
19535
19556
|
}
|
|
19536
19557
|
|
|
19537
19558
|
function getMyDeviceId() {
|
|
@@ -19709,7 +19730,7 @@ function getPrivilegeCMD(path, pri = '+x', relativePath = true) {
|
|
|
19709
19730
|
if (relativePath) {
|
|
19710
19731
|
command.push(goIntoRootDir())
|
|
19711
19732
|
}
|
|
19712
|
-
command.push(`echo "Innerken322." | sudo -S chmod ${pri} ${path}`)
|
|
19733
|
+
command.push(`echo "Innerken322." | sudo -S -p "" chmod ${pri} ${path}`)
|
|
19713
19734
|
return command
|
|
19714
19735
|
}
|
|
19715
19736
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# 一次性修复:摘掉老 git 通道的 doUpdate cron。
|
|
3
|
+
#
|
|
4
|
+
# 病症:设备 crontab 里有
|
|
5
|
+
# 59 4 * * * curl -X POST 'http://localhost/PHP/UpdateSelf.php?op=doUpdate'
|
|
6
|
+
# @reboot ... curl -X POST '.../UpdateSelf.php?op=doUpdate'
|
|
7
|
+
# 它每天 04:59(和 @reboot)从**设备本地陈旧 gitCache** 部署后端;而 git fetch 因 deploy key
|
|
8
|
+
# 未分发到全网而失败(FETCH_HEAD 0 字节),缓存卡在旧版本;git 通道又没有"绝不降级"保护 →
|
|
9
|
+
# 于是把 light-update 刚更好的新版本降级回退(实测 1.9.63 → 1.9.62/1.9.61,每天来回打架)。
|
|
10
|
+
#
|
|
11
|
+
# 结论:light-update(S3/code.zip 通道)已是后端唯一活着的更新通道,且自带"只升不降"版本门。
|
|
12
|
+
# 摘掉 doUpdate cron,终结两条通道打架。crontab 不走 git/S3 部署 → 改了就稳。
|
|
13
|
+
#
|
|
14
|
+
# 幂等:没有该行就不动;grep -vF 精确匹配整串,不误伤 crontab.sh / light-update 那几行。
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
MARK='UpdateSelf.php?op=doUpdate'
|
|
18
|
+
|
|
19
|
+
strip_for() { # $1 = 目标用户(空=当前用户)
|
|
20
|
+
local u="$1" cur new
|
|
21
|
+
local args=()
|
|
22
|
+
[ -n "$u" ] && args=(-u "$u")
|
|
23
|
+
cur=$(crontab "${args[@]}" -l 2>/dev/null) || return 0
|
|
24
|
+
printf '%s\n' "$cur" | grep -qF "$MARK" || return 0 # 没有该 cron → 不动
|
|
25
|
+
new=$(printf '%s\n' "$cur" | grep -vF "$MARK")
|
|
26
|
+
printf '%s\n' "$new" | crontab "${args[@]}" - \
|
|
27
|
+
&& echo " 已从 ${u:-当前用户} 的 crontab 摘除 doUpdate cron"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# doUpdate cron 在 aaden 用户的 crontab。patch 正常由 root 的 auto-upgrade 触发 → 用 -u aaden;
|
|
31
|
+
# 兜底再扫一遍当前用户(万一某些设备以 aaden 直接跑 patch),谁有就摘谁。
|
|
32
|
+
if [ "$(id -u)" = "0" ]; then
|
|
33
|
+
strip_for aaden
|
|
34
|
+
strip_for ""
|
|
35
|
+
else
|
|
36
|
+
strip_for ""
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo " removeGitDoUpdateCron 完成(light-update 成为后端唯一更新通道)"
|
package/index.js
CHANGED
|
@@ -40,6 +40,8 @@ program.command('rollback').action(rollback)
|
|
|
40
40
|
program
|
|
41
41
|
.command('install <deviceId>')
|
|
42
42
|
.action(install)
|
|
43
|
+
// 设定本机设备号(= ERP 门店编号):撞号检查 + config.ini + 主机名 + ngrok + 立即上报。装机和镜像克隆来的机器改号都用它
|
|
44
|
+
program.command('set-device-id [deviceId]').action(setDeviceId)
|
|
43
45
|
program.command('remove-all-data').action(removeAllData)
|
|
44
46
|
program.command('mount-tse').action(remountTSE)
|
|
45
47
|
program.command('upgrade').action(upgrade) // auto execute.
|
|
@@ -307,12 +309,13 @@ async function updateNgrokConfig(deviceId) {
|
|
|
307
309
|
console.log('Start to config Ngrok service')
|
|
308
310
|
console.log('开始配置' + deviceId + '设备的Ngrok服务')
|
|
309
311
|
|
|
312
|
+
// 和其他地方一样用 -S 喂密码:aaden 没有免密 sudo、又没有终端时(set-device-id 被脚本调用)裸 sudo 会直接失败
|
|
310
313
|
const command = [
|
|
311
314
|
'cd /etc',
|
|
312
|
-
'sudo mkdir -p aaden',
|
|
315
|
+
'echo "Innerken322." | sudo -S -p \'\' mkdir -p aaden',
|
|
313
316
|
'cd aaden',
|
|
314
|
-
'sudo touch ngrok-config.yml',
|
|
315
|
-
'sudo chmod 777 ngrok-config.yml',
|
|
317
|
+
'echo "Innerken322." | sudo -S -p \'\' touch ngrok-config.yml',
|
|
318
|
+
'echo "Innerken322." | sudo -S -p \'\' chmod 777 ngrok-config.yml',
|
|
316
319
|
`echo "
|
|
317
320
|
server_addr: ngrok.aaden.io:4443
|
|
318
321
|
trust_host_root_certs: true
|
|
@@ -724,11 +727,29 @@ async function install(deviceId) {
|
|
|
724
727
|
'cd AadenDeploy',
|
|
725
728
|
`./aadensetup.sh ${deviceId} ${channel}` + (installApp ? ' b' : '')
|
|
726
729
|
]
|
|
727
|
-
|
|
730
|
+
// 「出厂安装」事件由 aadensetup.sh 自己在最后上报(带每一步的结果和自检),这里不再重复记
|
|
731
|
+
const {code} = await cli.executeInShell(command, program.debug)
|
|
732
|
+
process.exitCode = code
|
|
728
733
|
} else {
|
|
729
734
|
console.log('Device Id is invalid.')
|
|
730
735
|
}
|
|
731
|
-
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
async function setDeviceId(deviceId) {
|
|
739
|
+
const oldId = getMyDeviceId()
|
|
740
|
+
const command = [
|
|
741
|
+
...getPrivilegeCMD('AadenDeploy/setDeviceId.sh'),
|
|
742
|
+
'cd AadenDeploy',
|
|
743
|
+
`./setDeviceId.sh ${deviceId && deviceId !== 'notset' ? deviceId : ''}`
|
|
744
|
+
]
|
|
745
|
+
const {code} = await cli.executeInShell(command, program.debug)
|
|
746
|
+
// aadensetup.sh 按退出码判断这一步成没成
|
|
747
|
+
process.exitCode = code
|
|
748
|
+
if (code !== 0) {
|
|
749
|
+
return
|
|
750
|
+
}
|
|
751
|
+
const newId = getMyDeviceId()
|
|
752
|
+
await logAction(String(oldId) === String(newId) ? `重新应用设备号 ${newId}` : `设定设备号 ${oldId === -1 ? '(无)' : oldId} → ${newId}`)
|
|
732
753
|
}
|
|
733
754
|
|
|
734
755
|
function getMyDeviceId() {
|
|
@@ -906,7 +927,7 @@ function getPrivilegeCMD(path, pri = '+x', relativePath = true) {
|
|
|
906
927
|
if (relativePath) {
|
|
907
928
|
command.push(goIntoRootDir())
|
|
908
929
|
}
|
|
909
|
-
command.push(`echo "Innerken322." | sudo -S chmod ${pri} ${path}`)
|
|
930
|
+
command.push(`echo "Innerken322." | sudo -S -p "" chmod ${pri} ${path}`)
|
|
910
931
|
return command
|
|
911
932
|
}
|
|
912
933
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aaden-cli",
|
|
3
|
-
"version": "1.6.109
|
|
3
|
+
"version": "1.6.109",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"license": "ISC",
|
|
20
20
|
"release-it": {
|
|
21
21
|
"hooks": {
|
|
22
|
-
"after:bump": "ncc build index.js -o dist -C"
|
|
22
|
+
"after:bump": "rm -rf dist && ncc build index.js -o dist -C"
|
|
23
23
|
},
|
|
24
24
|
"npm": {
|
|
25
25
|
"publish": false
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# 一次性修复:摘掉老 git 通道的 doUpdate cron。
|
|
3
|
+
#
|
|
4
|
+
# 病症:设备 crontab 里有
|
|
5
|
+
# 59 4 * * * curl -X POST 'http://localhost/PHP/UpdateSelf.php?op=doUpdate'
|
|
6
|
+
# @reboot ... curl -X POST '.../UpdateSelf.php?op=doUpdate'
|
|
7
|
+
# 它每天 04:59(和 @reboot)从**设备本地陈旧 gitCache** 部署后端;而 git fetch 因 deploy key
|
|
8
|
+
# 未分发到全网而失败(FETCH_HEAD 0 字节),缓存卡在旧版本;git 通道又没有"绝不降级"保护 →
|
|
9
|
+
# 于是把 light-update 刚更好的新版本降级回退(实测 1.9.63 → 1.9.62/1.9.61,每天来回打架)。
|
|
10
|
+
#
|
|
11
|
+
# 结论:light-update(S3/code.zip 通道)已是后端唯一活着的更新通道,且自带"只升不降"版本门。
|
|
12
|
+
# 摘掉 doUpdate cron,终结两条通道打架。crontab 不走 git/S3 部署 → 改了就稳。
|
|
13
|
+
#
|
|
14
|
+
# 幂等:没有该行就不动;grep -vF 精确匹配整串,不误伤 crontab.sh / light-update 那几行。
|
|
15
|
+
set -u
|
|
16
|
+
|
|
17
|
+
MARK='UpdateSelf.php?op=doUpdate'
|
|
18
|
+
|
|
19
|
+
strip_for() { # $1 = 目标用户(空=当前用户)
|
|
20
|
+
local u="$1" cur new
|
|
21
|
+
local args=()
|
|
22
|
+
[ -n "$u" ] && args=(-u "$u")
|
|
23
|
+
cur=$(crontab "${args[@]}" -l 2>/dev/null) || return 0
|
|
24
|
+
printf '%s\n' "$cur" | grep -qF "$MARK" || return 0 # 没有该 cron → 不动
|
|
25
|
+
new=$(printf '%s\n' "$cur" | grep -vF "$MARK")
|
|
26
|
+
printf '%s\n' "$new" | crontab "${args[@]}" - \
|
|
27
|
+
&& echo " 已从 ${u:-当前用户} 的 crontab 摘除 doUpdate cron"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# doUpdate cron 在 aaden 用户的 crontab。patch 正常由 root 的 auto-upgrade 触发 → 用 -u aaden;
|
|
31
|
+
# 兜底再扫一遍当前用户(万一某些设备以 aaden 直接跑 patch),谁有就摘谁。
|
|
32
|
+
if [ "$(id -u)" = "0" ]; then
|
|
33
|
+
strip_for aaden
|
|
34
|
+
strip_for ""
|
|
35
|
+
else
|
|
36
|
+
strip_for ""
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo " removeGitDoUpdateCron 完成(light-update 成为后端唯一更新通道)"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
echo "Innerken322." | sudo -S su
|
|
2
|
-
sudo touch /etc/aaden/AbstractDatevCsvFile.php
|
|
3
|
-
sudo chmod 777 /etc/aaden/AbstractDatevCsvFile.php
|
|
4
|
-
php -r $'print preg_replace(\'/ {4}public function toCsvArray\(\$items\)\r?\n(?:.*\r?\n)+? {4}}/\', <<<\'PHP\'
|
|
5
|
-
public function toCsvArray($items)
|
|
6
|
-
{
|
|
7
|
-
yield $this->getHeader()->toArray($items[\'header\']);
|
|
8
|
-
|
|
9
|
-
$fields = $this->getFields();
|
|
10
|
-
|
|
11
|
-
yield array_map(Utils::itAccessMethod(\'getName\'), $fields);
|
|
12
|
-
|
|
13
|
-
foreach ($items[\'body\'] as $item) {
|
|
14
|
-
yield array_map(Utils::itAccessMethod(\'transform\', $item), $fields);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
PHP
|
|
18
|
-
, file_get_contents("/var/www/html/PHP/Datev/FileStructures/AbstractDatevCsvFile.php"));' > /etc/aaden/AbstractDatevCsvFile.php
|
|
19
|
-
sudo cp /etc/aaden/AbstractDatevCsvFile.php /var/www/html/PHP/Datev/FileStructures/AbstractDatevCsvFile.php
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
echo "Innerken322." | sudo -S su
|
|
2
|
-
sudo touch /etc/aaden/AbstractDatevCsvFile.php
|
|
3
|
-
sudo chmod 777 /etc/aaden/AbstractDatevCsvFile.php
|
|
4
|
-
php -r $'print preg_replace(\'/ {4}public function toCsvArray\(\$items\)\r?\n(?:.*\r?\n)+? {4}}/\', <<<\'PHP\'
|
|
5
|
-
public function toCsvArray($items)
|
|
6
|
-
{
|
|
7
|
-
yield $this->getHeader()->toArray($items[\'header\']);
|
|
8
|
-
|
|
9
|
-
$fields = $this->getFields();
|
|
10
|
-
|
|
11
|
-
yield array_map(Utils::itAccessMethod(\'getName\'), $fields);
|
|
12
|
-
|
|
13
|
-
foreach ($items[\'body\'] as $item) {
|
|
14
|
-
yield array_map(Utils::itAccessMethod(\'transform\', $item), $fields);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
PHP
|
|
18
|
-
, file_get_contents("/var/www/html/PHP/Datev/FileStructures/AbstractDatevCsvFile.php"));' > /etc/aaden/AbstractDatevCsvFile.php
|
|
19
|
-
sudo cp /etc/aaden/AbstractDatevCsvFile.php /var/www/html/PHP/Datev/FileStructures/AbstractDatevCsvFile.php
|