Skip to content

Instantly share code, notes, and snippets.

@notcancername
Last active March 3, 2024 00:34
Show Gist options
  • Save notcancername/49f05971b55490250684b79142d1ff4c to your computer and use it in GitHub Desktop.
Save notcancername/49f05971b55490250684b79142d1ff4c to your computer and use it in GitHub Desktop.
zig server-sent events parser
const std = @import("std");
pub const Event = struct {
event: ?[]const u8,
data: ?std.ArrayListUnmanaged(u8),
id: ?[]const u8,
retry: ?u64,
pub fn deinit(event: Event, ally: std.mem.Allocator) void {
inline for (.{ event.event, event.id }) |mx| if (mx) |x| ally.free(x);
if (event.data) |d| {
var mut_d = d;
mut_d.deinit(ally);
}
}
pub const empty = .{ .event = null, .data = null, .id = null, .retry = null };
};
pub const EventStreamParser = struct {
event: Event = Event.empty,
pub fn feed(state: *EventStreamParser, line: []const u8, ally: std.mem.Allocator) !?Event {
if (line.len == 0) {
defer state.event = Event.empty;
// free up some memory
if (state.event.data) |d| d.shrinkAndFree(ally, d.items.len);
return state.event;
}
const index_of_colon = std.mem.indexOfScalar(u8, line, ':') orelse line.len;
if (index_of_colon == 0) return null; // comment
const kind = line[0..index_of_colon];
const raw_value = line[@min(index_of_colon + 1, line.len)..];
const value = if (std.mem.startsWith(u8, raw_value, " ")) raw_value[1..] else raw_value;
if (std.mem.eql(u8, kind, "data")) {
if (state.event.data) |d| {
try d.append(ally, '\n');
} else {
state.event.data = std.ArrayListUnmanaged(u8){};
}
try state.event.data.?.appendSlice(ally, value);
} else if (std.mem.eql(u8, kind, "event")) {
if (state.event.event != null) return error.DuplicateEvent;
state.event.event = try ally.dupe(u8, value);
} else if (std.mem.eql(u8, kind, "id")) {
if (state.event.id != null) return error.DuplicateId;
state.event.id = try ally.dupe(u8, value);
} else if (std.mem.eql(u8, kind, "retry")) {
state.event.retry = std.fmt.parseInt(u64, value, 10) catch null;
}
return null;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment