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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unitlab
3
- Version: 2.3.8
3
+ Version: 2.3.9
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="unitlab",
5
- version="2.3.8",
5
+ version="2.3.9",
6
6
  license="MIT",
7
7
  author="Unitlab Inc.",
8
8
  author_email="team@unitlab.ai",
@@ -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
- 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}"
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
- self.binary_manager = CloudflaredBinaryManager()
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
- # Get cloudflared binary
213
- cloudflared_path = self.binary_manager.get_binary_path()
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unitlab
3
- Version: 2.3.8
3
+ Version: 2.3.9
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes