Apache777 commited on
Commit
47d6c4e
·
verified ·
1 Parent(s): 842ff4f

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +3 -8
  2. README.md +6 -5
  3. entrypoint.sh +12 -10
  4. scripts/release-common.sh +263 -0
  5. scripts/update-loop.sh +15 -0
  6. supervisord.conf +12 -0
Dockerfile CHANGED
@@ -1,9 +1,6 @@
1
  FROM alpine:3.21
2
 
3
- ARG APP_VERSION=v9.1.18-sol
4
-
5
  ENV TZ=Asia/Shanghai
6
- ENV APP_BINARY_PATH=/app/app
7
  ENV RUNTIME_DIR=/tmp/runtime
8
  ENV SUPERVISOR_CONF=/etc/supervisord.conf
9
  ENV SUPERVISOR_CONF_TEMPLATE=/etc/supervisord.conf.template
@@ -13,12 +10,10 @@ RUN apk add --no-cache ca-certificates curl supervisor tzdata \
13
  && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
14
  && echo $TZ > /etc/timezone
15
 
16
- RUN mkdir -p "$(dirname "$APP_BINARY_PATH")" \
17
- && curl -fsSL "https://github.com/Apache-0201/CLIProxyAPI/releases/download/${APP_VERSION}/cli-proxy-api-linux-amd64" -o "$APP_BINARY_PATH" \
18
- && chmod +x "$APP_BINARY_PATH"
19
-
20
  COPY entrypoint.sh /usr/local/bin/entrypoint.sh
 
 
21
  COPY supervisord.conf /etc/supervisord.conf.template
22
- RUN chmod +x /usr/local/bin/entrypoint.sh
23
 
24
  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
 
10
  && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
11
  && echo $TZ > /etc/timezone
12
 
 
 
 
 
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.template
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"]
README.md CHANGED
@@ -1,9 +1,10 @@
1
  ---
2
- title: codex
3
- emoji: 🎨
4
- colorFrom: red
5
- colorTo: gray
6
  sdk: docker
7
  pinned: false
8
  app_port: 8317
9
- ---
 
 
1
  ---
2
+ title: Cpa
3
+ emoji: 💻
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
  app_port: 8317
9
+ ---
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
entrypoint.sh CHANGED
@@ -1,15 +1,15 @@
1
  #!/bin/sh
2
  set -eu
3
 
 
4
  : "${SUPERVISORD_BIN:=/usr/bin/supervisord}"
5
  : "${SUPERVISOR_CONF_TEMPLATE:=/etc/supervisord.conf.template}"
6
- : "${APP_BINARY_PATH:=/app/app}"
7
- : "${RUNTIME_DIR:=/tmp/runtime}"
8
- : "${SUPERVISOR_CONF:=/etc/supervisord.conf}"
9
- : "${SUPERVISOR_PROGRAM_NAME:=app}"
10
  : "${OPEN_FILE_LIMIT:=65535}"
11
 
 
 
12
  export RUNTIME_DIR
 
13
 
14
  shell_quote() {
15
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
@@ -22,9 +22,11 @@ escape_sed_replacement() {
22
  write_supervisord_conf() {
23
  mkdir -p "$(dirname "$SUPERVISOR_CONF")"
24
  app_program_name=$(escape_sed_replacement "$SUPERVISOR_PROGRAM_NAME")
 
25
 
26
  sed \
27
  -e "s/__APP_PROGRAM__/$app_program_name/g" \
 
28
  "$SUPERVISOR_CONF_TEMPLATE" > "$SUPERVISOR_CONF"
29
  }
30
 
@@ -34,7 +36,7 @@ write_run_app_script() {
34
  {
35
  printf '#!/bin/sh\n'
36
  printf 'set -eu\n'
37
- printf 'exec "%s"' "$APP_BINARY_PATH"
38
  for arg in "$@"; do
39
  printf ' %s' "$(shell_quote "$arg")"
40
  done
@@ -46,13 +48,13 @@ write_run_app_script() {
46
 
47
  prepare_runtime_environment() {
48
  ulimit -n "$OPEN_FILE_LIMIT"
49
- mkdir -p "$RUNTIME_DIR"
50
  rm -f "$RUNTIME_DIR/supervisor.sock" "$RUNTIME_DIR/supervisord.pid"
51
  }
52
 
53
- validate_app_binary_or_exit() {
54
- if [ ! -x "$APP_BINARY_PATH" ]; then
55
- echo "错误: APP_BINARY_PATH 指向的文件不存在或不可执行: $APP_BINARY_PATH" >&2
56
  exit 1
57
  fi
58
  }
@@ -63,8 +65,8 @@ start_supervisord() {
63
 
64
  main() {
65
  prepare_runtime_environment
66
- validate_app_binary_or_exit
67
  write_supervisord_conf
 
68
  write_run_app_script "$@"
69
  start_supervisord
70
  }
 
1
  #!/bin/sh
2
  set -eu
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"
10
+
11
  export RUNTIME_DIR
12
+ export SUPERVISOR_CONF
13
 
14
  shell_quote() {
15
  printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\"'\"'/g")"
 
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
 
 
36
  {
37
  printf '#!/bin/sh\n'
38
  printf 'set -eu\n'
39
+ printf 'exec "%s"' "$(current_binary_path)"
40
  for arg in "$@"; do
41
  printf ' %s' "$(shell_quote "$arg")"
42
  done
 
48
 
49
  prepare_runtime_environment() {
50
  ulimit -n "$OPEN_FILE_LIMIT"
51
+ ensure_runtime_dirs
52
  rm -f "$RUNTIME_DIR/supervisor.sock" "$RUNTIME_DIR/supervisord.pid"
53
  }
54
 
55
+ bootstrap_release_or_exit() {
56
+ if ! ensure_initial_release; then
57
+ echo "错误: 初次启动时无法准备可运行版本" >&2
58
  exit 1
59
  fi
60
  }
 
65
 
66
  main() {
67
  prepare_runtime_environment
 
68
  write_supervisord_conf
69
+ bootstrap_release_or_exit
70
  write_run_app_script "$@"
71
  start_supervisord
72
  }
scripts/release-common.sh ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ : "${REPO_RELEASES_URL:=https://github.com/caidaoli/CLIProxyAPI/releases}"
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
+ repo_base_url() {
43
+ # Strip a trailing "/releases" (and any trailing slash) to get the repo root.
44
+ printf '%s\n' "$REPO_RELEASES_URL" | sed -E 's#/+$##; s#/releases$##'
45
+ }
46
+
47
+ resolve_latest_tag() {
48
+ # /releases/latest 302-redirects to /releases/tag/<tag>; read the final URL.
49
+ effective_url=$(
50
+ curl -fsSL -o /dev/null -w '%{url_effective}' "$REPO_RELEASES_URL/latest"
51
+ ) || return 1
52
+
53
+ tag_name=$(
54
+ printf '%s\n' "$effective_url" \
55
+ | sed -n 's#.*/releases/tag/##p' \
56
+ | head -n 1
57
+ )
58
+
59
+ [ -n "$tag_name" ] || return 1
60
+ printf '%s\n' "$tag_name"
61
+ }
62
+
63
+ fetch_latest_release_info() {
64
+ tag_name=$(resolve_latest_tag) || return 1
65
+
66
+ base_url=$(repo_base_url)
67
+
68
+ # The expanded_assets fragment lists every asset as an <a href="..."> link.
69
+ assets_html=$(curl -fsSL "$base_url/releases/expanded_assets/$tag_name") || return 1
70
+
71
+ asset_path=$(
72
+ printf '%s\n' "$assets_html" \
73
+ | grep -Eo 'href="[^"]*/releases/download/[^"]+"' \
74
+ | cut -d '"' -f 2 \
75
+ | grep -E '/[^/]*linux[-_]amd64(\.tar\.gz)?$' \
76
+ | head -n 1 \
77
+ || true
78
+ )
79
+
80
+ [ -n "$asset_path" ] || return 1
81
+
82
+ case "$asset_path" in
83
+ http://*|https://*) asset_url=$asset_path ;;
84
+ /*) asset_url="https://github.com$asset_path" ;;
85
+ *) asset_url="$base_url/$asset_path" ;;
86
+ esac
87
+
88
+ printf '%s|%s\n' "$tag_name" "$asset_url"
89
+ }
90
+
91
+ load_latest_release() {
92
+ release_info=$(fetch_latest_release_info) || return 1
93
+ LATEST_TAG=${release_info%%|*}
94
+ LATEST_ASSET_URL=${release_info#*|}
95
+ }
96
+
97
+ find_release_binary() {
98
+ release_dir=$1
99
+
100
+ for name in $APP_BINARY_NAMES; do
101
+ if [ -f "$release_dir/$name" ]; then
102
+ printf '%s\n' "$release_dir/$name"
103
+ return 0
104
+ fi
105
+ done
106
+
107
+ for name in $APP_BINARY_NAMES; do
108
+ binary_path=$(find "$release_dir" -maxdepth 3 -type f -name "$name" | head -n 1)
109
+ if [ -n "$binary_path" ]; then
110
+ printf '%s\n' "$binary_path"
111
+ return 0
112
+ fi
113
+ done
114
+
115
+ file_list=$(find "$release_dir" -maxdepth 3 -type f ! -name '._*' ! -path '*/__MACOSX/*' | sort)
116
+ first_file=$(printf '%s\n' "$file_list" | sed -n '1p')
117
+ second_file=$(printf '%s\n' "$file_list" | sed -n '2p')
118
+ if [ -n "$first_file" ] && [ -z "$second_file" ]; then
119
+ printf '%s\n' "$first_file"
120
+ return 0
121
+ fi
122
+
123
+ return 1
124
+ }
125
+
126
+ activate_release() {
127
+ tag_name=$1
128
+ release_dir=$2
129
+
130
+ rm -f "$CURRENT_LINK"
131
+ ln -s "$release_dir" "$CURRENT_LINK"
132
+ printf '%s\n' "$tag_name" > "$CURRENT_TAG_FILE"
133
+ }
134
+
135
+ extract_release_binary() {
136
+ source_dir=$1
137
+ target_path=$2
138
+ binary_path=$(find_release_binary "$source_dir" || true)
139
+
140
+ if [ -z "$binary_path" ]; then
141
+ return 1
142
+ fi
143
+
144
+ if [ "$binary_path" != "$target_path" ]; then
145
+ cp "$binary_path" "$target_path"
146
+ fi
147
+ chmod +x "$target_path"
148
+ }
149
+
150
+ cleanup_workspace() {
151
+ workspace=$1
152
+ if [ -n "$workspace" ] && [ -d "$workspace" ]; then
153
+ rm -rf "$workspace"
154
+ fi
155
+ }
156
+
157
+ install_release() {
158
+ tag_name=$1
159
+ asset_url=$2
160
+
161
+ ensure_runtime_dirs
162
+ release_dir=$(release_dir_for_tag "$tag_name")
163
+ release_binary="$release_dir/$CURRENT_BINARY_NAME"
164
+
165
+ if [ -x "$release_binary" ]; then
166
+ activate_release "$tag_name" "$release_dir"
167
+ return 0
168
+ fi
169
+
170
+ workspace=$(mktemp -d "$RUNTIME_DIR/install.XXXXXX") || return 1
171
+ download_name=$(basename "$asset_url")
172
+ if [ -z "$download_name" ] || [ "$download_name" = "/" ] || [ "$download_name" = "." ]; then
173
+ download_name="release.asset"
174
+ fi
175
+ download_path="$DOWNLOADS_DIR/$download_name"
176
+ stage_dir="$workspace/stage"
177
+
178
+ rm -f "$download_path" || {
179
+ cleanup_workspace "$workspace"
180
+ return 1
181
+ }
182
+ mkdir -p "$stage_dir" || {
183
+ cleanup_workspace "$workspace"
184
+ return 1
185
+ }
186
+ curl -fsSL "$asset_url" -o "$download_path" || {
187
+ cleanup_workspace "$workspace"
188
+ return 1
189
+ }
190
+
191
+ case "$download_path" in
192
+ *.tar.gz)
193
+ tar -xzf "$download_path" -C "$stage_dir" || {
194
+ cleanup_workspace "$workspace"
195
+ return 1
196
+ }
197
+ extract_release_binary "$stage_dir" "$stage_dir/$CURRENT_BINARY_NAME" || {
198
+ cleanup_workspace "$workspace"
199
+ return 1
200
+ }
201
+ ;;
202
+ *)
203
+ cp "$download_path" "$stage_dir/$CURRENT_BINARY_NAME" || {
204
+ cleanup_workspace "$workspace"
205
+ return 1
206
+ }
207
+ chmod +x "$stage_dir/$CURRENT_BINARY_NAME" || {
208
+ cleanup_workspace "$workspace"
209
+ return 1
210
+ }
211
+ ;;
212
+ esac
213
+
214
+ rm -rf "$release_dir" || {
215
+ cleanup_workspace "$workspace"
216
+ return 1
217
+ }
218
+ mv "$stage_dir" "$release_dir" || {
219
+ cleanup_workspace "$workspace"
220
+ return 1
221
+ }
222
+ cleanup_workspace "$workspace"
223
+
224
+ activate_release "$tag_name" "$release_dir"
225
+ }
226
+
227
+ ensure_initial_release() {
228
+ if load_latest_release; then
229
+ if install_release "$LATEST_TAG" "$LATEST_ASSET_URL"; then
230
+ return 0
231
+ fi
232
+ log "警告: 安装最新版本失败,尝试使用已有版本继续启动"
233
+ fi
234
+
235
+ [ -x "$(current_binary_path)" ]
236
+ }
237
+
238
+ restart_managed_service() {
239
+ supervisorctl -c "$SUPERVISOR_CONF" restart "$SUPERVISOR_PROGRAM_NAME"
240
+ }
241
+
242
+ update_if_needed() {
243
+ load_latest_release || {
244
+ log "检查最新版本失败"
245
+ return 1
246
+ }
247
+
248
+ installed_tag=$(current_tag)
249
+ if [ "$LATEST_TAG" = "$installed_tag" ]; then
250
+ log "当前已是最新版本: $LATEST_TAG"
251
+ return 0
252
+ fi
253
+
254
+ log "发现新版本: ${installed_tag:-<none>} -> $LATEST_TAG"
255
+ install_release "$LATEST_TAG" "$LATEST_ASSET_URL" || {
256
+ log "安装新版本失败: $LATEST_TAG"
257
+ return 1
258
+ }
259
+
260
+ if [ -n "$installed_tag" ]; then
261
+ restart_managed_service
262
+ fi
263
+ }
scripts/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
supervisord.conf CHANGED
@@ -27,3 +27,15 @@ stdout_logfile=/dev/fd/1
27
  stdout_logfile_maxbytes=0
28
  stderr_logfile=/dev/fd/2
29
  stderr_logfile_maxbytes=0
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  stdout_logfile_maxbytes=0
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
35
+ startsecs=0
36
+ stopasgroup=true
37
+ killasgroup=true
38
+ stdout_logfile=/dev/fd/1
39
+ stdout_logfile_maxbytes=0
40
+ stderr_logfile=/dev/fd/2
41
+ stderr_logfile_maxbytes=0