GitHub Action
commited on
Commit
·
bc8a823
1
Parent(s):
8e795e3
Sync from GitHub with Git LFS
Browse files- agents/peer_sync.py +78 -9
- agents/start_repl.py +9 -9
- agents/web_ui.py +1 -1
agents/peer_sync.py
CHANGED
|
@@ -9,6 +9,7 @@ import ipaddress
|
|
| 9 |
import re
|
| 10 |
from tools.storage import Storage
|
| 11 |
from datetime import datetime
|
|
|
|
| 12 |
|
| 13 |
storage = Storage()
|
| 14 |
my_id = storage.get_config_value("agent_id", str(uuid.uuid4()))
|
|
@@ -62,7 +63,7 @@ tcp_ports, udp_ports = get_listening_ports()
|
|
| 62 |
# LAN Discovery (только local_addresses)
|
| 63 |
# ======================
|
| 64 |
def lan_discovery():
|
| 65 |
-
DISCOVERY_INTERVAL =
|
| 66 |
local_addresses = storage.get_config_value("local_addresses", [])
|
| 67 |
udp_port_set = set()
|
| 68 |
for a in local_addresses:
|
|
@@ -127,18 +128,34 @@ def udp_discovery_listener():
|
|
| 127 |
|
| 128 |
name = msg.get("name", "unknown")
|
| 129 |
addresses = msg.get("addresses", [f"{addr[0]}:{sock.getsockname()[1]}"])
|
| 130 |
-
|
|
|
|
| 131 |
for a in addresses:
|
| 132 |
norm = storage.normalize_address(a)
|
| 133 |
if norm is None:
|
| 134 |
continue
|
| 135 |
-
proto,
|
| 136 |
-
if proto in ["udp", "any"]:
|
| 137 |
-
normalized_addresses.append(norm)
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
continue
|
| 143 |
|
| 144 |
# ======================
|
|
@@ -173,6 +190,56 @@ def udp_discovery_sender():
|
|
| 173 |
last_broadcast = now
|
| 174 |
time.sleep(1)
|
| 175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
# ======================
|
| 177 |
# Peer Exchange (TCP)
|
| 178 |
# ======================
|
|
@@ -194,6 +261,7 @@ def peer_exchange():
|
|
| 194 |
proto, hostport = norm.split("://")
|
| 195 |
if proto not in ["tcp", "any"]:
|
| 196 |
continue
|
|
|
|
| 197 |
try:
|
| 198 |
host, port = parse_hostport(hostport)
|
| 199 |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
@@ -218,6 +286,7 @@ def start_sync():
|
|
| 218 |
threading.Thread(target=udp_discovery_sender, daemon=True).start()
|
| 219 |
threading.Thread(target=peer_exchange, daemon=True).start()
|
| 220 |
threading.Thread(target=lan_discovery, daemon=True).start()
|
|
|
|
| 221 |
|
| 222 |
while True:
|
| 223 |
-
time.sleep(60)
|
|
|
|
| 9 |
import re
|
| 10 |
from tools.storage import Storage
|
| 11 |
from datetime import datetime
|
| 12 |
+
import select
|
| 13 |
|
| 14 |
storage = Storage()
|
| 15 |
my_id = storage.get_config_value("agent_id", str(uuid.uuid4()))
|
|
|
|
| 63 |
# LAN Discovery (только local_addresses)
|
| 64 |
# ======================
|
| 65 |
def lan_discovery():
|
| 66 |
+
DISCOVERY_INTERVAL = 30
|
| 67 |
local_addresses = storage.get_config_value("local_addresses", [])
|
| 68 |
udp_port_set = set()
|
| 69 |
for a in local_addresses:
|
|
|
|
| 128 |
|
| 129 |
name = msg.get("name", "unknown")
|
| 130 |
addresses = msg.get("addresses", [f"{addr[0]}:{sock.getsockname()[1]}"])
|
| 131 |
+
|
| 132 |
+
expanded_addresses = []
|
| 133 |
for a in addresses:
|
| 134 |
norm = storage.normalize_address(a)
|
| 135 |
if norm is None:
|
| 136 |
continue
|
| 137 |
+
proto, rest = norm.split("://", 1)
|
|
|
|
|
|
|
| 138 |
|
| 139 |
+
# --- фильтруем loopback ---
|
| 140 |
+
host_port = rest.split(":")[0]
|
| 141 |
+
if host_port.startswith("127."):
|
| 142 |
+
continue
|
| 143 |
+
|
| 144 |
+
if proto == "udp":
|
| 145 |
+
expanded_addresses.append(f"udp://{rest}")
|
| 146 |
+
expanded_addresses.append(f"tcp://{rest}")
|
| 147 |
+
elif proto == "any":
|
| 148 |
+
expanded_addresses.append(f"udp://{rest}")
|
| 149 |
+
expanded_addresses.append(f"tcp://{rest}")
|
| 150 |
+
elif proto == "tcp":
|
| 151 |
+
expanded_addresses.append(f"tcp://{rest}")
|
| 152 |
+
|
| 153 |
+
if expanded_addresses:
|
| 154 |
+
print(f"[UDP Discovery] получен пакет от {addr}, id={peer_id}, "
|
| 155 |
+
f"addresses(raw)={addresses}, addresses(expanded)={expanded_addresses}")
|
| 156 |
+
storage.add_or_update_peer(peer_id, name, expanded_addresses, "discovery", "online")
|
| 157 |
+
except Exception as e:
|
| 158 |
+
print(f"[UDP Discovery] ошибка при обработке пакета: {e}")
|
| 159 |
continue
|
| 160 |
|
| 161 |
# ======================
|
|
|
|
| 190 |
last_broadcast = now
|
| 191 |
time.sleep(1)
|
| 192 |
|
| 193 |
+
# ======================
|
| 194 |
+
# TCP Listener (для Peer Exchange)
|
| 195 |
+
# ======================
|
| 196 |
+
def tcp_listener():
|
| 197 |
+
sockets = []
|
| 198 |
+
for host, port in tcp_ports:
|
| 199 |
+
try:
|
| 200 |
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 201 |
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
| 202 |
+
bind_host = "" if host in ["0.0.0.0", "any"] else host
|
| 203 |
+
sock.bind((bind_host, port))
|
| 204 |
+
sock.listen(5)
|
| 205 |
+
sockets.append(sock)
|
| 206 |
+
print(f"[TCP Listener] Слушаем на {bind_host}:{port}")
|
| 207 |
+
except Exception as e:
|
| 208 |
+
print(f"[TCP Listener] Ошибка bind/listen {host}:{port} -> {e}")
|
| 209 |
+
|
| 210 |
+
while True:
|
| 211 |
+
if not sockets:
|
| 212 |
+
time.sleep(1)
|
| 213 |
+
continue
|
| 214 |
+
readable, _, _ = select.select(sockets, [], [], 1)
|
| 215 |
+
for s in readable:
|
| 216 |
+
try:
|
| 217 |
+
conn, addr = s.accept()
|
| 218 |
+
data = conn.recv(1024)
|
| 219 |
+
if data == b"PEER_EXCHANGE_REQUEST":
|
| 220 |
+
print(f"[TCP Listener] Получен PEER_EXCHANGE_REQUEST от {addr}")
|
| 221 |
+
try:
|
| 222 |
+
peers = []
|
| 223 |
+
for pid, addresses_json in storage.get_online_peers(limit=50):
|
| 224 |
+
try:
|
| 225 |
+
addresses = json.loads(addresses_json)
|
| 226 |
+
except Exception:
|
| 227 |
+
addresses = []
|
| 228 |
+
peers.append({
|
| 229 |
+
"id": pid,
|
| 230 |
+
"addresses": addresses
|
| 231 |
+
})
|
| 232 |
+
payload = json.dumps(peers).encode("utf-8")
|
| 233 |
+
conn.sendall(payload)
|
| 234 |
+
print(f"[TCP Listener] Отправлен список пиров ({len(peers)}) в {addr}")
|
| 235 |
+
except Exception as e:
|
| 236 |
+
print(f"[TCP Listener] Ошибка при отправке списка пиров: {e}")
|
| 237 |
+
conn.close()
|
| 238 |
+
except Exception as e:
|
| 239 |
+
print(f"[TCP Listener] Ошибка при обработке соединения: {e}")
|
| 240 |
+
continue
|
| 241 |
+
|
| 242 |
+
|
| 243 |
# ======================
|
| 244 |
# Peer Exchange (TCP)
|
| 245 |
# ======================
|
|
|
|
| 261 |
proto, hostport = norm.split("://")
|
| 262 |
if proto not in ["tcp", "any"]:
|
| 263 |
continue
|
| 264 |
+
|
| 265 |
try:
|
| 266 |
host, port = parse_hostport(hostport)
|
| 267 |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
| 286 |
threading.Thread(target=udp_discovery_sender, daemon=True).start()
|
| 287 |
threading.Thread(target=peer_exchange, daemon=True).start()
|
| 288 |
threading.Thread(target=lan_discovery, daemon=True).start()
|
| 289 |
+
threading.Thread(target=tcp_listener, daemon=True).start()
|
| 290 |
|
| 291 |
while True:
|
| 292 |
+
time.sleep(60)
|
agents/start_repl.py
CHANGED
|
@@ -4,7 +4,7 @@ import threading
|
|
| 4 |
|
| 5 |
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
| 6 |
|
| 7 |
-
from
|
| 8 |
from tools.storage import Storage
|
| 9 |
|
| 10 |
# Проверка инициализации (вернёт config, если всё ОК)
|
|
@@ -28,7 +28,7 @@ def start_all():
|
|
| 28 |
if ENABLE_REPL:
|
| 29 |
if not storage.is_process_alive("REPL", max_delay=180):
|
| 30 |
def repl():
|
| 31 |
-
from
|
| 32 |
start_repl()
|
| 33 |
threads.append(threading.Thread(target=repl, name="REPL"))
|
| 34 |
else:
|
|
@@ -37,7 +37,7 @@ def start_all():
|
|
| 37 |
if ENABLE_UI:
|
| 38 |
if not storage.is_process_alive("NotebookUI", max_delay=180):
|
| 39 |
def ui():
|
| 40 |
-
from
|
| 41 |
start_notebook()
|
| 42 |
threads.append(threading.Thread(target=ui, name="NotebookUI"))
|
| 43 |
else:
|
|
@@ -46,7 +46,7 @@ def start_all():
|
|
| 46 |
if ENABLE_MESH:
|
| 47 |
if not storage.is_process_alive("MeshListener", max_delay=180):
|
| 48 |
def mesh():
|
| 49 |
-
from
|
| 50 |
start_listener()
|
| 51 |
threads.append(threading.Thread(target=mesh, name="MeshListener"))
|
| 52 |
else:
|
|
@@ -55,7 +55,7 @@ def start_all():
|
|
| 55 |
if ENABLE_SYNC:
|
| 56 |
if not storage.is_process_alive("PeerSync", max_delay=180):
|
| 57 |
def sync():
|
| 58 |
-
from
|
| 59 |
start_sync()
|
| 60 |
threads.append(threading.Thread(target=sync, name="PeerSync"))
|
| 61 |
else:
|
|
@@ -64,7 +64,7 @@ def start_all():
|
|
| 64 |
if ENABLE_TRANSPORT:
|
| 65 |
if not storage.is_process_alive("Transporter", max_delay=180):
|
| 66 |
def transport():
|
| 67 |
-
from
|
| 68 |
start_transporter()
|
| 69 |
threads.append(threading.Thread(target=transport, name="Transporter"))
|
| 70 |
else:
|
|
@@ -73,7 +73,7 @@ def start_all():
|
|
| 73 |
if ENABLE_CONTROL:
|
| 74 |
if not storage.is_process_alive("Controller", max_delay=180):
|
| 75 |
def control():
|
| 76 |
-
from
|
| 77 |
start_controller()
|
| 78 |
threads.append(threading.Thread(target=control, name="Controller"))
|
| 79 |
else:
|
|
@@ -82,7 +82,7 @@ def start_all():
|
|
| 82 |
if ENABLE_CONTAINER:
|
| 83 |
if not storage.is_process_alive("ContainerAgent", max_delay=180):
|
| 84 |
def container():
|
| 85 |
-
from
|
| 86 |
start_container()
|
| 87 |
threads.append(threading.Thread(target=container, name="ContainerAgent"))
|
| 88 |
else:
|
|
@@ -91,7 +91,7 @@ def start_all():
|
|
| 91 |
if ENABLE_ETHICS:
|
| 92 |
if not storage.is_process_alive("EthicsGuard", max_delay=180):
|
| 93 |
def ethics():
|
| 94 |
-
from
|
| 95 |
start_ethics_guard()
|
| 96 |
threads.append(threading.Thread(target=ethics, name="EthicsGuard"))
|
| 97 |
else:
|
|
|
|
| 4 |
|
| 5 |
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
| 6 |
|
| 7 |
+
from init import ensure_db_initialized
|
| 8 |
from tools.storage import Storage
|
| 9 |
|
| 10 |
# Проверка инициализации (вернёт config, если всё ОК)
|
|
|
|
| 28 |
if ENABLE_REPL:
|
| 29 |
if not storage.is_process_alive("REPL", max_delay=180):
|
| 30 |
def repl():
|
| 31 |
+
from repl import start_repl
|
| 32 |
start_repl()
|
| 33 |
threads.append(threading.Thread(target=repl, name="REPL"))
|
| 34 |
else:
|
|
|
|
| 37 |
if ENABLE_UI:
|
| 38 |
if not storage.is_process_alive("NotebookUI", max_delay=180):
|
| 39 |
def ui():
|
| 40 |
+
from web_ui import start_notebook
|
| 41 |
start_notebook()
|
| 42 |
threads.append(threading.Thread(target=ui, name="NotebookUI"))
|
| 43 |
else:
|
|
|
|
| 46 |
if ENABLE_MESH:
|
| 47 |
if not storage.is_process_alive("MeshListener", max_delay=180):
|
| 48 |
def mesh():
|
| 49 |
+
from agent_mesh_listener import start_listener
|
| 50 |
start_listener()
|
| 51 |
threads.append(threading.Thread(target=mesh, name="MeshListener"))
|
| 52 |
else:
|
|
|
|
| 55 |
if ENABLE_SYNC:
|
| 56 |
if not storage.is_process_alive("PeerSync", max_delay=180):
|
| 57 |
def sync():
|
| 58 |
+
from peer_sync import start_sync
|
| 59 |
start_sync()
|
| 60 |
threads.append(threading.Thread(target=sync, name="PeerSync"))
|
| 61 |
else:
|
|
|
|
| 64 |
if ENABLE_TRANSPORT:
|
| 65 |
if not storage.is_process_alive("Transporter", max_delay=180):
|
| 66 |
def transport():
|
| 67 |
+
from transporter import start_transporter
|
| 68 |
start_transporter()
|
| 69 |
threads.append(threading.Thread(target=transport, name="Transporter"))
|
| 70 |
else:
|
|
|
|
| 73 |
if ENABLE_CONTROL:
|
| 74 |
if not storage.is_process_alive("Controller", max_delay=180):
|
| 75 |
def control():
|
| 76 |
+
from agent_controller import start_controller
|
| 77 |
start_controller()
|
| 78 |
threads.append(threading.Thread(target=control, name="Controller"))
|
| 79 |
else:
|
|
|
|
| 82 |
if ENABLE_CONTAINER:
|
| 83 |
if not storage.is_process_alive("ContainerAgent", max_delay=180):
|
| 84 |
def container():
|
| 85 |
+
from container_agent import start_container
|
| 86 |
start_container()
|
| 87 |
threads.append(threading.Thread(target=container, name="ContainerAgent"))
|
| 88 |
else:
|
|
|
|
| 91 |
if ENABLE_ETHICS:
|
| 92 |
if not storage.is_process_alive("EthicsGuard", max_delay=180):
|
| 93 |
def ethics():
|
| 94 |
+
from ethics_guard import start_ethics_guard
|
| 95 |
start_ethics_guard()
|
| 96 |
threads.append(threading.Thread(target=ethics, name="EthicsGuard"))
|
| 97 |
else:
|
agents/web_ui.py
CHANGED
|
@@ -13,7 +13,7 @@ from fastapi import FastAPI
|
|
| 13 |
from fastapi.staticfiles import StaticFiles
|
| 14 |
from fastapi.templating import Jinja2Templates
|
| 15 |
from starlette.middleware.sessions import SessionMiddleware
|
| 16 |
-
from
|
| 17 |
from tools.storage import Storage
|
| 18 |
|
| 19 |
storage = Storage()
|
|
|
|
| 13 |
from fastapi.staticfiles import StaticFiles
|
| 14 |
from fastapi.templating import Jinja2Templates
|
| 15 |
from starlette.middleware.sessions import SessionMiddleware
|
| 16 |
+
from notebook.views import router as notebook_router
|
| 17 |
from tools.storage import Storage
|
| 18 |
|
| 19 |
storage = Storage()
|