Matrix bridge scaffold: test harness with texting E2E

- src/matrix.zig: minimal Matrix client (conduwuit @ matrix.chaosmith.systems)
  via curl subprocess transport (native TLS swap later): login, createRoom
  (trusted_private_chat, unencrypted — no olm), sendText, sync polling with
  window-scan event extraction reusing letta.jsonStr
- src/matrix_harness.zig: standalone entrypoint (independent of tray daemon):
  login -> DM with peer -> sync loop -> peer messages routed through letta
  CLI (chaos-prime) -> replies sent back to the room
- build.zig: second exe matrix_harness; use_llvm fix promoted into build.zig
  for both executables (native lld vs GCC16 .sframe relocations)
- calling/Element Call (livekit SFU already deployed on ass-host) layers on
  top of this harness next

👾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta Code <noreply@letta.com>
This commit is contained in:
pierreandLetta Code committed 2026-09-02 02:09:42 +03:00
1 parent 187bac9aa4
commit da50dea0d1
3 files changed
+274

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
//! Matrix client (scaffold) — conduwuit @ chaosmith.systems.
//!
//! HTTP via curl subprocess behind a narrow seam (native TLS swap later).
//! Sync loop + send + login. No olm/megolm: rooms must be unencrypted
//! (trusted_private_chat without encryption).
const std = @import("std");
const Io = std.Io;
const letta = @import("letta.zig");
pub const HOMESERVER = "https://matrix.chaosmith.systems";
pub const DEVICE_NAME = "inferon-harness";
// ------------------------------------------------------------- transport ---
/// HTTP via curl subprocess. Returns body (allocated; caller frees).
fn http(alloc: std.mem.Allocator, io: Io, method: []const u8, url: []const u8, token: ?[]const u8, json_body: ?[]const u8) ![]u8 {
var argv: std.ArrayList([]const u8) = .empty;
defer argv.deinit(alloc);
try argv.appendSlice(alloc, &.{ "curl", "-sS", "-m", "25", "-X", method });
if (token) |t| {
// NOTE: no defer-free — h must outlive the spawn below (argv holds it).
// Leaks one small string per call; fine for the harness, revisit with
// the native-TLS rewrite.
const h = try std.fmt.allocPrint(alloc, "Authorization: Bearer {s}", .{t});
try argv.appendSlice(alloc, &.{ "-H", h });
}
if (json_body) |b| {
try argv.appendSlice(alloc, &.{ "-H", "Content-Type: application/json", "-d", b });
}
try argv.append(alloc, url);
var child = try std.process.spawn(io, .{
.argv = argv.items,
.stdin = .ignore,
.stdout = .pipe,
.stderr = .ignore,
});
const out = child.stdout.?;
var buf: std.ArrayList(u8) = .empty;
errdefer buf.deinit(alloc);
var tmp: [16 * 1024]u8 = undefined;
while (true) {
const got = out.readStreaming(io, &.{&tmp}) catch break;
if (got == 0) break;
try buf.appendSlice(alloc, tmp[0..got]);
}
_ = child.wait(io) catch {};
return buf.toOwnedSlice(alloc);
}
// ------------------------------------------------------------- api calls ---
pub const Session = struct { token: []u8, user_id: []u8 }; // caller frees both
pub fn login(alloc: std.mem.Allocator, io: Io, user: []const u8, password: []const u8) !Session {
const body = try std.fmt.allocPrint(alloc,
\\{{"type":"m.login.password","identifier":{{"type":"m.id.user","user":"{s}"}},"password":"{s}","initial_device_display_name":"{s}"}}
, .{ user, password, DEVICE_NAME });
defer alloc.free(body);
const resp = try http(alloc, io, "POST", HOMESERVER ++ "/_matrix/client/v3/login", null, body);
defer alloc.free(resp);
const tok = letta.jsonStr(alloc, resp, 0, "access_token") orelse return error.LoginFailed;
errdefer alloc.free(tok.val);
const uid = letta.jsonStr(alloc, resp, 0, "user_id") orelse return error.LoginFailed;
return .{ .token = tok.val, .user_id = uid.val };
}
/// Send a text message. Returns event id (allocated; caller frees).
pub fn sendText(alloc: std.mem.Allocator, io: Io, token: []const u8, room: []const u8, body: []const u8) ![]u8 {
const ts = Io.Clock.now(.real, io).nanoseconds;
const url = try std.fmt.allocPrint(alloc, "{s}/_matrix/client/v3/rooms/{s}/send/m.room.message/infr-{d}", .{ HOMESERVER, room, ts });
defer alloc.free(url);
var esc: std.ArrayList(u8) = .empty;
defer esc.deinit(alloc);
for (body) |c| {
switch (c) {
'"' => try esc.appendSlice(alloc, "\\\""),
'\\' => try esc.appendSlice(alloc, "\\\\"),
'\n' => try esc.appendSlice(alloc, "\\n"),
'\r', '\t' => try esc.appendSlice(alloc, " "),
else => try esc.append(alloc, c),
}
}
const payload = try std.fmt.allocPrint(alloc, "{{\"msgtype\":\"m.text\",\"body\":\"{s}\"}}", .{esc.items});
defer alloc.free(payload);
const resp = try http(alloc, io, "PUT", url, token, payload);
defer alloc.free(resp);
const ev = letta.jsonStr(alloc, resp, 0, "event_id") orelse return error.SendFailed;
return ev.val;
}
/// Join a room by id (accepts invites).
pub fn joinRoom(alloc: std.mem.Allocator, io: Io, token: []const u8, room: []const u8) !void {
const url = try std.fmt.allocPrint(alloc, "{s}/_matrix/client/v3/rooms/{s}/join", .{ HOMESERVER, room });
defer alloc.free(url);
const resp = try http(alloc, io, "POST", url, token, "{}");
alloc.free(resp);
}
pub const Event = struct { sender: []u8, body: []u8 }; // both allocated
/// One sync poll. Returns message events + next `since` token. Caller frees.
/// (Sync first without a since token to establish one, then poll.)
pub fn sync(alloc: std.mem.Allocator, io: Io, token: []const u8, since: []const u8, timeout_ms: u32) !struct { events: []Event, next: []u8 } {
const url = if (since.len > 0)
try std.fmt.allocPrint(alloc, "{s}/_matrix/client/v3/sync?timeout={d}&since={s}", .{ HOMESERVER, timeout_ms, since })
else
try std.fmt.allocPrint(alloc, "{s}/_matrix/client/v3/sync?timeout=0", .{HOMESERVER});
defer alloc.free(url);
const resp = try http(alloc, io, "GET", url, token, null);
defer alloc.free(resp);
const next = if (letta.jsonStr(alloc, resp, 0, "next_batch")) |nb| nb.val else try alloc.dupe(u8, since);
var events: std.ArrayList(Event) = .empty;
errdefer events.deinit(alloc);
var i: usize = 0;
while (std.mem.indexOfPos(u8, resp, i, "\"m.room.message\"")) |pos| {
defer i = pos + 15;
const win_end = @min(resp.len, pos + 1500);
const win = resp[pos..win_end];
const sender = letta.jsonStr(alloc, win, 0, "sender") orelse continue;
const body = letta.jsonStr(alloc, win, 0, "body") orelse {
alloc.free(sender.val);
continue;
};
events.append(alloc, .{ .sender = sender.val, .body = body.val }) catch {
alloc.free(sender.val);
alloc.free(body.val);
};
}
return .{ .events = try events.toOwnedSlice(alloc), .next = next };
}
/// Create a direct chat room with `peer`; returns room id (allocated).
pub fn createDirect(alloc: std.mem.Allocator, io: Io, token: []const u8, peer: []const u8) ![]u8 {
const body = try std.fmt.allocPrint(alloc,
\\{{"preset":"trusted_private_chat","invite":["{s}"],"is_direct":true}}
, .{peer});
defer alloc.free(body);
const resp = try http(alloc, io, "POST", HOMESERVER ++ "/_matrix/client/v3/createRoom", token, body);
defer alloc.free(resp);
const room = letta.jsonStr(alloc, resp, 0, "room_id") orelse {
std.debug.print("matrix: createRoom failed, resp: {s}\n", .{resp});
return error.CreateFailed;
};
return room.val;
}