neuronum 5.7.0__tar.gz → 5.8.0__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.
Potentially problematic release.
This version of neuronum might be problematic. Click here for more details.
- {neuronum-5.7.0/neuronum.egg-info → neuronum-5.8.0}/PKG-INFO +12 -7
- {neuronum-5.7.0 → neuronum-5.8.0}/README.md +10 -6
- {neuronum-5.7.0 → neuronum-5.8.0}/cli/main.py +234 -131
- {neuronum-5.7.0 → neuronum-5.8.0/neuronum.egg-info}/PKG-INFO +12 -7
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum.egg-info/requires.txt +1 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/setup.py +2 -1
- {neuronum-5.7.0 → neuronum-5.8.0}/LICENSE.md +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/cli/__init__.py +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum/__init__.py +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum/neuronum.py +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum.egg-info/SOURCES.txt +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum.egg-info/dependency_links.txt +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum.egg-info/entry_points.txt +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/neuronum.egg-info/top_level.txt +0 -0
- {neuronum-5.7.0 → neuronum-5.8.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.8.0
|
|
4
4
|
Summary: Official client library to interact with the Neuronum Network
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -18,6 +18,7 @@ Requires-Dist: click
|
|
|
18
18
|
Requires-Dist: questionary
|
|
19
19
|
Requires-Dist: python-dotenv
|
|
20
20
|
Requires-Dist: requests
|
|
21
|
+
Requires-Dist: psutil
|
|
21
22
|
Dynamic: author
|
|
22
23
|
Dynamic: author-email
|
|
23
24
|
Dynamic: classifier
|
|
@@ -54,10 +55,11 @@ Dynamic: summary
|
|
|
54
55
|
------------------
|
|
55
56
|
|
|
56
57
|
### **A Getting Started into the Neuronum Network**
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
58
|
+
In this brief getting started guide, you will:
|
|
59
|
+
- [Learn about Neuronum](#about-neuronum)
|
|
60
|
+
- [Connect to the Network](#connect-to-neuronum)
|
|
61
|
+
- [Build a Neuronum Node](#build-on-neuronum)
|
|
62
|
+
- [Interact with your Node](#interact-with-neuronum)
|
|
61
63
|
|
|
62
64
|
------------------
|
|
63
65
|
|
|
@@ -101,10 +103,13 @@ neuronum connect-cell # connect Cell
|
|
|
101
103
|
------------------
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
### **Build On Neuronum**
|
|
106
|
+
### **Build On Neuronum**
|
|
107
|
+
[View Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes)
|
|
108
|
+
|
|
109
|
+
|
|
105
110
|
Initialize a Node (app template):
|
|
106
111
|
```sh
|
|
107
|
-
neuronum init-node --app # initialize a Node with app template
|
|
112
|
+
neuronum init-node --app # initialize a Node with app template
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
Change into Node folder
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
------------------
|
|
23
23
|
|
|
24
24
|
### **A Getting Started into the Neuronum Network**
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
25
|
+
In this brief getting started guide, you will:
|
|
26
|
+
- [Learn about Neuronum](#about-neuronum)
|
|
27
|
+
- [Connect to the Network](#connect-to-neuronum)
|
|
28
|
+
- [Build a Neuronum Node](#build-on-neuronum)
|
|
29
|
+
- [Interact with your Node](#interact-with-neuronum)
|
|
29
30
|
|
|
30
31
|
------------------
|
|
31
32
|
|
|
@@ -69,10 +70,13 @@ neuronum connect-cell # connect Cell
|
|
|
69
70
|
------------------
|
|
70
71
|
|
|
71
72
|
|
|
72
|
-
### **Build On Neuronum**
|
|
73
|
+
### **Build On Neuronum**
|
|
74
|
+
[View Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes)
|
|
75
|
+
|
|
76
|
+
|
|
73
77
|
Initialize a Node (app template):
|
|
74
78
|
```sh
|
|
75
|
-
neuronum init-node --app # initialize a Node with app template
|
|
79
|
+
neuronum init-node --app # initialize a Node with app template
|
|
76
80
|
```
|
|
77
81
|
|
|
78
82
|
Change into Node folder
|
|
@@ -10,6 +10,8 @@ import click
|
|
|
10
10
|
import questionary
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
import requests
|
|
13
|
+
import psutil
|
|
14
|
+
from datetime import datetime
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
@click.group()
|
|
@@ -251,9 +253,13 @@ def delete_cell():
|
|
|
251
253
|
@click.option('--stream', multiple=True, default=None, help="Optional stream ID for stream.")
|
|
252
254
|
@click.option('--app', is_flag=True, help="Generate a Node with app template")
|
|
253
255
|
def init_node(sync, stream, app):
|
|
254
|
-
|
|
256
|
+
descr = click.prompt("Node description: Type up to 25 characters").strip()
|
|
257
|
+
if descr and len(descr) > 25:
|
|
258
|
+
click.echo("Description too long. Max 25 characters allowed.")
|
|
259
|
+
return
|
|
260
|
+
asyncio.run(async_init_node(sync, stream, app, descr))
|
|
255
261
|
|
|
256
|
-
async def async_init_node(sync, stream, app):
|
|
262
|
+
async def async_init_node(sync, stream, app, descr):
|
|
257
263
|
credentials_folder_path = Path.home() / ".neuronum"
|
|
258
264
|
env_path = credentials_folder_path / ".env"
|
|
259
265
|
|
|
@@ -278,11 +284,16 @@ async def async_init_node(sync, stream, app):
|
|
|
278
284
|
return
|
|
279
285
|
|
|
280
286
|
url = f"https://{network}/api/init_node"
|
|
281
|
-
|
|
287
|
+
node = {
|
|
288
|
+
"host": host,
|
|
289
|
+
"password": password,
|
|
290
|
+
"synapse": synapse,
|
|
291
|
+
"descr": descr,
|
|
292
|
+
}
|
|
282
293
|
|
|
283
294
|
async with aiohttp.ClientSession() as session:
|
|
284
295
|
try:
|
|
285
|
-
async with session.post(url, json=
|
|
296
|
+
async with session.post(url, json=node) as response:
|
|
286
297
|
response.raise_for_status()
|
|
287
298
|
data = await response.json()
|
|
288
299
|
nodeID = data["nodeID"]
|
|
@@ -565,13 +576,38 @@ asyncio.run(main())
|
|
|
565
576
|
@click.command()
|
|
566
577
|
@click.option('--d', is_flag=True, help="Start node in detached mode")
|
|
567
578
|
def start_node(d):
|
|
579
|
+
pid_file = Path.cwd() / "status.txt"
|
|
580
|
+
system_name = platform.system()
|
|
581
|
+
active_pids = []
|
|
582
|
+
|
|
583
|
+
start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
584
|
+
|
|
585
|
+
if pid_file.exists():
|
|
586
|
+
try:
|
|
587
|
+
with open(pid_file, "r") as f:
|
|
588
|
+
pids = [int(line.strip()) for line in f if line.strip().isdigit()]
|
|
589
|
+
for pid in pids:
|
|
590
|
+
if system_name == "Windows":
|
|
591
|
+
if psutil.pid_exists(pid):
|
|
592
|
+
active_pids.append(pid)
|
|
593
|
+
else:
|
|
594
|
+
try:
|
|
595
|
+
os.kill(pid, 0)
|
|
596
|
+
active_pids.append(pid)
|
|
597
|
+
except OSError:
|
|
598
|
+
continue
|
|
599
|
+
except Exception as e:
|
|
600
|
+
click.echo(f"Failed to read PID file: {e}")
|
|
601
|
+
|
|
602
|
+
if active_pids:
|
|
603
|
+
click.echo(f"Node is already running. Active PIDs: {', '.join(map(str, active_pids))}")
|
|
604
|
+
return
|
|
605
|
+
|
|
568
606
|
click.echo("Starting Node...")
|
|
569
607
|
|
|
570
608
|
project_path = Path.cwd()
|
|
571
609
|
script_files = glob.glob("sync_*.py") + glob.glob("stream_*.py") + glob.glob("app.py")
|
|
572
|
-
|
|
573
610
|
processes = []
|
|
574
|
-
system_name = platform.system()
|
|
575
611
|
|
|
576
612
|
for script in script_files:
|
|
577
613
|
script_path = project_path / script
|
|
@@ -587,7 +623,10 @@ def start_node(d):
|
|
|
587
623
|
start_new_session=True
|
|
588
624
|
)
|
|
589
625
|
else:
|
|
590
|
-
process = subprocess.Popen(
|
|
626
|
+
process = subprocess.Popen(
|
|
627
|
+
[python_cmd, str(script_path)],
|
|
628
|
+
start_new_session=True
|
|
629
|
+
)
|
|
591
630
|
|
|
592
631
|
processes.append(process.pid)
|
|
593
632
|
|
|
@@ -595,55 +634,172 @@ def start_node(d):
|
|
|
595
634
|
click.echo("Error: No valid node script found. Ensure the node is set up correctly.")
|
|
596
635
|
return
|
|
597
636
|
|
|
598
|
-
with open(
|
|
637
|
+
with open(pid_file, "w") as f:
|
|
638
|
+
f.write(f"Started at: {start_time}\n")
|
|
599
639
|
f.write("\n".join(map(str, processes)))
|
|
600
640
|
|
|
601
|
-
click.echo("Node started successfully
|
|
641
|
+
click.echo(f"Node started successfully with PIDs: {', '.join(map(str, processes))}")
|
|
602
642
|
|
|
603
643
|
|
|
604
644
|
@click.command()
|
|
605
|
-
def
|
|
606
|
-
|
|
645
|
+
def check_node():
|
|
646
|
+
click.echo("Checking Node status...")
|
|
607
647
|
|
|
608
|
-
|
|
609
|
-
|
|
648
|
+
env_data = {}
|
|
649
|
+
try:
|
|
650
|
+
with open(".env", "r") as f:
|
|
651
|
+
for line in f:
|
|
652
|
+
if "=" in line:
|
|
653
|
+
key, value = line.strip().split("=", 1)
|
|
654
|
+
env_data[key] = value
|
|
655
|
+
nodeID = env_data.get("NODE", "")
|
|
656
|
+
except FileNotFoundError:
|
|
657
|
+
click.echo("Error: .env with credentials not found")
|
|
658
|
+
return
|
|
659
|
+
except Exception as e:
|
|
660
|
+
click.echo(f"Error reading .env file: {e}")
|
|
661
|
+
return
|
|
662
|
+
|
|
663
|
+
pid_file = Path.cwd() / "status.txt"
|
|
610
664
|
|
|
611
|
-
|
|
665
|
+
if not pid_file.exists():
|
|
666
|
+
click.echo(f"Node {nodeID} is not running. Status file missing.")
|
|
667
|
+
return
|
|
612
668
|
|
|
613
669
|
try:
|
|
614
|
-
with open(
|
|
615
|
-
|
|
670
|
+
with open(pid_file, "r") as f:
|
|
671
|
+
lines = f.readlines()
|
|
672
|
+
timestamp_line = next((line for line in lines if line.startswith("Started at:")), None)
|
|
673
|
+
pids = [int(line.strip()) for line in lines if line.strip().isdigit()]
|
|
674
|
+
|
|
675
|
+
if timestamp_line:
|
|
676
|
+
click.echo(timestamp_line.strip())
|
|
677
|
+
start_time = datetime.strptime(timestamp_line.split(":", 1)[1].strip(), "%Y-%m-%d %H:%M:%S")
|
|
678
|
+
now = datetime.now()
|
|
679
|
+
uptime = now - start_time
|
|
680
|
+
click.echo(f"Uptime: {str(uptime).split('.')[0]}")
|
|
681
|
+
except Exception as e:
|
|
682
|
+
click.echo(f"Failed to read PID file: {e}")
|
|
683
|
+
return
|
|
616
684
|
|
|
617
|
-
|
|
685
|
+
system_name = platform.system()
|
|
686
|
+
running_pids = []
|
|
618
687
|
|
|
619
|
-
|
|
688
|
+
for pid in pids:
|
|
689
|
+
if system_name == "Windows":
|
|
690
|
+
if psutil.pid_exists(pid):
|
|
691
|
+
running_pids.append(pid)
|
|
692
|
+
else:
|
|
620
693
|
try:
|
|
694
|
+
os.kill(pid, 0)
|
|
695
|
+
running_pids.append(pid)
|
|
696
|
+
except OSError:
|
|
697
|
+
continue
|
|
698
|
+
|
|
699
|
+
if running_pids:
|
|
700
|
+
for pid in running_pids:
|
|
701
|
+
proc = psutil.Process(pid)
|
|
702
|
+
mem = proc.memory_info().rss / (1024 * 1024) # in MB
|
|
703
|
+
cpu = proc.cpu_percent(interval=0.1)
|
|
704
|
+
click.echo(f"PID {pid} → Memory: {mem:.2f} MB | CPU: {cpu:.1f}%")
|
|
705
|
+
click.echo(f"Node {nodeID} is running. Active PIDs: {', '.join(map(str, running_pids))}")
|
|
706
|
+
else:
|
|
707
|
+
click.echo(f"Node {nodeID} is not running.")
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
@click.command()
|
|
711
|
+
@click.option('--d', is_flag=True, help="Restart node in detached mode")
|
|
712
|
+
def restart_node(d):
|
|
713
|
+
pid_file = Path.cwd() / "status.txt"
|
|
714
|
+
system_name = platform.system()
|
|
715
|
+
|
|
716
|
+
start_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
717
|
+
|
|
718
|
+
env_data = {}
|
|
719
|
+
try:
|
|
720
|
+
with open(".env", "r") as f:
|
|
721
|
+
for line in f:
|
|
722
|
+
key, value = line.strip().split("=")
|
|
723
|
+
env_data[key] = value
|
|
724
|
+
|
|
725
|
+
nodeID = env_data.get("NODE", "")
|
|
726
|
+
|
|
727
|
+
except FileNotFoundError:
|
|
728
|
+
print("Error: .env with credentials not found")
|
|
729
|
+
return
|
|
730
|
+
except Exception as e:
|
|
731
|
+
print(f"Error reading .env file: {e}")
|
|
732
|
+
return
|
|
733
|
+
|
|
734
|
+
if pid_file.exists():
|
|
735
|
+
try:
|
|
736
|
+
with open(pid_file, "r") as f:
|
|
737
|
+
pids = [int(line.strip()) for line in f if line.strip().isdigit()]
|
|
738
|
+
|
|
739
|
+
for pid in pids:
|
|
621
740
|
if system_name == "Windows":
|
|
622
|
-
|
|
741
|
+
if psutil.pid_exists(pid):
|
|
742
|
+
proc = psutil.Process(pid)
|
|
743
|
+
proc.terminate()
|
|
623
744
|
else:
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
745
|
+
try:
|
|
746
|
+
os.kill(pid, 15)
|
|
747
|
+
except OSError:
|
|
748
|
+
continue
|
|
627
749
|
|
|
628
|
-
|
|
629
|
-
click.echo("Node stopped successfully!")
|
|
750
|
+
pid_file.unlink()
|
|
630
751
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
752
|
+
click.echo(f"Terminated existing {nodeID} processes: {', '.join(map(str, pids))}")
|
|
753
|
+
|
|
754
|
+
except Exception as e:
|
|
755
|
+
click.echo(f"Failed to terminate processes: {e}")
|
|
756
|
+
return
|
|
757
|
+
else:
|
|
758
|
+
click.echo(f"Node {nodeID} is not running")
|
|
759
|
+
|
|
760
|
+
click.echo(f"Starting Node {nodeID}...")
|
|
761
|
+
project_path = Path.cwd()
|
|
762
|
+
script_files = glob.glob("sync_*.py") + glob.glob("stream_*.py") + glob.glob("app.py")
|
|
763
|
+
processes = []
|
|
764
|
+
|
|
765
|
+
python_cmd = "pythonw" if system_name == "Windows" else "python"
|
|
766
|
+
|
|
767
|
+
for script in script_files:
|
|
768
|
+
script_path = project_path / script
|
|
769
|
+
if script_path.exists():
|
|
770
|
+
if d:
|
|
771
|
+
process = subprocess.Popen(
|
|
772
|
+
["nohup", python_cmd, str(script_path), "&"] if system_name != "Windows"
|
|
773
|
+
else [python_cmd, str(script_path)],
|
|
774
|
+
stdout=subprocess.DEVNULL,
|
|
775
|
+
stderr=subprocess.DEVNULL,
|
|
776
|
+
start_new_session=True
|
|
777
|
+
)
|
|
778
|
+
else:
|
|
779
|
+
process = subprocess.Popen([python_cmd, str(script_path)], start_new_session=True)
|
|
780
|
+
|
|
781
|
+
processes.append(process.pid)
|
|
782
|
+
|
|
783
|
+
if not processes:
|
|
784
|
+
click.echo("Error: No valid node script found.")
|
|
785
|
+
return
|
|
786
|
+
|
|
787
|
+
with open(pid_file, "w") as f:
|
|
788
|
+
f.write(f"Started at: {start_time}\n")
|
|
789
|
+
f.write("\n".join(map(str, processes)))
|
|
790
|
+
|
|
791
|
+
click.echo(f"Node {nodeID} started with new PIDs: {', '.join(map(str, processes))}")
|
|
635
792
|
|
|
636
793
|
|
|
637
794
|
@click.command()
|
|
638
|
-
def
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
795
|
+
def stop_node():
|
|
796
|
+
asyncio.run(async_stop_node())
|
|
797
|
+
|
|
798
|
+
async def async_stop_node():
|
|
799
|
+
click.echo("Stopping Node...")
|
|
800
|
+
|
|
801
|
+
node_pid_path = Path("status.txt")
|
|
645
802
|
|
|
646
|
-
async def async_connect_node(descr, node_type):
|
|
647
803
|
env_data = {}
|
|
648
804
|
try:
|
|
649
805
|
with open(".env", "r") as f:
|
|
@@ -652,10 +808,6 @@ async def async_connect_node(descr, node_type):
|
|
|
652
808
|
env_data[key] = value
|
|
653
809
|
|
|
654
810
|
nodeID = env_data.get("NODE", "")
|
|
655
|
-
host = env_data.get("HOST", "")
|
|
656
|
-
password = env_data.get("PASSWORD", "")
|
|
657
|
-
network = env_data.get("NETWORK", "")
|
|
658
|
-
synapse = env_data.get("SYNAPSE", "")
|
|
659
811
|
|
|
660
812
|
except FileNotFoundError:
|
|
661
813
|
print("Error: .env with credentials not found")
|
|
@@ -665,52 +817,46 @@ async def async_connect_node(descr, node_type):
|
|
|
665
817
|
return
|
|
666
818
|
|
|
667
819
|
try:
|
|
668
|
-
with open("
|
|
669
|
-
|
|
820
|
+
with open("status.txt", "r") as f:
|
|
821
|
+
pids = [int(line.strip()) for line in f if line.strip().isdigit()]
|
|
670
822
|
|
|
671
|
-
|
|
672
|
-
print("Error: NODE.md file not found")
|
|
673
|
-
return
|
|
674
|
-
except Exception as e:
|
|
675
|
-
print(f"Error reading NODE.md file: {e}")
|
|
676
|
-
return
|
|
823
|
+
system_name = platform.system()
|
|
677
824
|
|
|
678
|
-
|
|
825
|
+
for pid in pids:
|
|
826
|
+
try:
|
|
827
|
+
if system_name == "Windows":
|
|
828
|
+
await asyncio.to_thread(subprocess.run, ["taskkill", "/F", "/PID", str(pid)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
829
|
+
else:
|
|
830
|
+
await asyncio.to_thread(os.kill, pid, 9)
|
|
831
|
+
except ProcessLookupError:
|
|
832
|
+
click.echo(f"Warning: Process {pid} already stopped or does not exist.")
|
|
679
833
|
|
|
680
|
-
|
|
681
|
-
"nodeID"
|
|
682
|
-
"descr": descr,
|
|
683
|
-
"host": host,
|
|
684
|
-
"password": password,
|
|
685
|
-
"synapse": synapse,
|
|
686
|
-
"nodemd_file": nodemd_file
|
|
687
|
-
}
|
|
834
|
+
await asyncio.to_thread(os.remove, node_pid_path)
|
|
835
|
+
click.echo(f"Node {nodeID} stopped successfully!")
|
|
688
836
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
data = await response.json()
|
|
694
|
-
nodeID = data["nodeID"]
|
|
695
|
-
node_url = data["node_url"]
|
|
696
|
-
except aiohttp.ClientError as e:
|
|
697
|
-
click.echo(f"Error sending request: {e}")
|
|
698
|
-
return
|
|
699
|
-
|
|
700
|
-
if nodeID == "Node does not exist":
|
|
701
|
-
click.echo(f"Neuronum Node not found! Make sure you initialized your Node correctly")
|
|
702
|
-
else:
|
|
703
|
-
if node_type == "public":
|
|
704
|
-
click.echo(f"Public Neuronum Node '{nodeID}' connected! Visit: {node_url}")
|
|
705
|
-
else:
|
|
706
|
-
click.echo(f"Private Neuronum Node '{nodeID}' connected!")
|
|
837
|
+
except FileNotFoundError:
|
|
838
|
+
click.echo("Error: No active node process found.")
|
|
839
|
+
except subprocess.CalledProcessError:
|
|
840
|
+
click.echo("Error: Unable to stop some node processes.")
|
|
707
841
|
|
|
708
842
|
|
|
709
843
|
@click.command()
|
|
710
844
|
def update_node():
|
|
711
|
-
|
|
845
|
+
node_type = questionary.select(
|
|
846
|
+
"Update Node type:",
|
|
847
|
+
choices=["public", "private"]
|
|
848
|
+
).ask()
|
|
849
|
+
descr = click.prompt(
|
|
850
|
+
"Update Node description: Type up to 25 characters, or press Enter to leave it unchanged",
|
|
851
|
+
default="None",
|
|
852
|
+
show_default=False
|
|
853
|
+
).strip()
|
|
854
|
+
if descr and len(descr) > 25:
|
|
855
|
+
click.echo("Description too long. Max 25 characters allowed.")
|
|
856
|
+
return
|
|
857
|
+
asyncio.run(async_update_node(node_type, descr))
|
|
712
858
|
|
|
713
|
-
async def async_update_node():
|
|
859
|
+
async def async_update_node(node_type: str, descr: str) -> None:
|
|
714
860
|
env_data = {}
|
|
715
861
|
|
|
716
862
|
try:
|
|
@@ -744,17 +890,19 @@ async def async_update_node():
|
|
|
744
890
|
return
|
|
745
891
|
|
|
746
892
|
url = f"https://{network}/api/update_node"
|
|
747
|
-
|
|
893
|
+
node = {
|
|
748
894
|
"nodeID": nodeID,
|
|
749
895
|
"host": host,
|
|
750
896
|
"password": password,
|
|
751
897
|
"synapse": synapse,
|
|
752
|
-
"
|
|
898
|
+
"node_type": node_type,
|
|
899
|
+
"nodemd_file": nodemd_file,
|
|
900
|
+
"descr": descr,
|
|
753
901
|
}
|
|
754
902
|
|
|
755
903
|
async with aiohttp.ClientSession() as session:
|
|
756
904
|
try:
|
|
757
|
-
async with session.post(url, json=
|
|
905
|
+
async with session.post(url, json=node) as response:
|
|
758
906
|
response.raise_for_status()
|
|
759
907
|
data = await response.json()
|
|
760
908
|
nodeID = data["nodeID"]
|
|
@@ -782,54 +930,10 @@ async def async_update_node():
|
|
|
782
930
|
await asyncio.to_thread(Path("streams.json").write_text, json.dumps(stx, indent=4))
|
|
783
931
|
await asyncio.to_thread(Path("nodes.json").write_text, json.dumps(nodes, indent=4))
|
|
784
932
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
def disconnect_node():
|
|
790
|
-
asyncio.run(async_disconnect_node())
|
|
791
|
-
|
|
792
|
-
async def async_disconnect_node():
|
|
793
|
-
env_data = {}
|
|
794
|
-
|
|
795
|
-
try:
|
|
796
|
-
with open(".env", "r") as f:
|
|
797
|
-
for line in f:
|
|
798
|
-
key, value = line.strip().split("=")
|
|
799
|
-
env_data[key] = value
|
|
800
|
-
|
|
801
|
-
nodeID = env_data.get("NODE", "")
|
|
802
|
-
host = env_data.get("HOST", "")
|
|
803
|
-
password = env_data.get("PASSWORD", "")
|
|
804
|
-
network = env_data.get("NETWORK", "")
|
|
805
|
-
synapse = env_data.get("SYNAPSE", "")
|
|
806
|
-
|
|
807
|
-
except FileNotFoundError:
|
|
808
|
-
click.echo("Error: .env with credentials not found")
|
|
809
|
-
return
|
|
810
|
-
except Exception as e:
|
|
811
|
-
click.echo(f"Error reading .env file: {e}")
|
|
812
|
-
return
|
|
813
|
-
|
|
814
|
-
url = f"https://{network}/api/disconnect_node"
|
|
815
|
-
node_payload = {
|
|
816
|
-
"nodeID": nodeID,
|
|
817
|
-
"host": host,
|
|
818
|
-
"password": password,
|
|
819
|
-
"synapse": synapse
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
async with aiohttp.ClientSession() as session:
|
|
823
|
-
try:
|
|
824
|
-
async with session.post(url, json=node_payload) as response:
|
|
825
|
-
response.raise_for_status()
|
|
826
|
-
data = await response.json()
|
|
827
|
-
nodeID = data["nodeID"]
|
|
828
|
-
except aiohttp.ClientError as e:
|
|
829
|
-
click.echo(f"Error sending request: {e}")
|
|
830
|
-
return
|
|
831
|
-
|
|
832
|
-
click.echo(f"Neuronum Node '{nodeID}' disconnected!")
|
|
933
|
+
if node_type == "public":
|
|
934
|
+
click.echo(f"Neuronum Node '{nodeID}' updated! Visit: {node_url}")
|
|
935
|
+
else:
|
|
936
|
+
click.echo(f"Neuronum Node '{nodeID}' updated!")
|
|
833
937
|
|
|
834
938
|
|
|
835
939
|
@click.command()
|
|
@@ -1004,16 +1108,15 @@ async def async_sync(stx):
|
|
|
1004
1108
|
|
|
1005
1109
|
|
|
1006
1110
|
cli.add_command(create_cell)
|
|
1007
|
-
cli.add_command(connect_cell)
|
|
1008
1111
|
cli.add_command(view_cell)
|
|
1009
1112
|
cli.add_command(disconnect_cell)
|
|
1010
1113
|
cli.add_command(delete_cell)
|
|
1011
1114
|
cli.add_command(init_node)
|
|
1012
1115
|
cli.add_command(start_node)
|
|
1116
|
+
cli.add_command(restart_node)
|
|
1013
1117
|
cli.add_command(stop_node)
|
|
1014
|
-
cli.add_command(
|
|
1118
|
+
cli.add_command(check_node)
|
|
1015
1119
|
cli.add_command(update_node)
|
|
1016
|
-
cli.add_command(disconnect_node)
|
|
1017
1120
|
cli.add_command(delete_node)
|
|
1018
1121
|
cli.add_command(activate)
|
|
1019
1122
|
cli.add_command(load)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.8.0
|
|
4
4
|
Summary: Official client library to interact with the Neuronum Network
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -18,6 +18,7 @@ Requires-Dist: click
|
|
|
18
18
|
Requires-Dist: questionary
|
|
19
19
|
Requires-Dist: python-dotenv
|
|
20
20
|
Requires-Dist: requests
|
|
21
|
+
Requires-Dist: psutil
|
|
21
22
|
Dynamic: author
|
|
22
23
|
Dynamic: author-email
|
|
23
24
|
Dynamic: classifier
|
|
@@ -54,10 +55,11 @@ Dynamic: summary
|
|
|
54
55
|
------------------
|
|
55
56
|
|
|
56
57
|
### **A Getting Started into the Neuronum Network**
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
58
|
+
In this brief getting started guide, you will:
|
|
59
|
+
- [Learn about Neuronum](#about-neuronum)
|
|
60
|
+
- [Connect to the Network](#connect-to-neuronum)
|
|
61
|
+
- [Build a Neuronum Node](#build-on-neuronum)
|
|
62
|
+
- [Interact with your Node](#interact-with-neuronum)
|
|
61
63
|
|
|
62
64
|
------------------
|
|
63
65
|
|
|
@@ -101,10 +103,13 @@ neuronum connect-cell # connect Cell
|
|
|
101
103
|
------------------
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
### **Build On Neuronum**
|
|
106
|
+
### **Build On Neuronum**
|
|
107
|
+
[View Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes)
|
|
108
|
+
|
|
109
|
+
|
|
105
110
|
Initialize a Node (app template):
|
|
106
111
|
```sh
|
|
107
|
-
neuronum init-node --app # initialize a Node with app template
|
|
112
|
+
neuronum init-node --app # initialize a Node with app template
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
Change into Node folder
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='neuronum',
|
|
5
|
-
version='5.
|
|
5
|
+
version='5.8.0',
|
|
6
6
|
author='Neuronum Cybernetics',
|
|
7
7
|
author_email='welcome@neuronum.net',
|
|
8
8
|
description='Official client library to interact with the Neuronum Network',
|
|
@@ -26,6 +26,7 @@ setup(
|
|
|
26
26
|
'questionary',
|
|
27
27
|
'python-dotenv',
|
|
28
28
|
'requests',
|
|
29
|
+
'psutil',
|
|
29
30
|
],
|
|
30
31
|
entry_points={
|
|
31
32
|
"console_scripts": [
|
|
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
|