golem-vm-provider 0.1.51__tar.gz → 0.1.52__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.
Files changed (43) hide show
  1. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/PKG-INFO +1 -1
  2. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/main.py +154 -13
  3. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/pricing.py +8 -0
  4. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/pyproject.toml +1 -1
  5. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/README.md +0 -0
  6. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/__init__.py +0 -0
  7. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/api/__init__.py +0 -0
  8. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/api/models.py +0 -0
  9. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/api/routes.py +0 -0
  10. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/config.py +0 -0
  11. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/container.py +0 -0
  12. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/data/deployments/l2.json +0 -0
  13. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/__init__.py +0 -0
  14. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/advertiser.py +0 -0
  15. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/golem_base_advertiser.py +0 -0
  16. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/golem_base_utils.py +0 -0
  17. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/multi_advertiser.py +0 -0
  18. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/resource_monitor.py +0 -0
  19. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/resource_tracker.py +0 -0
  20. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/discovery/service.py +0 -0
  21. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/network/port_verifier.py +0 -0
  22. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/payments/blockchain_service.py +0 -0
  23. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/payments/monitor.py +0 -0
  24. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/payments/stream_map.py +0 -0
  25. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/security/ethereum.py +0 -0
  26. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/security/faucet.py +0 -0
  27. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/service.py +0 -0
  28. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/__init__.py +0 -0
  29. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/ascii_art.py +0 -0
  30. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/logging.py +0 -0
  31. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/port_display.py +0 -0
  32. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/retry.py +0 -0
  33. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/utils/setup.py +0 -0
  34. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/__init__.py +0 -0
  35. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/cloud_init.py +0 -0
  36. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/models.py +0 -0
  37. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/multipass.py +0 -0
  38. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/multipass_adapter.py +0 -0
  39. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/name_mapper.py +0 -0
  40. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/port_manager.py +0 -0
  41. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/provider.py +0 -0
  42. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/proxy_manager.py +0 -0
  43. {golem_vm_provider-0.1.51 → golem_vm_provider-0.1.52}/provider/vm/service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: golem-vm-provider
3
- Version: 0.1.51
3
+ Version: 0.1.52
4
4
  Summary: VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network
5
5
  Keywords: golem,vm,provider,cloud,decentralized
6
6
  Author: Phillip Jensen
@@ -191,6 +191,9 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
191
191
  from .container import Container
192
192
  from .config import settings
193
193
  from .payments.blockchain_service import StreamPaymentReader
194
+ from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
195
+ from decimal import Decimal
196
+ from web3 import Web3
194
197
  import json as _json
195
198
  try:
196
199
  if not settings.STREAM_PAYMENT_ADDRESS or settings.STREAM_PAYMENT_ADDRESS == "0x0000000000000000000000000000000000000000":
@@ -213,6 +216,7 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
213
216
  rows.append({
214
217
  "vm_id": vm_id,
215
218
  "stream_id": int(stream_id),
219
+ "token": str(s.get("token")),
216
220
  "recipient": s["recipient"],
217
221
  "start": int(s["startTime"]),
218
222
  "stop": int(s["stopTime"]),
@@ -232,12 +236,66 @@ def streams_list(json_out: bool = typer.Option(False, "--json", help="Output in
232
236
  if not rows:
233
237
  print("No streams mapped.")
234
238
  return
235
- print("\nStreams (VM stream_id, remaining s, verified):")
239
+ # Prepare human-friendly display (ETH/GLM + USD)
240
+ ZERO = "0x0000000000000000000000000000000000000000"
241
+ # Cache prices so we don't query per-row
242
+ price_cache: dict[str, Optional[Decimal]] = {"ETH": None, "GLM": None}
243
+ # Determine which symbols are present
244
+ symbols_present = set()
236
245
  for r in rows:
237
246
  if "error" in r:
238
- print(f"- {r['vm_id']}: {r['stream_id']} ERROR: {r['error']}")
239
- else:
240
- print(f"- {r['vm_id']}: {r['stream_id']} remaining={r['remaining']}s verified={r['verified']} reason={r['reason']} withdrawable={r['withdrawable']}")
247
+ continue
248
+ token_addr = (r.get("token") or "").lower()
249
+ sym = "ETH" if token_addr == ZERO.lower() else "GLM"
250
+ symbols_present.add(sym)
251
+ if "ETH" in symbols_present:
252
+ price_cache["ETH"] = fetch_eth_usd_price()
253
+ if "GLM" in symbols_present:
254
+ price_cache["GLM"] = fetch_glm_usd_price()
255
+
256
+ # Build table rows
257
+ table_rows = []
258
+ for r in rows:
259
+ if "error" in r:
260
+ table_rows.append([r["vm_id"], str(r["stream_id"]), "—", "ERROR", r.get("error", ""), "—"])
261
+ continue
262
+ token_addr = (r.get("token") or "").lower()
263
+ sym = "ETH" if token_addr == ZERO.lower() else "GLM"
264
+ withdrawable_eth = Decimal(str(Web3.from_wei(int(r["withdrawable"]), "ether")))
265
+ withdrawable_str = f"{withdrawable_eth:.6f} {sym}"
266
+ price = price_cache.get(sym)
267
+ usd_str = "—"
268
+ if price is not None:
269
+ try:
270
+ usd_val = (withdrawable_eth * price).quantize(Decimal("0.01"))
271
+ usd_str = f"${usd_val}"
272
+ except Exception:
273
+ usd_str = "—"
274
+ table_rows.append([
275
+ r["vm_id"],
276
+ str(r["stream_id"]),
277
+ f"{int(r['remaining'])}s",
278
+ "yes" if r["verified"] else "no",
279
+ withdrawable_str,
280
+ usd_str,
281
+ ])
282
+
283
+ headers = ["VM", "Stream", "Remaining", "Verified", "Withdrawable", "USD"]
284
+ # Compute column widths
285
+ cols = len(headers)
286
+ col_widths = [len(h) for h in headers]
287
+ for row in table_rows:
288
+ for i in range(cols):
289
+ col_widths[i] = max(col_widths[i], len(str(row[i])))
290
+
291
+ def fmt_row(values: list[str]) -> str:
292
+ return " ".join(str(values[i]).ljust(col_widths[i]) for i in range(cols))
293
+
294
+ print("\nStreams")
295
+ print(fmt_row(headers))
296
+ print(" ".join("-" * w for w in col_widths))
297
+ for row in table_rows:
298
+ print(fmt_row(row))
241
299
  except Exception as e:
242
300
  print(f"Error: {e}")
243
301
  raise typer.Exit(code=1)
@@ -249,6 +307,9 @@ def streams_show(vm_id: str = typer.Argument(..., help="VM id (requestor_name)")
249
307
  from .container import Container
250
308
  from .config import settings
251
309
  from .payments.blockchain_service import StreamPaymentReader
310
+ from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
311
+ from decimal import Decimal
312
+ from web3 import Web3
252
313
  import json as _json
253
314
  try:
254
315
  c = Container()
@@ -281,7 +342,43 @@ def streams_show(vm_id: str = typer.Argument(..., help="VM id (requestor_name)")
281
342
  if json_out:
282
343
  print(_json.dumps(out, indent=2))
283
344
  else:
284
- print(f"VM {vm_id}: stream {sid} remaining={remaining}s verified={ok} withdrawable={withdrawable}")
345
+ ZERO = "0x0000000000000000000000000000000000000000"
346
+ token_addr = (s.get("token") or "").lower()
347
+ sym = "ETH" if token_addr == ZERO.lower() else "GLM"
348
+ nat = Decimal(str(Web3.from_wei(int(withdrawable), "ether")))
349
+ price = fetch_eth_usd_price() if sym == "ETH" else fetch_glm_usd_price()
350
+ usd_str = "—"
351
+ if price is not None:
352
+ try:
353
+ usd_val = (nat * price).quantize(Decimal("0.01"))
354
+ usd_str = f"${usd_val}"
355
+ except Exception:
356
+ usd_str = "—"
357
+ def _fmt_seconds(sec: int) -> str:
358
+ m, s2 = divmod(int(sec), 60)
359
+ h, m = divmod(m, 60)
360
+ d, h = divmod(h, 24)
361
+ parts = []
362
+ if d: parts.append(f"{d}d")
363
+ if h: parts.append(f"{h}h")
364
+ if m and not d: parts.append(f"{m}m")
365
+ if s2 and not d and not h and not m: parts.append(f"{s2}s")
366
+ return " ".join(parts) or "0s"
367
+ # Pretty single-record display
368
+ print("\nStream Details")
369
+ headers = ["VM", "Stream", "Remaining", "Verified", "Withdrawable", "USD"]
370
+ cols = [
371
+ vm_id,
372
+ str(sid),
373
+ _fmt_seconds(remaining),
374
+ "yes" if ok else "no",
375
+ f"{nat:.6f} {sym}",
376
+ usd_str,
377
+ ]
378
+ w = [max(len(headers[i]), len(str(cols[i]))) for i in range(len(headers))]
379
+ print(" ".join(headers[i].ljust(w[i]) for i in range(len(w))))
380
+ print(" ".join("-" * wi for wi in w))
381
+ print(" ".join(str(cols[i]).ljust(w[i]) for i in range(len(w))))
285
382
  except Exception as e:
286
383
  print(f"Error: {e}")
287
384
  raise typer.Exit(code=1)
@@ -292,6 +389,9 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
292
389
  from .container import Container
293
390
  from .config import settings
294
391
  from .payments.blockchain_service import StreamPaymentReader
392
+ from .utils.pricing import fetch_glm_usd_price, fetch_eth_usd_price
393
+ from decimal import Decimal
394
+ from web3 import Web3
295
395
  import json as _json
296
396
  try:
297
397
  c = Container()
@@ -304,6 +404,8 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
304
404
  total_vested = 0
305
405
  total_withdrawn = 0
306
406
  total_withdrawable = 0
407
+ ZERO = "0x0000000000000000000000000000000000000000"
408
+ sums_native: dict[str, Decimal] = {"ETH": Decimal("0"), "GLM": Decimal("0")}
307
409
  for vm_id, stream_id in items.items():
308
410
  try:
309
411
  s = reader.get_stream(int(stream_id))
@@ -312,9 +414,12 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
312
414
  total_vested += int(vested)
313
415
  total_withdrawn += int(s["withdrawn"]) # type: ignore
314
416
  total_withdrawable += int(withdrawable)
417
+ sym = "ETH" if (s.get("token") or "").lower() == ZERO.lower() else "GLM"
418
+ sums_native[sym] += Decimal(str(Web3.from_wei(int(withdrawable), "ether")))
315
419
  rows.append({
316
420
  "vm_id": vm_id,
317
421
  "stream_id": int(stream_id),
422
+ "token": str(s.get("token")),
318
423
  "vested": int(vested),
319
424
  "withdrawn": int(s["withdrawn"]),
320
425
  "withdrawable": int(withdrawable),
@@ -332,17 +437,53 @@ def streams_earnings(json_out: bool = typer.Option(False, "--json", help="Output
332
437
  if json_out:
333
438
  print(_json.dumps(out, indent=2))
334
439
  return
335
- print("\nEarnings summary (wei):")
336
- print(f" Vested total : {total_vested}")
337
- print(f" Withdrawn total : {total_withdrawn}")
338
- print(f" Withdrawable total: {total_withdrawable}")
440
+ # Human summary by token with USD
441
+ price_eth = fetch_eth_usd_price()
442
+ price_glm = fetch_glm_usd_price()
443
+ def _fmt_usd(amount_native: Decimal, price: Optional[Decimal]) -> str:
444
+ if price is None:
445
+ return "—"
446
+ try:
447
+ return f"${(amount_native * price).quantize(Decimal('0.01'))}"
448
+ except Exception:
449
+ return "—"
450
+ print("\nEarnings Summary")
451
+ headers = ["Token", "Withdrawable", "USD"]
452
+ data_rows = [
453
+ ["ETH", f"{sums_native['ETH']:.6f} ETH", _fmt_usd(sums_native["ETH"], price_eth)],
454
+ ["GLM", f"{sums_native['GLM']:.6f} GLM", _fmt_usd(sums_native["GLM"], price_glm)],
455
+ ]
456
+ # Table widths
457
+ w = [len(h) for h in headers]
458
+ for r in data_rows:
459
+ for i in range(3):
460
+ w[i] = max(w[i], len(str(r[i])))
461
+ print(" ".join(headers[i].ljust(w[i]) for i in range(3)))
462
+ print(" ".join("-" * wi for wi in w))
463
+ for r in data_rows:
464
+ print(" ".join(str(r[i]).ljust(w[i]) for i in range(3)))
465
+ # Per stream table
339
466
  if rows:
340
- print("\nPer-stream:")
467
+ table = []
341
468
  for r in rows:
342
469
  if "error" in r:
343
- print(f"- {r['vm_id']} [{r['stream_id']}] ERROR: {r['error']}")
344
- else:
345
- print(f"- {r['vm_id']} [{r['stream_id']}]: vested={r['vested']} withdrawn={r['withdrawn']} withdrawable={r['withdrawable']}")
470
+ table.append([r["vm_id"], str(r["stream_id"]), "ERROR", r.get("error", "")])
471
+ continue
472
+ sym = "ETH" if (r.get("token") or "").lower() == ZERO.lower() else "GLM"
473
+ nat = Decimal(str(Web3.from_wei(int(r["withdrawable"]), "ether")))
474
+ price = price_eth if sym == "ETH" else price_glm
475
+ usd = _fmt_usd(nat, price)
476
+ table.append([r["vm_id"], str(r["stream_id"]), f"{nat:.6f} {sym}", usd])
477
+ h2 = ["VM", "Stream", "Withdrawable", "USD"]
478
+ w2 = [len(x) for x in h2]
479
+ for row in table:
480
+ for i in range(4):
481
+ w2[i] = max(w2[i], len(str(row[i])))
482
+ print("\nPer Stream")
483
+ print(" ".join(h2[i].ljust(w2[i]) for i in range(4)))
484
+ print(" ".join("-" * wi for wi in w2))
485
+ for row in table:
486
+ print(" ".join(str(row[i]).ljust(w2[i]) for i in range(4)))
346
487
  except Exception as e:
347
488
  print(f"Error: {e}")
348
489
  raise typer.Exit(code=1)
@@ -47,6 +47,14 @@ def fetch_glm_usd_price() -> Optional[Decimal]:
47
47
  return _coingecko_simple_price(settings.COINGECKO_IDS)
48
48
 
49
49
 
50
+ def fetch_eth_usd_price() -> Optional[Decimal]:
51
+ """Fetch the current ETH price in USD from CoinGecko.
52
+
53
+ Uses the canonical "ethereum" id.
54
+ """
55
+ return _coingecko_simple_price("ethereum")
56
+
57
+
50
58
  def usd_to_glm(usd_amount: Decimal, glm_usd: Decimal) -> Decimal:
51
59
  if glm_usd <= 0:
52
60
  raise ValueError("Invalid GLM/USD price")
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "golem-vm-provider"
3
- version = "0.1.51"
3
+ version = "0.1.52"
4
4
  description = "VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network"
5
5
  authors = ["Phillip Jensen <phillip+vm-on-golem@golemgrid.com>"]
6
6
  readme = "README.md"