orrin-cli 0.3.0b2__tar.gz → 0.3.0b4__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.
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: orrin-cli
3
+ Version: 0.3.0b4
4
+ Summary: Orrin CLI
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: typer[all]>=0.12.0
9
+ Requires-Dist: click<8.2
10
+ Dynamic: license-file
11
+
12
+ # Orrin CLI v0.3.0b3
13
+
14
+ ## What's New
15
+
16
+ In v0.3.0b4, we introduce support for creating "mounts" for websocket connectivity with our newly released Exegesis Specification for Interactivity.
@@ -0,0 +1,5 @@
1
+ # Orrin CLI v0.3.0b3
2
+
3
+ ## What's New
4
+
5
+ In v0.3.0b4, we introduce support for creating "mounts" for websocket connectivity with our newly released Exegesis Specification for Interactivity.
@@ -1,16 +1,21 @@
1
1
  import webbrowser
2
- from click import Choice
3
- import typer
4
- import requests
2
+ from click import Choice # type: ignore
3
+ import typer # type: ignore
4
+ import requests # type: ignore
5
5
  import json
6
6
  import os
7
7
  from pathlib import Path
8
- from platformdirs import user_config_dir
9
- import yaml, tomli, toml
8
+ from platformdirs import user_config_dir # type: ignore
9
+ import yaml, tomli, toml # type: ignore
10
10
  from pathlib import Path
11
11
  from orrin.Spinner import Spinner
12
- import websockets
12
+ import websockets # type: ignore
13
13
  import asyncio
14
+ import importlib.util
15
+ import sys
16
+ from pathlib import Path
17
+ from urllib.parse import urlparse
18
+ import ipaddress
14
19
 
15
20
  app = typer.Typer(help="""
16
21
  Welcome to Orrin CLI v0.1.9!\n\n
@@ -33,6 +38,9 @@ app.add_typer(projects, name='projects')
33
38
  sessions = typer.Typer(help='Terminal Sessions enabling projects to be created in your terminal env from iOS and Web app')
34
39
  app.add_typer(sessions, name='sessions')
35
40
 
41
+ especi = typer.Typer(help='Exegesis Specification for Interactivity (ESPECI) configurations')
42
+ app.add_typer(especi, name='especi')
43
+
36
44
  API_BASE = "https://stellr-company.com"
37
45
 
38
46
  APP_NAME = "orrin"
@@ -42,6 +50,7 @@ config_dir = Path(user_config_dir(APP_NAME, APP_AUTHOR))
42
50
  config_dir.mkdir(parents=True, exist_ok=True)
43
51
 
44
52
  config_file = config_dir / "config.json"
53
+ print(config_file)
45
54
 
46
55
  # ---- Configuration based commands/helper functions ----
47
56
 
@@ -1196,7 +1205,276 @@ def start_default_handler():
1196
1205
  typer.echo('\nValue must be non-zero, or within bounds.')
1197
1206
  return
1198
1207
 
1199
- asyncio.run(establish_default_handler(config['terminal_sessions'][session_to_start]['session_id'], config['api_key']))
1208
+ try:
1209
+ asyncio.run(establish_default_handler(config['terminal_sessions'][session_to_start]['session_id'], config['api_key'], refresh))
1210
+ except KeyboardInterrupt as _:
1211
+ typer.echo('Exited handler connection. Connection closed.')
1212
+
1213
+ # Volantarily call `refresh` to ensure sessions are updated
1214
+ refresh()
1215
+ except Exception as e:
1216
+ typer.echo(f'Exception: {str(e)}')
1217
+
1218
+ def load_handler_module(handler_path: str | Path):
1219
+ """Load a handler module with proper support for relative imports."""
1220
+ handler_path = Path(handler_path).resolve()
1221
+
1222
+ if not handler_path.is_file():
1223
+ typer.echo(f"\n❌ Could not load file: {handler_path}")
1224
+ raise typer.Exit(1)
1225
+
1226
+ module_name = handler_path.stem
1227
+ module_dir = handler_path.parent
1228
+
1229
+ # Create module spec
1230
+ spec = importlib.util.spec_from_file_location(module_name, handler_path)
1231
+ if spec is None:
1232
+ typer.echo(f"\n❌ Could not create spec for: {handler_path}")
1233
+ raise typer.Exit(1)
1234
+
1235
+ # Create module
1236
+ module = importlib.util.module_from_spec(spec)
1237
+
1238
+ # === Critical for relative imports (especially 'from . import TSHandler') ===
1239
+ # Set the package name so relative imports work
1240
+ try:
1241
+ # If the file is inside the orrinsdk package, use proper package name
1242
+ if "orrinsdk" in str(handler_path):
1243
+ module.__package__ = "orrinsdk"
1244
+ else:
1245
+ # Fallback
1246
+ module.__package__ = module_dir.name
1247
+ except:
1248
+ module.__package__ = module_name
1249
+
1250
+ # Register and execute
1251
+ sys.modules[spec.name] = module
1252
+ spec.loader.exec_module(module)
1253
+
1254
+ return module
1255
+
1256
+ @sessions.command(help='Mount handler to a terminal session')
1257
+ def mount_handler(
1258
+ handler_file: str,
1259
+ run: bool = typer.Option(False, "--run", "-r", help="Run the handler immediately after mounting")
1260
+ ):
1261
+ """Mount a custom handler to a terminal session."""
1262
+
1263
+ # === Validation ===
1264
+ if not os.path.isfile(handler_file):
1265
+ typer.echo("\n❌ " + typer.style("File not found:", fg=typer.colors.RED) + f" {handler_file}")
1266
+ raise typer.Exit(1)
1267
+
1268
+ config = load_config()
1269
+
1270
+ if config is None or "api_key" not in config:
1271
+ typer.echo("\n⚠️ " + typer.style("Developer API not configured.", fg=typer.colors.YELLOW))
1272
+ typer.echo(" Run: " + typer.style("orrin config configure-dev", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1273
+ raise typer.Exit(1)
1274
+
1275
+ if not config.get("terminal_sessions"):
1276
+ typer.echo("\n⚠️ " + typer.style("No terminal sessions found.", fg=typer.colors.YELLOW))
1277
+ typer.echo(" Create one with: " + typer.style("orrin sessions create", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1278
+ raise typer.Exit(1)
1279
+
1280
+ # === Show available sessions ===
1281
+ typer.echo("\n" + typer.style("Available Terminal Sessions:", fg=typer.colors.BLUE, bold=True))
1282
+ for i, session in enumerate(config["terminal_sessions"]):
1283
+ typer.echo(f" {i+1}. {session['session_name']} (ID: {session['session_id']})")
1284
+
1285
+ # === User selection ===
1286
+ try:
1287
+ selection = typer.prompt(
1288
+ "\nSelect session number",
1289
+ type=int,
1290
+ default=1
1291
+ )
1292
+ session_idx = selection - 1
1293
+
1294
+ if session_idx < 0 or session_idx >= len(config["terminal_sessions"]):
1295
+ typer.echo("\n❌ " + typer.style("Invalid selection.", fg=typer.colors.RED))
1296
+ raise typer.Exit(1)
1297
+
1298
+ except Exception:
1299
+ typer.echo("\n❌ " + typer.style("Invalid input.", fg=typer.colors.RED))
1300
+ raise typer.Exit(1)
1301
+
1302
+ selected_session = config["terminal_sessions"][session_idx]
1303
+
1304
+ # === Load and validate handler ===
1305
+ try:
1306
+ module = load_handler_module(handler_file) # ← Recommended to extract this
1307
+ if not hasattr(module, "handler_entry"):
1308
+ raise AttributeError("Function 'handler_entry' not found")
1309
+ handler_func = getattr(module, "handler_entry")
1310
+ except Exception as e:
1311
+ typer.echo("\n❌ " + typer.style(f"Failed to load handler: {e}", fg=typer.colors.RED))
1312
+ raise typer.Exit(1)
1313
+
1314
+ # === Check for existing mounted handler ===
1315
+ if "mounted_handlers" in config:
1316
+ for mh in config["mounted_handlers"]:
1317
+ if mh.get("terminal_session_id") == selected_session["session_id"]:
1318
+ typer.echo("\n⚠️ " + typer.style("This session already has a mounted handler.", fg=typer.colors.YELLOW))
1319
+ typer.echo(f" Current handler: {mh['path']}")
1320
+ typer.echo(" Unmount it first using: " + typer.style("orrin sessions unmount-handler", fg=typer.colors.BRIGHT_YELLOW))
1321
+ raise typer.Exit(1)
1322
+
1323
+ # === Run handler if requested ===
1324
+ if run:
1325
+ typer.echo(f"\n▶️ Running handler {typer.style(Path(handler_file).name, fg=typer.colors.BRIGHT_GREEN)}...")
1326
+ try:
1327
+ handler_func(terminal_session_id=selected_session["session_id"])
1328
+ typer.echo("✅ Handler executed successfully.\n")
1329
+ except Exception as e:
1330
+ typer.echo("⚠️ " + typer.style(f"Handler execution failed: {e}", fg=typer.colors.RED))
1331
+
1332
+ # === Save mounted handler ===
1333
+ if "mounted_handlers" not in config:
1334
+ config["mounted_handlers"] = []
1335
+
1336
+ config["mounted_handlers"].append({
1337
+ "path": str(handler_file),
1338
+ "terminal_session_id": selected_session["session_id"]
1339
+ })
1340
+
1341
+ write_config(config)
1342
+
1343
+ # === Final success message ===
1344
+ typer.echo("\n" + typer.style("✅ Successfully mounted handler!", fg=typer.colors.GREEN, bold=True))
1345
+ typer.echo(f" Handler : {typer.style(Path(handler_file).name, fg=typer.colors.BRIGHT_GREEN)}")
1346
+ typer.echo(f" Session : {typer.style(selected_session['session_name'], bold=True)}")
1347
+ typer.echo(f" Session ID : {selected_session['session_id']}")
1348
+
1349
+ @sessions.command(help='Unmount a custom handler from a terminal session')
1350
+ def unmount_handler():
1351
+ config = load_config()
1352
+
1353
+ if config is None or "api_key" not in config:
1354
+ typer.echo("\n⚠️ " + typer.style("Developer API not configured.", fg=typer.colors.YELLOW))
1355
+ typer.echo(" Run: " + typer.style("orrin config configure-dev", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1356
+ raise typer.Exit(1)
1357
+
1358
+ if not config.get("terminal_sessions"):
1359
+ typer.echo("\n⚠️ " + typer.style("No terminal sessions found.", fg=typer.colors.YELLOW))
1360
+ typer.echo(" Create one with: " + typer.style("orrin sessions create", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1361
+ raise typer.Exit(1)
1362
+
1363
+ if not config.get('mounted_handlers'):
1364
+ typer.echo("\n⚠️ " + typer.style("No mounted handlers.", fg=typer.colors.YELLOW))
1365
+ typer.echo(" Mount a new handler with: " + typer.style("orrin sessions mount-handler", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1366
+ raise typer.Exit(1)
1367
+
1368
+ # Get terminal sessions with custom handlers mounted
1369
+ sessions_with_mh = []
1370
+ for mh in config.get('mounted_handlers'):
1371
+ sessions_with_mh.append(mh['terminal_session_id'])
1372
+
1373
+ # === Show available sessions ===
1374
+ typer.echo("\n" + typer.style("Available Terminal Sessions:", fg=typer.colors.BLUE, bold=True))
1375
+ for i, sessionID in enumerate(sessions_with_mh):
1376
+ typer.echo(f" {i+1}. {sessionID}")
1377
+
1378
+ # === User selection ===
1379
+ try:
1380
+ selection = typer.prompt(
1381
+ "\nSelect session number",
1382
+ type=int,
1383
+ default=1
1384
+ )
1385
+ session_idx = selection - 1
1386
+
1387
+ if session_idx < 0 or session_idx >= len(sessions_with_mh):
1388
+ typer.echo("\n❌ " + typer.style("Invalid selection.", fg=typer.colors.RED))
1389
+ raise typer.Exit(1)
1390
+ except Exception as e:
1391
+ typer.echo("\n❌ " + typer.style(f"Failed to load handler: {e}", fg=typer.colors.RED))
1392
+ raise typer.Exit(1)
1393
+
1394
+ for i in range(len(config.get('mounted_handlers'))):
1395
+ if config.get('mounted_handlers')[i]['terminal_session_id'] == sessions_with_mh[session_idx]:
1396
+ del config.get('mounted_handlers')[i]
1397
+ break
1398
+
1399
+ if config['mounted_handlers'] == []:
1400
+ del config['mounted_handlers']
1401
+
1402
+ write_config(config)
1403
+ typer.echo("✅ Handler unmounted successfully.\n")
1404
+
1405
+ @sessions.command(help='Run a terminal sessions custom handler')
1406
+ def run_handler():
1407
+ config = load_config()
1408
+
1409
+ if config is None or "api_key" not in config:
1410
+ typer.echo("\n⚠️ " + typer.style("Developer API not configured.", fg=typer.colors.YELLOW))
1411
+ typer.echo(" Run: " + typer.style("orrin config configure-dev", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1412
+ raise typer.Exit(1)
1413
+
1414
+ if not config.get("terminal_sessions"):
1415
+ typer.echo("\n⚠️ " + typer.style("No terminal sessions found.", fg=typer.colors.YELLOW))
1416
+ typer.echo(" Create one with: " + typer.style("orrin sessions create", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1417
+ raise typer.Exit(1)
1418
+
1419
+ if not config.get('mounted_handlers'):
1420
+ typer.echo("\n⚠️ " + typer.style("No mounted handlers.", fg=typer.colors.YELLOW))
1421
+ typer.echo(" Mount a new handler with: " + typer.style("orrin sessions mount-handler", fg=typer.colors.BRIGHT_YELLOW, bold=True))
1422
+ raise typer.Exit(1)
1423
+
1424
+ # Get terminal sessions with custom handlers mounted
1425
+ sessions_with_mh = []
1426
+ for mh in config.get('mounted_handlers'):
1427
+ sessions_with_mh.append(mh['terminal_session_id'])
1428
+
1429
+ # === Show available sessions ===
1430
+ typer.echo("\n" + typer.style("Available Terminal Sessions:", fg=typer.colors.BLUE, bold=True))
1431
+ for i, sessionID in enumerate(sessions_with_mh):
1432
+ typer.echo(f" {i+1}. {sessionID}")
1433
+
1434
+ # === User selection ===
1435
+ try:
1436
+ selection = typer.prompt(
1437
+ "\nSelect session number",
1438
+ type=int,
1439
+ default=1
1440
+ )
1441
+ session_idx = selection - 1
1442
+
1443
+ if session_idx < 0 or session_idx >= len(sessions_with_mh):
1444
+ typer.echo("\n❌ " + typer.style("Invalid selection.", fg=typer.colors.RED))
1445
+ raise typer.Exit(1)
1446
+ except Exception as e:
1447
+ typer.echo("\n❌ " + typer.style(f"Failed to load handler: {e}", fg=typer.colors.RED))
1448
+ raise typer.Exit(1)
1449
+
1450
+ # === Load and validate handler ===
1451
+ try:
1452
+ handler_file = next(
1453
+ (
1454
+ mh['path']
1455
+ for mh in config.get('mounted_handlers')
1456
+ if mh['terminal_session_id'] == sessions_with_mh[session_idx]
1457
+ ),
1458
+ None
1459
+ )
1460
+
1461
+ if handler_file is None:
1462
+ raise Exception('No mounted handler found for selected terminal session')
1463
+
1464
+ module = load_handler_module(handler_file) # ← Recommended to extract this
1465
+ if not hasattr(module, "handler_entry"):
1466
+ raise AttributeError("Function 'handler_entry' not found")
1467
+ handler_func = getattr(module, "handler_entry")
1468
+ except Exception as e:
1469
+ typer.echo("\n❌ " + typer.style(f"Failed to load handler: {e}", fg=typer.colors.RED))
1470
+ raise typer.Exit(1)
1471
+
1472
+ typer.echo(f"\n▶️ Running handler {typer.style(Path(handler_file).name, fg=typer.colors.BRIGHT_GREEN)}...")
1473
+ try:
1474
+ handler_func(terminal_session_id=sessions_with_mh[session_idx])
1475
+ typer.echo("✅ Handler executed successfully.\n")
1476
+ except Exception as e:
1477
+ typer.echo("⚠️ " + typer.style(f"Handler execution failed: {e}", fg=typer.colors.RED))
1200
1478
 
1201
1479
  @sessions.command(help='Remove a specific connection')
1202
1480
  def remove_connection(session_name: str, type: str, connection_name: str):
@@ -1273,7 +1551,7 @@ def refresh():
1273
1551
 
1274
1552
  if resp.ok:
1275
1553
  sessions = resp.json()['Sessions']
1276
- config['sessions'] = sessions
1554
+ config['terminal_sessions'] = sessions
1277
1555
  write_config(config)
1278
1556
 
1279
1557
  typer.echo(
@@ -1302,8 +1580,230 @@ def refresh():
1302
1580
  fg=typer.colors.RED
1303
1581
  )
1304
1582
  )
1583
+
1584
+ @sessions.command(help='Show all active and inactive sessions')
1585
+ def show():
1586
+ config = load_config()
1587
+
1588
+ if config is None:
1589
+ typer.echo('\nYou have not configured a developer API. Please run:')
1590
+ typer.echo('\t' + typer.style(' orrin config configure-dev ', fg=typer.colors.YELLOW) + '\n')
1591
+ return
1592
+
1593
+ if not 'terminal_sessions' in config:
1594
+ typer.echo('\nYou have no sessions. You can create one by running:')
1595
+ typer.echo('\t' + typer.style(' orrin sessions create ', fg=typer.colors.YELLOW) + '\n')
1596
+ return
1597
+
1598
+ active_sessions = [session for session in config['terminal_sessions'] if session['active']]
1599
+ inactive_sessions = [session for session in config['terminal_sessions'] if not session['active']]
1600
+
1601
+ typer.echo('\nActive Terminal Sessions:')
1602
+
1603
+ if active_sessions == []:
1604
+ typer.echo('\tNo active sessions')
1605
+ else:
1606
+ for i in range(len(active_sessions)):
1607
+ typer.echo('\t' + f'{active_sessions[i]["session_name"]}, id: {active_sessions[i]["session_id"]}')
1608
+
1609
+
1610
+ typer.echo('\nInactive Terminal Sessions:')
1611
+
1612
+ if inactive_sessions == []:
1613
+ typer.echo('\tAll sessions are active')
1614
+ else:
1615
+ for i in range(len(inactive_sessions)):
1616
+ typer.echo('\t' + f'{inactive_sessions[i]["session_name"]}, id: {inactive_sessions[i]["session_id"]}')
1617
+
1618
+ typer.echo('')
1619
+
1305
1620
  # ---------------------------
1306
1621
 
1622
+ def is_development_url(url: str) -> bool:
1623
+ parsed = urlparse(url)
1624
+ host = parsed.hostname
1625
+
1626
+ if host is None:
1627
+ return False
1628
+
1629
+ # Common localhost names
1630
+ if host.lower() in {
1631
+ "localhost",
1632
+ "localhost.localdomain",
1633
+ }:
1634
+ return True
1635
+
1636
+ try:
1637
+ ip = ipaddress.ip_address(host)
1638
+
1639
+ # Loopback: 127.0.0.0/8, ::1
1640
+ if ip.is_loopback:
1641
+ return True
1642
+
1643
+ # Private networks: 10.x, 172.16-31.x, 192.168.x
1644
+ if ip.is_private:
1645
+ return True
1646
+
1647
+ # Link-local: 169.254.x.x
1648
+ if ip.is_link_local:
1649
+ return True
1650
+
1651
+ except ValueError:
1652
+ # Not an IP address
1653
+ pass
1654
+
1655
+ return False
1656
+
1657
+ @especi.command(help='Create a mount for your webpage to use to enable websocket-based dynamic adaptability')
1658
+ def cmount():
1659
+ config = load_config()
1660
+
1661
+ if config is None or not 'api_key' in config:
1662
+ typer.echo('\nYou have not configured a developer API. Please run:')
1663
+ typer.echo('\t' + typer.style(' orrin config configure-dev ', fg=typer.colors.YELLOW) + '\n')
1664
+ return
1665
+
1666
+ url = typer.prompt('Production URL')
1667
+
1668
+ while is_development_url(url):
1669
+ typer.echo(
1670
+ typer.style(
1671
+ f'Invalid URL. A production URL is required.',
1672
+ fg=typer.colors.RED
1673
+ )
1674
+ )
1675
+
1676
+ url = typer.prompt('Production URL')
1677
+
1678
+ r = requests.post(
1679
+ 'http://192.168.1.96:8081/v1/create_especi_mount',
1680
+ headers={ 'fsdk': 'yes', 'authorization': config['api_key'] },
1681
+ json={
1682
+ 'url': url
1683
+ }
1684
+ )
1685
+
1686
+ if r.ok:
1687
+ typer.echo(
1688
+ '\n' + typer.style(
1689
+ f'ESPECI mount for {url} created.',
1690
+ fg=typer.colors.GREEN
1691
+ ) + '\n'
1692
+ )
1693
+
1694
+ r = r.json()
1695
+
1696
+ typer.echo(f'Mount ID: {r["mount_id"]}')
1697
+
1698
+ if 'especi_mounts' in config:
1699
+ config['especi_mounts'].append({
1700
+ 'url': url,
1701
+ 'mount_id': r['mount_id']
1702
+ })
1703
+ else:
1704
+ config['especi_mounts'] = [{
1705
+ 'url': url,
1706
+ 'mount_id': r['mount_id']
1707
+ }]
1708
+
1709
+ write_config(config)
1710
+ else:
1711
+ try:
1712
+ r = r.json()
1713
+
1714
+ if r['message'] == 'url_mount_exists':
1715
+ typer.echo(
1716
+ '\n' + typer.style(
1717
+ f'Failed to create ESPECI mount: mount exists for {url}.',
1718
+ fg=typer.colors.RED
1719
+ )
1720
+ )
1721
+ return
1722
+
1723
+ raise Exception
1724
+ except:
1725
+ typer.echo(
1726
+ '\n' + typer.style(
1727
+ f'Failed to create ESPECI mount.',
1728
+ fg=typer.colors.RED
1729
+ )
1730
+ )
1731
+
1732
+ @especi.command(help='Create a mount for your webpage that runs on local addresses to use to enable websocket-based dynamic adaptability')
1733
+ def cmount_dev():
1734
+ config = load_config()
1735
+
1736
+ if config is None or not 'api_key' in config:
1737
+ typer.echo('\nYou have not configured a developer API. Please run:')
1738
+ typer.echo('\t' + typer.style(' orrin config configure-dev ', fg=typer.colors.YELLOW) + '\n')
1739
+ return
1740
+
1741
+ url = typer.prompt('Development URL')
1742
+
1743
+ while not is_development_url(url):
1744
+ typer.echo(
1745
+ typer.style(
1746
+ f'Invalid URL. A production URL is required.',
1747
+ fg=typer.colors.RED
1748
+ )
1749
+ )
1750
+
1751
+ url = typer.prompt('Production URL')
1752
+
1753
+ r = requests.post(
1754
+ 'http://192.168.1.96:8081/v1/create_especi_mount',
1755
+ headers={ 'fsdk': 'yes', 'authorization': config['api_key'] },
1756
+ json={
1757
+ 'url': url
1758
+ }
1759
+ )
1760
+
1761
+ if r.ok:
1762
+ typer.echo(
1763
+ '\n' + typer.style(
1764
+ f'ESPECI mount for {url} created.',
1765
+ fg=typer.colors.GREEN
1766
+ ) + '\n'
1767
+ )
1768
+
1769
+ r = r.json()
1770
+
1771
+ typer.echo(f'Mount ID: {r["mount_id"]}')
1772
+
1773
+ if 'especi_mounts' in config:
1774
+ config['especi_mounts'].append({
1775
+ 'url': url,
1776
+ 'mount_id': r['mount_id']
1777
+ })
1778
+ else:
1779
+ config['especi_mounts'] = [{
1780
+ 'url': url,
1781
+ 'mount_id': r['mount_id']
1782
+ }]
1783
+
1784
+ write_config(config)
1785
+ else:
1786
+ try:
1787
+ r = r.json()
1788
+
1789
+ if r['message'] == 'url_mount_exists':
1790
+ typer.echo(
1791
+ '\n' + typer.style(
1792
+ f'Failed to create ESPECI mount: mount exists for {url}.',
1793
+ fg=typer.colors.RED
1794
+ )
1795
+ )
1796
+ return
1797
+
1798
+ raise Exception
1799
+ except:
1800
+ typer.echo(
1801
+ '\n' + typer.style(
1802
+ f'Failed to create ESPECI mount.',
1803
+ fg=typer.colors.RED
1804
+ )
1805
+ )
1806
+
1307
1807
  def main():
1308
1808
  app()
1309
1809
 
@@ -1,26 +1,42 @@
1
1
  import websockets
2
- import json
2
+ import json, subprocess
3
3
  import typer
4
4
 
5
5
  # Helper function: establish websockt connection as default handler
6
6
  # Developer can create a sender websocket
7
- async def establish_default_handler(session_id, auth):
7
+ async def establish_default_handler(session_id, auth, r):
8
8
  async with websockets.connect(
9
- f"wss://stellr-company.com/terminal_sessions/connect/{session_id}",
10
- additional_headers={ 'authorization': auth }
9
+ f"wss://stellr-company.com/terminal_sessions/connect/{session_id}"
11
10
  ) as ws:
12
- await ws.send(json.dumps({'connection_type': 'handler', 'websocket_dependencies': []}))
11
+ # Send authorization
12
+ await ws.send(f'AUTH: {auth}')
13
+
14
+ # Send intitial data telling connection what we are
15
+ await ws.send(json.dumps({
16
+ 'connection_type': 'handler',
17
+ 'websocket_dependencies': [], # no inherent dependencies
18
+ 'handler_name': 'test'
19
+ }))
20
+
13
21
  data = await ws.recv()
14
22
  data = json.loads(data)
15
23
  connection_id = data['connection_id']
16
24
 
17
25
  typer.echo(f'Default handler connection id: {connection_id}\nSession ID: {session_id}\nUse this when creating sender websockets.\nYou are free to create as many custom handlers/senders as you would like, and are not restricted to the default handler.\n')
18
26
 
27
+ r()
28
+
19
29
  while True:
20
30
  data = await ws.recv()
21
31
  data = json.loads(data)
22
32
 
23
- if not 'type' in data: continue
33
+ if not 'type' in data:
34
+ await ws.send(json.dumps({
35
+ 'type': 'respond',
36
+ 'message': 'fuck off.',
37
+ 'to': data['sender'],
38
+ 'response_type': 'string'
39
+ }))
24
40
 
25
41
  match data['type']:
26
42
  case 'close':
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: orrin-cli
3
+ Version: 0.3.0b4
4
+ Summary: Orrin CLI
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: typer[all]>=0.12.0
9
+ Requires-Dist: click<8.2
10
+ Dynamic: license-file
11
+
12
+ # Orrin CLI v0.3.0b3
13
+
14
+ ## What's New
15
+
16
+ In v0.3.0b4, we introduce support for creating "mounts" for websocket connectivity with our newly released Exegesis Specification for Interactivity.
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "orrin-cli"
3
3
  readme = "README.md"
4
- version = "0.3.0b2"
4
+ version = "0.3.0b4"
5
5
  description = "Orrin CLI"
6
6
  requires-python = ">=3.9"
7
7
  dependencies = [
@@ -1,16 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: orrin-cli
3
- Version: 0.3.0b2
4
- Summary: Orrin CLI
5
- Requires-Python: >=3.9
6
- Description-Content-Type: text/markdown
7
- License-File: LICENSE
8
- Requires-Dist: typer[all]>=0.12.0
9
- Requires-Dist: click<8.2
10
- Dynamic: license-file
11
-
12
- # Orrin CLI v0.3.0b1
13
-
14
- ## What's New
15
-
16
- In v0.3.0b1, the ability to create terminal sessions have been added. This includes many sub commands surrounding terminal sessions, including commands to pause and start sessions, as well as start default terminal session handlers.
@@ -1,5 +0,0 @@
1
- # Orrin CLI v0.3.0b1
2
-
3
- ## What's New
4
-
5
- In v0.3.0b1, the ability to create terminal sessions have been added. This includes many sub commands surrounding terminal sessions, including commands to pause and start sessions, as well as start default terminal session handlers.
@@ -1,16 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: orrin-cli
3
- Version: 0.3.0b2
4
- Summary: Orrin CLI
5
- Requires-Python: >=3.9
6
- Description-Content-Type: text/markdown
7
- License-File: LICENSE
8
- Requires-Dist: typer[all]>=0.12.0
9
- Requires-Dist: click<8.2
10
- Dynamic: license-file
11
-
12
- # Orrin CLI v0.3.0b1
13
-
14
- ## What's New
15
-
16
- In v0.3.0b1, the ability to create terminal sessions have been added. This includes many sub commands surrounding terminal sessions, including commands to pause and start sessions, as well as start default terminal session handlers.
File without changes
File without changes