///|
fn arg_at(args : Array[String], index : Int) -> String? {
if index < args.length() {
Some(args[index])
} else {
None
}
}
///|
fn print_usage() -> Unit {
println("MoonHook demo CLI")
println(" moon run cmd/main -- demo")
println(" moon run cmd/main -- sign ")
println(" moon run cmd/main -- verify ")
println(" moon run cmd/main -- request ")
println(" moon run cmd/main -- providers")
println(
" moon run cmd/main -- sign-provider ",
)
println(" moon run cmd/main -- help")
}
///|
fn parse_seconds(text : String) -> Int? {
let value = @string.parse_int(text.trim()) catch { _ => return None }
Some(value)
}
///|
fn run_providers() -> Unit {
println("supported outbound signature providers:")
for provider in @MoonHook.signature_providers() {
println(" \{provider.describe()}")
}
}
///|
fn run_sign_provider(
name : String,
secret : String,
timestamp_s : Int,
payload : String,
) -> Unit {
match @MoonHook.SignatureProvider::parse(name) {
None => {
println("unknown provider: \{name}")
run_providers()
}
Some(provider) => {
println("provider: \{provider.describe()}")
println("signature: \{provider.sign_value(secret, payload, timestamp_s)}")
let headers = provider.sign_headers(secret, payload, timestamp_s)
if headers.length() == 0 {
println(
"body: \{@MoonHook.feishu_bot_text_body(secret, payload, timestamp_s)}",
)
} else {
for header in headers {
println("\{header.0}: \{header.1}")
}
}
}
}
}
///|
fn run_request(
hook_id : String,
url : String,
secret : String,
payload : String,
) -> Unit {
let hook = @MoonHook.Hook::new(hook_id, url).with_secret(secret)
let event_result = @MoonHook.EventBuilder::new()
.with_id("evt-cli")
.with_event_type("cli.request")
.with_payload(payload)
.build()
let event = match event_result {
Ok(event) => event
Err(message) => abort(message)
}
let request = @MoonHook.build_signed_request(hook, event)
println("method: \{request.http_method}")
println("url: \{request.url}")
for item in request.headers {
println("\{item.0}: \{item.1}")
}
println("body: \{request.body}")
println("signature: \{request.signature}")
}
///|
fn run_demo() -> Unit {
let registry = @MoonHook.HookRegistry::new()
let hook = @MoonHook.Hook::new("orders", "https://example.com/hooks/orders")
.with_secret("demo-secret")
.with_header("X-Team", "payments")
registry.register(hook) |> ignore
let event_result = @MoonHook.EventBuilder::new()
.with_id("evt-demo-1")
.with_event_type("order.created")
.with_subject("order/42")
.with_payload("{\"total\": 99}")
.build()
let event = match event_result {
Ok(event) => event
Err(message) => abort(message)
}
let signature = @MoonHook.sign_hmac_sha256(hook.secret, event.payload)
let mock = @MoonHook.MockTransport::new([@MoonHook.DeliveryResult::success(6)])
let engine = @MoonHook.DeliveryEngine::new(registry, mock.as_transport())
let outcome = engine.deliver("orders", event)
println("event: \{event.id} (\{event.event_type})")
println("signature: \{signature}")
println("status: \{outcome.status.describe()}")
println("attempts: \{outcome.attempts.length()}")
}
///|
fn main {
let args = @env.args()
let command = if args.length() > 1 { args[1] } else { "" }
match command {
"demo" => run_demo()
"sign" =>
match (arg_at(args, 2), arg_at(args, 3)) {
(Some(secret), Some(payload)) =>
println(@MoonHook.sign_hmac_sha256(secret, payload))
_ => print_usage()
}
"verify" =>
match (arg_at(args, 2), arg_at(args, 3), arg_at(args, 4)) {
(Some(secret), Some(payload), Some(signature)) =>
println(
@MoonHook.verify_hmac_sha256(secret, payload, signature).to_string(),
)
_ => print_usage()
}
"request" =>
match
(arg_at(args, 2), arg_at(args, 3), arg_at(args, 4), arg_at(args, 5)) {
(Some(hook_id), Some(url), Some(secret), Some(payload)) =>
run_request(hook_id, url, secret, payload)
_ => print_usage()
}
"providers" => run_providers()
"sign-provider" =>
match
(arg_at(args, 2), arg_at(args, 3), arg_at(args, 4), arg_at(args, 5)) {
(Some(name), Some(secret), Some(timestamp), Some(payload)) =>
match parse_seconds(timestamp) {
Some(timestamp_s) =>
run_sign_provider(name, secret, timestamp_s, payload)
None => print_usage()
}
_ => print_usage()
}
"help" => print_usage()
_ => print_usage()
}
}