-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathentrypoint.sh
More file actions
203 lines (182 loc) · 8.06 KB
/
Copy pathentrypoint.sh
File metadata and controls
203 lines (182 loc) · 8.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/bin/bash
set -e -o pipefail
DATA_DIR="/data"
DB_PREFIX="$DATA_DIR/simplex"
DB_FILE="${DB_PREFIX}_v1_chat.db"
# ── Resolve PUID/PGID ──────────────────────────────────────────────
PUID="${PUID:-99}"
PGID="${PGID:-100}"
echo "[entrypoint] Using PUID=$PUID PGID=$PGID"
# Ensure the 'simplex' user/group matches the runtime-requested IDs.
# Only recreate if the existing user has a different UID/GID.
if getent passwd simplex >/dev/null 2>&1; then
EXISTING_UID=$(id -u simplex 2>/dev/null)
EXISTING_GID=$(id -g simplex 2>/dev/null)
if [ "$EXISTING_UID" = "$PUID" ] && [ "$EXISTING_GID" = "$PGID" ]; then
echo "[entrypoint] simplex user already has PUID=$PUID PGID=$PGID — no change needed"
else
echo "[entrypoint] Recreating simplex user (UID $EXISTING_UID → $PUID, GID $EXISTING_GID → $PGID)..."
if getent group simplex >/dev/null 2>&1; then groupdel simplex 2>/dev/null || true; fi
if getent passwd simplex >/dev/null 2>&1; then userdel simplex 2>/dev/null || true; fi
groupadd --system --gid "$PGID" simplex 2>/dev/null || \
groupadd --system simplex 2>/dev/null
useradd --system --no-log-init -g simplex -u "$PUID" --create-home simplex
fi
else
groupadd --system --gid "$PGID" simplex 2>/dev/null || \
groupadd --system simplex 2>/dev/null
useradd --system --no-log-init -g simplex -u "$PUID" --create-home simplex
fi
# ── Graceful shutdown handler ──────────────────────────────────────
shutdown() {
signal=$1
echo "[entrypoint] Received $signal — forwarding to simplex-chat..."
kill "-$signal" "$DAEMON_PID" 2>/dev/null || true
for i in $(seq 1 10); do
if ! kill -0 "$DAEMON_PID" 2>/dev/null; then
echo "[entrypoint] simplex-chat exited cleanly"
break
fi
sleep 1
done
if [ -n "${SOCAT_PID:-}" ]; then
kill "$SOCAT_PID" 2>/dev/null || true
fi
echo "[entrypoint] Goodbye"
exit 0
}
trap 'shutdown SIGTERM' SIGTERM
trap 'shutdown SIGINT' SIGINT
# ── Timezone ───────────────────────────────────────────────────────
if [ -n "$TZ" ] && [ -f "/usr/share/zoneinfo/$TZ" ]; then
ln -sf "/usr/share/zoneinfo/$TZ" /etc/localtime
echo "$TZ" > /etc/timezone
fi
# Fix data dir ownership so the runtime user can write to it
chown -R "$PUID:$PGID" "$DATA_DIR"
# ── Build extra flags (array — no shell re-parsing of env values) ──
FLAGS=(-d "$DATA_DIR/simplex" -p 5225)
# v7.x auto-migrates older DB schemas non-interactively with this flag;
# without it a v6-era data dir triggers an interactive Continue (y/N) prompt
# that dies headless.
FLAGS+=(-y)
if [ ! -f "$DB_FILE" ]; then
echo "[entrypoint] First run: creating bot profile..."
FLAGS+=(--create-bot-display-name "$SIMPLEX_DISPLAY_NAME")
if [ "$SIMPLEX_FILES_ENABLED" = "true" ]; then
FLAGS+=(--create-bot-allow-files)
fi
fi
if [ "$SIMPLEX_MARK_READ" = "true" ]; then
FLAGS+=(-r)
fi
if [ "$SIMPLEX_TOR" = "true" ]; then
FLAGS+=(-x)
fi
# ── Start simplex-chat daemon as non-root user ─────────────────────
echo "[entrypoint] Starting simplex-chat daemon as UID $PUID..."
echo "[entrypoint] simplex-chat ${FLAGS[*]}"
gosu "$PUID:$PGID" simplex-chat "${FLAGS[@]}" > "$DATA_DIR/daemon.log" 2>&1 &
DAEMON_PID=$!
echo "[entrypoint] PID: $DAEMON_PID"
for i in $(seq 1 15); do
if ss -tln 2>/dev/null | grep -q :5225; then
echo "[entrypoint] WebSocket API ready on port 5225"
break
fi
if [ "$i" -eq 15 ]; then
echo "[entrypoint] ERROR: simplex-chat failed to start within 15s"
tail -10 "$DATA_DIR/daemon.log"
kill "$DAEMON_PID" 2>/dev/null || true
exit 1
fi
sleep 1
done
SETUP_MARKER="$DATA_DIR/.setup-complete"
if [ ! -f "$SETUP_MARKER" ]; then
sleep 2
echo "[entrypoint] Setting up bot address..."
SETUP_LOG="$DATA_DIR/setup.log"
# Run as the daemon user; capture exit status explicitly — the sed pipe
# would otherwise mask python's exit code (sed always exits 0).
if gosu "$PUID:$PGID" python3 - <<'PYEOF' > "$SETUP_LOG" 2>&1
import asyncio, json, os, sys
import websockets
async def setup():
async with websockets.connect('ws://127.0.0.1:5225', open_timeout=10) as ws:
await ws.send(json.dumps({'corrId': 's1', 'cmd': '/user'}))
await asyncio.sleep(1)
await ws.send(json.dumps({'corrId': 's2', 'cmd': '/ad'}))
await asyncio.sleep(2)
address = None
for _ in range(10):
try:
evt = await asyncio.wait_for(ws.recv(), timeout=1)
except asyncio.TimeoutError:
break
data = json.loads(evt)
resp = data.get('resp', {})
if resp.get('type') == 'userContactLinkCreated':
link = resp.get('connLinkContact', {})
address = link.get('connFullLink', link.get('connShortLink', ''))
if os.environ.get('SIMPLEX_AUTO_ACCEPT', 'true') == 'true':
settings = json.dumps({'businessAddress': False, 'autoAccept': {'acceptIncognito': False}})
await ws.send(json.dumps({'corrId': 's3', 'cmd': f'/_address_settings 1 {settings}'}))
await asyncio.sleep(1)
try:
evt = await asyncio.wait_for(ws.recv(), timeout=2)
if 'userContactLinkUpdated' in evt:
print('[setup] Auto-accept enabled')
except asyncio.TimeoutError:
pass
if address:
print(f'[setup] Bot address: {address[:80]}...')
with open('/data/bot_address.txt', 'w') as f:
f.write(address + '\n')
else:
print('[setup] ERROR: no contact link received — setup will retry on next start')
sys.exit(1)
asyncio.run(setup())
PYEOF
then
sed 's/^/[setup] /' "$SETUP_LOG"
touch "$SETUP_MARKER"
else
echo "[entrypoint] WARNING: first-run setup did not complete — will retry on next restart"
tail -5 "$SETUP_LOG" | sed 's/^/[setup] /'
fi
fi
# ── Optional socat bridge ──────────────────────────────────────────
# WARNING: When enabled, the WebSocket API becomes accessible from any
# IP that can reach the container on 0.0.0.0:$SIMPLEX_SOCAT_PORT.
# The simplex-chat WebSocket protocol has no built-in authentication.
# Only enable on trusted networks or behind a firewall.
# This feature is experimental — use at your own risk.
if [ -n "$SIMPLEX_SOCAT_PORT" ]; then
case "$SIMPLEX_SOCAT_PORT" in
''|*[!0-9]*)
echo "[entrypoint] ERROR: SIMPLEX_SOCAT_PORT must be a numeric TCP port (got: '$SIMPLEX_SOCAT_PORT')"
exit 1
;;
esac
if [ "$SIMPLEX_SOCAT_PORT" -lt 1 ] || [ "$SIMPLEX_SOCAT_PORT" -gt 65535 ]; then
echo "[entrypoint] ERROR: SIMPLEX_SOCAT_PORT must be between 1 and 65535 (got: $SIMPLEX_SOCAT_PORT)"
exit 1
fi
echo "[entrypoint] *** WARNING: Exposing WebSocket API on 0.0.0.0:$SIMPLEX_SOCAT_PORT ***"
echo "[entrypoint] *** No authentication — only use on trusted networks ***"
echo "[entrypoint] Starting socat bridge on 0.0.0.0:$SIMPLEX_SOCAT_PORT → 127.0.0.1:5225"
socat "TCP-LISTEN:$SIMPLEX_SOCAT_PORT,reuseaddr,fork" TCP:127.0.0.1:5225 &
SOCAT_PID=$!
echo "[entrypoint] socat PID: $SOCAT_PID"
fi
# ── Ready ──────────────────────────────────────────────────────────
echo ""
echo "=== SimpleX Bridge ready ==="
echo " Bot name: $SIMPLEX_DISPLAY_NAME"
echo " Running as: PUID=$PUID PGID=$PGID"
if [ -f "$DATA_DIR/bot_address.txt" ]; then
echo " Bot address: $(cat "$DATA_DIR/bot_address.txt")"
fi
echo ""
wait "$DAEMON_PID"