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