caidao78 commited on
Commit
eea264b
·
verified ·
1 Parent(s): 265144e

Upload 7 files

Browse files
Dockerfile CHANGED
@@ -1,8 +1,9 @@
1
  FROM alpine:3.21
2
 
3
  ENV TZ=Asia/Shanghai
4
- ENV RUNTIME_DIR=/tmp/cliproxyapi
5
  ENV SUPERVISOR_CONF=/etc/supervisord.conf
 
6
  ENV UPDATE_INTERVAL_SECONDS=14400
7
  ENV STOP_WAIT_SECS=60
8
 
@@ -13,7 +14,7 @@ RUN apk add --no-cache ca-certificates curl supervisor tzdata \
13
  COPY entrypoint.sh /usr/local/bin/entrypoint.sh
14
  COPY scripts/release-common.sh /usr/local/bin/release-common.sh
15
  COPY scripts/update-loop.sh /usr/local/bin/update-loop.sh
16
- COPY supervisord.conf /etc/supervisord.conf
17
  RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/release-common.sh /usr/local/bin/update-loop.sh
18
 
19
  ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
 
1
  FROM alpine:3.21
2
 
3
  ENV TZ=Asia/Shanghai
4
+ ENV RUNTIME_DIR=/tmp/runtime
5
  ENV SUPERVISOR_CONF=/etc/supervisord.conf
6
+ ENV SUPERVISOR_CONF_TEMPLATE=/etc/supervisord.conf.template
7
  ENV UPDATE_INTERVAL_SECONDS=14400
8
  ENV STOP_WAIT_SECS=60
9
 
 
14
  COPY entrypoint.sh /usr/local/bin/entrypoint.sh
15
  COPY scripts/release-common.sh /usr/local/bin/release-common.sh
16
  COPY scripts/update-loop.sh /usr/local/bin/update-loop.sh
17
+ COPY supervisord.conf /etc/supervisord.conf.template
18
  RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/release-common.sh /usr/local/bin/update-loop.sh
19
 
20
  ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
entrypoint.sh CHANGED
@@ -3,6 +3,7 @@ set -eu
3
 
4
  : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
5
  : "${SUPERVISORD_BIN:=/usr/bin/supervisord}"
 
6
  : "${OPEN_FILE_LIMIT:=65535}"
7
 
8
  . "$RELEASE_COMMON_SH"
@@ -14,6 +15,21 @@ shell_quote() {
14
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
15
  }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  write_run_app_script() {
18
  run_app_script="$RUNTIME_DIR/run-app.sh"
19
 
@@ -49,6 +65,7 @@ start_supervisord() {
49
 
50
  main() {
51
  prepare_runtime_environment
 
52
  bootstrap_release_or_exit
53
  write_run_app_script "$@"
54
  start_supervisord
 
3
 
4
  : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
5
  : "${SUPERVISORD_BIN:=/usr/bin/supervisord}"
6
+ : "${SUPERVISOR_CONF_TEMPLATE:=/etc/supervisord.conf.template}"
7
  : "${OPEN_FILE_LIMIT:=65535}"
8
 
9
  . "$RELEASE_COMMON_SH"
 
15
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
16
  }
17
 
18
+ escape_sed_replacement() {
19
+ printf '%s' "$1" | sed 's/[\/&]/\\&/g'
20
+ }
21
+
22
+ write_supervisord_conf() {
23
+ mkdir -p "$(dirname "$SUPERVISOR_CONF")"
24
+ app_program_name=$(escape_sed_replacement "$SUPERVISOR_PROGRAM_NAME")
25
+ updater_program_name=$(escape_sed_replacement "$SUPERVISOR_UPDATER_PROGRAM_NAME")
26
+
27
+ sed \
28
+ -e "s/__APP_PROGRAM__/$app_program_name/g" \
29
+ -e "s/__UPDATER_PROGRAM__/$updater_program_name/g" \
30
+ "$SUPERVISOR_CONF_TEMPLATE" > "$SUPERVISOR_CONF"
31
+ }
32
+
33
  write_run_app_script() {
34
  run_app_script="$RUNTIME_DIR/run-app.sh"
35
 
 
65
 
66
  main() {
67
  prepare_runtime_environment
68
+ write_supervisord_conf
69
  bootstrap_release_or_exit
70
  write_run_app_script "$@"
71
  start_supervisord
release-common.sh ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ : "${REPO_API_URL:=https://api.github.com/repos/caidaoli/CLIProxyAPI/releases/latest}"
4
+ : "${RUNTIME_DIR:=/tmp/runtime}"
5
+ : "${RELEASES_DIR:=$RUNTIME_DIR/releases}"
6
+ : "${CURRENT_LINK:=$RUNTIME_DIR/current}"
7
+ : "${CURRENT_TAG_FILE:=$RUNTIME_DIR/current.tag}"
8
+ : "${DOWNLOADS_DIR:=$RUNTIME_DIR/downloads}"
9
+ : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
10
+ : "${SUPERVISOR_PROGRAM_NAME:=app}"
11
+ : "${SUPERVISOR_UPDATER_PROGRAM_NAME:=${SUPERVISOR_PROGRAM_NAME}-updater}"
12
+ : "${CURRENT_BINARY_NAME:=app}"
13
+ : "${APP_BINARY_NAMES:=}"
14
+
15
+ log() {
16
+ timestamp=$(date '+%Y-%m-%d %H:%M:%S %z')
17
+ printf '[%s] %s\n' "$timestamp" "$*" >&2
18
+ }
19
+
20
+ tag_to_dir_name() {
21
+ printf '%s\n' "$1" | tr '/:' '__'
22
+ }
23
+
24
+ release_dir_for_tag() {
25
+ printf '%s/%s\n' "$RELEASES_DIR" "$(tag_to_dir_name "$1")"
26
+ }
27
+
28
+ ensure_runtime_dirs() {
29
+ mkdir -p "$RUNTIME_DIR" "$RELEASES_DIR" "$DOWNLOADS_DIR"
30
+ }
31
+
32
+ current_tag() {
33
+ if [ -f "$CURRENT_TAG_FILE" ]; then
34
+ tr -d '\n' < "$CURRENT_TAG_FILE"
35
+ fi
36
+ }
37
+
38
+ current_binary_path() {
39
+ printf '%s/%s\n' "$CURRENT_LINK" "$CURRENT_BINARY_NAME"
40
+ }
41
+
42
+ fetch_latest_release_info() {
43
+ response=$(curl -fsSL "$REPO_API_URL") || return 1
44
+
45
+ tag_name=$(
46
+ printf '%s\n' "$response" \
47
+ | grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"[^"]+"' \
48
+ | head -n 1 \
49
+ | cut -d '"' -f 4 \
50
+ || true
51
+ )
52
+ asset_url=$(
53
+ printf '%s\n' "$response" \
54
+ | grep -Eo '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
55
+ | cut -d '"' -f 4 \
56
+ | grep -E '/[^/]*linux[-_]amd64(\.tar\.gz)?$' \
57
+ | head -n 1 \
58
+ || true
59
+ )
60
+
61
+ if [ -z "$tag_name" ] || [ -z "$asset_url" ]; then
62
+ return 1
63
+ fi
64
+
65
+ printf '%s|%s\n' "$tag_name" "$asset_url"
66
+ }
67
+
68
+ load_latest_release() {
69
+ release_info=$(fetch_latest_release_info) || return 1
70
+ LATEST_TAG=${release_info%%|*}
71
+ LATEST_ASSET_URL=${release_info#*|}
72
+ }
73
+
74
+ find_release_binary() {
75
+ release_dir=$1
76
+
77
+ for name in $APP_BINARY_NAMES; do
78
+ if [ -f "$release_dir/$name" ]; then
79
+ printf '%s\n' "$release_dir/$name"
80
+ return 0
81
+ fi
82
+ done
83
+
84
+ for name in $APP_BINARY_NAMES; do
85
+ binary_path=$(find "$release_dir" -maxdepth 3 -type f -name "$name" | head -n 1)
86
+ if [ -n "$binary_path" ]; then
87
+ printf '%s\n' "$binary_path"
88
+ return 0
89
+ fi
90
+ done
91
+
92
+ file_list=$(find "$release_dir" -maxdepth 3 -type f ! -name '._*' ! -path '*/__MACOSX/*' | sort)
93
+ first_file=$(printf '%s\n' "$file_list" | sed -n '1p')
94
+ second_file=$(printf '%s\n' "$file_list" | sed -n '2p')
95
+ if [ -n "$first_file" ] && [ -z "$second_file" ]; then
96
+ printf '%s\n' "$first_file"
97
+ return 0
98
+ fi
99
+
100
+ return 1
101
+ }
102
+
103
+ activate_release() {
104
+ tag_name=$1
105
+ release_dir=$2
106
+
107
+ rm -f "$CURRENT_LINK"
108
+ ln -s "$release_dir" "$CURRENT_LINK"
109
+ printf '%s\n' "$tag_name" > "$CURRENT_TAG_FILE"
110
+ }
111
+
112
+ extract_release_binary() {
113
+ source_dir=$1
114
+ target_path=$2
115
+ binary_path=$(find_release_binary "$source_dir" || true)
116
+
117
+ if [ -z "$binary_path" ]; then
118
+ return 1
119
+ fi
120
+
121
+ if [ "$binary_path" != "$target_path" ]; then
122
+ cp "$binary_path" "$target_path"
123
+ fi
124
+ chmod +x "$target_path"
125
+ }
126
+
127
+ cleanup_workspace() {
128
+ workspace=$1
129
+ if [ -n "$workspace" ] && [ -d "$workspace" ]; then
130
+ rm -rf "$workspace"
131
+ fi
132
+ }
133
+
134
+ install_release() {
135
+ tag_name=$1
136
+ asset_url=$2
137
+
138
+ ensure_runtime_dirs
139
+ release_dir=$(release_dir_for_tag "$tag_name")
140
+ release_binary="$release_dir/$CURRENT_BINARY_NAME"
141
+
142
+ if [ -x "$release_binary" ]; then
143
+ activate_release "$tag_name" "$release_dir"
144
+ return 0
145
+ fi
146
+
147
+ workspace=$(mktemp -d "$RUNTIME_DIR/install.XXXXXX") || return 1
148
+ download_name=$(basename "$asset_url")
149
+ if [ -z "$download_name" ] || [ "$download_name" = "/" ] || [ "$download_name" = "." ]; then
150
+ download_name="release.asset"
151
+ fi
152
+ download_path="$DOWNLOADS_DIR/$download_name"
153
+ stage_dir="$workspace/stage"
154
+
155
+ rm -f "$download_path" || {
156
+ cleanup_workspace "$workspace"
157
+ return 1
158
+ }
159
+ mkdir -p "$stage_dir" || {
160
+ cleanup_workspace "$workspace"
161
+ return 1
162
+ }
163
+ curl -fsSL "$asset_url" -o "$download_path" || {
164
+ cleanup_workspace "$workspace"
165
+ return 1
166
+ }
167
+
168
+ case "$download_path" in
169
+ *.tar.gz)
170
+ tar -xzf "$download_path" -C "$stage_dir" || {
171
+ cleanup_workspace "$workspace"
172
+ return 1
173
+ }
174
+ extract_release_binary "$stage_dir" "$stage_dir/$CURRENT_BINARY_NAME" || {
175
+ cleanup_workspace "$workspace"
176
+ return 1
177
+ }
178
+ ;;
179
+ *)
180
+ cp "$download_path" "$stage_dir/$CURRENT_BINARY_NAME" || {
181
+ cleanup_workspace "$workspace"
182
+ return 1
183
+ }
184
+ chmod +x "$stage_dir/$CURRENT_BINARY_NAME" || {
185
+ cleanup_workspace "$workspace"
186
+ return 1
187
+ }
188
+ ;;
189
+ esac
190
+
191
+ rm -rf "$release_dir" || {
192
+ cleanup_workspace "$workspace"
193
+ return 1
194
+ }
195
+ mv "$stage_dir" "$release_dir" || {
196
+ cleanup_workspace "$workspace"
197
+ return 1
198
+ }
199
+ cleanup_workspace "$workspace"
200
+
201
+ activate_release "$tag_name" "$release_dir"
202
+ }
203
+
204
+ ensure_initial_release() {
205
+ if load_latest_release; then
206
+ if install_release "$LATEST_TAG" "$LATEST_ASSET_URL"; then
207
+ return 0
208
+ fi
209
+ log "警告: 安装最新版本失败,尝试使用已有版本继续启动"
210
+ fi
211
+
212
+ [ -x "$(current_binary_path)" ]
213
+ }
214
+
215
+ restart_managed_service() {
216
+ supervisorctl -c "$SUPERVISOR_CONF" restart "$SUPERVISOR_PROGRAM_NAME"
217
+ }
218
+
219
+ update_if_needed() {
220
+ load_latest_release || {
221
+ log "检查最新版本失败"
222
+ return 1
223
+ }
224
+
225
+ installed_tag=$(current_tag)
226
+ if [ "$LATEST_TAG" = "$installed_tag" ]; then
227
+ log "当前已是最新版本: $LATEST_TAG"
228
+ return 0
229
+ fi
230
+
231
+ log "发现新版本: ${installed_tag:-<none>} -> $LATEST_TAG"
232
+ install_release "$LATEST_TAG" "$LATEST_ASSET_URL" || {
233
+ log "安装新版本失败: $LATEST_TAG"
234
+ return 1
235
+ }
236
+
237
+ if [ -n "$installed_tag" ]; then
238
+ restart_managed_service
239
+ fi
240
+ }
scripts/release-common.sh CHANGED
@@ -1,15 +1,16 @@
1
  #!/bin/sh
2
 
3
  : "${REPO_API_URL:=https://api.github.com/repos/caidaoli/CLIProxyAPI/releases/latest}"
4
- : "${RUNTIME_DIR:=/tmp/cliproxyapi}"
5
  : "${RELEASES_DIR:=$RUNTIME_DIR/releases}"
6
  : "${CURRENT_LINK:=$RUNTIME_DIR/current}"
7
  : "${CURRENT_TAG_FILE:=$RUNTIME_DIR/current.tag}"
8
  : "${DOWNLOADS_DIR:=$RUNTIME_DIR/downloads}"
9
  : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
10
- : "${SUPERVISOR_PROGRAM_NAME:=cliproxyapi}"
11
- : "${CURRENT_BINARY_NAME:=cli-proxy-api}"
12
- : "${APP_BINARY_NAMES:=cli-proxy-api CLIProxyAPI}"
 
13
 
14
  log() {
15
  timestamp=$(date '+%Y-%m-%d %H:%M:%S %z')
@@ -80,7 +81,23 @@ find_release_binary() {
80
  fi
81
  done
82
 
83
- find "$release_dir" -maxdepth 3 -type f \( -name 'cli-proxy-api' -o -name 'CLIProxyAPI' \) | head -n 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  activate_release() {
 
1
  #!/bin/sh
2
 
3
  : "${REPO_API_URL:=https://api.github.com/repos/caidaoli/CLIProxyAPI/releases/latest}"
4
+ : "${RUNTIME_DIR:=/tmp/runtime}"
5
  : "${RELEASES_DIR:=$RUNTIME_DIR/releases}"
6
  : "${CURRENT_LINK:=$RUNTIME_DIR/current}"
7
  : "${CURRENT_TAG_FILE:=$RUNTIME_DIR/current.tag}"
8
  : "${DOWNLOADS_DIR:=$RUNTIME_DIR/downloads}"
9
  : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
10
+ : "${SUPERVISOR_PROGRAM_NAME:=app}"
11
+ : "${SUPERVISOR_UPDATER_PROGRAM_NAME:=${SUPERVISOR_PROGRAM_NAME}-updater}"
12
+ : "${CURRENT_BINARY_NAME:=app}"
13
+ : "${APP_BINARY_NAMES:=}"
14
 
15
  log() {
16
  timestamp=$(date '+%Y-%m-%d %H:%M:%S %z')
 
81
  fi
82
  done
83
 
84
+ for name in $APP_BINARY_NAMES; do
85
+ binary_path=$(find "$release_dir" -maxdepth 3 -type f -name "$name" | head -n 1)
86
+ if [ -n "$binary_path" ]; then
87
+ printf '%s\n' "$binary_path"
88
+ return 0
89
+ fi
90
+ done
91
+
92
+ file_list=$(find "$release_dir" -maxdepth 3 -type f ! -name '._*' ! -path '*/__MACOSX/*' | sort)
93
+ first_file=$(printf '%s\n' "$file_list" | sed -n '1p')
94
+ second_file=$(printf '%s\n' "$file_list" | sed -n '2p')
95
+ if [ -n "$first_file" ] && [ -z "$second_file" ]; then
96
+ printf '%s\n' "$first_file"
97
+ return 0
98
+ fi
99
+
100
+ return 1
101
  }
102
 
103
  activate_release() {
supervisord.conf CHANGED
@@ -15,7 +15,7 @@ supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
15
  [supervisorctl]
16
  serverurl=unix://%(ENV_RUNTIME_DIR)s/supervisor.sock
17
 
18
- [program:cliproxyapi]
19
  command=/bin/sh %(ENV_RUNTIME_DIR)s/run-app.sh
20
  autostart=true
21
  autorestart=true
@@ -28,7 +28,7 @@ stdout_logfile_maxbytes=0
28
  stderr_logfile=/dev/fd/2
29
  stderr_logfile_maxbytes=0
30
 
31
- [program:cliproxyapi-updater]
32
  command=/usr/local/bin/update-loop.sh
33
  autostart=true
34
  autorestart=true
 
15
  [supervisorctl]
16
  serverurl=unix://%(ENV_RUNTIME_DIR)s/supervisor.sock
17
 
18
+ [program:__APP_PROGRAM__]
19
  command=/bin/sh %(ENV_RUNTIME_DIR)s/run-app.sh
20
  autostart=true
21
  autorestart=true
 
28
  stderr_logfile=/dev/fd/2
29
  stderr_logfile_maxbytes=0
30
 
31
+ [program:__UPDATER_PROGRAM__]
32
  command=/usr/local/bin/update-loop.sh
33
  autostart=true
34
  autorestart=true
update-loop.sh ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ : "${UPDATE_INTERVAL_SECONDS:=3600}"
5
+ : "${RELEASE_COMMON_SH:=/usr/local/bin/release-common.sh}"
6
+
7
+ . "$RELEASE_COMMON_SH"
8
+
9
+ while true; do
10
+ sleep "$UPDATE_INTERVAL_SECONDS"
11
+ log "开始定时版本检查"
12
+ if ! update_if_needed; then
13
+ log "警告: 自动更新检查失败,继续运行当前版本"
14
+ fi
15
+ done