Compare commits

...

13 Commits

Author SHA1 Message Date
e5f5f0e8cd
update code to support compilation with zig 0.8.0 2021-06-09 16:26:42 -07:00
c6dbbf33af
allow different endpoing/sigv4 service names
This seems silly, but I guess in AWS it is a thing that these two values may
be different. Consumers of awshttp have the option of ignoring this, which
should be correct most of the time. Aws.zig will, however, use the service
metadata to do the right thing
2021-06-09 16:25:49 -07:00
bd5d509665
update servicemodel for generated model
This increases compilation time significantly as all 260+ services
need to be analyzed by zig during compilation. I plan to change
the model from a single "services" constant to a function
that will import only services that plan to be used. This
might be in addition to the single constant to allow
consumers to choose short compile times or all services
support
2021-06-09 16:22:44 -07:00
88632df671
update build.zig with zig 0.8.0 instructions
My PR is still open, so it will be 0.9.0 at least before we get static build.zig support
2021-06-09 16:18:01 -07:00
32afc2c622
update .gitignore for generated files 2021-06-09 16:16:54 -07:00
d7efe72f1b
enable compiling under zig 0.8.0 2021-06-09 16:14:44 -07:00
4a10450e0e
add metadata function
This blows up the number of parameters on generateComplexTypeFor
at least this is a private function, but still kinda messay
2021-06-09 16:14:09 -07:00
03ef89a362
use snake case sdk id for member name
There is still a bug in snake_case related to double underscores
2021-06-09 16:10:10 -07:00
578058dfc9
remove newline that disagreed with zig fmt 2021-06-09 16:06:30 -07:00
68fdeed2fc
update gitignore for generated files 2021-06-03 17:41:18 -07:00
59638df854
add manifest list (remove -s option) 2021-06-03 17:40:47 -07:00
329d732cd5
switch field names to snake_case 2021-06-03 17:39:38 -07:00
c2710be165
move codegen under src/ 2021-06-03 17:35:14 -07:00
279 changed files with 193 additions and 267 deletions

7
.gitignore vendored
View File

@ -1,4 +1,7 @@
.cache .cache
zig-cache zig-cache
codegen/models/*.zig src/codegen/models/*.zig
codegen/codegen src/codegen/codegen
*.tgz
service_manifest.zig
demo

View File

@ -38,7 +38,14 @@ pub fn build(b: *Builder) void {
// "-static", // "-static",
// "--strip", // "--strip",
// }); // });
//
// To compile on stock 0.8.0, comment this line of code, or use the Makefile
// See https://github.com/ziglang/zig/pull/8248
//
// On a musl-based x86_64 system, this pre-compiled zig can be used:
// https://github.com/elerch/zig/releases/download/0.8.0/zig-0.8.0-static-support-musl-libz.tgz
exe.is_static = true; exe.is_static = true;
exe.strip = true; exe.strip = true;
exe.install(); exe.install();

View File

@ -6,7 +6,10 @@ const servicemodel = @import("servicemodel.zig");
const log = std.log.scoped(.aws); const log = std.log.scoped(.aws);
pub const Options = awshttp.Options; pub const Options = struct {
region: []const u8 = "aws-global",
dualstack: bool = false,
};
pub const services = servicemodel.services; pub const services = servicemodel.services;
@ -27,18 +30,28 @@ pub const Aws = struct {
} }
pub fn call(self: Self, comptime request: anytype, options: Options) !FullResponse(request) { pub fn call(self: Self, comptime request: anytype, options: Options) !FullResponse(request) {
const action_info = actionForRequest(request); // every codegenned request object includes a metaInfo function to get
// This is true weirdness, but we are running into compiler bugs. Touch only if // pointers to service and action
// prepared... const meta_info = request.metaInfo();
const service = @field(services, action_info.service); const service = meta_info.service;
const action = @field(service, action_info.action); const action = meta_info.action;
const R = Response(request); const R = Response(request);
const FullR = FullResponse(request); const FullR = FullResponse(request);
log.debug("service {s}", .{action_info.service}); log.debug("service endpoint {s}", .{service.endpoint_prefix});
log.debug("service sigv4 name {s}", .{service.sigv4_name});
log.debug("version {s}", .{service.version}); log.debug("version {s}", .{service.version});
log.debug("action {s}", .{action.action_name}); log.debug("action {s}", .{action.action_name});
const response = try self.aws_http.callApi(action_info.service, service.version, action.action_name, options); const response = try self.aws_http.callApi(
service.endpoint_prefix,
service.version,
action.action_name,
.{
.region = options.region,
.dualstack = options.dualstack,
.sigv4_service_name = service.sigv4_name,
},
);
defer response.deinit(); defer response.deinit();
// TODO: Check status code for badness // TODO: Check status code for badness
var stream = json.TokenStream.init(response.body); var stream = json.TokenStream.init(response.body);
@ -73,40 +86,9 @@ pub const Aws = struct {
} }
}; };
fn actionForRequest(comptime request: anytype) struct { service: []const u8, action: []const u8, service_obj: anytype } {
const type_name = @typeName(@TypeOf(request));
var service_start: usize = 0;
var service_end: usize = 0;
var action_start: usize = 0;
var action_end: usize = 0;
for (type_name) |ch, i| {
switch (ch) {
'(' => service_start = i + 2,
')' => action_end = i - 1,
',' => {
service_end = i - 1;
action_start = i + 2;
},
else => continue,
}
}
// const zero: usize = 0;
// TODO: Figure out why if statement isn't working
// if (serviceStart == zero or serviceEnd == zero or actionStart == zero or actionEnd == zero) {
// @compileLog("Type must be a function with two parameters \"service\" and \"action\". Found: " ++ type_name);
// // @compileError("Type must be a function with two parameters \"service\" and \"action\". Found: " ++ type_name);
// }
return .{
.service = type_name[service_start..service_end],
.action = type_name[action_start..action_end],
.service_obj = @field(services, type_name[service_start..service_end]),
};
}
fn ServerResponse(comptime request: anytype) type { fn ServerResponse(comptime request: anytype) type {
const T = Response(request); const T = Response(request);
const action_info = actionForRequest(request); const action = request.metaInfo().action;
const service = @field(services, action_info.service);
const action = @field(service, action_info.action);
// NOTE: The non-standard capitalization here is used as a performance // NOTE: The non-standard capitalization here is used as a performance
// enhancement and to reduce allocations in json.zig. These fields are // enhancement and to reduce allocations in json.zig. These fields are
// not (nor are they ever intended to be) exposed outside this codebase // not (nor are they ever intended to be) exposed outside this codebase
@ -169,8 +151,5 @@ fn FullResponse(comptime request: anytype) type {
}; };
} }
fn Response(comptime request: anytype) type { fn Response(comptime request: anytype) type {
const action_info = actionForRequest(request); return request.metaInfo().action.Response;
const service = @field(services, action_info.service);
const action = @field(service, action_info.action);
return action.Response;
} }

View File

@ -27,7 +27,6 @@ const c = @cImport({
@cInclude("aws/io/socket.h"); @cInclude("aws/io/socket.h");
@cInclude("aws/io/stream.h"); @cInclude("aws/io/stream.h");
}); });
const std_atomic_bool = @import("bool.zig"); // This is in std in 0.8.0
const CN_NORTH_1_HASH = std.hash_map.hashString("cn-north-1"); const CN_NORTH_1_HASH = std.hash_map.hashString("cn-north-1");
const CN_NORTHWEST_1_HASH = std.hash_map.hashString("cn-northwest-1"); const CN_NORTHWEST_1_HASH = std.hash_map.hashString("cn-northwest-1");
@ -67,9 +66,10 @@ pub const AwsError = error{
pub const Options = struct { pub const Options = struct {
region: []const u8 = "aws-global", region: []const u8 = "aws-global",
dualstack: bool = false, dualstack: bool = false,
sigv4_service_name: ?[]const u8 = null,
}; };
pub const SigningOptions = struct { const SigningOptions = struct {
region: []const u8 = "aws-global", region: []const u8 = "aws-global",
service: []const u8, service: []const u8,
}; };
@ -240,7 +240,7 @@ pub const AwsHttp = struct {
httplog.debug("Calling {s}.{s}, endpoint {s}", .{ service, action, endpoint.uri }); httplog.debug("Calling {s}.{s}, endpoint {s}", .{ service, action, endpoint.uri });
const signing_options: SigningOptions = .{ const signing_options: SigningOptions = .{
.region = options.region, .region = options.region,
.service = service, .service = if (options.sigv4_service_name) |name| name else service,
}; };
return try self.makeRequest(endpoint, "POST", "/", body, signing_options); return try self.makeRequest(endpoint, "POST", "/", body, signing_options);
} }
@ -815,7 +815,7 @@ fn AsyncResult(comptime T: type) type {
return struct { return struct {
result: *T, result: *T,
requiredCount: u32 = 1, requiredCount: u32 = 1,
sync: std_atomic_bool.Bool = std_atomic_bool.Bool.init(false), // This is a 0.8.0 feature... :( sync: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false),
count: u8 = 0, count: u8 = 0,
}; };
} }
@ -911,8 +911,8 @@ fn endPointFromUri(allocator: *std.mem.Allocator, uri: []const u8) !EndPoint {
const RequestContext = struct { const RequestContext = struct {
connection: ?*c.aws_http_connection = null, connection: ?*c.aws_http_connection = null,
connection_complete: std_atomic_bool.Bool = std_atomic_bool.Bool.init(false), // This is a 0.8.0 feature... :( connection_complete: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false),
request_complete: std_atomic_bool.Bool = std_atomic_bool.Bool.init(false), // This is a 0.8.0 feature... :( request_complete: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(false),
return_error: ?AwsError = null, return_error: ?AwsError = null,
allocator: *std.mem.Allocator, allocator: *std.mem.Allocator,
body: ?[]const u8 = null, body: ?[]const u8 = null,

View File

@ -1,55 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2021 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("std");
const builtin = std.builtin;
const testing = std.testing;
/// Thread-safe, lock-free boolean
pub const Bool = extern struct {
unprotected_value: bool,
pub const Self = @This();
pub fn init(init_val: bool) Self {
return Self{ .unprotected_value = init_val };
}
// xchg is only valid rmw operation for a bool
/// Atomically modifies memory and then returns the previous value.
pub fn xchg(self: *Self, operand: bool, comptime ordering: std.builtin.AtomicOrder) bool {
switch (ordering) {
.Monotonic, .Acquire, .Release, .AcqRel, .SeqCst => {},
else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a RMW operation"),
}
return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering);
}
pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool {
switch (ordering) {
.Unordered, .Monotonic, .Acquire, .SeqCst => {},
else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"),
}
return @atomicLoad(bool, &self.unprotected_value, ordering);
}
pub fn store(self: *Self, value: bool, comptime ordering: std.builtin.AtomicOrder) void {
switch (ordering) {
.Unordered, .Monotonic, .Release, .SeqCst => {},
else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a store operation"),
}
@atomicStore(bool, &self.unprotected_value, value, ordering);
}
};
test "std.atomic.Bool" {
var a = Bool.init(false);
testing.expectEqual(false, a.xchg(false, .SeqCst));
testing.expectEqual(false, a.load(.SeqCst));
a.store(true, .SeqCst);
testing.expectEqual(true, a.xchg(false, .SeqCst));
testing.expectEqual(false, a.load(.SeqCst));
}

Some files were not shown because too many files have changed in this diff Show More