Compare commits
3 Commits
ec7183c7df
...
5351480102
Author | SHA1 | Date | |
---|---|---|---|
5351480102 | |||
389b6690b0 | |||
dfc82bb4bb |
|
@ -4,8 +4,12 @@
|
||||||
|
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.universal_lambda_build = .{
|
.universal_lambda_build = .{
|
||||||
.url = "https://git.lerch.org/lobo/universal-lambda-zig/archive/ff691a439105ca6800757a39c208c11fcdabb058.tar.gz",
|
.url = "https://git.lerch.org/lobo/universal-lambda-zig/archive/70b0fda03b9c54a6eda8d61cb8ab8b9d9f29b2ef.tar.gz",
|
||||||
.hash = "12205386f7353907deb7f195d920bc028e0e73f53dcd23c5e77210a39b31726bf46f",
|
.hash = "122004f2a4ad253be9b8d7989ca6508af1483d8a593ca7fee93627444b2b37d170d2",
|
||||||
|
},
|
||||||
|
.flexilib = .{
|
||||||
|
.url = "https://git.lerch.org/lobo/flexilib/archive/c44ad2ba84df735421bef23a2ad612968fb50f06.tar.gz",
|
||||||
|
.hash = "122051fdfeefdd75653d3dd678c8aa297150c2893f5fad0728e0d953481383690dbc",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
116
src/helpers.zig
Normal file
116
src/helpers.zig
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
//! This consists of helper functions to provide simple access using standard
|
||||||
|
//! patterns.
|
||||||
|
const std = @import("std");
|
||||||
|
const universal_lambda = @import("universal_lambda_handler");
|
||||||
|
|
||||||
|
const Option = struct {
|
||||||
|
short: []const u8,
|
||||||
|
long: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const target_option: Option = .{ .short = "t", .long = "target" };
|
||||||
|
const header_option: Option = .{ .short = "h", .long = "header" };
|
||||||
|
|
||||||
|
/// Finds the "target" for this request. In a web request, this is the path
|
||||||
|
/// used for the request (e.g. "/" vs "/admin"). In a non-web environment,
|
||||||
|
/// this is determined by a command line option -t or --target. Note that
|
||||||
|
/// AWS API Gateway is not supported here...this is a configured thing in
|
||||||
|
/// API Gateway, and so is pretty situational. It also would be presented in
|
||||||
|
/// event data rather than context
|
||||||
|
pub fn findTarget(allocator: std.mem.Allocator, context: universal_lambda.Context) ![]const u8 {
|
||||||
|
switch (context) {
|
||||||
|
.web_request => |res| return res.request.target,
|
||||||
|
.flexilib => |ctx| return ctx.request.target,
|
||||||
|
.none => return findTargetWithoutContext(allocator),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findTargetWithoutContext(allocator: std.mem.Allocator) ![]const u8 {
|
||||||
|
// without context, we have environment variables (but for this, I think not),
|
||||||
|
// possibly event data (API Gateway does this if so configured),
|
||||||
|
// or the command line. For now we'll just look at the command line
|
||||||
|
var argIterator = try std.process.argsWithAllocator(allocator);
|
||||||
|
_ = argIterator.next();
|
||||||
|
var is_target_option = false;
|
||||||
|
while (argIterator.next()) |arg| {
|
||||||
|
if (is_target_option) {
|
||||||
|
if (std.mem.startsWith(u8, arg, "-") or
|
||||||
|
std.mem.startsWith(u8, arg, "--"))
|
||||||
|
{
|
||||||
|
// bad user input, but we're not returning errors here
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
if (std.mem.startsWith(u8, arg, "-" ++ target_option.short) or
|
||||||
|
std.mem.startsWith(u8, arg, "--" ++ target_option.long))
|
||||||
|
{
|
||||||
|
// We'll search for --target=blah style first
|
||||||
|
var split = std.mem.splitSequence(u8, arg, "=");
|
||||||
|
_ = split.next();
|
||||||
|
if (split.next()) |s| return s; // found it
|
||||||
|
is_target_option = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFirstHeaderValue(allocator: std.mem.Allocator, context: universal_lambda.Context, header_name: []const u8) !?[]const u8 {
|
||||||
|
switch (context) {
|
||||||
|
.web_request => |res| return res.request.headers.getFirstValue(header_name),
|
||||||
|
.flexilib => |ctx| {
|
||||||
|
for (ctx.request.headers) |hdr| {
|
||||||
|
if (std.ascii.eqlIgnoreCase(hdr.name_ptr[0..hdr.name_len], header_name)) {
|
||||||
|
return hdr.value_ptr[0..hdr.value_len];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
.none => return findHeaderWithoutContext(allocator, header_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findHeaderWithoutContext(allocator: std.mem.Allocator, header_name: []const u8) !?[]const u8 {
|
||||||
|
// without context, we have environment variables
|
||||||
|
// possibly event data (API Gateway does this if so configured),
|
||||||
|
// or the command line. For headers, we'll prioritize command line options
|
||||||
|
// with a fallback to environment variables
|
||||||
|
var argIterator = try std.process.argsWithAllocator(allocator);
|
||||||
|
_ = argIterator.next();
|
||||||
|
var is_header_option = false;
|
||||||
|
while (argIterator.next()) |arg| {
|
||||||
|
if (is_header_option) {
|
||||||
|
if (std.mem.startsWith(u8, arg, "-") or
|
||||||
|
std.mem.startsWith(u8, arg, "--"))
|
||||||
|
{
|
||||||
|
return error.CommandLineError;
|
||||||
|
}
|
||||||
|
var split = std.mem.splitSequence(u8, arg, "=");
|
||||||
|
const name = split.next().?;
|
||||||
|
if (!std.ascii.eqlIgnoreCase(name, header_name)) continue;
|
||||||
|
if (split.next()) |s| return s; // found it
|
||||||
|
continue; // bad format, but we're not returning errors. We can cope with this one though
|
||||||
|
}
|
||||||
|
if (std.mem.startsWith(u8, arg, "-" ++ header_option.short) or
|
||||||
|
std.mem.startsWith(u8, arg, "--" ++ header_option.long))
|
||||||
|
{
|
||||||
|
// header option forms on command line:
|
||||||
|
// -h name=value
|
||||||
|
// --header name=value
|
||||||
|
is_header_option = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found on command line. Let's check environment
|
||||||
|
var map = try std.process.getEnvMap(allocator);
|
||||||
|
defer map.deinit();
|
||||||
|
var it = map.iterator();
|
||||||
|
while (it.next()) |kvp| {
|
||||||
|
// TODO: This is the only place where allocation is necessary. This
|
||||||
|
// will work, because in reality there is always an area allocator passed
|
||||||
|
// to us. But if there's not....
|
||||||
|
if (std.ascii.eqlIgnoreCase(kvp.key_ptr.*, header_name))
|
||||||
|
return try allocator.dupe(u8, kvp.value_ptr.*);
|
||||||
|
}
|
||||||
|
return null; // nowhere to be found
|
||||||
|
}
|
17
src/main.zig
17
src/main.zig
|
@ -1,13 +1,20 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const universal_lambda = @import("universal_lambda_handler");
|
const universal_lambda = @import("universal_lambda_handler");
|
||||||
|
const helpers = @import("helpers.zig"); // not necessary, but these functions provide common access to common things
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
try universal_lambda.run(null, handler);
|
try universal_lambda.run(null, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handler(allocator: std.mem.Allocator, event_data: []const u8, context: universal_lambda.Context) ![]const u8 {
|
pub fn handler(allocator: std.mem.Allocator, event_data: []const u8, context: universal_lambda.Context) ![]const u8 {
|
||||||
_ = event_data;
|
// our allocator is an area, so yolo
|
||||||
_ = allocator;
|
const target = try helpers.findTarget(allocator, context);
|
||||||
_ = context;
|
var al = std.ArrayList(u8).init(allocator);
|
||||||
return "hello world";
|
var writer = al.writer();
|
||||||
|
var args = try std.process.argsWithAllocator(allocator);
|
||||||
|
while (args.next()) |arg| {
|
||||||
|
try writer.print("\tcalled with arg: {s}\n", .{arg});
|
||||||
|
}
|
||||||
|
try writer.print("(target: {s}) Event data, from you, to me, to you: {s}\n", .{ target, event_data });
|
||||||
|
try writer.print("Value for header 'Foo' is: {s}\n", .{try helpers.getFirstHeaderValue(allocator, context, "foo") orelse "undefined"});
|
||||||
|
return al.items;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user