unitlab 2.3.8__tar.gz → 2.3.9__tar.gz
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.
- {unitlab-2.3.8/src/unitlab.egg-info → unitlab-2.3.9}/PKG-INFO +1 -1
- {unitlab-2.3.8 → unitlab-2.3.9}/setup.py +1 -1
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/client.py +4 -4
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/cloudflare_api_tunnel.py +79 -3
- {unitlab-2.3.8 → unitlab-2.3.9/src/unitlab.egg-info}/PKG-INFO +1 -1
- {unitlab-2.3.8 → unitlab-2.3.9}/LICENSE.md +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/README.md +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/setup.cfg +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/__init__.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/__main__.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/binary_manager.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/exceptions.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/main.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/tunnel_config.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/tunnel_service_token.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab/utils.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab.egg-info/SOURCES.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab.egg-info/dependency_links.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab.egg-info/entry_points.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab.egg-info/requires.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.9}/src/unitlab.egg-info/top_level.txt +0 -0
@@ -297,10 +297,10 @@ class UnitlabClient:
|
|
297
297
|
self.tunnel_manager = CloudflareTunnel(base_domain, device_id)
|
298
298
|
self.jupyter_url = self.tunnel_manager.jupyter_url
|
299
299
|
self.ssh_url = self.tunnel_manager.ssh_url
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
300
|
+
else:
|
301
|
+
self.tunnel_manager = None
|
302
|
+
self.jupyter_url = f"https://jupyter-{device_id}.{base_domain}"
|
303
|
+
self.ssh_url = f"https://ssh-{device_id}.{base_domain}"
|
304
304
|
|
305
305
|
# Setup signal handlers
|
306
306
|
signal.signal(signal.SIGINT, self._handle_shutdown)
|
@@ -62,7 +62,13 @@ class CloudflareAPITunnel:
|
|
62
62
|
|
63
63
|
self.tunnel_process = None
|
64
64
|
self.created_dns_records = []
|
65
|
-
|
65
|
+
|
66
|
+
# Try to initialize binary manager, but don't fail if it doesn't work
|
67
|
+
try:
|
68
|
+
self.binary_manager = CloudflaredBinaryManager()
|
69
|
+
except Exception as e:
|
70
|
+
logger.warning(f"Binary manager initialization failed: {e}")
|
71
|
+
self.binary_manager = None
|
66
72
|
|
67
73
|
def create_dns_records(self):
|
68
74
|
"""
|
@@ -209,8 +215,10 @@ class CloudflareAPITunnel:
|
|
209
215
|
self.create_dns_records()
|
210
216
|
self.update_tunnel_config()
|
211
217
|
|
212
|
-
#
|
213
|
-
cloudflared_path = self.
|
218
|
+
# Ensure cloudflared is available
|
219
|
+
cloudflared_path = self._ensure_cloudflared()
|
220
|
+
if not cloudflared_path:
|
221
|
+
raise RuntimeError("Failed to obtain cloudflared binary")
|
214
222
|
|
215
223
|
# Use the service token - hardcoded for zero-config experience
|
216
224
|
# This token can ONLY run the tunnel, cannot modify or delete it (safe to embed)
|
@@ -269,6 +277,74 @@ class CloudflareAPITunnel:
|
|
269
277
|
self.tunnel_process.wait(timeout=5)
|
270
278
|
print("Tunnel stopped")
|
271
279
|
|
280
|
+
def _ensure_cloudflared(self):
|
281
|
+
"""
|
282
|
+
Ensure cloudflared binary is available
|
283
|
+
Downloads it if necessary
|
284
|
+
"""
|
285
|
+
print("🔍 Checking for cloudflared binary...")
|
286
|
+
|
287
|
+
# Try binary manager first
|
288
|
+
if self.binary_manager:
|
289
|
+
try:
|
290
|
+
path = self.binary_manager.get_binary_path()
|
291
|
+
print(f"✅ Using cloudflared from binary manager: {path}")
|
292
|
+
return path
|
293
|
+
except Exception as e:
|
294
|
+
logger.warning(f"Binary manager failed, will download directly: {e}")
|
295
|
+
|
296
|
+
# Direct download fallback - simplified version
|
297
|
+
import platform
|
298
|
+
import urllib.request
|
299
|
+
|
300
|
+
cache_dir = Path.home() / '.unitlab' / 'bin'
|
301
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
302
|
+
|
303
|
+
cloudflared_path = cache_dir / 'cloudflared'
|
304
|
+
if platform.system() == 'Windows':
|
305
|
+
cloudflared_path = cache_dir / 'cloudflared.exe'
|
306
|
+
|
307
|
+
# If already exists, use it
|
308
|
+
if cloudflared_path.exists():
|
309
|
+
print(f"✅ Using cached cloudflared: {cloudflared_path}")
|
310
|
+
return str(cloudflared_path)
|
311
|
+
|
312
|
+
# Download based on platform
|
313
|
+
system = platform.system().lower()
|
314
|
+
machine = platform.machine().lower()
|
315
|
+
|
316
|
+
print(f"📥 Downloading cloudflared for {system}/{machine}...")
|
317
|
+
|
318
|
+
if system == 'linux':
|
319
|
+
if machine in ['x86_64', 'amd64']:
|
320
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64'
|
321
|
+
elif machine in ['aarch64', 'arm64']:
|
322
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64'
|
323
|
+
else:
|
324
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-386'
|
325
|
+
elif system == 'darwin':
|
326
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-amd64.tgz'
|
327
|
+
elif system == 'windows':
|
328
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe'
|
329
|
+
else:
|
330
|
+
raise RuntimeError(f"Unsupported platform: {system}")
|
331
|
+
|
332
|
+
try:
|
333
|
+
# Download the file
|
334
|
+
urllib.request.urlretrieve(url, cloudflared_path)
|
335
|
+
|
336
|
+
# Make executable on Unix
|
337
|
+
if system != 'windows':
|
338
|
+
import stat
|
339
|
+
cloudflared_path.chmod(cloudflared_path.stat().st_mode | stat.S_IEXEC)
|
340
|
+
|
341
|
+
print(f"✅ Downloaded cloudflared to: {cloudflared_path}")
|
342
|
+
return str(cloudflared_path)
|
343
|
+
|
344
|
+
except Exception as e:
|
345
|
+
print(f"❌ Failed to download cloudflared: {e}")
|
346
|
+
raise RuntimeError(f"Could not download cloudflared: {e}")
|
347
|
+
|
272
348
|
def cleanup_dns(self):
|
273
349
|
"""
|
274
350
|
Remove created DNS records (optional cleanup)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|