feat: show list of discovered servers
parent
ff7e3c70bf
commit
390eaebd90
|
@ -3,6 +3,7 @@ pub const HBox = @import("./Element/HBox.zig");
|
|||
pub const Link = @import("./Element/Link.zig");
|
||||
pub const Page = @import("./Element/Page.zig");
|
||||
pub const Pile = @import("./Element/Pile.zig");
|
||||
pub const ServerList = @import("./Element/ServerList.zig");
|
||||
pub const Text = @import("./Element/Text.zig");
|
||||
pub const View = @import("./Element/View.zig");
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
allocator: std.mem.Allocator,
|
||||
discovered: *Discovered,
|
||||
|
||||
pub const Discovered = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
mutex: std.Thread.Mutex = .{},
|
||||
servers: std.StringArrayHashMapUnmanaged(void) = .{},
|
||||
};
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, discovered: *Discovered) !*@This() {
|
||||
const this = try allocator.create(@This());
|
||||
errdefer allocator.destroy(this);
|
||||
|
||||
this.* = .{
|
||||
.allocator = allocator,
|
||||
.discovered = discovered,
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
pub fn element(this: *@This()) Element {
|
||||
return Element{
|
||||
.pointer = this,
|
||||
.interface = &Element.Interface{
|
||||
.destroy = &element_destroy,
|
||||
.minimum_size = &element_minimum_size,
|
||||
.render = &element_render,
|
||||
.event = &element_event,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn element_destroy(pointer: ?*anyopaque) void {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
this.allocator.destroy(this);
|
||||
}
|
||||
|
||||
pub fn element_minimum_size(pointer: ?*anyopaque, render_resources: Element.RenderResources) [2]f32 {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
_ = this;
|
||||
return render_resources.font.textSize("example_server.xyz:5711", 1);
|
||||
}
|
||||
|
||||
pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) void {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
_ = max;
|
||||
_ = render_resources;
|
||||
|
||||
var pos = min;
|
||||
|
||||
this.discovered.mutex.lock();
|
||||
defer this.discovered.mutex.unlock();
|
||||
for (this.discovered.servers.keys()) |url| {
|
||||
const text_size = canvas.writeText(pos, url, .{});
|
||||
pos[1] += text_size[1];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
_ = this;
|
||||
_ = event;
|
||||
return null;
|
||||
}
|
||||
|
||||
const Element = @import("../Element.zig");
|
||||
const assets = @import("../assets.zig");
|
||||
|
||||
const seizer = @import("seizer");
|
||||
const gl = seizer.gl;
|
||||
const std = @import("std");
|
|
@ -31,6 +31,11 @@ const SIOCGIFADDR = 0x8915;
|
|||
const JoinMultiplayerGame = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
discovery_thread: std.Thread,
|
||||
running: *std.atomic.Value(bool),
|
||||
|
||||
discovered: *Element.ServerList.Discovered,
|
||||
|
||||
const Server = struct { url: []const u8, port: u16 };
|
||||
|
||||
pub const INTERFACE = &Handler.Interface{
|
||||
.create = &create,
|
||||
|
@ -42,11 +47,21 @@ const JoinMultiplayerGame = struct {
|
|||
const this = try allocator.create(@This());
|
||||
errdefer allocator.destroy(this);
|
||||
|
||||
const discovery_thread = std.Thread.spawn(.{}, find_local_games_thread, .{allocator}) catch return error.OutOfMemory;
|
||||
const discovered = try allocator.create(Element.ServerList.Discovered);
|
||||
errdefer allocator.destroy(discovered);
|
||||
discovered.* = .{ .allocator = allocator };
|
||||
|
||||
const running = try allocator.create(std.atomic.Value(bool));
|
||||
errdefer allocator.destroy(running);
|
||||
running.store(true, .Monotonic);
|
||||
|
||||
const discovery_thread = std.Thread.spawn(.{}, find_local_games_thread, .{ running, discovered }) catch return error.OutOfMemory;
|
||||
|
||||
this.* = .{
|
||||
.allocator = allocator,
|
||||
.discovery_thread = discovery_thread,
|
||||
.running = running,
|
||||
.discovered = discovered,
|
||||
};
|
||||
|
||||
return this;
|
||||
|
@ -54,15 +69,17 @@ const JoinMultiplayerGame = struct {
|
|||
|
||||
fn handler(pointer: ?*anyopaque, request: Request) Handler.Error!Response {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
_ = this;
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(request.allocator);
|
||||
errdefer arena.deinit();
|
||||
|
||||
var text = try Element.Text.create(arena.allocator(), try std.fmt.allocPrint(arena.allocator(), "Looking for multiplayer games", .{}));
|
||||
|
||||
var server_list = try Element.ServerList.create(arena.allocator(), this.discovered);
|
||||
|
||||
var page = try Element.Page.create(request.allocator);
|
||||
try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, text.element());
|
||||
try page.addElement(.{ 0.5, 0.7 }, .{ 0.5, 0.5 }, server_list.element());
|
||||
|
||||
return Response{ .arena = arena, .body = .{ .element = page.element() } };
|
||||
}
|
||||
|
@ -70,12 +87,23 @@ const JoinMultiplayerGame = struct {
|
|||
fn deinit(pointer: ?*anyopaque) void {
|
||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||
|
||||
this.running.store(false, .Monotonic);
|
||||
|
||||
this.discovery_thread.join();
|
||||
for (this.discovered.servers.keys()) |url| {
|
||||
this.discovered.allocator.free(url);
|
||||
}
|
||||
this.discovered.servers.deinit(this.discovered.allocator);
|
||||
|
||||
this.allocator.destroy(this.discovered);
|
||||
this.allocator.destroy(this.running);
|
||||
|
||||
this.allocator.destroy(this);
|
||||
}
|
||||
|
||||
fn find_local_games_thread(allocator: std.mem.Allocator) !void {
|
||||
const buffer = try allocator.alloc(u8, 2048);
|
||||
defer allocator.free(buffer);
|
||||
fn find_local_games_thread(running: *std.atomic.Value(bool), discovered: *Element.ServerList.Discovered) !void {
|
||||
const buffer = try discovered.allocator.alloc(u8, 2048);
|
||||
defer discovered.allocator.free(buffer);
|
||||
|
||||
const log = std.log.scoped(.mdns);
|
||||
log.info("mdns discovery service started", .{});
|
||||
|
@ -95,7 +123,7 @@ const JoinMultiplayerGame = struct {
|
|||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (running.load(.Monotonic)) {
|
||||
var pollfds = [_]std.os.pollfd{
|
||||
.{ .fd = mdns_ipv4_socket, .events = std.os.POLL.IN, .revents = undefined },
|
||||
.{ .fd = mdns_ipv6_socket, .events = std.os.POLL.IN, .revents = undefined },
|
||||
|
@ -103,11 +131,11 @@ const JoinMultiplayerGame = struct {
|
|||
_ = std.os.poll(&pollfds, 1000) catch break;
|
||||
for (pollfds) |pollfd| {
|
||||
if (pollfd.revents & std.os.POLL.IN == 0) continue;
|
||||
_ = c.mdns_query_recv(pollfd.fd, buffer.ptr, buffer.len, &find_local_games_thread_query_callback, null, 0);
|
||||
_ = c.mdns_query_recv(pollfd.fd, buffer.ptr, buffer.len, &find_local_games_thread_query_callback, discovered, 0);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("mdns service stopping", .{});
|
||||
log.info("mdns discovery service stopping", .{});
|
||||
}
|
||||
|
||||
fn find_local_games_thread_query_callback(
|
||||
|
@ -129,8 +157,9 @@ const JoinMultiplayerGame = struct {
|
|||
) callconv(.C) c_int {
|
||||
const log = std.log.scoped(.mdns);
|
||||
|
||||
const discovered: *Element.ServerList.Discovered = @ptrCast(@alignCast(userdata));
|
||||
|
||||
_ = rclass;
|
||||
_ = userdata;
|
||||
_ = ttl;
|
||||
_ = name_length;
|
||||
_ = sock;
|
||||
|
@ -173,6 +202,15 @@ const JoinMultiplayerGame = struct {
|
|||
var strbuffer: [128]u8 = undefined;
|
||||
const record = c.mdns_record_parse_srv(data_ptr_opaque, data_len, record_offset, record_length, &strbuffer, strbuffer.len);
|
||||
log.info("{?} : {s} {s} \"{}\":{}", .{ std_from, entrytype_str, recordtype_str, std.zig.fmtEscapes(record.name.str[0..record.name.length]), record.port });
|
||||
|
||||
const url = std.fmt.allocPrint(discovered.allocator, "{s}:{}", .{ record.name.str[0..record.name.length], record.port }) catch unreachable;
|
||||
discovered.mutex.lock();
|
||||
defer discovered.mutex.unlock();
|
||||
|
||||
const gop = discovered.servers.getOrPut(discovered.allocator, url) catch unreachable;
|
||||
if (gop.found_existing) {
|
||||
discovered.allocator.free(url);
|
||||
}
|
||||
},
|
||||
c.MDNS_RECORDTYPE_A => {
|
||||
var std_address: std.net.Ip4Address = undefined;
|
||||
|
|
Loading…
Reference in New Issue