unaiverse 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
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 unaiverse might be problematic. Click here for more details.
- unaiverse/networking/node/node.py +18 -15
- unaiverse/networking/p2p/__init__.py +138 -114
- unaiverse/networking/p2p/golibp2p.pyi +2 -2
- unaiverse/networking/p2p/lib.go +10 -13
- unaiverse/networking/p2p/p2p.py +5 -5
- {unaiverse-0.1.0.dist-info → unaiverse-0.1.2.dist-info}/METADATA +3 -1
- {unaiverse-0.1.0.dist-info → unaiverse-0.1.2.dist-info}/RECORD +10 -10
- {unaiverse-0.1.0.dist-info → unaiverse-0.1.2.dist-info}/WHEEL +0 -0
- {unaiverse-0.1.0.dist-info → unaiverse-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {unaiverse-0.1.0.dist-info → unaiverse-0.1.2.dist-info}/top_level.txt +0 -0
|
@@ -135,6 +135,9 @@ class Node:
|
|
|
135
135
|
self.last_alive_time = 0.
|
|
136
136
|
self.skip_was_alive_check = os.getenv("NODE_IGNORE_ALIVE", "0") == "1"
|
|
137
137
|
|
|
138
|
+
# Alive messaging
|
|
139
|
+
self.run_start_time = 0.
|
|
140
|
+
|
|
138
141
|
# Root server-related
|
|
139
142
|
self.root_endpoint = 'https://unaiverse.io/api' # WARNING: EDITING THIS ADDRESS VIOLATES THE LICENSE
|
|
140
143
|
self.node_token = ""
|
|
@@ -206,7 +209,7 @@ class Node:
|
|
|
206
209
|
ips=None,
|
|
207
210
|
enable_relay_service=offer_relay_facilities,
|
|
208
211
|
enable_relay_client=allow_connection_through_relay,
|
|
209
|
-
|
|
212
|
+
knows_is_public=os.getenv("NODE_IS_PUBLIC", "0") == "1",
|
|
210
213
|
port=int(os.getenv("NODE_STARTING_PORT", "0")))
|
|
211
214
|
|
|
212
215
|
# Create another P2P node for the private world (it has fields 'addresses', and 'peer_id', and 'libp2p')
|
|
@@ -214,7 +217,7 @@ class Node:
|
|
|
214
217
|
ips=None,
|
|
215
218
|
enable_relay_service=offer_relay_facilities,
|
|
216
219
|
enable_relay_client=allow_connection_through_relay,
|
|
217
|
-
|
|
220
|
+
knows_is_public=os.getenv("NODE_IS_PUBLIC", "0") == "1",
|
|
218
221
|
port=(int(os.getenv("NODE_STARTING_PORT", "0")) + 3)
|
|
219
222
|
if int(os.getenv("NODE_STARTING_PORT", "0")) > 0 else 0)
|
|
220
223
|
|
|
@@ -447,7 +450,6 @@ class Node:
|
|
|
447
450
|
self.profile.get_dynamic_profile()})
|
|
448
451
|
except Exception as e:
|
|
449
452
|
self.err(f"Error while sending dynamic profile to from server [{e}]")
|
|
450
|
-
raise GenException(f"Error while sending dynamic profile to from server [{e}]")
|
|
451
453
|
|
|
452
454
|
def send_badges(self):
|
|
453
455
|
"""Sends new badges assigned by a world node to the root server and notifies the agents."""
|
|
@@ -768,8 +770,20 @@ class Node:
|
|
|
768
770
|
|
|
769
771
|
# Main loop
|
|
770
772
|
must_quit = False
|
|
773
|
+
self.run_start_time = self.clock.get_time()
|
|
771
774
|
while not must_quit:
|
|
772
775
|
|
|
776
|
+
# Sending alive message every "K" seconds
|
|
777
|
+
if self.clock.get_time() - self.last_alive_time >= self.send_alive_every:
|
|
778
|
+
was_alive = self.send_alive()
|
|
779
|
+
|
|
780
|
+
# Checking only at the first run
|
|
781
|
+
if self.last_alive_time == 0 and was_alive and not self.skip_was_alive_check:
|
|
782
|
+
print(f"The node is already alive, maybe running in a different machine? "
|
|
783
|
+
f"(set env variable NODE_IGNORE_ALIVE=1 to ignore this control)")
|
|
784
|
+
break # Stopping the running cycle
|
|
785
|
+
self.last_alive_time = self.clock.get_time()
|
|
786
|
+
|
|
773
787
|
# Check inspector
|
|
774
788
|
if self.inspector_activated:
|
|
775
789
|
if self.__inspector_told_to_pause:
|
|
@@ -916,17 +930,6 @@ class Node:
|
|
|
916
930
|
self.get_node_token(peer_ids=[self.get_public_peer_id(), self.get_world_peer_id()])
|
|
917
931
|
last_get_token_time = self.clock.get_time()
|
|
918
932
|
|
|
919
|
-
# Sending alive message every "K" seconds
|
|
920
|
-
if self.clock.get_time() - self.last_alive_time >= self.send_alive_every:
|
|
921
|
-
was_alive = self.send_alive()
|
|
922
|
-
|
|
923
|
-
# Checking only at the first run
|
|
924
|
-
if self.last_alive_time == 0 and was_alive and not self.skip_was_alive_check:
|
|
925
|
-
print(f"The node is already alive, maybe running in a different machine? "
|
|
926
|
-
f"(set env variable NODE_IGNORE_ALIVE=1 to ignore this control)")
|
|
927
|
-
break # Stopping the running cycle
|
|
928
|
-
self.last_alive_time = self.clock.get_time()
|
|
929
|
-
|
|
930
933
|
# Check for address changes every "N" seconds
|
|
931
934
|
if self.clock.get_time() - last_address_check_time >= self.address_check_every:
|
|
932
935
|
self.out("Performing periodic check for address changes...")
|
|
@@ -995,7 +998,7 @@ class Node:
|
|
|
995
998
|
# Stop conditions
|
|
996
999
|
if cycles is not None and ((self.clock.get_cycle() + 1) >= cycles):
|
|
997
1000
|
break
|
|
998
|
-
if max_time is not None and self.clock.get_time(
|
|
1001
|
+
if max_time is not None and (self.clock.get_time() - self.run_start_time) >= max_time:
|
|
999
1002
|
break
|
|
1000
1003
|
|
|
1001
1004
|
except KeyboardInterrupt:
|
|
@@ -18,6 +18,7 @@ from . import golibp2p
|
|
|
18
18
|
from . import lib_types
|
|
19
19
|
import os
|
|
20
20
|
import sys
|
|
21
|
+
import json
|
|
21
22
|
import ctypes
|
|
22
23
|
import platform
|
|
23
24
|
import requests
|
|
@@ -31,135 +32,159 @@ from .lib_types import TypeInterface # Assuming TypeInterface handles the void*
|
|
|
31
32
|
|
|
32
33
|
# --- Setup and Pre-build Checks ---
|
|
33
34
|
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
# Determine the correct library file extension and URL based on the OS
|
|
36
|
+
os_to_ext = {
|
|
37
|
+
"Windows": ".dll",
|
|
38
|
+
"Darwin": ".dylib",
|
|
39
|
+
"Linux": ".so"
|
|
40
|
+
}
|
|
41
|
+
os_to_url = {
|
|
42
|
+
"Windows": "https://raw.githubusercontent.com/collectionlessai/unaiverse-misc/main/precompiled/lib.dll",
|
|
43
|
+
"Darwin": "https://raw.githubusercontent.com/collectionlessai/unaiverse-misc/main/precompiled/lib.dylib",
|
|
44
|
+
"Linux": "https://raw.githubusercontent.com/collectionlessai/unaiverse-misc/main/precompiled/lib.so"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
current_os = platform.system()
|
|
48
|
+
lib_ext = os_to_ext.get(current_os, ".so")
|
|
49
|
+
lib_url = os_to_url.get(current_os, os_to_url["Linux"])
|
|
50
|
+
|
|
51
|
+
# --- Configuration & Paths ---
|
|
52
|
+
lib_dir = os.path.dirname(os.path.abspath(__file__))
|
|
37
53
|
go_source_file = os.path.join(lib_dir, "lib.go")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# Determine the correct library file extension based on the OS
|
|
41
|
-
if platform.system() == "Windows":
|
|
42
|
-
lib_url = "https://github.com/collectionlessai/unaiverse-misc/raw/main/precompiled/lib.dll"
|
|
43
|
-
lib_ext = ".dll"
|
|
44
|
-
elif platform.system() == "Darwin": # MacOS
|
|
45
|
-
lib_url = "https://github.com/collectionlessai/unaiverse-misc/raw/main/precompiled/lib.dylib"
|
|
46
|
-
lib_ext = ".dylib"
|
|
47
|
-
else: # Linux and other Unix-like
|
|
48
|
-
lib_url = "https://github.com/collectionlessai/unaiverse-misc/raw/main/precompiled/lib.so"
|
|
49
|
-
lib_ext = ".so"
|
|
50
|
-
|
|
51
|
-
lib_filename = f"{lib_name}{lib_ext}"
|
|
54
|
+
lib_filename = f"lib{lib_ext}"
|
|
52
55
|
lib_path = os.path.join(lib_dir, lib_filename)
|
|
53
|
-
|
|
56
|
+
go_mod_file = os.path.join(lib_dir, "go.mod")
|
|
57
|
+
version_file = os.path.join(lib_dir, "lib.version.json")
|
|
58
|
+
|
|
59
|
+
# --- Helper Functions ---
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
download_was_successful = False
|
|
61
|
+
def load_shared_library(path):
|
|
62
|
+
"""Attempt to load the shared library and return the handle."""
|
|
58
63
|
try:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
f.write(response.content)
|
|
65
|
-
download_was_successful = True
|
|
66
|
-
print(f"INFO: Download complete")
|
|
67
|
-
except Exception:
|
|
68
|
-
print(f"INFO: Download failed, attempting to compile from source (requires a Go compiler)...")
|
|
64
|
+
print(f"INFO: Attempting to load library from '{path}'...")
|
|
65
|
+
return ctypes.CDLL(path)
|
|
66
|
+
except OSError as e:
|
|
67
|
+
print(f"INFO: Failed to load library: {e}")
|
|
68
|
+
return None
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
def get_remote_version_info(url):
|
|
71
|
+
"""Performs a HEAD request to get ETag from the remote file."""
|
|
72
|
+
try:
|
|
73
|
+
print(f"INFO: Checking remote version at '{url}'...")
|
|
74
|
+
response = requests.head(url, allow_redirects=True, timeout=10)
|
|
75
|
+
response.raise_for_status()
|
|
76
|
+
etag = response.headers.get("ETag")
|
|
77
|
+
return etag
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"INFO: Failed to get remote version info: {e}")
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
def download_library(url, path, etag):
|
|
83
|
+
"""Downloads the shared library and saves version info."""
|
|
84
|
+
print(f"INFO: Downloading new library from '{url}'...")
|
|
85
|
+
try:
|
|
86
|
+
headers = {"User-Agent": "python-requests/2.31.0"}
|
|
87
|
+
response = requests.get(url, headers=headers, allow_redirects=True, timeout=30)
|
|
88
|
+
response.raise_for_status()
|
|
89
|
+
with open(path, "wb") as f:
|
|
90
|
+
f.write(response.content)
|
|
91
|
+
|
|
92
|
+
print("INFO: Download complete.")
|
|
93
|
+
return True
|
|
94
|
+
except Exception as e:
|
|
95
|
+
print(f"INFO: Failed to download library: {e}")
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
def build_go_library():
|
|
99
|
+
"""Build the Go shared library and saves version info."""
|
|
100
|
+
print("INFO: Building library from source...")
|
|
82
101
|
if not os.path.exists(go_mod_file):
|
|
83
|
-
print(f"INFO: 'go.mod' not found. Initializing Go module
|
|
102
|
+
print(f"INFO: 'go.mod' not found. Initializing Go module...")
|
|
103
|
+
module_path = "unaiverse/networking/p2p/lib"
|
|
84
104
|
try:
|
|
85
|
-
|
|
86
|
-
# Define a module path. This can be anything, but a path-like name is conventional.
|
|
87
|
-
module_path = "unaiverse/networking/p2p/lib"
|
|
88
|
-
|
|
89
|
-
# Run 'go mod init'
|
|
90
|
-
subprocess.run(
|
|
91
|
-
["go", "mod", "init", module_path],
|
|
92
|
-
cwd=lib_dir, # Run the command in the directory containing lib.go
|
|
93
|
-
check=True, # Raise an exception if the command fails
|
|
94
|
-
capture_output=True, # Capture stdout/stderr
|
|
95
|
-
text=True
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# Run 'go mod tidy' to find dependencies and create go.sum
|
|
105
|
+
subprocess.run(["go", "mod", "init", module_path], cwd=lib_dir, check=True, capture_output=True, text=True)
|
|
99
106
|
print("INFO: Go module initialized. Running 'go mod tidy'...")
|
|
100
|
-
subprocess.run(
|
|
101
|
-
["go", "mod", "tidy"],
|
|
102
|
-
cwd=lib_dir,
|
|
103
|
-
check=True,
|
|
104
|
-
capture_output=True,
|
|
105
|
-
text=True
|
|
106
|
-
)
|
|
107
|
-
print("INFO: 'go.mod' and 'go.sum' created successfully.")
|
|
107
|
+
subprocess.run(["go", "mod", "tidy"], cwd=lib_dir, check=True, capture_output=True, text=True)
|
|
108
108
|
except (subprocess.CalledProcessError, FileNotFoundError) as e:
|
|
109
|
-
print("FATAL: Failed to initialize Go module.", file=sys.stderr)
|
|
110
|
-
print("Please ensure Go is installed and in your system's PATH.", file=sys.stderr)
|
|
111
|
-
|
|
112
|
-
# If 'go mod' failed, print its output for debugging
|
|
113
|
-
if isinstance(e, subprocess.CalledProcessError):
|
|
114
|
-
print(f"Go command stderr:\n{e.stderr}", file=sys.stderr)
|
|
109
|
+
print(f"FATAL: Failed to initialize Go module. Is Go installed? Error: {e}", file=sys.stderr)
|
|
115
110
|
raise e
|
|
116
111
|
|
|
117
|
-
# --- Automatically build the shared library if it's missing or outdated ---
|
|
118
|
-
rebuild_needed = False
|
|
119
|
-
reason = ""
|
|
120
|
-
|
|
121
|
-
if downloaded_shared_lib is None:
|
|
122
|
-
if not os.path.exists(lib_path):
|
|
123
|
-
rebuild_needed = True
|
|
124
|
-
reason = f"the shared library '{lib_filename}' was not found."
|
|
125
|
-
elif os.path.getmtime(go_source_file) > os.path.getmtime(lib_path):
|
|
126
|
-
rebuild_needed = True
|
|
127
|
-
reason = f"the last modification to '{go_source_file}' is more recent than the '{lib_filename}' last build."
|
|
128
|
-
|
|
129
|
-
if rebuild_needed:
|
|
130
|
-
print(f"INFO: Rebuilding shared library because {reason}")
|
|
131
112
|
try:
|
|
132
113
|
build_command = ["go", "build", "-buildmode=c-shared", "-ldflags", "-s -w", "-o", lib_filename, "lib.go"]
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
build_command,
|
|
136
|
-
cwd=lib_dir,
|
|
137
|
-
check=True,
|
|
138
|
-
capture_output=True,
|
|
139
|
-
text=True
|
|
140
|
-
)
|
|
141
|
-
if result.stdout:
|
|
142
|
-
print(f"Go build stdout:\n{result.stdout}")
|
|
114
|
+
subprocess.run(build_command, cwd=lib_dir, check=True, capture_output=True, text=True)
|
|
115
|
+
|
|
143
116
|
print(f"INFO: Successfully built '{lib_filename}'.")
|
|
144
|
-
|
|
117
|
+
return True
|
|
145
118
|
except (subprocess.CalledProcessError, FileNotFoundError) as e:
|
|
146
|
-
print(f"FATAL: Failed to build Go
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
119
|
+
print(f"FATAL: Failed to build library. Is Go installed? Error: {e}", file=sys.stderr)
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
# --- Main Logic Flow ---
|
|
123
|
+
_shared_lib = None
|
|
124
|
+
should_update = False
|
|
125
|
+
go_source_time = os.path.getmtime(go_source_file)
|
|
126
|
+
|
|
127
|
+
# Step 1: Check for existing local binary and version info
|
|
128
|
+
if os.path.exists(lib_path):
|
|
129
|
+
print(f"INFO: Found existing library '{lib_filename}'.")
|
|
130
|
+
if os.path.exists(version_file):
|
|
131
|
+
try:
|
|
132
|
+
with open(version_file, "r") as f:
|
|
133
|
+
version_info = json.load(f)
|
|
134
|
+
|
|
135
|
+
if version_info.get("source") == "remote":
|
|
136
|
+
remote_etag = get_remote_version_info(lib_url)
|
|
137
|
+
if remote_etag and remote_etag != version_info.get("etag"):
|
|
138
|
+
print("INFO: Remote binary is newer (different ETag). An update is required.")
|
|
139
|
+
should_update = True
|
|
140
|
+
else:
|
|
141
|
+
print("INFO: Local binary is up-to-date with remote.")
|
|
142
|
+
elif version_info.get("source") == "local":
|
|
143
|
+
if go_source_time > version_info.get("timestamp", 0):
|
|
144
|
+
print("INFO: Go source file is newer than local binary. Re-compilation is required.")
|
|
145
|
+
should_update = True
|
|
146
|
+
else:
|
|
147
|
+
print("INFO: Local binary is up-to-date with source.")
|
|
148
|
+
|
|
149
|
+
except (IOError, json.JSONDecodeError):
|
|
150
|
+
print("INFO: Could not read version file. Assuming outdated.")
|
|
151
|
+
should_update = True
|
|
152
|
+
else:
|
|
153
|
+
print("INFO: No version file found. Assuming outdated.")
|
|
154
|
+
should_update = True
|
|
155
|
+
|
|
156
|
+
if should_update:
|
|
157
|
+
if os.path.exists(lib_path):
|
|
158
|
+
os.remove(lib_path)
|
|
159
|
+
else:
|
|
160
|
+
# Load if it exists and is up-to-date
|
|
161
|
+
_shared_lib = load_shared_library(lib_path)
|
|
162
|
+
|
|
163
|
+
# Step 2: Try to get a library if none is loaded
|
|
164
|
+
if _shared_lib is None: # same as should_update being True
|
|
165
|
+
# Attempt to download the latest binary
|
|
166
|
+
remote_etag = get_remote_version_info(lib_url)
|
|
167
|
+
if remote_etag and download_library(lib_url, lib_path, remote_etag):
|
|
168
|
+
_shared_lib = load_shared_library(lib_path)
|
|
169
|
+
if _shared_lib is not None:
|
|
170
|
+
with open(version_file, "w") as f:
|
|
171
|
+
json.dump({"source": "remote", "etag": remote_etag}, f)
|
|
172
|
+
|
|
173
|
+
# Step 3: Fallback to local build if download failed or the file is invalid
|
|
174
|
+
if _shared_lib is None: # meaning that the download and load failed
|
|
175
|
+
print("INFO: Download failed or produced an invalid library. Building from source...")
|
|
176
|
+
if build_go_library():
|
|
177
|
+
_shared_lib = load_shared_library(lib_path)
|
|
178
|
+
if _shared_lib is not None:
|
|
179
|
+
with open(version_file, "w") as f:
|
|
180
|
+
json.dump({"source": "local", "timestamp": go_source_time}, f)
|
|
181
|
+
|
|
182
|
+
# Final check
|
|
183
|
+
if _shared_lib is None:
|
|
184
|
+
print("FATAL: Critical failure. Could not obtain or load the shared library.", file=sys.stderr)
|
|
185
|
+
sys.exit(1)
|
|
161
186
|
else:
|
|
162
|
-
|
|
187
|
+
print("SUCCESS: Library is ready to use.")
|
|
163
188
|
|
|
164
189
|
# --- Function Prototypes (argtypes and restype) ---
|
|
165
190
|
# Using void* for returned C strings, requiring TypeInterface for conversion/freeing.
|
|
@@ -244,7 +269,6 @@ except ImportError:
|
|
|
244
269
|
# Cast the loaded library object to the stub type
|
|
245
270
|
_shared_lib_typed = cast(GoLibP2P, _shared_lib)
|
|
246
271
|
|
|
247
|
-
|
|
248
272
|
# Attach the typed shared library object to the P2P class
|
|
249
273
|
P2P.libp2p = _shared_lib_typed
|
|
250
274
|
TypeInterface.libp2p = _shared_lib_typed # Attach to TypeInterface if needed
|
|
@@ -10,9 +10,9 @@ class GoLibP2P:
|
|
|
10
10
|
"""
|
|
11
11
|
...
|
|
12
12
|
|
|
13
|
-
def CreateNode(self, instance: int, port: int, ips: List[str], enable_relay_client: int, enable_relay_service: int,
|
|
13
|
+
def CreateNode(self, instance: int, port: int, ips: List[str], enable_relay_client: int, enable_relay_service: int, knows_is_public: int, max_connections: int) -> bytes:
|
|
14
14
|
"""
|
|
15
|
-
CreateNode(instance: int, port: int, ips: List[str], enable_relay_client: int, enable_relay_service: int,
|
|
15
|
+
CreateNode(instance: int, port: int, ips: List[str], enable_relay_client: int, enable_relay_service: int, knows_is_public: int, max_connections: int) -> bytes
|
|
16
16
|
|
|
17
17
|
Creates a node in the P2P network and returns a JSON string with node information.
|
|
18
18
|
"""
|
unaiverse/networking/p2p/lib.go
CHANGED
|
@@ -1137,7 +1137,7 @@ func InitializeLibrary(
|
|
|
1137
1137
|
// - predefinedPortC (C.int): The TCP port to listen on (0 for random).
|
|
1138
1138
|
// - enableRelayClientC (C.int): 1 if this node should enable relay communications (client mode)
|
|
1139
1139
|
// - enableRelayServiceC (C.int): 1 to set this node as a relay service (server mode),
|
|
1140
|
-
// -
|
|
1140
|
+
// - knowsIsPublicC (C.int): 1 to assume public reachability, 0 otherwise (-> tries to assess it in any possible way).
|
|
1141
1141
|
// - maxConnectionsC (C.int): The maximum number of connections this node can maintain.
|
|
1142
1142
|
//
|
|
1143
1143
|
// Returns:
|
|
@@ -1153,7 +1153,7 @@ func CreateNode(
|
|
|
1153
1153
|
ipsJSONC *C.char,
|
|
1154
1154
|
enableRelayClientC C.int,
|
|
1155
1155
|
enableRelayServiceC C.int,
|
|
1156
|
-
|
|
1156
|
+
knowsIsPublicC C.int,
|
|
1157
1157
|
maxConnectionsC C.int,
|
|
1158
1158
|
) *C.char {
|
|
1159
1159
|
|
|
@@ -1190,11 +1190,11 @@ func CreateNode(
|
|
|
1190
1190
|
ipsJSON := C.GoString(ipsJSONC)
|
|
1191
1191
|
enableRelayClient := int(enableRelayClientC) == 1
|
|
1192
1192
|
enableRelayService := int(enableRelayServiceC) == 1
|
|
1193
|
-
|
|
1193
|
+
knowsIsPublic := int(knowsIsPublicC) == 1
|
|
1194
1194
|
maxConnections := int(maxConnectionsC)
|
|
1195
1195
|
|
|
1196
|
-
log.Printf("[GO] 🔧 Instance %d: Config: Port=%d, IPsJSON=%s, EnableRelayClient=%t, EnableRelayService=%t,
|
|
1197
|
-
instanceIndex, predefinedPort, ipsJSON, enableRelayClient, enableRelayService,
|
|
1196
|
+
log.Printf("[GO] 🔧 Instance %d: Config: Port=%d, IPsJSON=%s, EnableRelayClient=%t, EnableRelayService=%t, KnowsIsPublic=%t, MaxConnections=%d",
|
|
1197
|
+
instanceIndex, predefinedPort, ipsJSON, enableRelayClient, enableRelayService, knowsIsPublic, maxConnections)
|
|
1198
1198
|
|
|
1199
1199
|
// --- 4. Libp2p Options Assembly ---
|
|
1200
1200
|
listenAddrs, err := getListenAddrs(ipsJSON, predefinedPort)
|
|
@@ -1246,7 +1246,7 @@ func CreateNode(
|
|
|
1246
1246
|
// Prepare discovering the bootstrap peers
|
|
1247
1247
|
var idht *dht.IpfsDHT
|
|
1248
1248
|
isPublic := false
|
|
1249
|
-
if
|
|
1249
|
+
if !knowsIsPublic {
|
|
1250
1250
|
// Add any possible option to be publicly reachable
|
|
1251
1251
|
options = append(
|
|
1252
1252
|
options,
|
|
@@ -1266,11 +1266,8 @@ func CreateNode(
|
|
|
1266
1266
|
}),)
|
|
1267
1267
|
log.Printf("[GO] - Instance %d: Trying to be publicly reachable.\n", instanceIndex)
|
|
1268
1268
|
} else {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
options = append(options, libp2p.ForceReachabilityPublic())
|
|
1272
|
-
isPublic = true // We assume it's public if we are a relay service and not trying to be public ourselves.
|
|
1273
|
-
}
|
|
1269
|
+
options = append(options, libp2p.ForceReachabilityPublic())
|
|
1270
|
+
isPublic = true
|
|
1274
1271
|
}
|
|
1275
1272
|
|
|
1276
1273
|
// Create the libp2p Host instance with the configured options for this instance.
|
|
@@ -1300,9 +1297,9 @@ func CreateNode(
|
|
|
1300
1297
|
// Give discovery mechanisms a moment to find the public address.
|
|
1301
1298
|
log.Printf("[GO] ⏳ Instance %d: Waiting for address discovery and NAT to settle...\n", instanceIndex)
|
|
1302
1299
|
|
|
1303
|
-
if
|
|
1300
|
+
if !knowsIsPublic {
|
|
1304
1301
|
// --- 🎯 : Wait for Public Reachability ---
|
|
1305
|
-
// This replaces
|
|
1302
|
+
// This replaces the old address polling loop. We wait a maximum of 30 seconds.
|
|
1306
1303
|
isPublic = waitForPublicReachability(instanceHost, 30*time.Second)
|
|
1307
1304
|
if !isPublic {
|
|
1308
1305
|
log.Printf("[GO] ⚠️ Instance %d: The node may not be directly dialable.", instanceIndex)
|
unaiverse/networking/p2p/p2p.py
CHANGED
|
@@ -89,7 +89,7 @@ class P2P:
|
|
|
89
89
|
|
|
90
90
|
# Configure Python logging based on the flag
|
|
91
91
|
if not enable_logging:
|
|
92
|
-
logger.setLevel(logging.
|
|
92
|
+
logger.setLevel(logging.CRITICAL)
|
|
93
93
|
else:
|
|
94
94
|
logger.setLevel(logging.INFO)
|
|
95
95
|
|
|
@@ -124,7 +124,7 @@ class P2P:
|
|
|
124
124
|
ips: List[str] = None,
|
|
125
125
|
enable_relay_client: bool = True,
|
|
126
126
|
enable_relay_service: bool = False,
|
|
127
|
-
|
|
127
|
+
knows_is_public: bool = False,
|
|
128
128
|
max_connections: int = 1000,
|
|
129
129
|
) -> None:
|
|
130
130
|
"""
|
|
@@ -135,7 +135,7 @@ class P2P:
|
|
|
135
135
|
ips: A list of specific IP addresses to listen on. Defaults to ["0.0.0.0"].
|
|
136
136
|
enable_relay_client: Enable listening to relayed connections for this node.
|
|
137
137
|
enable_relay_service: Enable relay service capabilities for this node.
|
|
138
|
-
|
|
138
|
+
knows_is_public: If you already know that the node is public this forces its public reachability. Otherwise it tries every possible attempt to make the node publicly reachable (UPnP, HolePunching, AutoNat via DHT...).
|
|
139
139
|
max_connections: Maximum number of connections this node can handle.
|
|
140
140
|
|
|
141
141
|
Raises:
|
|
@@ -168,7 +168,7 @@ class P2P:
|
|
|
168
168
|
self._ips = ips if ips is not None else []
|
|
169
169
|
self._enable_relay_client = enable_relay_client or enable_relay_service
|
|
170
170
|
self._enable_relay_service = enable_relay_service
|
|
171
|
-
self.
|
|
171
|
+
self._knows_is_public = knows_is_public
|
|
172
172
|
self._max_connections = max_connections
|
|
173
173
|
self._peer_id: Optional[str] = None
|
|
174
174
|
self._peer_map: Dict[str, Any] = {} # Map to store peer info {peer_id: info}
|
|
@@ -185,7 +185,7 @@ class P2P:
|
|
|
185
185
|
P2P._type_interface.to_go_json(self._ips),
|
|
186
186
|
P2P._type_interface.to_go_bool(enable_relay_client),
|
|
187
187
|
P2P._type_interface.to_go_bool(enable_relay_service),
|
|
188
|
-
P2P._type_interface.to_go_bool(
|
|
188
|
+
P2P._type_interface.to_go_bool(knows_is_public),
|
|
189
189
|
P2P._type_interface.to_go_int(max_connections),
|
|
190
190
|
)
|
|
191
191
|
result = P2P._type_interface.from_go_ptr_to_json(result_ptr)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unaiverse
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: UNaIVERSE: A Collectionless AI Project. The new web of humans & AI Agents, built on privacy, control, and reduced energy consumption.
|
|
5
5
|
Author-email: Stefano Melacci <stefano.melacci@unisi.it>, Christian Di Maio <christian.dimaio@phd.unipi.it>, Tommaso Guidi <tommaso.guidi.1998@gmail.com>
|
|
6
6
|
Maintainer-email: Stefano Melacci <stefano.melacci@unisi.it>, Christian Di Maio <christian.dimaio@phd.unipi.it>, Tommaso Guidi <tommaso.guidi.1998@gmail.com>
|
|
@@ -31,9 +31,11 @@ Requires-Dist: Pillow
|
|
|
31
31
|
Requires-Dist: protobuf
|
|
32
32
|
Requires-Dist: psutil
|
|
33
33
|
Requires-Dist: PyJWT
|
|
34
|
+
Requires-Dist: cryptography
|
|
34
35
|
Requires-Dist: Requests
|
|
35
36
|
Requires-Dist: torch
|
|
36
37
|
Requires-Dist: torchvision
|
|
38
|
+
Requires-Dist: transformers
|
|
37
39
|
Dynamic: license-file
|
|
38
40
|
|
|
39
41
|
<div align="center">
|
|
@@ -18,18 +18,18 @@ unaiverse/modules/hl/hl_utils.py,sha256=Xt2eWuwak6kDtTy2hQ1Ps8_M_REtte9HA-PzfCov
|
|
|
18
18
|
unaiverse/networking/__init__.py,sha256=qc3A8KJpTLFM6hefwmqj-wAaUULtzXivaXsr-xKKYGU,2460
|
|
19
19
|
unaiverse/networking/node/__init__.py,sha256=DEXbZzPt7dgall1TZKODuQIXhjq3lr39QCBISGUSWww,2508
|
|
20
20
|
unaiverse/networking/node/connpool.py,sha256=hctRoYYGZA2D7sy1elIgE7o4umm8B9dZKq-QI0bgE24,52726
|
|
21
|
-
unaiverse/networking/node/node.py,sha256=
|
|
21
|
+
unaiverse/networking/node/node.py,sha256=q740PylBIqHm6jKN32A1_meYUhbmHdDWmZ9ySJ7sMkY,117733
|
|
22
22
|
unaiverse/networking/node/profile.py,sha256=lbB35MoI20oDxDqb97zH2NNNUCGJs8-8KIGNjjmnTio,20203
|
|
23
23
|
unaiverse/networking/node/tokens.py,sha256=UHyPnl6TDvPitrkP2AYAIegSWq4CpvsjRvmio3T-3nA,5281
|
|
24
|
-
unaiverse/networking/p2p/__init__.py,sha256=
|
|
24
|
+
unaiverse/networking/p2p/__init__.py,sha256=ikRpQyJa2PRIeCLXcMWLWioJyyu1aS5I6twArCkhGhQ,13599
|
|
25
25
|
unaiverse/networking/p2p/golibp2p.py,sha256=ibVCLERzM2JgPP_A5FTooCoxYW5Zm2HBbzX28aQIFzo,2450
|
|
26
|
-
unaiverse/networking/p2p/golibp2p.pyi,sha256=
|
|
27
|
-
unaiverse/networking/p2p/lib.go,sha256=
|
|
26
|
+
unaiverse/networking/p2p/golibp2p.pyi,sha256=ri7ZL8LQHx2rnwhXmQ9q2RiaTXeU6nitw1lB_L5Bhq4,4079
|
|
27
|
+
unaiverse/networking/p2p/lib.go,sha256=l40IsZEC4a70LfJr8qzl8YDuh-fAcOaqaMPDLNG7IkI,108699
|
|
28
28
|
unaiverse/networking/p2p/lib_types.py,sha256=b7NJmN636o-X3TEWdp4YVIJ9Snr8AGT0GUuaYITZ6PY,13956
|
|
29
29
|
unaiverse/networking/p2p/message_pb2.py,sha256=-kEXvIYJZqGOh47i5e7qYHZdsKJ5uQtfDVQrnrAewCg,5697
|
|
30
30
|
unaiverse/networking/p2p/messages.py,sha256=6fN-3INvnUoWu_YwQPfx4WRx8DD7LEOu511nRWKI-fM,12287
|
|
31
31
|
unaiverse/networking/p2p/mylogger.py,sha256=-WW6qT39rptXwUlpQg1BuU7u8o9MKLF_-Cbe7EaQKsc,4773
|
|
32
|
-
unaiverse/networking/p2p/p2p.py,sha256=
|
|
32
|
+
unaiverse/networking/p2p/p2p.py,sha256=JSGhIBmz4KMsC0RfkvgQS-7Tu5QveW1sYwDmTuwBHSU,47070
|
|
33
33
|
unaiverse/streamlib/__init__.py,sha256=VpsL7-gwML7nbrMQumtEDpuEH4g7iNqQaCzd-zX49cQ,2447
|
|
34
34
|
unaiverse/streamlib/streamlib.py,sha256=yz6G8eez3VnF_fvA9G3KS-WCoLvPYlk0IdqdB9dDzOI,10366
|
|
35
35
|
unaiverse/utils/__init__.py,sha256=_iomQ_GviAS5c4ZVBrm1h_rLYWH-f-T9SI-b0697gn0,2464
|
|
@@ -38,8 +38,8 @@ unaiverse/utils/lone_wolf.json,sha256=_rHfeqV8gqvPc0h-cZF7mPCG0Z4HuVkV-mKoXXwjbN
|
|
|
38
38
|
unaiverse/utils/misc.py,sha256=4J3HotzosgsnEr9MgeuQmdrrISPuKl85oOAuKAfcz-U,12085
|
|
39
39
|
unaiverse/utils/sandbox.py,sha256=S_eocNIGTyckovYMxmWb56wsCG7M-mxmGHqdLavSWQA,14436
|
|
40
40
|
unaiverse/utils/server.py,sha256=hCxHTNmYGrgGYrwZ5RaQ9kdmmfqWuIVTUdPYLCwpTQU,21974
|
|
41
|
-
unaiverse-0.1.
|
|
42
|
-
unaiverse-0.1.
|
|
43
|
-
unaiverse-0.1.
|
|
44
|
-
unaiverse-0.1.
|
|
45
|
-
unaiverse-0.1.
|
|
41
|
+
unaiverse-0.1.2.dist-info/licenses/LICENSE,sha256=02v7juVPTazXHV7TG9WtaWrtmeC3BAd49itKH_SiHOs,1396
|
|
42
|
+
unaiverse-0.1.2.dist-info/METADATA,sha256=H-V1qkzJhcKhX_tmABnnA1SG2iPHfXY3TlSzyCjMKkI,18268
|
|
43
|
+
unaiverse-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
unaiverse-0.1.2.dist-info/top_level.txt,sha256=0rP09tH9hv17TDQs66OHbJaRSnADpZsDsODy6JVsTtw,10
|
|
45
|
+
unaiverse-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|