|
@@ -2,16 +2,12 @@ const std = @import("std");
|
|
|
const httpz = @import("httpz");
|
|
|
const pg = @import("pg");
|
|
|
const datetimez = @import("datetimez");
|
|
|
-const mustache = @import("mustache");
|
|
|
|
|
|
-const Thread = std.Thread;
|
|
|
-const Mutex = Thread.Mutex;
|
|
|
-const template = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{{#fortunes}}<tr><td>{{id}}</td><td>{{message}}</td></tr>{{/fortunes}}</table></body></html>";
|
|
|
+pub var date_str: []u8 = "";
|
|
|
|
|
|
pub const Global = struct {
|
|
|
pool: *pg.Pool,
|
|
|
rand: *std.rand.Random,
|
|
|
- mutex: std.Thread.Mutex = .{},
|
|
|
};
|
|
|
|
|
|
const World = struct {
|
|
@@ -40,9 +36,7 @@ pub fn json(_: *Global, _: *httpz.Request, res: *httpz.Response) !void {
|
|
|
pub fn db(global: *Global, _: *httpz.Request, res: *httpz.Response) !void {
|
|
|
try setHeaders(res.arena, res);
|
|
|
|
|
|
- global.mutex.lock();
|
|
|
const random_number = 1 + (global.rand.uintAtMostBiased(u32, 9999));
|
|
|
- global.mutex.unlock();
|
|
|
|
|
|
const world = getWorld(global.pool, random_number) catch |err| {
|
|
|
std.debug.print("Error querying database: {}\n", .{err});
|
|
@@ -76,31 +70,37 @@ fn getWorld(pool: *pg.Pool, random_number: u32) !World {
|
|
|
fn setHeaders(allocator: std.mem.Allocator, res: *httpz.Response) !void {
|
|
|
res.header("Server", "Httpz");
|
|
|
|
|
|
- const now = datetimez.datetime.Date.now();
|
|
|
- const time = datetimez.datetime.Time.now();
|
|
|
+ //const now = datetimez.datetime.Date.now();
|
|
|
+ //const time = datetimez.datetime.Time.now();
|
|
|
|
|
|
// Wed, 17 Apr 2013 12:00:00 GMT
|
|
|
// Return date in ISO format YYYY-MM-DD
|
|
|
- const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT";
|
|
|
- const now_str = try std.fmt.allocPrint(allocator, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second });
|
|
|
+ //const TB_DATE_FMT = "{s:0>3}, {d:0>2} {s:0>3} {d:0>4} {d:0>2}:{d:0>2}:{d:0>2} GMT";
|
|
|
+ //const now_str = try std.fmt.allocPrint(allocator, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second });
|
|
|
|
|
|
//defer allocator.free(now_str);
|
|
|
|
|
|
- res.header("Date", now_str);
|
|
|
+ res.header("Date", try allocator.dupe(u8, date_str));
|
|
|
}
|
|
|
|
|
|
fn getFortunesHtml(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const u8 {
|
|
|
const fortunes = try getFortunes(allocator, pool);
|
|
|
|
|
|
- const raw = try mustache.allocRenderText(allocator, template, .{ .fortunes = fortunes });
|
|
|
+ var sb = try std.ArrayListUnmanaged(u8).initCapacity(allocator, 0);
|
|
|
|
|
|
- // std.debug.print("mustache output {s}\n", .{raw});
|
|
|
+ const writer = sb.writer(allocator);
|
|
|
+ try sb.appendSlice(allocator, "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>");
|
|
|
|
|
|
- const html = try deescapeHtml(allocator, raw);
|
|
|
+ for (fortunes) |ft| {
|
|
|
+ try writer.print("<tr><td>{d}</td><td>{s}</td></tr>", .{
|
|
|
+ ft.id,
|
|
|
+ try escape_html(allocator, ft.message),
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
- // std.debug.print("html output {s}\n", .{html});
|
|
|
+ try sb.appendSlice(allocator, "</table></body></html>");
|
|
|
|
|
|
- return html;
|
|
|
+ return sb.toOwnedSlice(allocator);
|
|
|
}
|
|
|
|
|
|
fn getFortunes(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const Fortune {
|
|
@@ -110,18 +110,18 @@ fn getFortunes(allocator: std.mem.Allocator, pool: *pg.Pool) ![]const Fortune {
|
|
|
var rows = try conn.query("SELECT id, message FROM Fortune", .{});
|
|
|
defer rows.deinit();
|
|
|
|
|
|
- var fortunes = std.ArrayList(Fortune).init(allocator);
|
|
|
- defer fortunes.deinit();
|
|
|
+ var fortunes = try std.ArrayListUnmanaged(Fortune).initCapacity(allocator, 0);
|
|
|
+ defer fortunes.deinit(allocator);
|
|
|
|
|
|
while (try rows.next()) |row| {
|
|
|
const current_fortune = Fortune{ .id = row.get(i32, 0), .message = row.get([]const u8, 1) };
|
|
|
- try fortunes.append(current_fortune);
|
|
|
+ try fortunes.append(allocator, current_fortune);
|
|
|
}
|
|
|
|
|
|
const zero_fortune = Fortune{ .id = 0, .message = "Additional fortune added at request time." };
|
|
|
- try fortunes.append(zero_fortune);
|
|
|
+ try fortunes.append(allocator, zero_fortune);
|
|
|
|
|
|
- const fortunes_slice = try fortunes.toOwnedSlice();
|
|
|
+ const fortunes_slice = try fortunes.toOwnedSlice(allocator);
|
|
|
std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage);
|
|
|
|
|
|
return fortunes_slice;
|
|
@@ -131,53 +131,17 @@ fn cmpFortuneByMessage(_: void, a: Fortune, b: Fortune) bool {
|
|
|
return std.mem.order(u8, a.message, b.message).compare(std.math.CompareOperator.lt);
|
|
|
}
|
|
|
|
|
|
-fn deescapeHtml(allocator: std.mem.Allocator, input: []const u8) ![]const u8 {
|
|
|
- var output = std.ArrayList(u8).init(allocator);
|
|
|
- defer output.deinit();
|
|
|
-
|
|
|
- var i: usize = 0;
|
|
|
- while (i < input.len) {
|
|
|
- if (std.mem.startsWith(u8, input[i..], " ")) {
|
|
|
- try output.append(' ');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], """)) {
|
|
|
- try output.append('"');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], "&")) {
|
|
|
- try output.append('&');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], "'")) {
|
|
|
- try output.append('\'');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], "(")) {
|
|
|
- try output.append('(');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], ")")) {
|
|
|
- try output.append(')');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], "+")) {
|
|
|
- try output.append('+');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], ",")) {
|
|
|
- try output.append(',');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], ".")) {
|
|
|
- try output.append('.');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], "/")) {
|
|
|
- try output.append('/');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], ":")) {
|
|
|
- try output.append(':');
|
|
|
- i += 5;
|
|
|
- } else if (std.mem.startsWith(u8, input[i..], ";")) {
|
|
|
- try output.append(';');
|
|
|
- i += 5;
|
|
|
- } else {
|
|
|
- try output.append(input[i]);
|
|
|
- i += 1;
|
|
|
+fn escape_html(allocator: std.mem.Allocator, input: []const u8) ![]const u8 {
|
|
|
+ var output = try std.ArrayListUnmanaged(u8).initCapacity(allocator, 0);
|
|
|
+ defer output.deinit(allocator);
|
|
|
+
|
|
|
+ for (input) |char| {
|
|
|
+ switch (char) {
|
|
|
+ '<' => try output.appendSlice(allocator, "<"),
|
|
|
+ '>' => try output.appendSlice(allocator, ">"),
|
|
|
+ else => try output.append(allocator, char),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return output.toOwnedSlice();
|
|
|
+ return output.toOwnedSlice(allocator);
|
|
|
}
|