refactor: Extraer tipos de connection.zig (1212 → 793 líneas)
Nuevo módulo connection/types.zig (200 líneas): - ConnectionState, NatType, ConnectionMethod - Error enum - PeerInfo, PeerAddress structs - Tests de tipos connection.zig ahora importa y re-exporta los tipos. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8b968d7add
commit
789236092b
2 changed files with 277 additions and 495 deletions
File diff suppressed because it is too large
Load diff
200
src/connection/types.zig
Normal file
200
src/connection/types.zig
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
//! Tipos y estructuras para el módulo de conexión
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const identity = @import("../identity.zig");
|
||||||
|
const utils = @import("../utils.zig");
|
||||||
|
|
||||||
|
pub const DeviceId = identity.DeviceId;
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Estados y tipos
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/// Estado de conexión
|
||||||
|
pub const ConnectionState = enum {
|
||||||
|
disconnected,
|
||||||
|
resolving,
|
||||||
|
connecting,
|
||||||
|
handshaking,
|
||||||
|
connected,
|
||||||
|
disconnecting,
|
||||||
|
@"error",
|
||||||
|
|
||||||
|
pub fn isActive(self: ConnectionState) bool {
|
||||||
|
return self == .connecting or self == .handshaking or self == .connected;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Tipo de NAT detectado
|
||||||
|
pub const NatType = enum {
|
||||||
|
unknown,
|
||||||
|
none,
|
||||||
|
full_cone,
|
||||||
|
restricted,
|
||||||
|
port_restricted,
|
||||||
|
symmetric,
|
||||||
|
blocked,
|
||||||
|
|
||||||
|
pub fn canAcceptIncoming(self: NatType) bool {
|
||||||
|
return self == .none or self == .full_cone;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needsHolePunch(self: NatType) bool {
|
||||||
|
return self == .restricted or self == .port_restricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needsRelay(self: NatType) bool {
|
||||||
|
return self == .symmetric or self == .blocked;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Método de conexión usado
|
||||||
|
pub const ConnectionMethod = enum {
|
||||||
|
direct,
|
||||||
|
hole_punch,
|
||||||
|
relay,
|
||||||
|
local,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Errores del módulo
|
||||||
|
pub const Error = error{
|
||||||
|
AlreadyInitialized,
|
||||||
|
NotInitialized,
|
||||||
|
InvalidDeviceId,
|
||||||
|
ConnectionFailed,
|
||||||
|
ConnectionTimeout,
|
||||||
|
ConnectionClosed,
|
||||||
|
PeerNotFound,
|
||||||
|
CertificateError,
|
||||||
|
TlsError,
|
||||||
|
ProtocolError,
|
||||||
|
CompressionError,
|
||||||
|
OutOfMemory,
|
||||||
|
IoError,
|
||||||
|
InvalidConfig,
|
||||||
|
AddressInUse,
|
||||||
|
NetworkUnreachable,
|
||||||
|
HandshakeFailed,
|
||||||
|
InvalidMessage,
|
||||||
|
RelayFailed,
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Información de peers
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/// Información de un peer
|
||||||
|
pub const PeerInfo = struct {
|
||||||
|
device_id: DeviceId,
|
||||||
|
device_name: []const u8,
|
||||||
|
client_name: []const u8,
|
||||||
|
client_version: []const u8,
|
||||||
|
addresses: [][]const u8,
|
||||||
|
connected_at: i64,
|
||||||
|
is_local: bool,
|
||||||
|
bytes_sent: u64,
|
||||||
|
bytes_received: u64,
|
||||||
|
connection_method: ConnectionMethod,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn deinit(self: *PeerInfo) void {
|
||||||
|
self.allocator.free(self.device_name);
|
||||||
|
self.allocator.free(self.client_name);
|
||||||
|
self.allocator.free(self.client_version);
|
||||||
|
for (self.addresses) |addr| {
|
||||||
|
self.allocator.free(addr);
|
||||||
|
}
|
||||||
|
self.allocator.free(self.addresses);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Dirección de peer con metadatos
|
||||||
|
pub const PeerAddress = struct {
|
||||||
|
address: []const u8,
|
||||||
|
port: u16,
|
||||||
|
is_local: bool,
|
||||||
|
is_relay: bool,
|
||||||
|
last_seen: i64,
|
||||||
|
priority: u8,
|
||||||
|
|
||||||
|
pub fn parse(addr_str: []const u8, allocator: std.mem.Allocator) !PeerAddress {
|
||||||
|
if (std.mem.startsWith(u8, addr_str, "relay://")) {
|
||||||
|
return .{
|
||||||
|
.address = try allocator.dupe(u8, addr_str),
|
||||||
|
.port = 0,
|
||||||
|
.is_local = false,
|
||||||
|
.is_relay = true,
|
||||||
|
.last_seen = utils.timestamp(),
|
||||||
|
.priority = 100,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std.mem.lastIndexOf(u8, addr_str, ":")) |colon| {
|
||||||
|
const port = std.fmt.parseInt(u16, addr_str[colon + 1 ..], 10) catch 22000;
|
||||||
|
const ip = addr_str[0..colon];
|
||||||
|
|
||||||
|
const is_local = std.mem.startsWith(u8, ip, "192.168.") or
|
||||||
|
std.mem.startsWith(u8, ip, "10.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.16.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.17.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.18.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.19.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.2") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.30.") or
|
||||||
|
std.mem.startsWith(u8, ip, "172.31.");
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.address = try allocator.dupe(u8, ip),
|
||||||
|
.port = port,
|
||||||
|
.is_local = is_local,
|
||||||
|
.is_relay = false,
|
||||||
|
.last_seen = utils.timestamp(),
|
||||||
|
.priority = if (is_local) 10 else 50,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.InvalidAddress;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Tests
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
test "connection state active check" {
|
||||||
|
try std.testing.expect(!ConnectionState.disconnected.isActive());
|
||||||
|
try std.testing.expect(ConnectionState.connecting.isActive());
|
||||||
|
try std.testing.expect(ConnectionState.connected.isActive());
|
||||||
|
try std.testing.expect(!ConnectionState.@"error".isActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "nat type capabilities" {
|
||||||
|
try std.testing.expect(NatType.none.canAcceptIncoming());
|
||||||
|
try std.testing.expect(NatType.full_cone.canAcceptIncoming());
|
||||||
|
try std.testing.expect(!NatType.restricted.canAcceptIncoming());
|
||||||
|
|
||||||
|
try std.testing.expect(NatType.restricted.needsHolePunch());
|
||||||
|
try std.testing.expect(NatType.port_restricted.needsHolePunch());
|
||||||
|
try std.testing.expect(!NatType.symmetric.needsHolePunch());
|
||||||
|
|
||||||
|
try std.testing.expect(NatType.symmetric.needsRelay());
|
||||||
|
try std.testing.expect(NatType.blocked.needsRelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "peer address parse" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
const local = try PeerAddress.parse("192.168.1.100:22000", allocator);
|
||||||
|
defer allocator.free(local.address);
|
||||||
|
try std.testing.expect(local.is_local);
|
||||||
|
try std.testing.expect(!local.is_relay);
|
||||||
|
try std.testing.expectEqual(@as(u16, 22000), local.port);
|
||||||
|
|
||||||
|
const public_addr = try PeerAddress.parse("8.8.8.8:22000", allocator);
|
||||||
|
defer allocator.free(public_addr.address);
|
||||||
|
try std.testing.expect(!public_addr.is_local);
|
||||||
|
|
||||||
|
const relay_addr = try PeerAddress.parse("relay://relay.example.com/device123", allocator);
|
||||||
|
defer allocator.free(relay_addr.address);
|
||||||
|
try std.testing.expect(relay_addr.is_relay);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue