///|
priv struct ServiceSettings {
port : Double
logging_level : String
workers : Double
auth_enabled : Bool
}
///|
/// This sample consumer reads its own configuration directly. It deliberately
/// does not import ConfigScope or use its rule interpreter.
fn decode_settings(value : Json) -> Result[ServiceSettings, String] {
let root = match value {
Object(root) => root
_ => return Err("configuration must be an object")
}
let server = match root.get("server") {
Some(Object(server)) => server
_ => return Err("server must be present and an object")
}
let port = match server.get("port") {
Some(Number(port, ..)) if port == 8080.0 || port == 9090.0 => port
_ => return Err("server.port must be an accepted numeric port")
}
let logging_level = match root.get("logging") {
None => "info"
Some(Object(logging)) =>
match logging.get("level") {
None => "info"
Some(String(level)) if level == "info" || level == "warn" => level
_ => return Err("logging.level must be an accepted string")
}
_ => return Err("logging must be an object when present")
}
let workers = match server.get("workers") {
None => 4.0
Some(Number(workers, ..)) if workers >= 1.0 &&
workers <= 64.0 &&
workers.floor() == workers => workers
_ => return Err("server.workers must be an integer from 1 to 64")
}
let auth_enabled = match root.get("auth") {
None => false
Some(Object(auth)) => {
let enabled = match auth.get("enabled") {
None | Some(False) => false
Some(True) => true
_ => return Err("auth.enabled must be boolean")
}
if enabled {
match auth.get("token") {
Some(String(_)) => ()
_ =>
return Err("auth.token must be present and a string when enabled")
}
}
enabled
}
_ => return Err("auth must be an object when present")
}
Ok({ port, logging_level, workers, auth_enabled, })
}
///|
fn load_settings(args : Array[String]) -> Result[ServiceSettings, String] {
let file = match args.get(1) {
Some(file) if args.length() == 2 => file
_ => return Err("usage: service_consumer SNAPSHOT_JSON")
}
let source : Result[String, String] = Ok(@fs.read_file_to_string(file)) catch {
_ => Err("cannot read snapshot")
}
let source = match source {
Ok(source) => source
Err(error) => return Err(error)
}
let value : Result[Json, String] = Ok(@json.parse(source)) catch {
_ => Err("invalid JSON snapshot")
}
match value {
Ok(value) => decode_settings(value)
Err(error) => Err(error)
}
}
///|
fn main {
match load_settings(@env.args()) {
Ok(settings) =>
println(
"settings accepted: port=\{settings.port} log=\{settings.logging_level} workers=\{settings.workers} auth=\{settings.auth_enabled}",
)
Err(error) => {
println("consumer rejected: " + error)
@sys.exit(1)
}
}
}