Skip to content

Commit daa0a88

Browse files
author
Ryan Miville
committed
first commit of generated services
1 parent 12850bb commit daa0a88

File tree

327 files changed

+257092
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

327 files changed

+257092
-5
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
*.ez
33
/build
44
erl_crash.dump
5+
.DS_Store

gleam.toml

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ version = "1.0.0"
1414

1515
[dependencies]
1616
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
17+
envoy = ">= 1.0.1 and < 2.0.0"
18+
aws4_request = ">= 0.1.1 and < 1.0.0"
19+
gleam_http = ">= 3.6.0 and < 4.0.0"
1720

1821
[dev-dependencies]
1922
gleeunit = ">= 1.0.0 and < 2.0.0"

manifest.toml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This file was generated by Gleam
2+
# You typically do not need to edit this file
3+
4+
packages = [
5+
{ name = "aws4_request", version = "0.1.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_http", "gleam_stdlib"], otp_app = "aws4_request", source = "hex", outer_checksum = "90B1DB6E2A7F0396CD4713850B14B3A910331B5BA76D051E411D1499AAA2EA9A" },
6+
{ name = "envoy", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "CFAACCCFC47654F7E8B75E614746ED924C65BD08B1DE21101548AC314A8B6A41" },
7+
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
8+
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
9+
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
10+
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
11+
]
12+
13+
[requirements]
14+
aws4_request = { version = ">= 0.1.1 and < 1.0.0" }
15+
envoy = { version = ">= 1.0.1 and < 2.0.0" }
16+
gleam_http = { version = ">= 3.6.0 and < 4.0.0" }
17+
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
18+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }

src/aws_request.gleam

-5
This file was deleted.

src/aws_request/config.gleam

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import envoy
2+
import gleam/option.{type Option, None}
3+
import gleam/result
4+
5+
const aws_access_key_id = "AWS_ACCESS_KEY_ID"
6+
7+
const aws_secret_access_key = "AWS_SECRET_ACCESS_KEY"
8+
9+
const aws_session_token = "AWS_SESSION_TOKEN"
10+
11+
const aws_default_region = "AWS_DEFAULT_REGION"
12+
13+
type Env =
14+
Result(String, String)
15+
16+
pub type ConfigError {
17+
ConfigError(message: String)
18+
}
19+
20+
pub opaque type ConfigBuilder {
21+
ConfigBuilder(
22+
access_key_id: Env,
23+
secret_access_key: Env,
24+
session_token: Env,
25+
region: Env,
26+
endpoint: Option(String),
27+
proto: String,
28+
port: Int,
29+
)
30+
}
31+
32+
pub type Config {
33+
Config(
34+
access_key_id: String,
35+
secret_access_key: String,
36+
region: String,
37+
session_token: Option(String),
38+
endpoint: Option(String),
39+
)
40+
}
41+
42+
pub fn new() -> ConfigBuilder {
43+
let access_key_id = env(aws_access_key_id)
44+
let secret_access_key = env(aws_secret_access_key)
45+
let region = env(aws_default_region)
46+
let session_token = env(aws_session_token)
47+
48+
ConfigBuilder(
49+
access_key_id:,
50+
secret_access_key:,
51+
session_token:,
52+
region:,
53+
endpoint: None,
54+
proto: "https",
55+
port: 443,
56+
)
57+
}
58+
59+
pub fn with_region(builder: ConfigBuilder, region: String) {
60+
ConfigBuilder(..builder, region: Ok(region))
61+
}
62+
63+
pub fn with_credentials(
64+
builder: ConfigBuilder,
65+
access_key_id: String,
66+
secret_access_key: String,
67+
) {
68+
ConfigBuilder(
69+
..builder,
70+
access_key_id: Ok(access_key_id),
71+
secret_access_key: Ok(secret_access_key),
72+
)
73+
}
74+
75+
pub fn with_session_token(builder: ConfigBuilder, session_token: String) {
76+
ConfigBuilder(..builder, session_token: Ok(session_token))
77+
}
78+
79+
pub fn build(builder: ConfigBuilder) -> Result(Config, ConfigError) {
80+
builder |> do_build |> result.map_error(ConfigError)
81+
}
82+
83+
fn do_build(builder: ConfigBuilder) -> Result(Config, String) {
84+
use access_key_id <- result.try(builder.access_key_id)
85+
use secret_access_key <- result.try(builder.secret_access_key)
86+
use region <- result.map(builder.region)
87+
let session_token = option.from_result(builder.session_token)
88+
Config(
89+
access_key_id:,
90+
secret_access_key:,
91+
region:,
92+
session_token:,
93+
endpoint: builder.endpoint,
94+
)
95+
}
96+
97+
fn env(name: String) -> Env {
98+
envoy.get(name)
99+
|> result.replace_error(name <> "not set")
100+
}
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import aws_request/config.{type Config}
2+
import aws_request/internal/metadata.{type Metadata, Global}
3+
import gleam/option.{None, Some}
4+
import gleam/string
5+
6+
pub type Endpoint {
7+
Endpoint(
8+
hostname: String,
9+
protocol: String,
10+
signing_region: String,
11+
signing_name: String,
12+
)
13+
}
14+
15+
pub fn from(config: Config, metadata: Metadata) -> Endpoint {
16+
case config.endpoint {
17+
Some(ep) -> {
18+
let #(protocol, hostname) = split_scheme(ep)
19+
Endpoint(hostname, protocol, config.region, metadata.signing_name)
20+
}
21+
None -> resolve(config, metadata)
22+
}
23+
}
24+
25+
fn split_scheme(uri: String) {
26+
case uri {
27+
"https://" <> host -> #("https", host)
28+
"http://" <> host -> #("http", host)
29+
other -> #("https", other)
30+
}
31+
}
32+
33+
fn resolve(config: Config, metadata: Metadata) -> Endpoint {
34+
case config.region, metadata.global {
35+
"local", _ ->
36+
Endpoint("localhost:8000", "http", "us-east-1", metadata.signing_name)
37+
_, Some(Global(region, hostname)) ->
38+
Endpoint(hostname, "https", region, metadata.signing_name)
39+
region, None ->
40+
Endpoint(
41+
default(config, metadata),
42+
"https",
43+
region,
44+
metadata.signing_name,
45+
)
46+
}
47+
}
48+
49+
fn default(config: Config, metadata: Metadata) {
50+
string.concat([
51+
metadata.endpoint_prefix,
52+
".",
53+
config.region,
54+
".",
55+
"amazonaws.com",
56+
])
57+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import gleam/option.{type Option}
2+
3+
pub type Metadata {
4+
Metadata(
5+
endpoint_prefix: String,
6+
service_id: String,
7+
signing_name: String,
8+
global: Option(Global),
9+
)
10+
}
11+
12+
pub type Global {
13+
Global(credential_scope: String, hostname: String)
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import aws4_request
2+
import aws_request/internal/endpoint.{type Endpoint}
3+
import aws_request/internal/time
4+
import gleam/bit_array
5+
import gleam/http.{type Header}
6+
import gleam/http/request.{type Request, Request}
7+
import gleam/option.{type Option}
8+
9+
pub type RequestBuilder {
10+
RequestBuilder(
11+
access_key_id: String,
12+
secret_access_key: String,
13+
service_id: String,
14+
endpoint: Endpoint,
15+
)
16+
}
17+
18+
fn sign_v4(builder: RequestBuilder, request: Request(BitArray)) {
19+
let date_time = time.utc_now() |> time.to_parts
20+
aws4_request.sign(
21+
request,
22+
date_time,
23+
builder.access_key_id,
24+
builder.secret_access_key,
25+
builder.endpoint.signing_region,
26+
builder.endpoint.signing_name,
27+
)
28+
}
29+
30+
pub fn build(
31+
builder: RequestBuilder,
32+
method: http.Method,
33+
path: String,
34+
headers: List(Header),
35+
query: Option(String),
36+
body: Option(BitArray),
37+
) -> Request(BitArray) {
38+
let assert Ok(request) = request.to(url(builder.endpoint) <> path)
39+
let headers = [#("host", builder.endpoint.hostname), ..headers]
40+
41+
let body = option.unwrap(body, bit_array.from_string(""))
42+
let request =
43+
request.Request(..request, headers: headers, query: query)
44+
|> request.set_method(method)
45+
|> request.set_body(body)
46+
47+
sign_v4(builder, request)
48+
}
49+
50+
fn url(endpoint: Endpoint) -> String {
51+
endpoint.protocol <> "://" <> endpoint.hostname <> "/"
52+
}

src/aws_request/internal/time.gleam

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import gleam/option
2+
3+
pub opaque type Time {
4+
Time(wall_time: Int, monotonic_time: option.Option(Int))
5+
}
6+
7+
pub type Date {
8+
Date(year: Int, month: Int, day: Int)
9+
}
10+
11+
pub type DayTime {
12+
DayTime(hour: Int, minute: Int, second: Int, millisecond: Int)
13+
}
14+
15+
pub fn to_parts(value: Time) -> #(#(Int, Int, Int), #(Int, Int, Int)) {
16+
let #(#(year, month, day), #(hour, minute, second, _)) = do_to_parts(value)
17+
#(#(year, month, day), #(hour, minute, second))
18+
}
19+
20+
fn do_to_parts(value: Time) -> #(#(Int, Int, Int), #(Int, Int, Int, Int)) {
21+
case value {
22+
Time(wall_time: t, monotonic_time: _) -> {
23+
let #(date, time) = ffi_to_parts(t, 0)
24+
#(date, time)
25+
}
26+
}
27+
}
28+
29+
pub fn utc_now() -> Time {
30+
let now = ffi_now()
31+
let monotonic_now = ffi_monotonic_now()
32+
Time(now, option.Some(monotonic_now))
33+
}
34+
35+
@external(erlang, "time_ffi", "now")
36+
@external(javascript, "./time_ffi.mjs", "now")
37+
fn ffi_now() -> Int
38+
39+
@external(erlang, "time_ffi", "monotonic_now")
40+
@external(javascript, "./time_ffi.mjs", "monotonic_now")
41+
fn ffi_monotonic_now() -> Int
42+
43+
@external(erlang, "time_ffi", "to_parts")
44+
@external(javascript, "./time_ffi.mjs", "to_parts")
45+
fn ffi_to_parts(a: Int, b: Int) -> #(#(Int, Int, Int), #(Int, Int, Int, Int))

0 commit comments

Comments
 (0)