Compare commits

..

2 commits

Author SHA1 Message Date
79213a991d
temporary force nightly to home server
All checks were successful
AWS-Zig Build / build-zig-amd64-host (push) Successful in 7m46s
On the home server, git.lerch.org will resolve to
an A record (split-horizon DNS). This works around
https://github.com/ziglang/zig/issues/25811.
2025-11-06 13:08:21 -08:00
0e63e501db
add note about nightly build
All checks were successful
AWS-Zig Build / build-zig-amd64-host (push) Successful in 7m48s
2025-11-06 12:37:30 -08:00
15 changed files with 78 additions and 131 deletions

View file

@ -1,5 +1,5 @@
[tools] [tools]
pre-commit = "latest" pre-commit = "latest"
"ubi:DonIsaac/zlint" = "latest" "ubi:DonIsaac/zlint" = "latest"
zig = "master" zig = "0.15.1"
zls = "0.15.0" zls = "0.15.0"

View file

@ -9,6 +9,8 @@ AWS SDK for Zig
[![Build Status: Zig Nightly](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-nightly.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-nightly.yaml&state=closed) [![Build Status: Zig Nightly](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-nightly.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-nightly.yaml&state=closed)
**NOTE**: Nightly should be working currently, but a [bug in the http Client](https://github.com/ziglang/zig/issues/25811) is breaking the example
[Zig 0.14.1](https://ziglang.org/download/#release-0.14.1): [Zig 0.14.1](https://ziglang.org/download/#release-0.14.1):
[![Build Status: Zig 0.14.x](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-previous.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-previous.yaml&state=closed) [![Build Status: Zig 0.14.x](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-previous.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-previous.yaml&state=closed)

View file

@ -15,13 +15,17 @@
.dependencies = .{ .dependencies = .{
.smithy = .{ .smithy = .{
.url = "git+https://github.com/elerch/smithy.git#5882330451ac6379829af16dd87b66f9fbae6f24", .url = "git+https://git.lerch.org/lobo/smithy.git#09c0a618877ebaf8e15fbfc505983876f4e063d5",
.hash = "smithy-1.0.0-uAyBgV7TAgBIOKSaTb0Bvy6ndj0qFn9mAD375E_3F4yR", .hash = "smithy-1.0.0-uAyBgTnTAgBp2v6vypGcK5-YOCtxs2iEqR-4LfC5FTlS",
}, },
.models = .{ .models = .{
.url = "https://github.com/aws/aws-sdk-go-v2/archive/refs/tags/release-2025-05-05.tar.gz", .url = "https://github.com/aws/aws-sdk-go-v2/archive/refs/tags/release-2025-05-05.tar.gz",
.hash = "N-V-__8AAKWdeiawujEcrfukQbb8lLAiQIRT0uG5gCcm4b7W", .hash = "N-V-__8AAKWdeiawujEcrfukQbb8lLAiQIRT0uG5gCcm4b7W",
}, },
.zeit = .{
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
.hash = "zeit-0.6.0-5I6bk0J9AgCVa0nnyL0lNY9Xa9F68hHq-ZarhuXNV-Jb",
},
.date = .{ .date = .{
.path = "lib/date", .path = "lib/date",
}, },
@ -32,9 +36,5 @@
.url = "git+https://github.com/travisstaloch/case.git#f8003fe5f93b65f673d10d41323e347225e8cb87", .url = "git+https://github.com/travisstaloch/case.git#f8003fe5f93b65f673d10d41323e347225e8cb87",
.hash = "case-0.0.1-chGYqx_EAADaGJjmoln5M1iMBDTrMdd8to5wdEVpfXm4", .hash = "case-0.0.1-chGYqx_EAADaGJjmoln5M1iMBDTrMdd8to5wdEVpfXm4",
}, },
.zeit = .{
.url = "git+https://github.com/elerch/zeit#8190461dc1f892f6370fa9d5cd76690aac0e1c71",
.hash = "zeit-0.6.0-5I6bk99-AgDNMIDuw2Zcoe_9QYIpzwZJqeqMpU54egTd",
},
}, },
} }

View file

@ -33,10 +33,6 @@ pub fn main() anyerror!void {
defer arena.deinit(); defer arena.deinit();
const allocator = arena.allocator(); const allocator = arena.allocator();
var threaded: std.Io.Threaded = .init(allocator);
defer threaded.deinit();
const io = threaded.io();
const args = try std.process.argsAlloc(allocator); const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args); defer std.process.argsFree(allocator, args);
var stdout_writer = std.fs.File.stdout().writer(&.{}); var stdout_writer = std.fs.File.stdout().writer(&.{});
@ -83,7 +79,7 @@ pub fn main() anyerror!void {
skip_next = true; skip_next = true;
continue; continue;
} }
try processFile(io, arg, output_dir, &manifest); try processFile(arg, output_dir, &manifest);
files_processed += 1; files_processed += 1;
} }
if (files_processed == 0) { if (files_processed == 0) {
@ -97,12 +93,12 @@ pub fn main() anyerror!void {
defer cwd.setAsCwd() catch unreachable; defer cwd.setAsCwd() catch unreachable;
try m.setAsCwd(); try m.setAsCwd();
try processDirectories(io, m, output_dir, &root_progress_node); try processDirectories(m, output_dir, &root_progress_node);
} }
} }
if (args.len == 0) if (args.len == 0)
_ = try generateServices(allocator, io, ";", std.fs.File.stdin(), stdout); _ = try generateServices(allocator, ";", std.fs.File.stdin(), stdout);
if (verbose) { if (verbose) {
const output_path = try output_dir.realpathAlloc(allocator, "."); const output_path = try output_dir.realpathAlloc(allocator, ".");
@ -114,7 +110,7 @@ const OutputManifest = struct {
model_dir_hash_digest: [Hasher.hex_multihash_len]u8, model_dir_hash_digest: [Hasher.hex_multihash_len]u8,
output_dir_hash_digest: [Hasher.hex_multihash_len]u8, output_dir_hash_digest: [Hasher.hex_multihash_len]u8,
}; };
fn processDirectories(io: std.Io, models_dir: std.fs.Dir, output_dir: std.fs.Dir, parent_progress: *const std.Progress.Node) !void { fn processDirectories(models_dir: std.fs.Dir, output_dir: std.fs.Dir, parent_progress: *const std.Progress.Node) !void {
// Let's get ready to hash!! // Let's get ready to hash!!
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
@ -158,7 +154,7 @@ fn processDirectories(io: std.Io, models_dir: std.fs.Dir, output_dir: std.fs.Dir
while (try mi.next()) |e| { while (try mi.next()) |e| {
if ((e.kind == .file or e.kind == .sym_link) and std.mem.endsWith(u8, e.name, ".json")) { if ((e.kind == .file or e.kind == .sym_link) and std.mem.endsWith(u8, e.name, ".json")) {
try processFile(io, e.name, output_dir, &manifest.interface); try processFile(e.name, output_dir, &manifest.interface);
generating_models_progress.completeOne(); generating_models_progress.completeOne();
} }
} }
@ -214,7 +210,7 @@ fn calculateDigests(models_dir: std.fs.Dir, output_dir: std.fs.Dir, thread_pool:
}, },
}; };
} }
fn processFile(io: std.Io, file_name: []const u8, output_dir: std.fs.Dir, manifest: *std.Io.Writer) !void { fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: *std.Io.Writer) !void {
// It's probably best to create our own allocator here so we can deint at the end and // It's probably best to create our own allocator here so we can deint at the end and
// toss all allocations related to the services in this file // toss all allocations related to the services in this file
// I can't guarantee we're not leaking something, and at the end of the // I can't guarantee we're not leaking something, and at the end of the
@ -241,7 +237,6 @@ fn processFile(io: std.Io, file_name: []const u8, output_dir: std.fs.Dir, manife
const service_names = generateServicesForFilePath( const service_names = generateServicesForFilePath(
allocator, allocator,
io,
";", ";",
file_name, file_name,
writer, writer,
@ -293,14 +288,13 @@ fn zigFmt(allocator: std.mem.Allocator, buffer: [:0]const u8) ![]const u8 {
fn generateServicesForFilePath( fn generateServicesForFilePath(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
io: std.Io,
comptime terminator: []const u8, comptime terminator: []const u8,
path: []const u8, path: []const u8,
writer: *std.Io.Writer, writer: *std.Io.Writer,
) ![][]const u8 { ) ![][]const u8 {
const file = try std.fs.cwd().openFile(path, .{}); const file = try std.fs.cwd().openFile(path, .{});
defer file.close(); defer file.close();
return try generateServices(allocator, io, terminator, file, writer); return try generateServices(allocator, terminator, file, writer);
} }
fn addReference(id: []const u8, map: *std.StringHashMap(u64)) !void { fn addReference(id: []const u8, map: *std.StringHashMap(u64)) !void {
@ -402,13 +396,12 @@ fn countReferences(
fn generateServices( fn generateServices(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
io: std.Io,
comptime _: []const u8, comptime _: []const u8,
file: std.fs.File, file: std.fs.File,
writer: *std.Io.Writer, writer: *std.Io.Writer,
) ![][]const u8 { ) ![][]const u8 {
var fbuf: [1024]u8 = undefined; var fbuf: [1024]u8 = undefined;
var freader = file.reader(io, &fbuf); var freader = file.reader(&fbuf);
var reader = &freader.interface; var reader = &freader.interface;
const json = try reader.allocRemaining(allocator, .limited(1024 * 1024 * 1024)); const json = try reader.allocRemaining(allocator, .limited(1024 * 1024 * 1024));
defer allocator.free(json); defer allocator.free(json);

View file

@ -6,8 +6,8 @@
.dependencies = .{ .dependencies = .{
.aws = .{ .aws = .{
.url = "https://git.lerch.org/api/packages/lobo/generic/aws-sdk-with-models/d400e50a9c0257b44e68f9b6474ff0e5193b7e9f/d400e50a9c0257b44e68f9b6474ff0e5193b7e9fnightly-zig-with-models.tar.gz", .url = "https://git.lerch.org/api/packages/lobo/generic/aws-sdk-with-models/e41f98b389539c8bc6b1a231d25e2980318e5ef4/e41f98b389539c8bc6b1a231d25e2980318e5ef4-with-models.tar.gz",
.hash = "aws-0.0.1-SbsFcMsaCgAjwIAbxiCn2rIC1l4vGHDzC4_n70x2cRgs", .hash = "aws-0.0.1-SbsFcI0RCgBdf1nak95gi1kAtI6sv3Ntb7BPETH30fpS",
}, },
}, },
} }

View file

@ -28,10 +28,7 @@ pub fn main() anyerror!void {
// }; // };
// //
// var client = aws.Client.init(allocator, .{ .proxy = proxy }); // var client = aws.Client.init(allocator, .{ .proxy = proxy });
var threaded: std.Io.Threaded = .init(allocator); var client = aws.Client.init(allocator, .{});
defer threaded.deinit();
const io = threaded.io();
var client = aws.Client.init(allocator, .{ .io = io });
defer client.deinit(); defer client.deinit();
const options = aws.Options{ const options = aws.Options{

View file

@ -5,8 +5,8 @@
.minimum_zig_version = "0.14.0", .minimum_zig_version = "0.14.0",
.dependencies = .{ .dependencies = .{
.zeit = .{ .zeit = .{
.url = "git+https://github.com/elerch/zeit#8190461dc1f892f6370fa9d5cd76690aac0e1c71", .url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
.hash = "zeit-0.6.0-5I6bk99-AgDNMIDuw2Zcoe_9QYIpzwZJqeqMpU54egTd", .hash = "zeit-0.6.0-5I6bk0J9AgCVa0nnyL0lNY9Xa9F68hHq-ZarhuXNV-Jb",
}, },
.json = .{ .json = .{
.path = "../json", .path = "../json",

View file

@ -83,10 +83,8 @@ fn printDateTime(dt: DateTime) void {
}); });
} }
pub fn printNowUtc(io: std.Io) void { pub fn printNowUtc() void {
const now = std.Io.Clock.Timestamp.now(io, .awake) catch return; printDateTime(timestampToDateTime(std.time.timestamp()));
const timestamp = @as(i64, @intCast(@divFloor(now.raw.nanoseconds, std.time.ns_per_s)));
printDateTime(timestampToDateTime(timestamp));
} }
test "Convert timestamp to datetime" { test "Convert timestamp to datetime" {

View file

@ -113,7 +113,6 @@ pub const Services = servicemodel.Services;
pub const ClientOptions = struct { pub const ClientOptions = struct {
proxy: ?std.http.Client.Proxy = null, proxy: ?std.http.Client.Proxy = null,
io: std.Io,
}; };
pub const Client = struct { pub const Client = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
@ -124,7 +123,7 @@ pub const Client = struct {
pub fn init(allocator: std.mem.Allocator, options: ClientOptions) Self { pub fn init(allocator: std.mem.Allocator, options: ClientOptions) Self {
return Self{ return Self{
.allocator = allocator, .allocator = allocator,
.aws_http = awshttp.AwsHttp.init(allocator, options.io, options.proxy), .aws_http = awshttp.AwsHttp.init(allocator, options.proxy),
}; };
} }
pub fn deinit(self: *Client) void { pub fn deinit(self: *Client) void {
@ -456,7 +455,7 @@ pub fn Request(comptime request_action: anytype) type {
log.err("Could not set header value: Response header {s}. Field {s}. Value {s}", .{ header.name, f.?.name, header.value }); log.err("Could not set header value: Response header {s}. Field {s}. Value {s}", .{ header.name, f.?.name, header.value });
log.err("Error: {}", .{e}); log.err("Error: {}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
}; };

View file

@ -77,7 +77,7 @@ pub const Options = struct {
pub var static_credentials: ?auth.Credentials = null; pub var static_credentials: ?auth.Credentials = null;
pub fn getCredentials(allocator: std.mem.Allocator, io: std.Io, options: Options) !auth.Credentials { pub fn getCredentials(allocator: std.mem.Allocator, options: Options) !auth.Credentials {
if (static_credentials) |c| return c; if (static_credentials) |c| return c;
if (try getEnvironmentCredentials(allocator)) |cred| { if (try getEnvironmentCredentials(allocator)) |cred| {
log.debug("Found credentials in environment. Access key: {s}", .{cred.access_key}); log.debug("Found credentials in environment. Access key: {s}", .{cred.access_key});
@ -87,11 +87,11 @@ pub fn getCredentials(allocator: std.mem.Allocator, io: std.Io, options: Options
// GetWebIdentity is not currently implemented. The rest are tested and gtg // GetWebIdentity is not currently implemented. The rest are tested and gtg
// Note: Lambda just sets environment variables // Note: Lambda just sets environment variables
if (try getWebIdentityToken(allocator)) |cred| return cred; if (try getWebIdentityToken(allocator)) |cred| return cred;
if (try getProfileCredentials(allocator, io, options.profile)) |cred| return cred; if (try getProfileCredentials(allocator, options.profile)) |cred| return cred;
if (try getContainerCredentials(allocator, io)) |cred| return cred; if (try getContainerCredentials(allocator)) |cred| return cred;
// I don't think we need v1 at all? // I don't think we need v1 at all?
if (try getImdsv2Credentials(allocator, io)) |cred| return cred; if (try getImdsv2Credentials(allocator)) |cred| return cred;
return error.CredentialsNotFound; return error.CredentialsNotFound;
} }
@ -125,7 +125,7 @@ fn getWebIdentityToken(allocator: std.mem.Allocator) !?auth.Credentials {
// TODO: implement // TODO: implement
return null; return null;
} }
fn getContainerCredentials(allocator: std.mem.Allocator, io: std.Io) !?auth.Credentials { fn getContainerCredentials(allocator: std.mem.Allocator) !?auth.Credentials {
// A note on testing: The best way I have found to test this process is // A note on testing: The best way I have found to test this process is
// the following. Setup an ECS Fargate cluster and create a task definition // the following. Setup an ECS Fargate cluster and create a task definition
// with the command ["/bin/bash","-c","while true; do sleep 10; done"]. // with the command ["/bin/bash","-c","while true; do sleep 10; done"].
@ -171,7 +171,7 @@ fn getContainerCredentials(allocator: std.mem.Allocator, io: std.Io) !?auth.Cred
const container_uri = try std.fmt.allocPrint(allocator, "http://169.254.170.2{s}", .{container_relative_uri}); const container_uri = try std.fmt.allocPrint(allocator, "http://169.254.170.2{s}", .{container_relative_uri});
defer allocator.free(container_uri); defer allocator.free(container_uri);
var cl = std.http.Client{ .allocator = allocator, .io = io }; var cl = std.http.Client{ .allocator = allocator };
defer cl.deinit(); // I don't belive connection pooling would help much here as it's non-ssl and local defer cl.deinit(); // I don't belive connection pooling would help much here as it's non-ssl and local
var aw: std.Io.Writer.Allocating = .init(allocator); var aw: std.Io.Writer.Allocating = .init(allocator);
defer aw.deinit(); defer aw.deinit();
@ -201,7 +201,7 @@ fn getContainerCredentials(allocator: std.mem.Allocator, io: std.Io) !?auth.Cred
log.err("Unexpected Json response from container credentials endpoint: {s}", .{aw.written()}); log.err("Unexpected Json response from container credentials endpoint: {s}", .{aw.written()});
log.err("Error parsing json: {}", .{e}); log.err("Error parsing json: {}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
return null; return null;
@ -218,10 +218,10 @@ fn getContainerCredentials(allocator: std.mem.Allocator, io: std.Io) !?auth.Cred
); );
} }
fn getImdsv2Credentials(allocator: std.mem.Allocator, io: std.Io) !?auth.Credentials { fn getImdsv2Credentials(allocator: std.mem.Allocator) !?auth.Credentials {
var token: ?[]u8 = null; var token: ?[]u8 = null;
defer if (token) |t| allocator.free(t); defer if (token) |t| allocator.free(t);
var cl = std.http.Client{ .allocator = allocator, .io = io }; var cl = std.http.Client{ .allocator = allocator };
defer cl.deinit(); // I don't belive connection pooling would help much here as it's non-ssl and local defer cl.deinit(); // I don't belive connection pooling would help much here as it's non-ssl and local
// Get token // Get token
{ {
@ -299,7 +299,7 @@ fn getImdsRoleName(allocator: std.mem.Allocator, client: *std.http.Client, imds_
log.err("Unexpected Json response from IMDS endpoint: {s}", .{aw.written()}); log.err("Unexpected Json response from IMDS endpoint: {s}", .{aw.written()});
log.err("Error parsing json: {}", .{e}); log.err("Error parsing json: {}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
return null; return null;
}; };
@ -354,7 +354,7 @@ fn getImdsCredentials(allocator: std.mem.Allocator, client: *std.http.Client, ro
log.err("Unexpected Json response from IMDS endpoint: {s}", .{aw.written()}); log.err("Unexpected Json response from IMDS endpoint: {s}", .{aw.written()});
log.err("Error parsing json: {}", .{e}); log.err("Error parsing json: {}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
return null; return null;
@ -383,7 +383,7 @@ fn getImdsCredentials(allocator: std.mem.Allocator, client: *std.http.Client, ro
} }
fn getProfileCredentials(allocator: std.mem.Allocator, io: std.Io, options: Profile) !?auth.Credentials { fn getProfileCredentials(allocator: std.mem.Allocator, options: Profile) !?auth.Credentials {
var default_path: ?[]const u8 = null; var default_path: ?[]const u8 = null;
defer if (default_path) |p| allocator.free(p); defer if (default_path) |p| allocator.free(p);
@ -416,13 +416,13 @@ fn getProfileCredentials(allocator: std.mem.Allocator, io: std.Io, options: Prof
defer if (credentials_file) |f| f.close(); defer if (credentials_file) |f| f.close();
// It's much more likely that we'll find credentials in the credentials file // It's much more likely that we'll find credentials in the credentials file
// so we'll try that first // so we'll try that first
const creds_file_creds = try credsForFile(allocator, io, credentials_file, profile); const creds_file_creds = try credsForFile(allocator, credentials_file, profile);
var conf_file_creds = PartialCredentials{}; var conf_file_creds = PartialCredentials{};
if (creds_file_creds.access_key == null or creds_file_creds.secret_key == null) { if (creds_file_creds.access_key == null or creds_file_creds.secret_key == null) {
log.debug("Checking config file: {s}", .{config_file_path.evaluated_path}); log.debug("Checking config file: {s}", .{config_file_path.evaluated_path});
const config_file = std.fs.openFileAbsolute(creds_file_path.evaluated_path, .{}) catch null; const config_file = std.fs.openFileAbsolute(creds_file_path.evaluated_path, .{}) catch null;
defer if (config_file) |f| f.close(); defer if (config_file) |f| f.close();
conf_file_creds = try credsForFile(allocator, io, config_file, profile); conf_file_creds = try credsForFile(allocator, config_file, profile);
} }
const access_key = keyFrom(allocator, creds_file_creds.access_key, conf_file_creds.access_key); const access_key = keyFrom(allocator, creds_file_creds.access_key, conf_file_creds.access_key);
const secret_key = keyFrom(allocator, creds_file_creds.secret_key, conf_file_creds.secret_key); const secret_key = keyFrom(allocator, creds_file_creds.secret_key, conf_file_creds.secret_key);
@ -461,10 +461,10 @@ const PartialCredentials = struct {
access_key: ?[]const u8 = null, access_key: ?[]const u8 = null,
secret_key: ?[]const u8 = null, secret_key: ?[]const u8 = null,
}; };
fn credsForFile(allocator: std.mem.Allocator, io: std.Io, file: ?std.fs.File, profile: []const u8) !PartialCredentials { fn credsForFile(allocator: std.mem.Allocator, file: ?std.fs.File, profile: []const u8) !PartialCredentials {
if (file == null) return PartialCredentials{}; if (file == null) return PartialCredentials{};
var fbuf: [1024]u8 = undefined; var fbuf: [1024]u8 = undefined;
var freader = file.?.reader(io, &fbuf); var freader = file.?.reader(&fbuf);
var reader = &freader.interface; var reader = &freader.interface;
const text = try reader.allocRemaining(allocator, .unlimited); const text = try reader.allocRemaining(allocator, .unlimited);
defer allocator.free(text); defer allocator.free(text);
@ -629,7 +629,7 @@ fn getHomeDir(allocator: std.mem.Allocator) ![]const u8 {
else => return error.HomeDirUnavailable, else => return error.HomeDirUnavailable,
}; };
}, },
.macos, .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .illumos => { .macos, .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => {
const home_dir = std.posix.getenv("HOME") orelse { const home_dir = std.posix.getenv("HOME") orelse {
// TODO look in /etc/passwd // TODO look in /etc/passwd
return error.HomeDirUnavailable; return error.HomeDirUnavailable;

View file

@ -144,15 +144,13 @@ const EndPoint = struct {
pub const AwsHttp = struct { pub const AwsHttp = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
proxy: ?std.http.Client.Proxy, proxy: ?std.http.Client.Proxy,
io: std.Io,
const Self = @This(); const Self = @This();
pub fn init(allocator: std.mem.Allocator, io: std.Io, proxy: ?std.http.Client.Proxy) Self { pub fn init(allocator: std.mem.Allocator, proxy: ?std.http.Client.Proxy) Self {
return Self{ return Self{
.allocator = allocator, .allocator = allocator,
.proxy = proxy, .proxy = proxy,
.io = io,
// .credentialsProvider = // creds provider could be useful // .credentialsProvider = // creds provider could be useful
}; };
} }
@ -188,7 +186,7 @@ pub const AwsHttp = struct {
defer endpoint.deinit(); defer endpoint.deinit();
log.debug("Calling endpoint {s}", .{endpoint.uri}); log.debug("Calling endpoint {s}", .{endpoint.uri});
// TODO: Should we allow customization here? // TODO: Should we allow customization here?
const creds = try credentials.getCredentials(self.allocator, self.io, .{}); const creds = try credentials.getCredentials(self.allocator, .{});
defer creds.deinit(); defer creds.deinit();
const signing_config: signing.Config = .{ const signing_config: signing.Config = .{
.region = getRegion(service, options.region), .region = getRegion(service, options.region),
@ -243,7 +241,7 @@ pub const AwsHttp = struct {
defer if (len) |l| self.allocator.free(l); defer if (len) |l| self.allocator.free(l);
request_cp.headers = request_headers.items; request_cp.headers = request_headers.items;
if (signing_config) |opts| request_cp = try signing.signRequest(self.allocator, self.io, request_cp, opts); if (signing_config) |opts| request_cp = try signing.signRequest(self.allocator, request_cp, opts);
defer { defer {
if (signing_config) |opts| { if (signing_config) |opts| {
signing.freeSignedRequest(self.allocator, &request_cp, opts); signing.freeSignedRequest(self.allocator, &request_cp, opts);
@ -263,7 +261,7 @@ pub const AwsHttp = struct {
defer self.allocator.free(url); defer self.allocator.free(url);
log.debug("Request url: {s}", .{url}); log.debug("Request url: {s}", .{url});
// TODO: Fix this proxy stuff. This is all a kludge just to compile, but std.http.Client has it all built in now // TODO: Fix this proxy stuff. This is all a kludge just to compile, but std.http.Client has it all built in now
var cl = std.http.Client{ .allocator = self.allocator, .io = self.io, .https_proxy = if (self.proxy) |*p| @constCast(p) else null }; var cl = std.http.Client{ .allocator = self.allocator, .https_proxy = if (self.proxy) |*p| @constCast(p) else null };
defer cl.deinit(); // TODO: Connection pooling defer cl.deinit(); // TODO: Connection pooling
const method = std.meta.stringToEnum(std.http.Method, request_cp.method).?; const method = std.meta.stringToEnum(std.http.Method, request_cp.method).?;

View file

@ -157,7 +157,7 @@ pub const SigningError = error{
XAmzExpiresHeaderInRequest, XAmzExpiresHeaderInRequest,
/// Used if the request headers already includes x-amz-region-set /// Used if the request headers already includes x-amz-region-set
XAmzRegionSetHeaderInRequest, XAmzRegionSetHeaderInRequest,
} || error{OutOfMemory} || std.Io.Clock.Error; } || error{OutOfMemory};
const forbidden_headers = .{ const forbidden_headers = .{
.{ .name = "x-amz-content-sha256", .err = SigningError.XAmzContentSha256HeaderInRequest }, .{ .name = "x-amz-content-sha256", .err = SigningError.XAmzContentSha256HeaderInRequest },
@ -185,7 +185,7 @@ const skipped_headers = .{
/// Signs a request. Only header signing is currently supported. Note that /// Signs a request. Only header signing is currently supported. Note that
/// This adds two headers to the request, which will need to be freed by the /// This adds two headers to the request, which will need to be freed by the
/// caller. Use freeSignedRequest with the same parameters to free /// caller. Use freeSignedRequest with the same parameters to free
pub fn signRequest(allocator: std.mem.Allocator, io: std.Io, request: base.Request, config: Config) SigningError!base.Request { pub fn signRequest(allocator: std.mem.Allocator, request: base.Request, config: Config) SigningError!base.Request {
try validateConfig(config); try validateConfig(config);
for (request.headers) |h| { for (request.headers) |h| {
inline for (forbidden_headers) |f| { inline for (forbidden_headers) |f| {
@ -195,10 +195,7 @@ pub fn signRequest(allocator: std.mem.Allocator, io: std.Io, request: base.Reque
} }
var rc = request; var rc = request;
const signing_time = config.signing_time orelse blk: { const signing_time = config.signing_time orelse std.time.timestamp();
const now = try std.Io.Clock.Timestamp.now(io, .awake);
break :blk @as(i64, @intCast(@divFloor(now.raw.nanoseconds, std.time.ns_per_s)));
};
const signed_date = date.timestampToDateTime(signing_time); const signed_date = date.timestampToDateTime(signing_time);
@ -337,7 +334,7 @@ pub fn freeSignedRequest(allocator: std.mem.Allocator, request: *base.Request, c
validateConfig(config) catch |e| { validateConfig(config) catch |e| {
log.err("Signing validation failed during signature free: {}", .{e}); log.err("Signing validation failed during signature free: {}", .{e});
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
return; return;
}; };
@ -355,10 +352,10 @@ pub fn freeSignedRequest(allocator: std.mem.Allocator, request: *base.Request, c
pub const credentialsFn = *const fn ([]const u8) ?Credentials; pub const credentialsFn = *const fn ([]const u8) ?Credentials;
pub fn verifyServerRequest(allocator: std.mem.Allocator, io: std.Io, request: *std.http.Server.Request, request_body_reader: *std.Io.Reader, credentials_fn: credentialsFn) !bool { pub fn verifyServerRequest(allocator: std.mem.Allocator, request: *std.http.Server.Request, request_body_reader: *std.Io.Reader, credentials_fn: credentialsFn) !bool {
var unverified_request = try UnverifiedRequest.init(allocator, request); var unverified_request = try UnverifiedRequest.init(allocator, request);
defer unverified_request.deinit(); defer unverified_request.deinit();
return verify(allocator, io, unverified_request, request_body_reader, credentials_fn); return verify(allocator, unverified_request, request_body_reader, credentials_fn);
} }
pub const UnverifiedRequest = struct { pub const UnverifiedRequest = struct {
@ -396,7 +393,7 @@ pub const UnverifiedRequest = struct {
} }
}; };
pub fn verify(allocator: std.mem.Allocator, io: std.Io, request: UnverifiedRequest, request_body_reader: *std.Io.Reader, credentials_fn: credentialsFn) !bool { pub fn verify(allocator: std.mem.Allocator, request: UnverifiedRequest, request_body_reader: *std.Io.Reader, credentials_fn: credentialsFn) !bool {
var arena = std.heap.ArenaAllocator.init(allocator); var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit(); defer arena.deinit();
const aa = arena.allocator(); const aa = arena.allocator();
@ -428,7 +425,6 @@ pub fn verify(allocator: std.mem.Allocator, io: std.Io, request: UnverifiedReque
if (signature == null) return error.AuthorizationHeaderMissingSignature; if (signature == null) return error.AuthorizationHeaderMissingSignature;
return verifyParsedAuthorization( return verifyParsedAuthorization(
aa, aa,
io,
request, request,
credential.?, credential.?,
signed_headers.?, signed_headers.?,
@ -440,7 +436,6 @@ pub fn verify(allocator: std.mem.Allocator, io: std.Io, request: UnverifiedReque
fn verifyParsedAuthorization( fn verifyParsedAuthorization(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
io: std.Io,
request: UnverifiedRequest, request: UnverifiedRequest,
credential: []const u8, credential: []const u8,
signed_headers: []const u8, signed_headers: []const u8,
@ -507,7 +502,7 @@ fn verifyParsedAuthorization(
signed_request.query = request.target[signed_request.path.len..]; // TODO: should this be +1? query here would include '?' signed_request.query = request.target[signed_request.path.len..]; // TODO: should this be +1? query here would include '?'
signed_request.body = try request_body_reader.allocRemaining(allocator, .unlimited); signed_request.body = try request_body_reader.allocRemaining(allocator, .unlimited);
defer allocator.free(signed_request.body); defer allocator.free(signed_request.body);
signed_request = try signRequest(allocator, io, signed_request, config); signed_request = try signRequest(allocator, signed_request, config);
defer freeSignedRequest(allocator, &signed_request, config); defer freeSignedRequest(allocator, &signed_request, config);
return verifySignedRequest(signed_request, signature); return verifySignedRequest(signed_request, signature);
} }
@ -1105,9 +1100,6 @@ test "can sign" {
// [debug] (awshttp): Content-Length: 43 // [debug] (awshttp): Content-Length: 43
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var threaded: std.Io.Threaded = .init(allocator);
defer threaded.deinit();
const io = threaded.io();
var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5); var headers = try std.ArrayList(std.http.Header).initCapacity(allocator, 5);
defer headers.deinit(allocator); defer headers.deinit(allocator);
try headers.append(allocator, .{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" }); try headers.append(allocator, .{ .name = "Content-Type", .value = "application/x-www-form-urlencoded; charset=utf-8" });
@ -1139,7 +1131,7 @@ test "can sign" {
.signing_time = 1440938160, // 20150830T123600Z .signing_time = 1440938160, // 20150830T123600Z
}; };
// TODO: There is an x-amz-content-sha256. Investigate // TODO: There is an x-amz-content-sha256. Investigate
var signed_req = try signRequest(allocator, io, req, config); var signed_req = try signRequest(allocator, req, config);
defer freeSignedRequest(allocator, &signed_req, config); defer freeSignedRequest(allocator, &signed_req, config);
try std.testing.expectEqualStrings("X-Amz-Date", signed_req.headers[signed_req.headers.len - 3].name); try std.testing.expectEqualStrings("X-Amz-Date", signed_req.headers[signed_req.headers.len - 3].name);
@ -1159,9 +1151,6 @@ test "can sign" {
var test_credential: ?Credentials = null; var test_credential: ?Credentials = null;
test "can verify server request" { test "can verify server request" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var threaded: std.Io.Threaded = .init(allocator);
defer threaded.deinit();
const io = threaded.io();
const access_key = try allocator.dupe(u8, "ACCESS"); const access_key = try allocator.dupe(u8, "ACCESS");
const secret_key = try allocator.dupe(u8, "SECRET"); const secret_key = try allocator.dupe(u8, "SECRET");
@ -1202,7 +1191,7 @@ test "can verify server request" {
// const old_level = std.testing.log_level; // const old_level = std.testing.log_level;
// std.testing.log_level = .debug; // std.testing.log_level = .debug;
// defer std.testing.log_level = old_level; // defer std.testing.log_level = old_level;
try std.testing.expect(try verifyServerRequest(allocator, io, &request, &body_reader, struct { try std.testing.expect(try verifyServerRequest(allocator, &request, &body_reader, struct {
cred: Credentials, cred: Credentials,
const Self = @This(); const Self = @This();
@ -1214,9 +1203,6 @@ test "can verify server request" {
} }
test "can verify server request without x-amz-content-sha256" { test "can verify server request without x-amz-content-sha256" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var threaded: std.Io.Threaded = .init(allocator);
defer threaded.deinit();
const io = threaded.io();
const access_key = try allocator.dupe(u8, "ACCESS"); const access_key = try allocator.dupe(u8, "ACCESS");
const secret_key = try allocator.dupe(u8, "SECRET"); const secret_key = try allocator.dupe(u8, "SECRET");
@ -1307,7 +1293,7 @@ test "can verify server request without x-amz-content-sha256" {
} }
{ // verification { // verification
try std.testing.expect(try verifyServerRequest(allocator, io, &request, &body_reader, struct { try std.testing.expect(try verifyServerRequest(allocator, &request, &body_reader, struct {
cred: Credentials, cred: Credentials,
const Self = @This(); const Self = @This();

View file

@ -254,8 +254,6 @@ const TestOptions = struct {
}; };
const TestSetup = struct { const TestSetup = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
threaded: std.Io.Threaded,
io: std.Io,
options: TestOptions, options: TestOptions,
creds: aws_auth.Credentials, creds: aws_auth.Credentials,
client: aws.Client, client: aws.Client,
@ -308,7 +306,6 @@ const TestSetup = struct {
allocator.free(self.trace); allocator.free(self.trace);
allocator.free(self.request_uri); allocator.free(self.request_uri);
allocator.destroy(self.request.reader.in); allocator.destroy(self.request.reader.in);
allocator.destroy(self.request.client);
allocator.destroy(self.request); allocator.destroy(self.request);
} }
}; };
@ -336,32 +333,22 @@ const TestSetup = struct {
var stderr = std.fs.File.stderr().writer(&.{}); var stderr = std.fs.File.stderr().writer(&.{});
stderr.interface.writeAll(r.trace) catch @panic("could not write to stderr"); stderr.interface.writeAll(r.trace) catch @panic("could not write to stderr");
std.debug.print("Current stack trace:\n", .{}); std.debug.print("Current stack trace:\n", .{});
std.debug.dumpCurrentStackTrace(.{}); std.debug.dumpCurrentStackTrace(null);
return error.ConnectionRefused; // we should not be called twice return error.ConnectionRefused; // we should not be called twice
} }
const acts = try self.allocator.create(RequestActuals); const acts = try self.allocator.create(RequestActuals);
errdefer self.allocator.destroy(acts); errdefer self.allocator.destroy(acts);
var aw = std.Io.Writer.Allocating.init(self.allocator); var aw = std.Io.Writer.Allocating.init(self.allocator);
defer aw.deinit(); defer aw.deinit();
std.debug.writeCurrentStackTrace(.{}, &aw.writer, .no_color) catch return error.OutOfMemory; std.debug.dumpCurrentStackTraceToWriter(null, &aw.writer) catch return error.OutOfMemory;
const req = try self.allocator.create(std.http.Client.Request); const req = try self.allocator.create(std.http.Client.Request);
errdefer self.allocator.destroy(req); errdefer self.allocator.destroy(req);
const reader = try self.allocator.create(std.Io.Reader); const reader = try self.allocator.create(std.Io.Reader);
errdefer self.allocator.destroy(reader); errdefer self.allocator.destroy(reader);
reader.* = .fixed(self.options.server_response); reader.* = .fixed(self.options.server_response);
// Create a minimal mock client that only provides io for deinit
// By creating it with the allocator, we leave critical fields like
// connection_pool as undefined, which will fail spectacularly if
// a real request were to be attempted
const mock_client = try self.allocator.create(std.http.Client);
errdefer self.allocator.destroy(mock_client);
mock_client.* = .{
.allocator = self.allocator,
.io = self.io,
};
req.* = .{ req.* = .{
.uri = uri, .uri = uri,
.client = mock_client, .client = undefined,
.connection = options.connection, .connection = options.connection,
.reader = .{ .reader = .{
.in = reader, .in = reader,
@ -446,9 +433,7 @@ const TestSetup = struct {
return self.request_actuals.?.request.reader.in; return self.request_actuals.?.request.reader.in;
} }
fn init(options: TestOptions) !*Self { fn init(options: TestOptions) !*Self {
var threaded: std.Io.Threaded = .init(options.allocator); const client = aws.Client.init(options.allocator, .{});
const io = threaded.io();
const client = aws.Client.init(options.allocator, .{ .io = io });
const call_options = try options.allocator.create(aws.Options); const call_options = try options.allocator.create(aws.Options);
const self = try options.allocator.create(Self); const self = try options.allocator.create(Self);
call_options.* = .{ call_options.* = .{
@ -468,8 +453,6 @@ const TestSetup = struct {
self.* = .{ self.* = .{
.options = options, .options = options,
.allocator = options.allocator, .allocator = options.allocator,
.threaded = threaded,
.io = io,
.creds = aws_auth.Credentials.init( .creds = aws_auth.Credentials.init(
options.allocator, options.allocator,
try options.allocator.dupe(u8, "ACCESS"), try options.allocator.dupe(u8, "ACCESS"),
@ -493,7 +476,6 @@ const TestSetup = struct {
} }
self.allocator.destroy(self.call_options); self.allocator.destroy(self.call_options);
self.call_options = undefined; self.call_options = undefined;
self.threaded.deinit();
self.allocator.destroy(self); self.allocator.destroy(self);
aws_creds.static_credentials = null; aws_creds.static_credentials = null;
} }
@ -1326,7 +1308,6 @@ test "jsonStringify nullable object" {
test "works against a live server" { test "works against a live server" {
const Server = struct { const Server = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
io: std.Io,
ready: std.Thread.Semaphore = .{}, ready: std.Thread.Semaphore = .{},
requests_received: usize = 0, requests_received: usize = 0,
thread: ?std.Thread = null, thread: ?std.Thread = null,
@ -1358,7 +1339,7 @@ test "works against a live server" {
pub fn stop(self: *Server) !void { pub fn stop(self: *Server) !void {
if (self.thread == null) return; // thread not started, nothing to do if (self.thread == null) return; // thread not started, nothing to do
// post stop message // post stop message
var client = std.http.Client{ .allocator = self.allocator, .io = self.io }; var client = std.http.Client{ .allocator = self.allocator };
_ = try client.fetch(.{ // we ignore return because that should just shut down _ = try client.fetch(.{ // we ignore return because that should just shut down
.method = .POST, .method = .POST,
.payload = "quit", .payload = "quit",
@ -1369,10 +1350,10 @@ test "works against a live server" {
} }
fn threadMain(self: *Server) !void { fn threadMain(self: *Server) !void {
const address = try std.Io.net.IpAddress.parseLiteral("127.0.0.1:0"); const address = try std.net.Address.parseIp("127.0.0.1", 0);
var server = try address.listen(self.io, .{}); var server = try address.listen(.{});
defer server.deinit(self.io); defer server.deinit();
const server_port = server.socket.address.getPort(); const server_port = server.listen_address.in.getPort();
self.listening_uri = try std.fmt.allocPrint(self.allocator, "http://127.0.0.1:{d}", .{server_port}); self.listening_uri = try std.fmt.allocPrint(self.allocator, "http://127.0.0.1:{d}", .{server_port});
defer { defer {
self.allocator.free(self.listening_uri); self.allocator.free(self.listening_uri);
@ -1380,13 +1361,13 @@ test "works against a live server" {
} }
self.ready.post(); self.ready.post();
while (true) { while (true) {
var connection = try server.accept(self.io); var connection = try server.accept();
defer connection.close(self.io); defer connection.stream.close();
var recv_buffer: [4000]u8 = undefined; var recv_buffer: [4000]u8 = undefined;
var send_buffer: [4000]u8 = undefined; var send_buffer: [4000]u8 = undefined;
var conn_reader = connection.reader(self.io, &recv_buffer); var conn_reader = connection.stream.reader(&recv_buffer);
var conn_writer = connection.writer(self.io, &send_buffer); var conn_writer = connection.stream.writer(&send_buffer);
var http_server = std.http.Server.init(&conn_reader.interface, &conn_writer.interface); var http_server = std.http.Server.init(conn_reader.interface(), &conn_writer.interface);
while (http_server.reader.state == .ready) { while (http_server.reader.state == .ready) {
var req = try http_server.receiveHead(); var req = try http_server.receiveHead();
if (req.head.content_length) |l| { if (req.head.content_length) |l| {
@ -1411,10 +1392,7 @@ test "works against a live server" {
} }
}; };
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
var threaded: std.Io.Threaded = .init(allocator); var server = Server{ .allocator = allocator };
defer threaded.deinit();
const io = threaded.io();
var server = Server{ .allocator = allocator, .io = io };
try server.start(); try server.start();
var stopped = false; var stopped = false;
defer if (!stopped) server.stop() catch log.err("error stopping server", .{}); defer if (!stopped) server.stop() catch log.err("error stopping server", .{});
@ -1434,7 +1412,7 @@ test "works against a live server" {
// } // }
const sts = (Services(.{.sts}){}).sts; const sts = (Services(.{.sts}){}).sts;
const client = aws.Client.init(std.testing.allocator, .{ .io = io }); const client = aws.Client.init(std.testing.allocator, .{});
const creds = aws_auth.Credentials.init( const creds = aws_auth.Credentials.init(
allocator, allocator,
try allocator.dupe(u8, "ACCESS"), try allocator.dupe(u8, "ACCESS"),

View file

@ -111,10 +111,7 @@ pub fn main() anyerror!void {
} }
std.log.info("Start\n", .{}); std.log.info("Start\n", .{});
var threaded: std.Io.Threaded = .init(allocator); const client_options = aws.ClientOptions{ .proxy = proxy };
defer threaded.deinit();
const io = threaded.io();
const client_options = aws.ClientOptions{ .proxy = proxy, .io = io };
var client = aws.Client.init(allocator, client_options); var client = aws.Client.init(allocator, client_options);
const options = aws.Options{ const options = aws.Options{
.region = "us-west-2", .region = "us-west-2",
@ -376,8 +373,7 @@ fn proxyFromString(string: []const u8) !std.http.Client.Proxy {
rc.protocol = .tls; rc.protocol = .tls;
} else return error.InvalidScheme; } else return error.InvalidScheme;
var split_iterator = std.mem.splitScalar(u8, remaining, ':'); var split_iterator = std.mem.splitScalar(u8, remaining, ':');
const host_str = std.mem.trimRight(u8, split_iterator.first(), "/"); rc.host = std.mem.trimRight(u8, split_iterator.first(), "/");
rc.host = try std.Io.net.HostName.init(host_str);
if (split_iterator.next()) |port| if (split_iterator.next()) |port|
rc.port = try std.fmt.parseInt(u16, port, 10); rc.port = try std.fmt.parseInt(u16, port, 10);
return rc; return rc;

View file

@ -168,7 +168,7 @@ fn parseInternal(comptime T: type, element: *xml.Element, options: ParseOptions)
}, },
); );
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
} }
return e; return e;
@ -193,7 +193,7 @@ fn parseInternal(comptime T: type, element: *xml.Element, options: ParseOptions)
}, },
); );
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
} }
return e; return e;