create-entity-app-server 0.1.16 → 0.2.1
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/dist-create/template/.gateway-version +1 -1
- package/dist-create/template/app/plugins/ocr/cache.ts +1 -1
- package/dist-create/template/app/plugins/ocr/config.ts +1 -1
- package/dist-create/template/app/plugins/ocr/direction.ts +1 -1
- package/dist-create/template/app/plugins/ocr/dispatch.ts +1 -1
- package/dist-create/template/app/plugins/ocr/entity-adapter.ts +1 -1
- package/dist-create/template/app/plugins/ocr/errors.ts +1 -1
- package/dist-create/template/app/plugins/ocr/handlers.ts +1 -1
- package/dist-create/template/app/plugins/ocr/index.ts +1 -1
- package/dist-create/template/app/plugins/ocr/llm-parser.ts +1 -1
- package/dist-create/template/app/plugins/ocr/parsing-pipeline.ts +1 -1
- package/dist-create/template/app/plugins/ocr/pdf-converter.ts +1 -1
- package/dist-create/template/app/plugins/ocr/preprocessor.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/aws.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/azure.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/google.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/index.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/naver.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/tesseract.ts +1 -1
- package/dist-create/template/app/plugins/ocr/providers/upstage.ts +1 -1
- package/dist-create/template/app/plugins/ocr/quota.ts +1 -1
- package/dist-create/template/app/plugins/ocr/refiner.ts +1 -1
- package/dist-create/template/app/plugins/ocr/routes.ts +1 -1
- package/dist-create/template/app/plugins/ocr/service.ts +1 -1
- package/dist-create/template/app/plugins/ocr/template-loader.ts +1 -1
- package/dist-create/template/app/plugins/ocr/template-matcher.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/config.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/driver.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/index.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/parsed.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/store.ts +1 -1
- package/dist-create/template/app/plugins/ocr/types/template.ts +1 -1
- package/dist-create/template/app/plugins/ocr/utils.ts +1 -1
- package/dist-create/template/app/plugins/smtp/config.ts +41 -1
- package/dist-create/template/app/plugins/smtp/handlers.ts +52 -1
- package/dist-create/template/app/plugins/smtp/index.ts +33 -1
- package/dist-create/template/app/plugins/smtp/routes.ts +19 -1
- package/dist-create/template/app/plugins/smtp/types/config.ts +8 -1
- package/dist-create/template/app/plugins/smtp/types/index.ts +1 -1
- package/dist-create/template/docs/configs.md +7 -7
- package/dist-create/template/docs/scripts-guide.md +49 -19
- package/dist-create/template/scripts/build.sh +222 -0
- package/dist-create/template/scripts/run.sh +25 -6
- package/dist-create/template/scripts/service-install.sh +174 -0
- package/dist-create/template/scripts/service-remove.sh +102 -0
- package/dist-create/template/scripts/update-server.sh +25 -20
- package/dist-create/template/system-api.js +1 -1
- package/dist-create/template/system.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# build.sh — Gateway TypeScript 빌드 + dist/ dist-create/ 패키징
|
|
3
|
+
#
|
|
4
|
+
# dist/ 구조:
|
|
5
|
+
# 실행/배포용 산출물. build 결과를 바로 실행하거나 서버에 배포할 때 사용한다.
|
|
6
|
+
#
|
|
7
|
+
# dist-create/ 구조:
|
|
8
|
+
# npm create entity-app-server 가 내려받는 템플릿 원본.
|
|
9
|
+
# create 스캐폴딩 시 복사될 파일만 template/ 아래에 담는다.
|
|
10
|
+
#
|
|
11
|
+
# 실행:
|
|
12
|
+
# ./scripts/build.sh — 빌드 + 패키징
|
|
13
|
+
# ./scripts/build.sh --no-tar — tar.gz 없이 빌드만
|
|
14
|
+
|
|
15
|
+
set -eo pipefail
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
19
|
+
|
|
20
|
+
cd "$PROJECT_ROOT"
|
|
21
|
+
|
|
22
|
+
is_source_repo_mode() {
|
|
23
|
+
[ -d "$PROJECT_ROOT/src/system" ] && [ -f "$PROJECT_ROOT/scripts/build-obfuscate-system.mjs" ]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
package_generated_project() {
|
|
27
|
+
VERSION=$(grep '"version"' package.json | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
28
|
+
COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
29
|
+
BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
30
|
+
|
|
31
|
+
echo ""
|
|
32
|
+
echo " Entity App Server v${VERSION} · ${COMMIT} · ${BUILD_TIME}"
|
|
33
|
+
echo ""
|
|
34
|
+
|
|
35
|
+
echo " [1/3] Packaging runtime files..."
|
|
36
|
+
|
|
37
|
+
rm -rf dist
|
|
38
|
+
mkdir -p dist/scripts
|
|
39
|
+
|
|
40
|
+
[ -f "system.js" ] && cp "system.js" dist/system.js
|
|
41
|
+
[ -f "system-api.js" ] && cp "system-api.js" dist/system-api.js
|
|
42
|
+
[ -f "tsconfig.json" ] && cp "tsconfig.json" dist/tsconfig.json
|
|
43
|
+
|
|
44
|
+
[ -d "app" ] && cp -R app dist/app
|
|
45
|
+
[ -d "configs" ] && cp -R configs dist/configs
|
|
46
|
+
[ -d "entities" ] && cp -R entities dist/entities
|
|
47
|
+
|
|
48
|
+
for script in build.sh reset-all.sh run.sh entity.sh update-server.sh service-install.sh service-remove.sh; do
|
|
49
|
+
[ -f "scripts/$script" ] && install -m 755 "scripts/$script" "dist/scripts/$script"
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
if [ -d "docs" ]; then
|
|
53
|
+
cp -R docs dist/docs
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
[ -f ".env.example" ] && cp .env.example dist/.env
|
|
57
|
+
[ -f ".env.example" ] && cp .env.example dist/.env.example
|
|
58
|
+
[ -f ".gateway-version" ] && cp .gateway-version dist/.gateway-version
|
|
59
|
+
|
|
60
|
+
echo " ✓ dist/"
|
|
61
|
+
|
|
62
|
+
if [ "${1:-}" != "--no-tar" ]; then
|
|
63
|
+
echo " [2/3] Creating dist.tar.gz..."
|
|
64
|
+
(cd dist && tar -czf "$PROJECT_ROOT/dist.tar.gz" .)
|
|
65
|
+
echo " ✓ dist.tar.gz"
|
|
66
|
+
else
|
|
67
|
+
echo " [2/3] Skipped dist.tar.gz (--no-tar)"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
echo " [3/3] Done"
|
|
71
|
+
echo ""
|
|
72
|
+
echo " 실행: ./scripts/run.sh start"
|
|
73
|
+
echo " 개발: ./scripts/run.sh dev"
|
|
74
|
+
echo ""
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ! is_source_repo_mode; then
|
|
78
|
+
package_generated_project "$1"
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
replace_example_configs() {
|
|
83
|
+
local target_root="$1"
|
|
84
|
+
|
|
85
|
+
for scope in plugins routes schedules; do
|
|
86
|
+
[ -d "$target_root/app/$scope" ] || continue
|
|
87
|
+
|
|
88
|
+
find "$target_root/app/$scope" -name "config.example.json" | while read -r file; do
|
|
89
|
+
dir="$(dirname "$file")"
|
|
90
|
+
rm -f "$dir/config.json"
|
|
91
|
+
cp "$file" "$dir/config.json"
|
|
92
|
+
rm -f "$file"
|
|
93
|
+
done
|
|
94
|
+
done
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
VERSION=$(grep '"version"' package.json | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
98
|
+
COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
99
|
+
BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
100
|
+
|
|
101
|
+
echo ""
|
|
102
|
+
echo " Entity Server Gateway v${VERSION} · ${COMMIT} · ${BUILD_TIME}"
|
|
103
|
+
echo ""
|
|
104
|
+
|
|
105
|
+
# ─── [1/5] TypeScript 빌드 (난독화 번들 + 타입 체크) ──────────────────────────
|
|
106
|
+
|
|
107
|
+
echo " [1/5] Building TypeScript..."
|
|
108
|
+
npm run build
|
|
109
|
+
node "$SCRIPT_DIR/build-obfuscate-system.mjs" 2>&1 | grep -v "\[javascript-obfuscator\]" || true
|
|
110
|
+
echo " ✓ dist/system.js (난독화 번들)"
|
|
111
|
+
echo " ✓ dist/system-api.js (공개 API 번들)"
|
|
112
|
+
|
|
113
|
+
# ─── [2/5] 소스 복사 ──────────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
echo " [2/5] Copying sources..."
|
|
116
|
+
|
|
117
|
+
# 이전 빌드 잔재 system/ 폴더 제거 (system-api.js 번들로 대체됨)
|
|
118
|
+
rm -rf dist/system
|
|
119
|
+
|
|
120
|
+
# app/ — 사용자 편집 가능 TypeScript 소스
|
|
121
|
+
rm -rf dist/app
|
|
122
|
+
cp -r src/app dist/app
|
|
123
|
+
|
|
124
|
+
# example config 초기화:
|
|
125
|
+
# - plugins/routes/schedules 에 config.example.json 이 있으면 dist 의 config.json 으로 교체
|
|
126
|
+
# - source config.json 은 deploy/minify 판단용으로만 유지
|
|
127
|
+
replace_example_configs "dist"
|
|
128
|
+
|
|
129
|
+
echo " ✓ dist/app/ (plugins/routes/schedules config.json ← config.example.json)"
|
|
130
|
+
|
|
131
|
+
# deploy 가 true가 아닌 항목(false 또는 누락)은 dist에서 제거
|
|
132
|
+
for category in plugins routes schedules; do
|
|
133
|
+
src_base="src/app/${category}"
|
|
134
|
+
dist_base="dist/app/${category}"
|
|
135
|
+
for cfg in "${src_base}"/*/config.json "${src_base}"/*/*/config.json; do
|
|
136
|
+
[ -f "$cfg" ] || continue
|
|
137
|
+
if ! grep -q '"deploy"[[:space:]]*:[[:space:]]*true' "$cfg" 2>/dev/null; then
|
|
138
|
+
rel="${cfg#${src_base}/}"
|
|
139
|
+
name="${rel%/config.json}"
|
|
140
|
+
rm -rf "${dist_base}/${name}"
|
|
141
|
+
echo " ✗ app/${category}/${name} (배포 제외)"
|
|
142
|
+
fi
|
|
143
|
+
done
|
|
144
|
+
done
|
|
145
|
+
|
|
146
|
+
# 난독화 실행 (복사 후 dist .ts 파일 인플레이스 처리)
|
|
147
|
+
node "$SCRIPT_DIR/build-minify-plugins.mjs" 2>&1 | grep -v "\[javascript-obfuscator\]" || true
|
|
148
|
+
|
|
149
|
+
# 배포 결과물의 app config 는 config.example.json 기준으로 생성됨
|
|
150
|
+
|
|
151
|
+
# tsconfig.json — tsx 런타임 경로 별칭 (@system/* @app/*)
|
|
152
|
+
cp "$SCRIPT_DIR/dist-tsconfig.json" dist/tsconfig.json
|
|
153
|
+
echo " ✓ dist/tsconfig.json"
|
|
154
|
+
|
|
155
|
+
# ─── [3/5] 설정·리소스 복사 ────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
echo " [3/5] Packaging resources..."
|
|
158
|
+
|
|
159
|
+
# configs/
|
|
160
|
+
if [ -d "configs" ]; then
|
|
161
|
+
rm -rf dist/configs && mkdir -p dist/configs
|
|
162
|
+
cp -r configs/. dist/configs/
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# entities/
|
|
166
|
+
if [ -d "entities" ]; then
|
|
167
|
+
rm -rf dist/entities && mkdir -p dist/entities
|
|
168
|
+
cp -r entities/. dist/entities/
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# scripts/
|
|
172
|
+
mkdir -p dist/scripts
|
|
173
|
+
for script in build.sh reset-all.sh run.sh entity.sh update-server.sh service-install.sh service-remove.sh; do
|
|
174
|
+
[ -f "scripts/$script" ] && install -m 755 "scripts/$script" "dist/scripts/$script"
|
|
175
|
+
done
|
|
176
|
+
|
|
177
|
+
# docs/ (design/ 제외)
|
|
178
|
+
if [ -d "docs" ]; then
|
|
179
|
+
rm -rf dist/docs
|
|
180
|
+
cp -r docs dist/docs
|
|
181
|
+
rm -rf dist/docs/design
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
# .env / .env.example
|
|
185
|
+
[ -f ".env.example" ] && cp .env.example dist/.env
|
|
186
|
+
[ -f ".env.example" ] && cp .env.example dist/.env.example
|
|
187
|
+
printf 'v%s\n' "$VERSION" > dist/.gateway-version
|
|
188
|
+
|
|
189
|
+
echo " ✓ configs/ entities/ scripts/ docs/ .env .env.example"
|
|
190
|
+
|
|
191
|
+
# ─── [4/5] create 템플릿 패키징 ───────────────────────────────────────────────
|
|
192
|
+
|
|
193
|
+
echo " [4/5] Packaging dist-create/..."
|
|
194
|
+
|
|
195
|
+
rm -rf dist-create
|
|
196
|
+
mkdir -p dist-create/template
|
|
197
|
+
|
|
198
|
+
for entry in app configs docs scripts system.js system-api.js tsconfig.json .env .env.example .gateway-version; do
|
|
199
|
+
[ -e "dist/$entry" ] && cp -R "dist/$entry" dist-create/template/
|
|
200
|
+
done
|
|
201
|
+
|
|
202
|
+
echo " ✓ dist-create/template/"
|
|
203
|
+
|
|
204
|
+
# ─── [5/5] tar.gz 패키징 ──────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
if [ "$1" != "--no-tar" ]; then
|
|
207
|
+
echo " [5/5] Creating dist.tar.gz..."
|
|
208
|
+
(cd dist && tar -czf "$PROJECT_ROOT/dist.tar.gz" .)
|
|
209
|
+
echo " ✓ dist.tar.gz"
|
|
210
|
+
else
|
|
211
|
+
echo " [5/5] Skipped dist.tar.gz (--no-tar)"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
echo ""
|
|
215
|
+
echo " Done."
|
|
216
|
+
echo ""
|
|
217
|
+
echo " 스크립트 사용법:"
|
|
218
|
+
echo " ./scripts/run.sh start # 프로덕션 실행"
|
|
219
|
+
echo " ./scripts/run.sh stop # 서버 종료"
|
|
220
|
+
echo " ./scripts/run.sh dev # 개발 모드 (tsx watch)"
|
|
221
|
+
echo ""
|
|
222
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# run.sh — Entity App Server 실행 / 종료
|
|
3
3
|
#
|
|
4
4
|
# 사용법:
|
|
5
|
-
# ./scripts/run.sh start — 프로덕션 모드 백그라운드 실행 (dist/system.js)
|
|
5
|
+
# ./scripts/run.sh start — 프로덕션 모드 백그라운드 실행 (dist/system.js 또는 system.js)
|
|
6
6
|
# ./scripts/run.sh stop — 실행 중인 서버 종료
|
|
7
7
|
# ./scripts/run.sh dev — 개발 모드 실행 (tsx watch)
|
|
8
8
|
|
|
@@ -272,6 +272,20 @@ show_port_in_use_error() {
|
|
|
272
272
|
echo " 먼저 종료하려면: $0 stop"
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
get_runtime_entry() {
|
|
276
|
+
if [ -f "$PROJECT_ROOT/dist/system.js" ]; then
|
|
277
|
+
echo "$PROJECT_ROOT/dist/system.js"
|
|
278
|
+
return 0
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
if [ -f "$PROJECT_ROOT/system.js" ]; then
|
|
282
|
+
echo "$PROJECT_ROOT/system.js"
|
|
283
|
+
return 0
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
return 1
|
|
287
|
+
}
|
|
288
|
+
|
|
275
289
|
ensure_port_available() {
|
|
276
290
|
mapfile -t PORT_PIDS < <(find_gateway_pids)
|
|
277
291
|
if [ "${#PORT_PIDS[@]}" -gt 0 ]; then
|
|
@@ -312,7 +326,7 @@ _print_help() {
|
|
|
312
326
|
echo " 사용법: $0 <명령>"
|
|
313
327
|
echo ""
|
|
314
328
|
echo " 명령:"
|
|
315
|
-
echo " start 프로덕션 모드로 백그라운드 실행 (dist/system.js)"
|
|
329
|
+
echo " start 프로덕션 모드로 백그라운드 실행 (dist/system.js 또는 system.js)"
|
|
316
330
|
echo " stop 실행 중인 서버 종료"
|
|
317
331
|
echo " status 실행 상태 확인"
|
|
318
332
|
echo " dev 개발 모드 실행 (tsx watch)"
|
|
@@ -337,19 +351,24 @@ _print_help() {
|
|
|
337
351
|
|
|
338
352
|
if [ $# -eq 0 ]; then
|
|
339
353
|
_print_help
|
|
354
|
+
echo ""
|
|
355
|
+
echo "현재 상태:"
|
|
356
|
+
show_status
|
|
340
357
|
exit 0
|
|
341
358
|
fi
|
|
342
359
|
|
|
343
360
|
case "$1" in
|
|
344
361
|
start)
|
|
362
|
+
local_runtime_entry=""
|
|
345
363
|
ensure_port_available
|
|
346
364
|
ensure_env_ready
|
|
347
365
|
ensure_runtime_dependencies_installed
|
|
348
366
|
verify_entity_server_credentials
|
|
349
367
|
|
|
350
|
-
if
|
|
351
|
-
echo "❌
|
|
352
|
-
echo "
|
|
368
|
+
if ! local_runtime_entry="$(get_runtime_entry)"; then
|
|
369
|
+
echo "❌ 실행할 system.js를 찾지 못했습니다."
|
|
370
|
+
echo " dist/system.js 또는 system.js 중 하나가 있어야 합니다."
|
|
371
|
+
echo " 패키지가 손상됐다면 ./scripts/update-server.sh latest 를 다시 실행하세요."
|
|
353
372
|
exit 1
|
|
354
373
|
fi
|
|
355
374
|
|
|
@@ -365,7 +384,7 @@ case "$1" in
|
|
|
365
384
|
fi
|
|
366
385
|
|
|
367
386
|
mkdir -p "$(dirname "$LOG_FILE")"
|
|
368
|
-
|
|
387
|
+
nohup node --import tsx/esm "$local_runtime_entry" >> "$LOG_FILE" 2>&1 &
|
|
369
388
|
echo $! > "$PID_FILE"
|
|
370
389
|
PID=$(cat "$PID_FILE")
|
|
371
390
|
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
7
|
+
SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
|
|
8
|
+
|
|
9
|
+
if [ -f "$PROJECT_ROOT/.env" ]; then
|
|
10
|
+
LANGUAGE=$(grep '^LANGUAGE=' "$PROJECT_ROOT/.env" | cut -d '=' -f2)
|
|
11
|
+
fi
|
|
12
|
+
LANGUAGE=${LANGUAGE:-ko}
|
|
13
|
+
|
|
14
|
+
SERVICE_NAME="entity-app-server"
|
|
15
|
+
RUN_USER="${SUDO_USER:-$(stat -c '%U' "$PROJECT_ROOT")}"
|
|
16
|
+
RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
|
|
17
|
+
START_NOW=true
|
|
18
|
+
INTERACTIVE=false
|
|
19
|
+
|
|
20
|
+
load_service_name() {
|
|
21
|
+
local namespace=""
|
|
22
|
+
if [ -f "$SERVER_CONFIG" ]; then
|
|
23
|
+
namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
|
|
27
|
+
|
|
28
|
+
if [ -z "$namespace" ]; then
|
|
29
|
+
SERVICE_NAME="entity-app-server"
|
|
30
|
+
elif [[ "$namespace" == "entity-app-server" ]] || [[ "$namespace" == *"-entity-app-server" ]]; then
|
|
31
|
+
SERVICE_NAME="$namespace"
|
|
32
|
+
else
|
|
33
|
+
SERVICE_NAME="${namespace}-entity-app-server"
|
|
34
|
+
fi
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
load_service_name
|
|
38
|
+
|
|
39
|
+
if [ $# -eq 0 ]; then
|
|
40
|
+
INTERACTIVE=true
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
for arg in "$@"; do
|
|
44
|
+
case "$arg" in
|
|
45
|
+
--user=*)
|
|
46
|
+
RUN_USER="${arg#*=}"
|
|
47
|
+
;;
|
|
48
|
+
--group=*)
|
|
49
|
+
RUN_GROUP="${arg#*=}"
|
|
50
|
+
;;
|
|
51
|
+
--no-start)
|
|
52
|
+
START_NOW=false
|
|
53
|
+
;;
|
|
54
|
+
*)
|
|
55
|
+
if [ "$LANGUAGE" = "en" ]; then
|
|
56
|
+
echo "❌ Unknown option: $arg"
|
|
57
|
+
else
|
|
58
|
+
echo "❌ 알 수 없는 옵션: $arg"
|
|
59
|
+
fi
|
|
60
|
+
exit 1
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
if [ "$INTERACTIVE" = true ]; then
|
|
66
|
+
if [ "$LANGUAGE" = "en" ]; then
|
|
67
|
+
echo "[interactive] systemd service setup"
|
|
68
|
+
echo "service name: $SERVICE_NAME"
|
|
69
|
+
read -r -p "Run user [$RUN_USER]: " input
|
|
70
|
+
else
|
|
71
|
+
echo "[interactive] systemd 서비스 설정"
|
|
72
|
+
echo "서비스명: $SERVICE_NAME"
|
|
73
|
+
read -r -p "실행 사용자 [$RUN_USER]: " input
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if [ -n "$input" ]; then
|
|
77
|
+
RUN_USER="$input"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
if [ -z "$RUN_GROUP" ]; then
|
|
81
|
+
RUN_GROUP="$(id -gn "$RUN_USER" 2>/dev/null || true)"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if [ "$LANGUAGE" = "en" ]; then
|
|
85
|
+
read -r -p "Run group [$RUN_GROUP]: " input
|
|
86
|
+
else
|
|
87
|
+
read -r -p "실행 그룹 [$RUN_GROUP]: " input
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
if [ -n "$input" ]; then
|
|
91
|
+
RUN_GROUP="$input"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
if [ "$LANGUAGE" = "en" ]; then
|
|
95
|
+
read -r -p "Start service now? [Y/n]: " input
|
|
96
|
+
else
|
|
97
|
+
read -r -p "서비스를 즉시 시작할까요? [Y/n]: " input
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
|
|
101
|
+
if [ "$input" = "n" ] || [ "$input" = "no" ]; then
|
|
102
|
+
START_NOW=false
|
|
103
|
+
fi
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if [ -z "$RUN_GROUP" ]; then
|
|
107
|
+
RUN_GROUP="$(id -gn "$RUN_USER")"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if ! id -u "$RUN_USER" >/dev/null 2>&1; then
|
|
111
|
+
echo "❌ 사용자를 찾을 수 없습니다: $RUN_USER"
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
if ! getent group "$RUN_GROUP" >/dev/null 2>&1; then
|
|
116
|
+
echo "❌ 그룹을 찾을 수 없습니다: $RUN_GROUP"
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
if [ ! -x "$PROJECT_ROOT/scripts/run.sh" ]; then
|
|
121
|
+
chmod +x "$PROJECT_ROOT/scripts/run.sh"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
if [ ! -f "$PROJECT_ROOT/system.js" ]; then
|
|
125
|
+
echo "❌ system.js 파일이 없습니다. create-entity-app-server 로 생성된 프로젝트 루트인지 확인하세요."
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
|
|
130
|
+
|
|
131
|
+
if [ "$EUID" -ne 0 ]; then
|
|
132
|
+
if command -v sudo >/dev/null 2>&1; then
|
|
133
|
+
SUDO_ARGS=("--user=$RUN_USER" "--group=$RUN_GROUP")
|
|
134
|
+
if [ "$START_NOW" = false ]; then
|
|
135
|
+
SUDO_ARGS+=("--no-start")
|
|
136
|
+
fi
|
|
137
|
+
exec sudo "$0" "${SUDO_ARGS[@]}"
|
|
138
|
+
fi
|
|
139
|
+
echo "❌ 이 스크립트는 root 권한이 필요합니다"
|
|
140
|
+
exit 1
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
cat > "$UNIT_PATH" <<EOF
|
|
144
|
+
[Unit]
|
|
145
|
+
Description=Entity App Server
|
|
146
|
+
After=network.target
|
|
147
|
+
|
|
148
|
+
[Service]
|
|
149
|
+
Type=simple
|
|
150
|
+
User=$RUN_USER
|
|
151
|
+
Group=$RUN_GROUP
|
|
152
|
+
WorkingDirectory=$PROJECT_ROOT
|
|
153
|
+
EnvironmentFile=-$PROJECT_ROOT/.env
|
|
154
|
+
ExecStart=$PROJECT_ROOT/scripts/run.sh start
|
|
155
|
+
Restart=always
|
|
156
|
+
RestartSec=3
|
|
157
|
+
LimitNOFILE=65535
|
|
158
|
+
|
|
159
|
+
[Install]
|
|
160
|
+
WantedBy=multi-user.target
|
|
161
|
+
EOF
|
|
162
|
+
|
|
163
|
+
systemctl daemon-reload
|
|
164
|
+
systemctl enable "$SERVICE_NAME"
|
|
165
|
+
|
|
166
|
+
if [ "$START_NOW" = true ]; then
|
|
167
|
+
systemctl restart "$SERVICE_NAME"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
echo "✅ 서비스 등록 완료: $SERVICE_NAME"
|
|
171
|
+
echo " Unit: $UNIT_PATH"
|
|
172
|
+
echo " 시작: sudo systemctl start $SERVICE_NAME"
|
|
173
|
+
echo " 중지: sudo systemctl stop $SERVICE_NAME"
|
|
174
|
+
echo " 상태: sudo systemctl status $SERVICE_NAME"
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
7
|
+
SERVER_CONFIG="$PROJECT_ROOT/configs/server.json"
|
|
8
|
+
|
|
9
|
+
if [ -f "$PROJECT_ROOT/.env" ]; then
|
|
10
|
+
LANGUAGE=$(grep '^LANGUAGE=' "$PROJECT_ROOT/.env" | cut -d '=' -f2)
|
|
11
|
+
fi
|
|
12
|
+
LANGUAGE=${LANGUAGE:-ko}
|
|
13
|
+
|
|
14
|
+
SERVICE_NAME="entity-app-server"
|
|
15
|
+
INTERACTIVE=false
|
|
16
|
+
CONFIRMED=false
|
|
17
|
+
|
|
18
|
+
load_service_name() {
|
|
19
|
+
local namespace=""
|
|
20
|
+
if [ -f "$SERVER_CONFIG" ]; then
|
|
21
|
+
namespace=$(sed -n 's/.*"namespace"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$SERVER_CONFIG" | head -n 1)
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
namespace=$(echo "$namespace" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
|
|
25
|
+
|
|
26
|
+
if [ -z "$namespace" ]; then
|
|
27
|
+
SERVICE_NAME="entity-app-server"
|
|
28
|
+
elif [[ "$namespace" == "entity-app-server" ]] || [[ "$namespace" == *"-entity-app-server" ]]; then
|
|
29
|
+
SERVICE_NAME="$namespace"
|
|
30
|
+
else
|
|
31
|
+
SERVICE_NAME="${namespace}-entity-app-server"
|
|
32
|
+
fi
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
load_service_name
|
|
36
|
+
|
|
37
|
+
if [ $# -eq 0 ]; then
|
|
38
|
+
INTERACTIVE=true
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
for arg in "$@"; do
|
|
42
|
+
case "$arg" in
|
|
43
|
+
--yes|-y)
|
|
44
|
+
CONFIRMED=true
|
|
45
|
+
;;
|
|
46
|
+
*)
|
|
47
|
+
echo "❌ 알 수 없는 옵션: $arg"
|
|
48
|
+
exit 1
|
|
49
|
+
;;
|
|
50
|
+
esac
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
if [ "$INTERACTIVE" = true ] && [ "$CONFIRMED" = false ]; then
|
|
54
|
+
echo "[interactive] systemd 서비스 제거"
|
|
55
|
+
echo "서비스명: $SERVICE_NAME"
|
|
56
|
+
read -r -p "'$SERVICE_NAME' 서비스를 제거할까요? [y/N]: " input
|
|
57
|
+
input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
|
|
58
|
+
if [ "$input" != "y" ] && [ "$input" != "yes" ]; then
|
|
59
|
+
echo "취소되었습니다."
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
UNIT_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
|
|
65
|
+
|
|
66
|
+
if [ "$EUID" -ne 0 ]; then
|
|
67
|
+
if command -v sudo >/dev/null 2>&1; then
|
|
68
|
+
exec sudo "$0" --yes
|
|
69
|
+
fi
|
|
70
|
+
echo "❌ 이 스크립트는 root 권한이 필요합니다"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
SERVICE_EXISTS=false
|
|
75
|
+
if systemctl list-unit-files | grep -q "^${SERVICE_NAME}\.service"; then
|
|
76
|
+
SERVICE_EXISTS=true
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [ ! -f "$UNIT_PATH" ] && [ "$SERVICE_EXISTS" = false ]; then
|
|
80
|
+
echo "ℹ️ '$SERVICE_NAME' 서비스가 등록되어 있지 않습니다."
|
|
81
|
+
echo " 제거할 항목이 없습니다."
|
|
82
|
+
echo ""
|
|
83
|
+
echo " 서비스를 등록하려면:"
|
|
84
|
+
echo " sudo $(dirname "$0")/service-install.sh"
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [ "$SERVICE_EXISTS" = true ]; then
|
|
89
|
+
systemctl stop "$SERVICE_NAME" 2>/dev/null || true
|
|
90
|
+
systemctl disable "$SERVICE_NAME" 2>/dev/null || true
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if [ -f "$UNIT_PATH" ]; then
|
|
94
|
+
rm -f "$UNIT_PATH"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
systemctl daemon-reload
|
|
98
|
+
|
|
99
|
+
echo "✅ 서비스 제거 완료: $SERVICE_NAME"
|
|
100
|
+
echo ""
|
|
101
|
+
echo " 서비스를 다시 등록하려면:"
|
|
102
|
+
echo " sudo $(dirname "$0")/service-install.sh"
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
# update-server.sh — Entity App Server 코어 업데이트
|
|
3
3
|
#
|
|
4
4
|
# 사용법:
|
|
5
|
-
# ./scripts/update-server.sh # 도움말
|
|
6
|
-
# ./scripts/update-server.sh version # 현재 코어 버전 + 최신 태그 확인
|
|
5
|
+
# ./scripts/update-server.sh # 도움말 + 현재/최신 버전 확인
|
|
7
6
|
# ./scripts/update-server.sh latest # 최신 태그로 업데이트
|
|
8
7
|
# ./scripts/update-server.sh 0.0.8 # 특정 버전으로 업데이트
|
|
9
8
|
# ./scripts/update-server.sh v0.0.8
|
|
@@ -15,7 +14,7 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
15
14
|
PACKAGE_NAME="create-entity-app-server"
|
|
16
15
|
VERSION_FILE="$PROJECT_ROOT/.gateway-version"
|
|
17
16
|
PID_FILE="$PROJECT_ROOT/.gateway.pid"
|
|
18
|
-
MANAGED_SCRIPTS=("run.sh" "entity.sh" "reset-all.sh" "update-server.sh")
|
|
17
|
+
MANAGED_SCRIPTS=("build.sh" "run.sh" "entity.sh" "reset-all.sh" "update-server.sh" "service-install.sh" "service-remove.sh")
|
|
19
18
|
MANAGED_FILES=("system.js" "system-api.js" "tsconfig.json" ".env.example" ".gateway-version")
|
|
20
19
|
|
|
21
20
|
cd "$PROJECT_ROOT"
|
|
@@ -113,6 +112,28 @@ latest_gateway_version() {
|
|
|
113
112
|
echo "$latest"
|
|
114
113
|
}
|
|
115
114
|
|
|
115
|
+
print_version_status() {
|
|
116
|
+
local current
|
|
117
|
+
local latest
|
|
118
|
+
|
|
119
|
+
echo "🔍 버전 확인 중..."
|
|
120
|
+
current="$(current_gateway_version)"
|
|
121
|
+
latest="$(latest_gateway_version)"
|
|
122
|
+
|
|
123
|
+
echo ""
|
|
124
|
+
echo " 현재 코어 버전: v${current}"
|
|
125
|
+
echo " 최신 패키지 버전: v${latest}"
|
|
126
|
+
echo ""
|
|
127
|
+
|
|
128
|
+
if [ "$current" = "$latest" ]; then
|
|
129
|
+
echo "✅ 최신 버전입니다."
|
|
130
|
+
elif is_semver "$current" && [ "$(compare_versions "$current" "$latest")" = "1" ]; then
|
|
131
|
+
echo "ℹ️ 현재 코어가 npm 최신 버전보다 더 새롭습니다."
|
|
132
|
+
else
|
|
133
|
+
echo "💡 업데이트 가능: ./scripts/update-server.sh latest"
|
|
134
|
+
fi
|
|
135
|
+
}
|
|
136
|
+
|
|
116
137
|
package_tarball_url() {
|
|
117
138
|
local version="$1"
|
|
118
139
|
local tarball
|
|
@@ -370,29 +391,13 @@ case "$ARG" in
|
|
|
370
391
|
echo "update-server.sh — Entity App Server 코어 업데이트"
|
|
371
392
|
echo ""
|
|
372
393
|
echo "사용법:"
|
|
373
|
-
echo " ./scripts/update-server.sh version"
|
|
374
394
|
echo " ./scripts/update-server.sh latest"
|
|
375
395
|
echo " ./scripts/update-server.sh <버전>"
|
|
376
396
|
echo ""
|
|
377
397
|
echo "업데이트 대상: system.js / system-api.js / scripts / docs / tsconfig.json / .env.example / package.json(deps)"
|
|
378
398
|
echo "보존 대상: app/ / configs/ / .env / package.json의 name/version/private"
|
|
379
|
-
;;
|
|
380
|
-
|
|
381
|
-
"version")
|
|
382
|
-
echo "🔍 버전 확인 중..."
|
|
383
|
-
CURRENT="$(current_gateway_version)"
|
|
384
|
-
LATEST="$(latest_gateway_version)"
|
|
385
399
|
echo ""
|
|
386
|
-
|
|
387
|
-
echo " 최신 패키지 버전: v${LATEST}"
|
|
388
|
-
echo ""
|
|
389
|
-
if [ "$CURRENT" = "$LATEST" ]; then
|
|
390
|
-
echo "✅ 최신 버전입니다."
|
|
391
|
-
elif is_semver "$CURRENT" && [ "$(compare_versions "$CURRENT" "$LATEST")" = "1" ]; then
|
|
392
|
-
echo "ℹ️ 현재 코어가 npm 최신 버전보다 더 새롭습니다."
|
|
393
|
-
else
|
|
394
|
-
echo "💡 업데이트 가능: ./scripts/update-server.sh latest"
|
|
395
|
-
fi
|
|
400
|
+
print_version_status
|
|
396
401
|
;;
|
|
397
402
|
|
|
398
403
|
"latest")
|