zig-pay/src/exchange/exchange_connection.zig
2025-08-07 21:08:10 -03:00

132 lines
3.9 KiB
Zig

const std = @import("std");
const net = std.net;
const heap = std.heap;
const Thread = std.Thread;
const log = std.log;
const Address = net.Address;
const Allocator = std.mem.Allocator;
const testing = std.testing;
const expect = testing.expect;
const FakeStream = @import("helpers").FakeStream;
const is_test = @import("builtin").is_test;
const ExchangeConnectionStatus = enum { waiting, trying, active, dead };
pub const ExchangeConnection = struct {
in_address: Address,
out_address: Address,
in: if (is_test) *FakeStream else net.Stream = undefined,
out: if (is_test) *FakeStream else net.Stream = undefined,
server_status: ExchangeConnectionStatus = .waiting,
out_status: ExchangeConnectionStatus = .trying,
listen_thread: Thread = undefined,
pub fn init(host: []const u8, port: u16) !ExchangeConnection {
var buf: [1024]u8 = undefined;
var pba = heap.FixedBufferAllocator.init(&buf);
const addrList = try net.getAddressList(pba.allocator(), host, port);
defer addrList.deinit();
var final_addr: ?Address = null;
for (addrList.addrs) |addr| {
final_addr = addr;
}
const in_address = Address.initIp4(.{ 0, 0, 0, 0 }, port);
return ExchangeConnection{
.out_address = final_addr.?,
.in_address = in_address,
};
}
pub fn start(self: *ExchangeConnection) void {
self.listen_thread = Thread.spawn(.{ .stack_size = 1024 * 16 }, ExchangeConnection.listen, .{self}) catch |err| {
log.err("Was not possible thread secret connection listen {any}", .{err});
unreachable;
};
_ = Thread.spawn(.{ .stack_size = 1024 * 16 }, ExchangeConnection.tryConnectOut, .{self}) catch |err| {
log.err("Was not possible create thread tryConenctOut {any}", .{err});
unreachable;
};
}
pub fn tryConnectOut(self: *ExchangeConnection) void {
if (is_test) {
return;
}
for (0..10) |_| {
Thread.sleep(1_000_000 * 1000);
self.out = net.tcpConnectToAddress(self.out_address) catch |err| {
log.err("Error connect to secret server {any}", .{err});
continue;
};
self.out_status = .active;
return;
}
}
fn listen(self: *ExchangeConnection) void {
if (is_test) {
return;
}
std.debug.print("Listening ...\n", .{});
for (0..10) |_| {
var server = self.in_address.listen(.{ .kernel_backlog = 1 }) catch |err| {
log.err("Error starting secret server connection {any}", .{err});
continue;
};
while (true) {
const server_conn = server.accept() catch |err| {
log.err("Error when accepting connection secret server {any}", .{err});
self.server_status = .waiting;
break;
};
self.server_status = .active;
self.in = server_conn.stream;
}
server.deinit();
Thread.sleep(1_000_000 * 1000);
}
self.server_status = .dead;
}
};
test "expect create a secret connection" {
const conn = try ExchangeConnection.init("uchoamp.dev", 80);
try expect(conn.in_address.getPort() == 80);
}
//test "expect start secret connection" {
// var conn1 = try ExchangeConnection.init("localhost", 5002);
// conn1.out_address.setPort(2323);
//
// conn1.start();
//
// //_ = try conn1.out.write("hello!\r\n");
// //Thread.sleep(1_000_000 * 1000 * 10);
// conn1.listen_thread.join();
//
// var buf: [100]u8 = undefined;
// try expect(conn1.server_status == .active);
// const size = try conn1.in.read(&buf);
// std.debug.print("Secret conn response: {s}", .{buf[0..size]});
//}