milestone 8: web server, rest api, sse, auth, metrics and static assets
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
//! `GET /api/version` — what this binary is and how long it has been running.
|
||||
//!
|
||||
//! Unauthenticated (ruling 18), like the other monitoring endpoints. The three
|
||||
//! strings are build options, so nothing here reads the running configuration.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const http_util = @import("../http_util.zig");
|
||||
const server = @import("../server.zig");
|
||||
const version = @import("../../version.zig");
|
||||
|
||||
pub const Body = struct {
|
||||
version: []const u8,
|
||||
git_commit: []const u8,
|
||||
zig_version: []const u8,
|
||||
/// Seconds since the process started. Zero until `started_unix` is wired,
|
||||
/// and never negative: a clock stepped backwards must not report a
|
||||
/// process that started in the future.
|
||||
uptime_seconds: u64,
|
||||
};
|
||||
|
||||
pub fn handle(
|
||||
state: *server.WebState,
|
||||
io: std.Io,
|
||||
request: *http_util.Request,
|
||||
) http_util.HandlerError!void {
|
||||
const now = std.Io.Clock.real.now(io).toSeconds();
|
||||
return http_util.respondJson(request, .ok, body(state.version, state.started_unix, now), &.{});
|
||||
}
|
||||
|
||||
pub fn body(version_string: []const u8, started_unix: i64, now_unix: i64) Body {
|
||||
return .{
|
||||
.version = if (version_string.len == 0) version.string else version_string,
|
||||
.git_commit = version.git_commit,
|
||||
.zig_version = version.zig_version_string,
|
||||
.uptime_seconds = uptime(started_unix, now_unix),
|
||||
};
|
||||
}
|
||||
|
||||
fn uptime(started_unix: i64, now_unix: i64) u64 {
|
||||
if (started_unix <= 0 or now_unix <= started_unix) return 0;
|
||||
return @intCast(now_unix - started_unix);
|
||||
}
|
||||
|
||||
const testing = std.testing;
|
||||
|
||||
test "the body carries the build strings and the elapsed time" {
|
||||
const out = body("", 1_000, 1_060);
|
||||
try testing.expectEqualStrings(version.string, out.version);
|
||||
try testing.expectEqualStrings(version.git_commit, out.git_commit);
|
||||
try testing.expectEqualStrings(version.zig_version_string, out.zig_version);
|
||||
try testing.expectEqual(@as(u64, 60), out.uptime_seconds);
|
||||
}
|
||||
|
||||
test "the state's version string wins over the compiled-in one" {
|
||||
try testing.expectEqualStrings("9.9.9", body("9.9.9", 0, 0).version);
|
||||
}
|
||||
|
||||
test "an unset start time and a clock that stepped back both read as zero uptime" {
|
||||
try testing.expectEqual(@as(u64, 0), body("", 0, 5_000).uptime_seconds);
|
||||
try testing.expectEqual(@as(u64, 0), body("", 5_000, 4_000).uptime_seconds);
|
||||
}
|
||||
|
||||
test "the body serializes with snake_case field names" {
|
||||
var buffer: [256]u8 = undefined;
|
||||
var writer: std.Io.Writer = .fixed(&buffer);
|
||||
try std.json.Stringify.value(body("1.2.3", 10, 20), .{}, &writer);
|
||||
const text = writer.buffered();
|
||||
try testing.expect(std.mem.containsAtLeast(u8, text, 1, "\"git_commit\":"));
|
||||
try testing.expect(std.mem.containsAtLeast(u8, text, 1, "\"zig_version\":"));
|
||||
try testing.expect(std.mem.containsAtLeast(u8, text, 1, "\"uptime_seconds\":10"));
|
||||
}
|
||||
Reference in New Issue
Block a user