Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
voigt committed Aug 14, 2023
1 parent 28f5073 commit 1a26de5
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 82 deletions.
38 changes: 34 additions & 4 deletions kits/zig/worker/examples/main.zig
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
const std = @import("std");
const w = @import("worker");
const io = std.io;
const http = std.http;
const worker = @import("worker");

var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena.allocator();

// Not working with *http.Server.Response
// fn cool(resp: *http.Server.Response, r: *http.Client.Request) void {
fn requestFn(resp: *worker.Response, r: *http.Client.Request) void {
_ = r;
std.debug.print("Hello from function\n", .{ });

// std.debug.print("+++ doing payload \n", .{ });
// var payload: []const u8 = "";
// var reqBody = r.reader().readAllAlloc(allocator, 8192) catch unreachable;
// defer allocator.free(reqBody);

// if (reqBody.len == 0) {
// payload = "-";
// } else {
// payload = reqBody;
// }
// std.debug.print("+++ finished payload \n", .{ });

// var resp = r.response;

_ = &resp.httpHeader.append("content-type", "text/plain");
_ = &resp.httpHeader.append("x-generated-by", "wasm-workers-server");

_ = &resp.writeAll("Zig World!");
}

pub fn main() !void {
var word = w.GetWord();
std.debug.print("Hello from {s}!\n", .{ word });
}
worker.ServeFunc(requestFn);
}
196 changes: 118 additions & 78 deletions kits/zig/worker/src/worker.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,41 @@ const std = @import("std");
const io = std.io;
const http = std.http;

pub fn GetWord() []const u8 {
return "lib";
// This is from ChatGPT - I have no clue whether this works, nor whats going on here :D
fn isValidUtf8(data: []const u8) bool {
var i: usize = 0;
while (i < data.len) {
const byte: u8 = data[i];
if (byte < 0x80) {
// ASCII character
i += 1;
} else if (byte < 0xC2) {
// Invalid continuation byte
return false;
} else if (byte < 0xE0) {
// 2-byte sequence
if ((i + 1 >= data.len) or ((data[i + 1] & 0xC0) != 0x80)) {
return false;
}
i += 2;
} else if (byte < 0xF0) {
// 3-byte sequence
if ((i + 2 >= data.len) or ((data[i + 1] & 0xC0) != 0x80) or ((data[i + 2] & 0xC0) != 0x80)) {
return false;
}
i += 3;
} else if (byte < 0xF5) {
// 4-byte sequence
if ((i + 3 >= data.len) or ((data[i + 1] & 0xC0) != 0x80) or ((data[i + 2] & 0xC0) != 0x80) or ((data[i + 3] & 0xC0) != 0x80)) {
return false;
}
i += 4;
} else {
// Invalid UTF-8 byte
return false;
}
}
return true;
}

var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
Expand All @@ -15,7 +48,7 @@ pub var params = std.StringHashMap([]const u8).init(allocator);
pub const Input = struct {
url: []const u8,
method: []const u8,
headers: std.StringHashMap([]const u8),
headers: std.StringArrayHashMap([]const u8),
body: []const u8,
};

Expand Down Expand Up @@ -52,7 +85,7 @@ pub const Output = struct {
}

pub fn write(self: *Self, data: []const u8) !u32 {
// if (isValidUtf8(data)) {

if (isValidUtf8(data)) {
self.data = data;
} else {
Expand All @@ -67,17 +100,15 @@ pub const Output = struct {
self.status = 200;
}

// self.headers.init(allocator); // can we init thissomewhere else?
for (self.httpHeader.list.items) |item| {
std.debug.print("Fields: {!}\n", .{item});
// try self.headers.put(item.name, item.value);
try self.headers.put(item.name, item.value);
}

// prepare writer for json
var out_buf: [1024]u8 = undefined;
var slice_stream = std.io.fixedBufferStream(&out_buf);
const out = slice_stream.writer();
var w = std.json.writeStream(out, .{ .whitespace = .indent_2 });
var w = std.json.writeStream(out, .{ .whitespace = .minified });

slice_stream.reset();
try w.beginObject();
Expand All @@ -92,7 +123,6 @@ pub const Output = struct {
try w.write(self.base64);

try w.objectField("headers");
try self.headers.put("hello", "world");
try w.write(try getHeadersJsonObject(self.headers));

try cache.put("hello", "world");
Expand All @@ -102,8 +132,10 @@ pub const Output = struct {
try w.endObject();
const result = slice_stream.getWritten();

std.debug.print("output json: {s}\n", .{ result });

// I assume this works, as no stdout seems to be logged by wws, only stderr
// https://zig.news/kristoff/where-is-print-in-zig-57e9
// std.debug.print("{s}", .{out});
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}", .{result});

Expand Down Expand Up @@ -144,14 +176,15 @@ pub fn readInput() !Input {
// delimiter "\n" might not be adequate?
if (r.readUntilDelimiterOrEof(&msg_buf, '\n')) |msg| {
if (msg) | m | {
std.debug.print("json: {s}\n", .{m});
std.debug.print("raw input json: {s}\n", .{m});
return getInput(m);
}
} else |err| {
std.debug.print("error parsing json: {!}\n", .{err});
}

return Input{};
// TODO: proper return value
return undefined;
}

fn getInput(s: []const u8) !Input {
Expand All @@ -162,26 +195,31 @@ fn getInput(s: []const u8) !Input {
.url = parsed.value.object.get("url").?.string,
.method = parsed.value.object.get("method").?.string,
.body = parsed.value.object.get("body").?.string,
.headers = std.StringHashMap([]const u8).init(allocator),
.headers = std.StringArrayHashMap([]const u8).init(allocator),
};

var headers_map = parsed.value.object.get("headers").?.object;

// can we maybe use an iterator here?
// var i = headers_map.iterator();
// while (i.next()) |kv| {
// try input.headers.put(kv.key_ptr.*.string, kv.value_ptr.*.string);
// }

// std.debug.print("headers1: {!}", .{ input.headers });

for (headers_map.keys()) |key| {
var v = try headers_map.getOrPut(key);
if (v.found_existing) {
var value = v.value_ptr.*.string;
std.debug.print("headers key: {s}, value: {s}\n", .{key, value});
// std.debug.print("headers key: {s}, value: {s}\n", .{key, value});
try input.headers.put(key, value);
}
}

return input;
}



pub fn createRequest(in: *Input) !http.Client.Request {

// Create an HTTP client.
Expand All @@ -190,90 +228,92 @@ pub fn createRequest(in: *Input) !http.Client.Request {
defer client.deinit();
// Parse the URI.

var req = client.Request{
.uri = in.url,
.method = in.method,
.headers = in.headers,
var req = http.Client.Request{
.client = &client,
.uri = try std.Uri.parseWithoutScheme(in.url),
.method = http.Method.GET,
.arena = arena,
.connection = null,
.headers = http.Headers.init(allocator),
.redirects_left = 0,
.handle_redirects = false,
.response = undefined,
};

// is it even necessary to copy headers from Input to Request struct?
var i = in.headers.iterator();
while (i.next()) |kv| {
try req.headers.append(kv.key_ptr.*, kv.value_ptr.*);
}

// req = req.WithContext(context.WithValue(req.Context(), CacheKey, cache));
// req = req.WithContext(context.WithValue(req.Context(), ParamsKey, params));

return req;
}

pub fn getWriterRequest() !@This() {
var in = readInput(allocator) catch |err| {
std.debug.print("error reading input: {s}\n", .{err});
const RequestAndOutput = struct {
req: http.Client.Request,
output: Output,
};

pub fn getWriterRequest() !RequestAndOutput {

var in = readInput() catch |err| {
std.debug.print("error reading input: {!}\n", .{err});
return std.os.exit(1);
};

var req = createRequest(&in, allocator) catch |err| {
std.debug.print("error creating request : {s}\n", .{err});
var req = createRequest(&in) catch |err| {
std.debug.print("error creating request : {!}\n", .{err});
return std.os.exit(1);
};

var w = Output{
.headers = std.StringHashMap([]const u8).init(allocator),
};
var output = Output.init();

return .{
return RequestAndOutput{
.req = req,
.w = w,
.output = output,
};
}

// works
// pub fn ServeFunc(f: anytype) void {
// f();
// }
pub const Response = struct {
data: []const u8,
httpHeader: http.Headers,

pub fn writeAll(self: *Response, data: []const u8) !u32 {
self.data = data;
return self.data.len;
}
};

// works as function budy, must be comptime-known
// pub fn ServeFunc(comptime cool: fn () void) void {
// cool();
// }
// Function parameter as function pointer
pub fn ServeFunc(requestFn: *const fn (*Response, *http.Client.Request) void) void {
var r = try getWriterRequest();
var request = r.req;
var output = r.output;

// works as function pointer
pub fn ServeFunc(cool: *const fn (*http.Server.Response) void) void {
var r = try getWriterRequest(allocator);
cool(r.req);
}
var response = Response{ .data = "", .httpHeader = http.Headers.init(allocator) };
requestFn(&response, &request);

// TODO: do we need request.headers in response?
// output.httpHeader = request.headers;
output.httpHeader = response.httpHeader;

// This is from ChatGPT - I have no clue whether this works, nor whats going on here :D
fn isValidUtf8(data: []const u8) bool {
var i: usize = 0;
while (i < data.len) {
const byte: u8 = data[i];
if (byte < 0x80) {
// ASCII character
i += 1;
} else if (byte < 0xC2) {
// Invalid continuation byte
return false;
} else if (byte < 0xE0) {
// 2-byte sequence
if ((i + 1 >= data.len) || ((data[i + 1] & 0xC0) != 0x80)) {
return false;
}
i += 2;
} else if (byte < 0xF0) {
// 3-byte sequence
if ((i + 2 >= data.len) || ((data[i + 1] & 0xC0) != 0x80) || ((data[i + 2] & 0xC0) != 0x80)) {
return false;
}
i += 3;
} else if (byte < 0xF5) {
// 4-byte sequence
if ((i + 3 >= data.len) || ((data[i + 1] & 0xC0) != 0x80) || ((data[i + 2] & 0xC0) != 0x80) || ((data[i + 3] & 0xC0) != 0x80)) {
return false;
}
i += 4;
} else {
// Invalid UTF-8 byte
return false;
}
}
return true;
_ = output.write(response.data) catch |err| {
std.debug.print("error writing data: {!} \n", .{ err });
};

std.debug.print("Done.\n", .{ });
}


// Alternative ways for function parameter
// pub fn ServeFunc(requestFn: anytype) void {
// requestFn();
// }

// works as function budy, must be comptime-known
// pub fn ServeFunc(comptime requestFn: fn () void) void {
// requestFn();
// }

0 comments on commit 1a26de5

Please sign in to comment.