unaiverse 0.1.5__tar.gz → 0.1.6__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 unaiverse might be problematic. Click here for more details.
- unaiverse-0.1.6/MANIFEST.in +10 -0
- {unaiverse-0.1.5/src/unaiverse.egg-info → unaiverse-0.1.6}/PKG-INFO +1 -1
- {unaiverse-0.1.5 → unaiverse-0.1.6}/pyproject.toml +47 -2
- unaiverse-0.1.6/setup.py +90 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/clock.py +6 -1
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/node/connpool.py +6 -4
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/node/node.py +26 -9
- unaiverse-0.1.6/src/unaiverse/networking/p2p/__init__.py +198 -0
- unaiverse-0.1.6/src/unaiverse/networking/p2p/go.mod +127 -0
- unaiverse-0.1.6/src/unaiverse/networking/p2p/go.sum +548 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/golibp2p.pyi +2 -2
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/lib.go +552 -330
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/p2p.py +23 -51
- unaiverse-0.1.6/src/unaiverse/networking/p2p/proto-go/message.pb.go +616 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/streams.py +7 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6/src/unaiverse.egg-info}/PKG-INFO +1 -1
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse.egg-info/SOURCES.txt +6 -0
- unaiverse-0.1.6/src/unaiverse.egg-info/not-zip-safe +1 -0
- unaiverse-0.1.5/src/unaiverse/networking/p2p/__init__.py +0 -283
- {unaiverse-0.1.5 → unaiverse-0.1.6}/LICENSE +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/README.md +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/setup.cfg +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/agent.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/agent_basics.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/dataprops.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/hsm.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/cnu/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/cnu/cnus.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/cnu/layers.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/cnu/psi.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/hl/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/hl/hl_utils.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/networks.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/modules/utils.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/node/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/node/profile.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/node/tokens.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/golibp2p.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/lib_types.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/message_pb2.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/messages.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/networking/p2p/mylogger.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/streamlib/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/streamlib/streamlib.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/__init__.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/ask_lone_wolf.json +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/lone_wolf.json +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/misc.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/sandbox.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/utils/server.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse/world.py +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse.egg-info/dependency_links.txt +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse.egg-info/requires.txt +0 -0
- {unaiverse-0.1.5 → unaiverse-0.1.6}/src/unaiverse.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# MANIFEST.in
|
|
2
|
+
|
|
3
|
+
# Include the Go source and module files in the source distribution (sdist)
|
|
4
|
+
# so that users on unsupported platforms can compile it themselves.
|
|
5
|
+
include src/unaiverse/networking/p2p/lib.go
|
|
6
|
+
include src/unaiverse/networking/p2p/go.mod
|
|
7
|
+
include src/unaiverse/networking/p2p/go.sum
|
|
8
|
+
|
|
9
|
+
# Recursively include all files from the proto-go directory
|
|
10
|
+
recursive-include src/unaiverse/networking/p2p/proto-go *
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unaiverse
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
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>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "unaiverse"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
requires-python = ">3.10"
|
|
9
9
|
dependencies = [
|
|
10
10
|
"opencv-python",
|
|
@@ -48,7 +48,7 @@ classifiers = [
|
|
|
48
48
|
]
|
|
49
49
|
|
|
50
50
|
[tool.setuptools.package-data]
|
|
51
|
-
"unaiverse" = ["utils/lone_wolf.json", "utils/ask_lone_wolf.json"
|
|
51
|
+
"unaiverse" = ["utils/lone_wolf.json", "utils/ask_lone_wolf.json"]
|
|
52
52
|
|
|
53
53
|
[project.urls]
|
|
54
54
|
A-Homepage = "https://unaiverse.io"
|
|
@@ -60,3 +60,48 @@ F-Documentation = "https://github.com/collectionlessai/unaiverse-src/blob/main/R
|
|
|
60
60
|
|
|
61
61
|
[tool.setuptools]
|
|
62
62
|
package-dir = {"" = "src"}
|
|
63
|
+
|
|
64
|
+
# --- CIBUILDWHEEL CONFIGURATION ---
|
|
65
|
+
[tool.cibuildwheel]
|
|
66
|
+
# Skip 32-bit builds to save CI time
|
|
67
|
+
skip = ["*-win32", "*-manylinux_i686"]
|
|
68
|
+
|
|
69
|
+
# Platform-specific configurations
|
|
70
|
+
[tool.cibuildwheel.linux]
|
|
71
|
+
# Step 1: Install the correct version of Go for the machine's architecture.
|
|
72
|
+
before-all = '''
|
|
73
|
+
set -euxo pipefail
|
|
74
|
+
|
|
75
|
+
# Detect architecture and set the corresponding Go arch name
|
|
76
|
+
case "$(uname -m)" in
|
|
77
|
+
x86_64)
|
|
78
|
+
GO_ARCH=amd64
|
|
79
|
+
;;
|
|
80
|
+
aarch64)
|
|
81
|
+
GO_ARCH=arm64
|
|
82
|
+
;;
|
|
83
|
+
*)
|
|
84
|
+
echo "Unsupported architecture: $(uname -m)"
|
|
85
|
+
exit 1
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
|
|
89
|
+
# Download and install the correct Go binary
|
|
90
|
+
curl -L -o go.tar.gz "https://go.dev/dl/go1.24.5.linux-${GO_ARCH}.tar.gz"
|
|
91
|
+
rm -rf /usr/local/go
|
|
92
|
+
tar -C /usr/local -xzf go.tar.gz
|
|
93
|
+
rm go.tar.gz
|
|
94
|
+
'''
|
|
95
|
+
# Step 2: Persistently add Go to the PATH for all subsequent steps.
|
|
96
|
+
environment = { PATH = "/usr/local/go/bin:$PATH" }
|
|
97
|
+
|
|
98
|
+
[tool.cibuildwheel.macos]
|
|
99
|
+
# Step 1: Install Go once on the runner.
|
|
100
|
+
before-all = "brew install go@1.24"
|
|
101
|
+
# Step 2: Persistently add the correct Go version to the PATH.
|
|
102
|
+
environment = { PATH = "$(brew --prefix go@1.24)/bin:$PATH" }
|
|
103
|
+
|
|
104
|
+
[tool.cibuildwheel.windows]
|
|
105
|
+
# On Windows, choco handles the PATH modification automatically,
|
|
106
|
+
# so we just need to install it once.
|
|
107
|
+
before-all = "choco install golang --version 1.24.5 -y"
|
unaiverse-0.1.6/setup.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# setup.py
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import hashlib
|
|
5
|
+
import platform
|
|
6
|
+
import subprocess
|
|
7
|
+
from setuptools import setup, Extension
|
|
8
|
+
from setuptools.command.build_ext import build_ext
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
GO_SOURCE_NAME = 'lib.go'
|
|
12
|
+
HASH_FILE_SUFFIX = '.sha256'
|
|
13
|
+
|
|
14
|
+
def get_ext_filename_with_path():
|
|
15
|
+
system = platform.system()
|
|
16
|
+
if system == 'Linux':
|
|
17
|
+
lib_name = 'unailib.so'
|
|
18
|
+
elif system == 'Darwin':
|
|
19
|
+
lib_name = 'unailib.dylib'
|
|
20
|
+
elif system == 'Windows':
|
|
21
|
+
lib_name = 'unailib.dll'
|
|
22
|
+
else:
|
|
23
|
+
raise RuntimeError(f"Unsupported OS: {system}")
|
|
24
|
+
return os.path.join('src', 'unaiverse', 'networking', 'p2p', lib_name)
|
|
25
|
+
|
|
26
|
+
def get_go_source_dir():
|
|
27
|
+
return os.path.join('src', 'unaiverse', 'networking', 'p2p')
|
|
28
|
+
|
|
29
|
+
def get_file_hash(filepath):
|
|
30
|
+
sha256_hash = hashlib.sha256()
|
|
31
|
+
with open(filepath, "rb") as f:
|
|
32
|
+
for byte_block in iter(lambda: f.read(4096), b""):
|
|
33
|
+
sha256_hash.update(byte_block)
|
|
34
|
+
return sha256_hash.hexdigest()
|
|
35
|
+
|
|
36
|
+
class GoBuildExtCommand(build_ext):
|
|
37
|
+
"""Custom build_ext that builds the Go library."""
|
|
38
|
+
def run(self):
|
|
39
|
+
go_dir = get_go_source_dir()
|
|
40
|
+
go_path = os.path.join(go_dir, GO_SOURCE_NAME)
|
|
41
|
+
out_path = get_ext_filename_with_path()
|
|
42
|
+
hash_path = go_path + HASH_FILE_SUFFIX
|
|
43
|
+
os.makedirs(os.path.dirname(out_path), exist_ok=True)
|
|
44
|
+
|
|
45
|
+
current_hash = get_file_hash(go_path)
|
|
46
|
+
stored_hash = None
|
|
47
|
+
if os.path.exists(hash_path):
|
|
48
|
+
with open(hash_path, 'r') as f:
|
|
49
|
+
stored_hash = f.read().strip()
|
|
50
|
+
|
|
51
|
+
# Only rebuild if Go source changed or lib missing
|
|
52
|
+
if current_hash != stored_hash or not os.path.exists(out_path):
|
|
53
|
+
print(f"--- Go source changed, building {out_path} ---")
|
|
54
|
+
subprocess.run(
|
|
55
|
+
['go', 'build', '-buildmode=c-shared', '-ldflags', '-s -w',
|
|
56
|
+
'-o', os.path.basename(out_path), GO_SOURCE_NAME],
|
|
57
|
+
check=True, cwd=go_dir
|
|
58
|
+
)
|
|
59
|
+
with open(hash_path, 'w') as f:
|
|
60
|
+
f.write(current_hash)
|
|
61
|
+
else:
|
|
62
|
+
print("--- Go source unchanged; skipping build. ---")
|
|
63
|
+
|
|
64
|
+
# We get the final destination path for the extension and copy our pre-built library there.
|
|
65
|
+
dest_path = self.get_ext_fullpath(self.extensions[0].name)
|
|
66
|
+
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
|
|
67
|
+
print(f"--- Copying {out_path} to {dest_path} ---")
|
|
68
|
+
shutil.copyfile(out_path, dest_path)
|
|
69
|
+
|
|
70
|
+
# Also copy the generated hash file to the final package directory
|
|
71
|
+
dest_dir = os.path.dirname(dest_path)
|
|
72
|
+
if os.path.abspath(os.path.dirname(hash_path)) != os.path.abspath(dest_dir):
|
|
73
|
+
print(f"--- Copying {hash_path} to {dest_dir} ---")
|
|
74
|
+
shutil.copy(hash_path, dest_dir)
|
|
75
|
+
else:
|
|
76
|
+
print(f"--- Hash file is already in the source directory (editable install); skipping copy. ---")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Fake extension only to mark wheel as platform-dependent
|
|
80
|
+
go_extension = Extension(
|
|
81
|
+
"unaiverse.networking.p2p.unailib",
|
|
82
|
+
sources=[], # dummy
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
setup(
|
|
86
|
+
cmdclass={'build_ext': GoBuildExtCommand},
|
|
87
|
+
ext_modules=[go_extension],
|
|
88
|
+
package_data={},
|
|
89
|
+
zip_safe=False,
|
|
90
|
+
)
|
|
@@ -43,6 +43,8 @@ class Clock:
|
|
|
43
43
|
'europe.pool.ntp.org',
|
|
44
44
|
]
|
|
45
45
|
self.__global_initial_t = self.__get_time_from_server() # Real-time, wall-clock
|
|
46
|
+
if self.__global_initial_t == -1.:
|
|
47
|
+
raise ValueError("Unable to get the initial time (for synchronization purposes) from the NTP servers")
|
|
46
48
|
self.__local_initial_t = datetime.now(timezone.utc).timestamp() # Corresponding local time
|
|
47
49
|
self.__timestamps = [] # List to store timestamps for cycles
|
|
48
50
|
self.__time2cycle_cache = 0 # Cached cycle value for optimization
|
|
@@ -62,7 +64,10 @@ class Clock:
|
|
|
62
64
|
break
|
|
63
65
|
except (NTPException, socket.gaierror):
|
|
64
66
|
continue
|
|
65
|
-
|
|
67
|
+
if response is not None:
|
|
68
|
+
return datetime.fromtimestamp(response.tx_time, timezone.utc).timestamp()
|
|
69
|
+
else:
|
|
70
|
+
return -1.
|
|
66
71
|
|
|
67
72
|
def __add_timestamp(self, timestamp: float):
|
|
68
73
|
"""Add a timestamp to the list of timestamps for the clock cycles.
|
|
@@ -875,8 +875,9 @@ class NodeConn(ConnectionPools):
|
|
|
875
875
|
|
|
876
876
|
for peer_id, misc in to_remove:
|
|
877
877
|
del self.peer_id_to_misc[peer_id]
|
|
878
|
-
|
|
879
|
-
|
|
878
|
+
if peer_id in self.peer_id_to_addrs:
|
|
879
|
+
del self.peer_id_to_addrs[peer_id]
|
|
880
|
+
self.role_to_peer_ids[misc].discard(peer_id)
|
|
880
881
|
|
|
881
882
|
# Setting new information
|
|
882
883
|
if world_agents_list_peer_infos is not None and len(world_agents_list_peer_infos) > 0:
|
|
@@ -904,8 +905,9 @@ class NodeConn(ConnectionPools):
|
|
|
904
905
|
|
|
905
906
|
for peer_id, misc in to_remove:
|
|
906
907
|
del self.peer_id_to_misc[peer_id]
|
|
907
|
-
|
|
908
|
-
|
|
908
|
+
if peer_id in self.peer_id_to_addrs:
|
|
909
|
+
del self.peer_id_to_addrs[peer_id]
|
|
910
|
+
self.role_to_peer_ids[misc].discard(peer_id)
|
|
909
911
|
|
|
910
912
|
# Setting new information
|
|
911
913
|
if world_masters_list_peer_infos is not None and len(world_masters_list_peer_infos) > 0:
|
|
@@ -59,6 +59,7 @@ class Node:
|
|
|
59
59
|
node_id: str | None = None,
|
|
60
60
|
hidden: bool = False,
|
|
61
61
|
clock_delta: float = 1. / 25.,
|
|
62
|
+
base_identity_dir: str = "./unaiverse_nodes_identity",
|
|
62
63
|
only_certified_agents: bool = False,
|
|
63
64
|
allowed_node_ids: list[str] | set[str] = None, # Optional: it is loaded from the online profile
|
|
64
65
|
world_masters_node_ids: list[str] | set[str] = None, # Optional: it is loaded from the online profile
|
|
@@ -186,6 +187,11 @@ class Node:
|
|
|
186
187
|
if were_alive[0]:
|
|
187
188
|
raise GenException(f"Cannot access node {node_name}, it is already running! "
|
|
188
189
|
f"(set env variable NODE_IGNORE_ALIVE=1 to ignore this control)")
|
|
190
|
+
|
|
191
|
+
# Automatically create a unique data directory for this specific node
|
|
192
|
+
node_identity_dir = os.path.join(base_identity_dir, self.node_id)
|
|
193
|
+
p2p_u_identity_dir = os.path.join(node_identity_dir, "p2p_public")
|
|
194
|
+
p2p_w_identity_dir = os.path.join(node_identity_dir, "p2p_private")
|
|
189
195
|
|
|
190
196
|
# Getting node ID of world masters, if needed
|
|
191
197
|
if world_masters_node_names is not None and len(world_masters_node_names) > 0:
|
|
@@ -205,21 +211,31 @@ class Node:
|
|
|
205
211
|
offer_relay_facilities = self.node_type is Node.WORLD # Only world nodes offer relay facilities
|
|
206
212
|
|
|
207
213
|
# Create P2P node in the whole universe (it has fields 'addresses', and 'peer_id', and 'libp2p')
|
|
208
|
-
p2p_u = P2P(
|
|
214
|
+
p2p_u = P2P(identity_dir=p2p_u_identity_dir,
|
|
215
|
+
port=int(os.getenv("NODE_STARTING_PORT", "0")),
|
|
209
216
|
ips=None,
|
|
210
|
-
enable_relay_service=offer_relay_facilities,
|
|
211
217
|
enable_relay_client=allow_connection_through_relay,
|
|
218
|
+
enable_relay_service=offer_relay_facilities,
|
|
212
219
|
knows_is_public=os.getenv("NODE_IS_PUBLIC", "0") == "1",
|
|
213
|
-
|
|
220
|
+
max_connections=1000,
|
|
221
|
+
enable_tls=os.getenv("NODE_USE_TLS", "0") == "1",
|
|
222
|
+
domain_name=os.getenv("DOMAIN", None),
|
|
223
|
+
tls_cert_path=os.getenv("TLS_CERT_PATH", None),
|
|
224
|
+
tls_key_path=os.getenv("TLS_KEY_PATH", None))
|
|
214
225
|
|
|
215
226
|
# Create another P2P node for the private world (it has fields 'addresses', and 'peer_id', and 'libp2p')
|
|
216
|
-
p2p_w = P2P(
|
|
227
|
+
p2p_w = P2P(identity_dir=p2p_w_identity_dir,
|
|
228
|
+
port=(int(os.getenv("NODE_STARTING_PORT", "0")) + 4)
|
|
229
|
+
if int(os.getenv("NODE_STARTING_PORT", "0")) > 0 else 0,
|
|
217
230
|
ips=None,
|
|
218
|
-
enable_relay_service=offer_relay_facilities,
|
|
219
231
|
enable_relay_client=allow_connection_through_relay,
|
|
232
|
+
enable_relay_service=offer_relay_facilities,
|
|
220
233
|
knows_is_public=os.getenv("NODE_IS_PUBLIC", "0") == "1",
|
|
221
|
-
|
|
222
|
-
|
|
234
|
+
max_connections=1000,
|
|
235
|
+
enable_tls=os.getenv("NODE_USE_TLS", "0") == "1",
|
|
236
|
+
domain_name=os.getenv("DOMAIN", None),
|
|
237
|
+
tls_cert_path=os.getenv("TLS_CERT_PATH", None),
|
|
238
|
+
tls_key_path=os.getenv("TLS_KEY_PATH", None))
|
|
223
239
|
|
|
224
240
|
# Get first node token
|
|
225
241
|
self.get_node_token(peer_ids=[p2p_u.peer_id, p2p_w.peer_id]) # Passing both the peer IDs
|
|
@@ -328,10 +344,11 @@ class Node:
|
|
|
328
344
|
Args:
|
|
329
345
|
msg: The error message to be printed.
|
|
330
346
|
"""
|
|
347
|
+
when = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
|
331
348
|
if self.print_enabled:
|
|
332
|
-
self.out("<ERROR> " + msg)
|
|
349
|
+
self.out(f"<ERROR> [{when}] " + msg)
|
|
333
350
|
else:
|
|
334
|
-
print("<ERROR> " + msg)
|
|
351
|
+
print(f"<ERROR> [{when}] " + msg)
|
|
335
352
|
|
|
336
353
|
def get_node_id_by_name(self, node_names: list[str], create_if_missing: bool = False,
|
|
337
354
|
node_type: str | None = None) -> tuple[list[str], list[bool]]:
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
█████ █████ ██████ █████ █████ █████ █████ ██████████ ███████████ █████████ ██████████
|
|
3
|
+
░░███ ░░███ ░░██████ ░░███ ░░███ ░░███ ░░███ ░░███░░░░░█░░███░░░░░███ ███░░░░░███░░███░░░░░█
|
|
4
|
+
░███ ░███ ░███░███ ░███ ██████ ░███ ░███ ░███ ░███ █ ░ ░███ ░███ ░███ ░░░ ░███ █ ░
|
|
5
|
+
░███ ░███ ░███░░███░███ ░░░░░███ ░███ ░███ ░███ ░██████ ░██████████ ░░█████████ ░██████
|
|
6
|
+
░███ ░███ ░███ ░░██████ ███████ ░███ ░░███ ███ ░███░░█ ░███░░░░░███ ░░░░░░░░███ ░███░░█
|
|
7
|
+
░███ ░███ ░███ ░░█████ ███░░███ ░███ ░░░█████░ ░███ ░ █ ░███ ░███ ███ ░███ ░███ ░ █
|
|
8
|
+
░░████████ █████ ░░█████░░████████ █████ ░░███ ██████████ █████ █████░░█████████ ██████████
|
|
9
|
+
░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░ ░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
|
|
10
|
+
A Collectionless AI Project (https://collectionless.ai)
|
|
11
|
+
Registration/Login: https://unaiverse.io
|
|
12
|
+
Code Repositories: https://github.com/collectionlessai/
|
|
13
|
+
Main Developers: Stefano Melacci (Project Leader), Christian Di Maio, Tommaso Guidi
|
|
14
|
+
"""
|
|
15
|
+
from . import messages
|
|
16
|
+
from . import p2p
|
|
17
|
+
from . import golibp2p
|
|
18
|
+
from . import lib_types
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
import glob
|
|
22
|
+
import json
|
|
23
|
+
import ctypes
|
|
24
|
+
import hashlib
|
|
25
|
+
import platform
|
|
26
|
+
import warnings
|
|
27
|
+
from typing import cast
|
|
28
|
+
from .messages import Msg
|
|
29
|
+
from .p2p import P2P, P2PError
|
|
30
|
+
from .golibp2p import GoLibP2P # Your stub interface definition
|
|
31
|
+
from .lib_types import TypeInterface # Assuming TypeInterface handles the void* results
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# --- Helper Functions ---
|
|
35
|
+
def _get_lib_filename():
|
|
36
|
+
"""Determines the correct shared library filename based on the OS."""
|
|
37
|
+
system = platform.system()
|
|
38
|
+
if system == 'Linux':
|
|
39
|
+
return 'unailib*.so'
|
|
40
|
+
elif system == 'Darwin':
|
|
41
|
+
return 'unailib*.dylib'
|
|
42
|
+
elif system == 'Windows':
|
|
43
|
+
return 'unailib*.pyd'
|
|
44
|
+
# This error should ideally never be reached if setup.py ran correctly.
|
|
45
|
+
raise ImportError(f"Unsupported operating system for shared library: {system}")
|
|
46
|
+
|
|
47
|
+
def _get_file_hash(filepath):
|
|
48
|
+
"""Calculates the SHA256 hash of a file, returning None if it doesn't exist."""
|
|
49
|
+
if not os.path.exists(filepath):
|
|
50
|
+
return None
|
|
51
|
+
sha256_hash = hashlib.sha256()
|
|
52
|
+
with open(filepath, "rb") as f:
|
|
53
|
+
for byte_block in iter(lambda: f.read(4096), b""):
|
|
54
|
+
sha256_hash.update(byte_block)
|
|
55
|
+
return sha256_hash.hexdigest()
|
|
56
|
+
|
|
57
|
+
def _developer_source_check():
|
|
58
|
+
"""
|
|
59
|
+
If source files are present (i.e., in a dev environment), check if the
|
|
60
|
+
compiled library is in sync with the source code.
|
|
61
|
+
"""
|
|
62
|
+
go_source_file = os.path.join(_lib_dir, 'lib.go')
|
|
63
|
+
hash_file = go_source_file + '.sha256'
|
|
64
|
+
|
|
65
|
+
# This check only runs if all dev files are present. For users who
|
|
66
|
+
# installed from a wheel, these files won't exist, and this is skipped.
|
|
67
|
+
if os.path.exists(go_source_file) and os.path.exists(hash_file):
|
|
68
|
+
current_source_hash = _get_file_hash(go_source_file)
|
|
69
|
+
|
|
70
|
+
stored_build_hash = None
|
|
71
|
+
with open(hash_file, 'r') as f:
|
|
72
|
+
stored_build_hash = f.read().strip()
|
|
73
|
+
|
|
74
|
+
if current_source_hash != stored_build_hash:
|
|
75
|
+
# Use warnings.warn for a standard, non-intrusive developer warning.
|
|
76
|
+
warnings.warn(
|
|
77
|
+
"\n" + "="*80 +
|
|
78
|
+
"\nWARNING: The Go source file (lib.go) has been modified since the shared\n"
|
|
79
|
+
"library was last compiled. Your running code may not reflect recent changes.\n\n"
|
|
80
|
+
"To fix this, run: pip install -e .\n" +
|
|
81
|
+
"="*80,
|
|
82
|
+
UserWarning
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# --- Main Library Loading ---
|
|
86
|
+
# The shared library is guaranteed by the build process to be in this directory.
|
|
87
|
+
_lib_dir = os.path.dirname(os.path.abspath(__file__))
|
|
88
|
+
_shared_lib = None
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
_results = glob.glob(os.path.join(_lib_dir, _get_lib_filename()))
|
|
92
|
+
_lib_path = os.path.join(_lib_dir, _results[0])
|
|
93
|
+
_shared_lib = ctypes.CDLL(_lib_path)
|
|
94
|
+
except OSError as e:
|
|
95
|
+
print(
|
|
96
|
+
f"FATAL: Could not load the required p2p shared library from {_lib_path}.\n"
|
|
97
|
+
"This indicates a corrupted or missing installation. "
|
|
98
|
+
"Please try reinstalling the 'unaiverse' package.\n"
|
|
99
|
+
f"Underlying error: {e}",
|
|
100
|
+
file=sys.stderr
|
|
101
|
+
)
|
|
102
|
+
raise ImportError("Failed to load the UNaIVERSE p2p shared library.") from e
|
|
103
|
+
|
|
104
|
+
# Run the check after successfully loading the library.
|
|
105
|
+
if _shared_lib is not None:
|
|
106
|
+
_developer_source_check()
|
|
107
|
+
print(f"UNaIVERSE: Successfully loaded p2p library from {_lib_path}")
|
|
108
|
+
|
|
109
|
+
# --- Function Prototypes (argtypes and restype) ---
|
|
110
|
+
# Using void* for returned C strings, requiring TypeInterface for conversion/freeing.
|
|
111
|
+
|
|
112
|
+
# Define argtypes for the Go init function here
|
|
113
|
+
_shared_lib.InitializeLibrary.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int]
|
|
114
|
+
_shared_lib.InitializeLibrary.restype = None
|
|
115
|
+
|
|
116
|
+
# Node Lifecycle & Info
|
|
117
|
+
_shared_lib.CreateNode.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_int,
|
|
118
|
+
ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
|
|
119
|
+
_shared_lib.CreateNode.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
120
|
+
|
|
121
|
+
_shared_lib.CloseNode.argtypes = [ctypes.c_int]
|
|
122
|
+
_shared_lib.CloseNode.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
123
|
+
|
|
124
|
+
_shared_lib.GetNodeAddresses.argtypes = [ctypes.c_int, ctypes.c_char_p] # Input is still a Python string -> C string
|
|
125
|
+
_shared_lib.GetNodeAddresses.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
126
|
+
|
|
127
|
+
_shared_lib.GetConnectedPeers.argtypes = [ctypes.c_int]
|
|
128
|
+
_shared_lib.GetConnectedPeers.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
129
|
+
|
|
130
|
+
_shared_lib.GetRendezvousPeers.argtypes = [ctypes.c_int]
|
|
131
|
+
_shared_lib.GetRendezvousPeers.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
132
|
+
|
|
133
|
+
# Peer Connection
|
|
134
|
+
_shared_lib.ConnectTo.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
135
|
+
_shared_lib.ConnectTo.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
136
|
+
|
|
137
|
+
_shared_lib.DisconnectFrom.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
138
|
+
_shared_lib.DisconnectFrom.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
139
|
+
|
|
140
|
+
# Direct Messaging
|
|
141
|
+
_shared_lib.SendMessageToPeer.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
|
|
142
|
+
_shared_lib.SendMessageToPeer.restype = ctypes.c_void_p # Returns status code, not pointer
|
|
143
|
+
|
|
144
|
+
# Message Queue
|
|
145
|
+
_shared_lib.MessageQueueLength.argtypes = [ctypes.c_int]
|
|
146
|
+
_shared_lib.MessageQueueLength.restype = ctypes.c_int # Returns length, not pointer
|
|
147
|
+
|
|
148
|
+
_shared_lib.PopMessages.argtypes = [ctypes.c_int]
|
|
149
|
+
_shared_lib.PopMessages.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
150
|
+
|
|
151
|
+
# PubSub
|
|
152
|
+
_shared_lib.SubscribeToTopic.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
153
|
+
_shared_lib.SubscribeToTopic.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
154
|
+
|
|
155
|
+
_shared_lib.UnsubscribeFromTopic.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
156
|
+
_shared_lib.UnsubscribeFromTopic.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
157
|
+
|
|
158
|
+
# Relay Client
|
|
159
|
+
_shared_lib.ReserveOnRelay.argtypes = [ctypes.c_int, ctypes.c_char_p]
|
|
160
|
+
_shared_lib.ReserveOnRelay.restype = ctypes.c_void_p # Treat returned *C.char as opaque pointer
|
|
161
|
+
|
|
162
|
+
# Memory Management
|
|
163
|
+
# FreeString now accepts the opaque pointer directly
|
|
164
|
+
_shared_lib.FreeString.argtypes = [ctypes.c_void_p]
|
|
165
|
+
_shared_lib.FreeString.restype = None # Void return
|
|
166
|
+
|
|
167
|
+
_shared_lib.FreeInt.argtypes = [ctypes.POINTER(ctypes.c_int)] # Still expects a pointer to int
|
|
168
|
+
_shared_lib.FreeInt.restype = None # Void return
|
|
169
|
+
|
|
170
|
+
# --- Python Interface Setup ---
|
|
171
|
+
|
|
172
|
+
# Import necessary components
|
|
173
|
+
# IMPORTANT: TypeInterface (or equivalent logic) MUST now handle converting
|
|
174
|
+
# the c_char_p results back to strings/JSON before freeing.
|
|
175
|
+
# Ensure TypeInterface methods like from_go_string_to_json are adapted for this.
|
|
176
|
+
|
|
177
|
+
# Import the stub type for type checking
|
|
178
|
+
try:
|
|
179
|
+
from .golibp2p import GoLibP2P # Your stub interface definition
|
|
180
|
+
except ImportError:
|
|
181
|
+
print("Warning: GoLibP2P stub not found. Type checking will be limited.", file=sys.stderr)
|
|
182
|
+
GoLibP2P = ctypes.CDLL
|
|
183
|
+
|
|
184
|
+
# Cast the loaded library object to the stub type
|
|
185
|
+
_shared_lib_typed = cast(GoLibP2P, _shared_lib)
|
|
186
|
+
|
|
187
|
+
# Attach the typed shared library object to the P2P class
|
|
188
|
+
P2P.libp2p = _shared_lib_typed
|
|
189
|
+
TypeInterface.libp2p = _shared_lib_typed # Attach to TypeInterface if needed
|
|
190
|
+
|
|
191
|
+
# Attach the typed shared library object to the P2PError class
|
|
192
|
+
|
|
193
|
+
# Define the public API of this package
|
|
194
|
+
__all__ = [
|
|
195
|
+
"P2P",
|
|
196
|
+
"P2PError",
|
|
197
|
+
"TypeInterface" # Expose TypeInterface if users need its conversion helpers directly
|
|
198
|
+
]
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module unaiverse/networking/p2p/lib
|
|
2
|
+
|
|
3
|
+
go 1.24.5
|
|
4
|
+
|
|
5
|
+
require (
|
|
6
|
+
github.com/caddyserver/certmagic v0.25.0
|
|
7
|
+
github.com/ipfs/go-log/v2 v2.8.0
|
|
8
|
+
github.com/ipshipyard/p2p-forge v0.6.1
|
|
9
|
+
github.com/libp2p/go-libp2p v0.43.0
|
|
10
|
+
github.com/libp2p/go-libp2p-kad-dht v0.34.0
|
|
11
|
+
github.com/libp2p/go-libp2p-pubsub v0.15.0
|
|
12
|
+
github.com/multiformats/go-multiaddr v0.16.1
|
|
13
|
+
google.golang.org/protobuf v1.36.9
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
require (
|
|
17
|
+
github.com/benbjohnson/clock v1.3.5 // indirect
|
|
18
|
+
github.com/beorn7/perks v1.0.1 // indirect
|
|
19
|
+
github.com/caddyserver/zerossl v0.1.3 // indirect
|
|
20
|
+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
|
21
|
+
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
|
22
|
+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
|
23
|
+
github.com/filecoin-project/go-clock v0.1.0 // indirect
|
|
24
|
+
github.com/flynn/noise v1.1.0 // indirect
|
|
25
|
+
github.com/francoispqt/gojay v1.2.13 // indirect
|
|
26
|
+
github.com/go-logr/logr v1.4.3 // indirect
|
|
27
|
+
github.com/go-logr/stdr v1.2.2 // indirect
|
|
28
|
+
github.com/gogo/protobuf v1.3.2 // indirect
|
|
29
|
+
github.com/google/gopacket v1.1.19 // indirect
|
|
30
|
+
github.com/google/uuid v1.6.0 // indirect
|
|
31
|
+
github.com/gorilla/websocket v1.5.3 // indirect
|
|
32
|
+
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
|
33
|
+
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
|
34
|
+
github.com/huin/goupnp v1.3.0 // indirect
|
|
35
|
+
github.com/ipfs/boxo v0.33.1 // indirect
|
|
36
|
+
github.com/ipfs/go-cid v0.5.0 // indirect
|
|
37
|
+
github.com/ipfs/go-datastore v0.8.2 // indirect
|
|
38
|
+
github.com/ipld/go-ipld-prime v0.21.0 // indirect
|
|
39
|
+
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
|
40
|
+
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
|
41
|
+
github.com/klauspost/compress v1.18.0 // indirect
|
|
42
|
+
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
|
43
|
+
github.com/koron/go-ssdp v0.0.6 // indirect
|
|
44
|
+
github.com/libdns/libdns v1.1.1 // indirect
|
|
45
|
+
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
|
46
|
+
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
|
47
|
+
github.com/libp2p/go-flow-metrics v0.3.0 // indirect
|
|
48
|
+
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
|
|
49
|
+
github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect
|
|
50
|
+
github.com/libp2p/go-libp2p-record v0.3.1 // indirect
|
|
51
|
+
github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
|
|
52
|
+
github.com/libp2p/go-msgio v0.3.0 // indirect
|
|
53
|
+
github.com/libp2p/go-netroute v0.2.2 // indirect
|
|
54
|
+
github.com/libp2p/go-reuseport v0.4.0 // indirect
|
|
55
|
+
github.com/libp2p/go-yamux/v5 v5.0.1 // indirect
|
|
56
|
+
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
|
57
|
+
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
58
|
+
github.com/mholt/acmez/v3 v3.1.3 // indirect
|
|
59
|
+
github.com/miekg/dns v1.1.68 // indirect
|
|
60
|
+
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
|
61
|
+
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
|
62
|
+
github.com/minio/sha256-simd v1.0.1 // indirect
|
|
63
|
+
github.com/mr-tron/base58 v1.2.0 // indirect
|
|
64
|
+
github.com/multiformats/go-base32 v0.1.0 // indirect
|
|
65
|
+
github.com/multiformats/go-base36 v0.2.0 // indirect
|
|
66
|
+
github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect
|
|
67
|
+
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
|
68
|
+
github.com/multiformats/go-multibase v0.2.0 // indirect
|
|
69
|
+
github.com/multiformats/go-multicodec v0.9.2 // indirect
|
|
70
|
+
github.com/multiformats/go-multihash v0.2.3 // indirect
|
|
71
|
+
github.com/multiformats/go-multistream v0.6.1 // indirect
|
|
72
|
+
github.com/multiformats/go-varint v0.0.7 // indirect
|
|
73
|
+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
|
74
|
+
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
|
75
|
+
github.com/pion/datachannel v1.5.10 // indirect
|
|
76
|
+
github.com/pion/dtls/v2 v2.2.12 // indirect
|
|
77
|
+
github.com/pion/dtls/v3 v3.0.6 // indirect
|
|
78
|
+
github.com/pion/ice/v4 v4.0.10 // indirect
|
|
79
|
+
github.com/pion/interceptor v0.1.40 // indirect
|
|
80
|
+
github.com/pion/logging v0.2.3 // indirect
|
|
81
|
+
github.com/pion/mdns/v2 v2.0.7 // indirect
|
|
82
|
+
github.com/pion/randutil v0.1.0 // indirect
|
|
83
|
+
github.com/pion/rtcp v1.2.15 // indirect
|
|
84
|
+
github.com/pion/rtp v1.8.19 // indirect
|
|
85
|
+
github.com/pion/sctp v1.8.39 // indirect
|
|
86
|
+
github.com/pion/sdp/v3 v3.0.13 // indirect
|
|
87
|
+
github.com/pion/srtp/v3 v3.0.6 // indirect
|
|
88
|
+
github.com/pion/stun v0.6.1 // indirect
|
|
89
|
+
github.com/pion/stun/v3 v3.0.0 // indirect
|
|
90
|
+
github.com/pion/transport/v2 v2.2.10 // indirect
|
|
91
|
+
github.com/pion/transport/v3 v3.0.7 // indirect
|
|
92
|
+
github.com/pion/turn/v4 v4.0.2 // indirect
|
|
93
|
+
github.com/pion/webrtc/v4 v4.1.2 // indirect
|
|
94
|
+
github.com/polydawn/refmt v0.89.0 // indirect
|
|
95
|
+
github.com/prometheus/client_golang v1.23.0 // indirect
|
|
96
|
+
github.com/prometheus/client_model v0.6.2 // indirect
|
|
97
|
+
github.com/prometheus/common v0.65.0 // indirect
|
|
98
|
+
github.com/prometheus/procfs v0.17.0 // indirect
|
|
99
|
+
github.com/quic-go/qpack v0.5.1 // indirect
|
|
100
|
+
github.com/quic-go/quic-go v0.54.0 // indirect
|
|
101
|
+
github.com/quic-go/webtransport-go v0.9.0 // indirect
|
|
102
|
+
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
|
103
|
+
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
|
104
|
+
github.com/wlynxg/anet v0.0.5 // indirect
|
|
105
|
+
github.com/zeebo/blake3 v0.2.4 // indirect
|
|
106
|
+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
|
107
|
+
go.opentelemetry.io/otel v1.37.0 // indirect
|
|
108
|
+
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
|
109
|
+
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
|
110
|
+
go.uber.org/dig v1.19.0 // indirect
|
|
111
|
+
go.uber.org/fx v1.24.0 // indirect
|
|
112
|
+
go.uber.org/mock v0.5.2 // indirect
|
|
113
|
+
go.uber.org/multierr v1.11.0 // indirect
|
|
114
|
+
go.uber.org/zap v1.27.0 // indirect
|
|
115
|
+
go.uber.org/zap/exp v0.3.0 // indirect
|
|
116
|
+
golang.org/x/crypto v0.41.0 // indirect
|
|
117
|
+
golang.org/x/exp v0.0.0-20250811191247-51f88131bc50 // indirect
|
|
118
|
+
golang.org/x/mod v0.27.0 // indirect
|
|
119
|
+
golang.org/x/net v0.43.0 // indirect
|
|
120
|
+
golang.org/x/sync v0.16.0 // indirect
|
|
121
|
+
golang.org/x/sys v0.35.0 // indirect
|
|
122
|
+
golang.org/x/text v0.28.0 // indirect
|
|
123
|
+
golang.org/x/time v0.12.0 // indirect
|
|
124
|
+
golang.org/x/tools v0.36.0 // indirect
|
|
125
|
+
gonum.org/v1/gonum v0.16.0 // indirect
|
|
126
|
+
lukechampine.com/blake3 v1.4.1 // indirect
|
|
127
|
+
)
|