Compare commits

..

No commits in common. "a2426dee1cb346446f360c6fd1a6d970bf6ca91b" and "717e545e349faae7ef9c2b3f89969166306d7deb" have entirely different histories.

3 changed files with 0 additions and 319 deletions

4
.gitignore vendored
View file

@ -1,4 +0,0 @@
out
.genorg-cache

View file

@ -1,18 +0,0 @@
const std = @import("std");
// zig fetch --save git+https://github.com/karlseguin/http.zig#master
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "genserve",
.root_source_file = b.path("src/main.zig"),
.target = b.graph.host,
});
const httpz = b.dependency("httpz", .{
.target = b.graph.host,
// .optimize = .standardOptimizeOption
});
exe.root_module.addImport("httpz", httpz.module("httpz"));
b.installArtifact(exe);
}

View file

@ -1,297 +0,0 @@
const std = @import("std");
const httpz = @import("httpz");
const expect = std.testing.expect;
const log = std.log.info;
const Allocator = std.mem.Allocator;
const IdStruct = struct {
blog_file: []const u8,
landing: []const u8,
blog_dir: []const u8,
main_rss_url: []const u8,
rss_dir: []const u8,
main_rss: []const u8,
files: []struct {
art: []const u8,
cat: []const u8,
file: []const u8,
},
cpath: []struct {
file: []const u8,
rss: []const u8,
cat: []const u8
},
};
pub var fo_flags: std.fs.File.OpenFlags = .{.mode = .read_only, .lock = .shared};
pub var cat_path_hash: std.StringHashMap(std.fs.File) = undefined;
pub var cat_rss_hash: std.StringHashMap(std.fs.File) = undefined;
pub var url_path_hash: std.StringHashMap(std.StringHashMap(std.fs.File)) = undefined;
pub var cwd: std.fs.Dir = undefined;
pub const max_buf_size = 1000000000;
pub var blog_file_h: std.fs.File = undefined;
pub var main_rss_h: std.fs.File = undefined;
pub var land_h: std.fs.File = undefined;
pub var server: httpz.Server(void) = undefined;
pub var server_on: bool = true;
fn interrupt(_ : i32) callconv(.C) void {
server.stop();
server_on = false;
}
pub fn main() !void {
var sa: std.posix.Sigaction = .{
.handler = .{ .handler = interrupt },
.mask = std.posix.empty_sigset,
.flags = std.posix.SA.RESTART,
};
std.posix.sigaction(std.posix.SIG.INT, &sa, null);
cwd = std.fs.cwd();
defer { cwd.close(); }
var json_file: []const u8 = ".genorg.json";
var args = std.process.args();
defer { args.deinit(); }
_ = args.skip();
if (args.next()) |val| {
cwd = cwd.openDir(val, .{}) catch {
log("Could not find directory {s}", .{val});
return;
};
if (args.next()) |v| {
json_file = v;
}
}
log("Using file {s}", .{json_file});
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alctr = gpa.allocator();
defer {
const deinit_status = gpa.deinit();
if (deinit_status == .leak) expect(false) catch @panic("TEST FAIL");
}
const file =
cwd.openFile(json_file, fo_flags) catch {
log("Could not find file {s}", .{json_file});
return;
};
defer file.close();
var reader = std.json.reader(alctr, file.reader());
defer reader.deinit();
const dom =
try std.json.parseFromTokenSource(IdStruct, alctr, &reader, .{});
defer dom.deinit();
log("{s}", .{dom.value.blog_file});
// We use arena allocator to help mitigate memory fragmentation
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const alctr2 = arena.allocator();
url_path_hash = std.StringHashMap(std.StringHashMap(std.fs.File)).init(alctr2);
defer {
var it = url_path_hash.valueIterator();
while (it.next()) |key| {
var it2 = key.valueIterator();
while (it2.next()) |val| {
val.close();
}
key.deinit();
}
url_path_hash.deinit();
}
for (dom.value.files) |fc| {
const res = url_path_hash.getPtr(fc.cat);
log("[{s}]->[{s}] = {s}", .{fc.cat,fc.art,fc.file});
const fh = try cwd.openFile(fc.file, fo_flags);
if (res) |p| {
try p.*.put(fc.art, fh);
} else {
var newmap = std.StringHashMap(std.fs.File).init(alctr2);
try newmap.put(fc.art, fh);
try url_path_hash.put(fc.cat, newmap);
}
}
cat_path_hash = std.StringHashMap(std.fs.File).init(alctr2);
cat_rss_hash = std.StringHashMap(std.fs.File).init(alctr2);
defer cat_path_hash.deinit();
for (dom.value.cpath) |s| {
const fh = try cwd.openFile(s.file, fo_flags);
log("File {s}", .{s.file});
try cat_path_hash.put(s.cat, fh);
const rfh = try cwd.openFile(s.rss, fo_flags);
try cat_rss_hash.put(s.cat, rfh);
}
defer {
var it = cat_path_hash.valueIterator();
while (it.next()) |val| {
val.close();
}
it = cat_rss_hash.valueIterator();
while (it.next()) |val| {
val.close();
}
}
// Now that we have done all the json stuff, we need to init web server now.
server = try httpz.Server(void).init(alctr, .{.port = 9669}, {});
defer {
if (server_on) {
server.stop();
}
server.deinit();
}
var router = try server.router(.{});
// We open the main file and the blog file
blog_file_h = try cwd.openFile(dom.value.blog_file, fo_flags);
defer blog_file_h.close();
main_rss_h = try cwd.openFile(dom.value.main_rss, fo_flags);
defer main_rss_h.close();
log("Landing file set to {s}", .{dom.value.landing});
land_h = try cwd.openFile(dom.value.landing, fo_flags);
defer land_h.close();
// This is a speical value, we make this sepcial in perl file
log("rss_dir is {s}", .{dom.value.rss_dir});
log("main rss url is {s}", .{dom.value.main_rss_url});
router.get(dom.value.main_rss_url,
struct {fn f(_: *httpz.Request, res: *httpz.Response) !void {
res.body = try main_rss_h.readToEndAlloc(res.arena, max_buf_size);
try main_rss_h.seekTo(0);
}}.f
,.{});
router.get(dom.value.rss_dir,
struct {fn f(req: *httpz.Request, res: *httpz.Response) !void {
const fh = cat_rss_hash.get(req.param("cat").?);
if (fh) |ff| {
res.body = try ff.readToEndAlloc(res.arena, max_buf_size);
try ff.seekTo(0);
} else {
res.body = "Not found";
}
}}.f
, .{});
router.get("/", struct {fn f(_: *httpz.Request, res: *httpz.Response) !void {
res.body = try land_h.readToEndAlloc(res.arena, max_buf_size);
try land_h.seekTo(0);
}}.f, .{});
var blog_routes = router.group(dom.value.blog_dir, .{});
blog_routes.get("/", struct {fn f(_: *httpz.Request, res: *httpz.Response) !void {
res.body = try blog_file_h.readToEndAlloc(res.arena, max_buf_size);
try blog_file_h.seekTo(0);
}}.f, .{});
blog_routes.get("/:cc", getCat, .{});
blog_routes.get("/:cat/:id", getArt, .{});
router.all("/*", getFile, .{});
log("Starting http server", .{});
try server.listen();
log("Shutting down", .{});
}
fn char_to_correct_number (c: u8) ?u8 {
if (c > 'F') {
return null;
}
if (c > 58) {
return c - 55;
} else {
return c - 48;
}
}
fn getFile (req: *httpz.Request, res: *httpz.Response) !void {
const strlen = req.url.path.len - 1;
if (strlen <= 1) {
return;
}
const path = req.url.path[1..];
var ci: usize = 0;
if (path[0] == req.url.path[0]) {
res.body = "Nice try, not tolerating it";
return;
}
var output = try res.arena.alloc(u8, strlen);
{
var pi: usize = 0;
while (pi < strlen) : (ci += 1) {
const char = path[pi];
if (char == '%') {
// We convert the hex to decimal
pi += 1;
const a = char_to_correct_number(path[pi]) orelse {
res.body = "Nice try";
return;
};
pi += 1;
const b = char_to_correct_number(path[pi]) orelse {
res.body = "Nice try";
return;
};
output[ci] = (a * 16) + b;
pi += 1;
} else {
output[ci] = char;
pi += 1;
}
}
}
var file = cwd.openFile(output[0..ci], fo_flags) catch {
res.body = "Not found";
return;
};
defer file.close();
res.body = try file.readToEndAlloc(res.arena, max_buf_size);
}
fn getCat(req: *httpz.Request, res: *httpz.Response) !void {
const fh = cat_path_hash.get(req.param("cc").?);
if (fh) |f| {
res.body = try f.readToEndAlloc(res.arena, max_buf_size);
try f.seekTo(0);
} else {
res.body = "Not found";
}
}
fn getArt(req: *httpz.Request, res: *httpz.Response) !void {
res.status = 200;
const chash = url_path_hash.get(req.param("cat").?);
if (chash) |ch| {
const ahash = ch.get(req.param("id").?);
if (ahash) |fh| {
// This means we show the article
res.body = try fh.readToEndAlloc(res.arena, max_buf_size);
try fh.seekTo(0);
} else {
res.body = "Not found";
}
} else {
res.body = "Not found";
}
}