Phoe2004 commited on
Commit
daa2fa7
·
verified ·
1 Parent(s): 4a089fc

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -18
app.py CHANGED
@@ -131,9 +131,41 @@ _VPS_SSH_PORT = os.environ.get('VPS_SSH_PORT', '22').strip()
131
  _VPS_SSH_USER = os.environ.get('VPS_SSH_USER', '').strip()
132
  _VPS_SSH_PASS = os.environ.get('VPS_SSH_PASS', '').strip()
133
  _SSH_TUNNEL_LOCAL_PORT = 1080
 
134
  _ssh_tunnel_proc = [None] # mutable box so the watchdog thread can replace it
135
 
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  def _start_ssh_socks_tunnel():
138
  """
139
  VPS ကို SSH password login ဖြင့် dynamic port-forward (SOCKS5) tunnel ဖွင့်သည်.
@@ -143,7 +175,7 @@ def _start_ssh_socks_tunnel():
143
  cmd = [
144
  'sshpass', '-p', _VPS_SSH_PASS,
145
  'ssh',
146
- '-D', str(_SSH_TUNNEL_LOCAL_PORT),
147
  '-N',
148
  '-o', 'StrictHostKeyChecking=no',
149
  '-o', 'UserKnownHostsFile=/dev/null',
@@ -159,28 +191,42 @@ def _start_ssh_socks_tunnel():
159
 
160
 
161
  def _ssh_tunnel_watchdog():
162
- """Background thread: SSH tunnel ပြတ်သွားရင် ပြန်ချိတ်ပေးသည်."""
 
 
 
 
163
  import threading as _th
 
 
 
 
 
 
 
 
 
164
  while True:
 
 
 
 
165
  proc = _ssh_tunnel_proc[0]
166
- if proc is None or proc.poll() is not None:
167
- if proc is not None:
168
- err = ''
169
- try:
170
- err = proc.stderr.read()[-300:] if proc.stderr else ''
171
- except Exception:
172
- pass
173
- print(f'[ssh_tunnel] Connection dropped (rc={proc.returncode}). '
174
- f'stderr: {err!r}. Reconnecting in 5s...')
175
- else:
176
- print('[ssh_tunnel] Starting SSH SOCKS tunnel to VPS...')
177
  try:
178
- _start_ssh_socks_tunnel()
179
- except Exception as e:
180
- print(f'[ssh_tunnel] Failed to start: {type(e).__name__}: {e}')
181
- _th.Event().wait(5)
 
182
  else:
183
- _th.Event().wait(10)
 
 
 
 
 
184
 
185
 
186
  if _VPS_SSH_HOST and _VPS_SSH_USER and _VPS_SSH_PASS and not YTDLP_PROXY:
 
131
  _VPS_SSH_USER = os.environ.get('VPS_SSH_USER', '').strip()
132
  _VPS_SSH_PASS = os.environ.get('VPS_SSH_PASS', '').strip()
133
  _SSH_TUNNEL_LOCAL_PORT = 1080
134
+ _SSH_TUNNEL_LOCK_FILE = '/tmp/ssh_tunnel.lock'
135
  _ssh_tunnel_proc = [None] # mutable box so the watchdog thread can replace it
136
 
137
 
138
+ def _port_is_listening(host, port, timeout=1.5):
139
+ """127.0.0.1:port ပေါ်မှာ တစ်ခုခု listen လုပ်နေပြီးလား စစ်သည် (process/worker မတူလည်း)."""
140
+ import socket as _socket
141
+ s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
142
+ s.settimeout(timeout)
143
+ try:
144
+ s.connect((host, port))
145
+ return True
146
+ except Exception:
147
+ return False
148
+ finally:
149
+ s.close()
150
+
151
+
152
+ def _acquire_ssh_tunnel_lock():
153
+ """
154
+ Gunicorn worker process များစွာ (သို့) restart အသစ်တစ်ခု တစ်ပြိုင်နက်တည်း
155
+ tunnel ကို ထပ်ဖွင့်ဖို့ ကြိုးစားလို့ port 1080 conflict မဖြစ်စေရန်,
156
+ file lock (flock) ဖြင့် worker တစ်ခုတည်းကိုသာ tunnel ဖွင့်ခွင့်ပေးသည်.
157
+ Lock ရအောင် ယူနိုင်ရင် file handle ကို ပြန်ပေးမည် (open ဖြစ်နေအောင် ကိုင်ထားရမည်) —
158
+ မရရင် None ပြန်မည် (တခြား worker/process က ကိုင်ထားပြီးသား).
159
+ """
160
+ import fcntl
161
+ try:
162
+ f = open(_SSH_TUNNEL_LOCK_FILE, 'w')
163
+ fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
164
+ return f
165
+ except (IOError, OSError):
166
+ return None
167
+
168
+
169
  def _start_ssh_socks_tunnel():
170
  """
171
  VPS ကို SSH password login ဖြင့် dynamic port-forward (SOCKS5) tunnel ဖွင့်သည်.
 
175
  cmd = [
176
  'sshpass', '-p', _VPS_SSH_PASS,
177
  'ssh',
178
+ '-D', f'127.0.0.1:{_SSH_TUNNEL_LOCAL_PORT}',
179
  '-N',
180
  '-o', 'StrictHostKeyChecking=no',
181
  '-o', 'UserKnownHostsFile=/dev/null',
 
191
 
192
 
193
  def _ssh_tunnel_watchdog():
194
+ """
195
+ Background thread: lock ရအောင်ယူနိုင်တဲ့ worker/process တစ်ခုတည်းကသာ
196
+ tunnel ကို ဖွင့်/ထိန်းသိမ်းမည်. ကျန် worker တွေက port ကို listen ဖြစ်နေမှန်း
197
+ check ပဲလုပ်ပြီး ဆက်စောင့်မည် (spawn ထပ်မလုပ်တော့ပါ).
198
+ """
199
  import threading as _th
200
+
201
+ lock_fh = _acquire_ssh_tunnel_lock()
202
+ if lock_fh is None:
203
+ print('[ssh_tunnel] Another worker already owns the tunnel — '
204
+ 'this worker will just reuse 127.0.0.1:1080 without spawning.')
205
+ while True:
206
+ _th.Event().wait(15)
207
+ return
208
+
209
  while True:
210
+ if _port_is_listening('127.0.0.1', _SSH_TUNNEL_LOCAL_PORT):
211
+ _th.Event().wait(10)
212
+ continue
213
+
214
  proc = _ssh_tunnel_proc[0]
215
+ if proc is not None:
216
+ err = ''
 
 
 
 
 
 
 
 
 
217
  try:
218
+ err = proc.stderr.read()[-300:] if proc.stderr else ''
219
+ except Exception:
220
+ pass
221
+ print(f'[ssh_tunnel] Connection dropped (rc={proc.returncode}). '
222
+ f'stderr: {err!r}. Reconnecting in 5s...')
223
  else:
224
+ print('[ssh_tunnel] Starting SSH SOCKS tunnel to VPS...')
225
+ try:
226
+ _start_ssh_socks_tunnel()
227
+ except Exception as e:
228
+ print(f'[ssh_tunnel] Failed to start: {type(e).__name__}: {e}')
229
+ _th.Event().wait(5)
230
 
231
 
232
  if _VPS_SSH_HOST and _VPS_SSH_USER and _VPS_SSH_PASS and not YTDLP_PROXY: