wit-bindgen-cli 0.61.1

CLI tool to generate bindings for WIT documents and the component model.
//@ wasmtime-flags = '-Wcomponent-model-async -S p3 -S http'
//@ [lang]
//@ path = 'gen/interface/wasi/http/handler/stub.mbt'
//@ pkg_config = """{ "supported-targets": "+wasm", "import": [{ "path": "moonbitlang/core/buffer", "alias": "buffer" }, { "path": "example/background-hook/async-core", "alias": "async-core" }, { "path": "example/background-hook/interface/wasi/http/types", "alias": "types" }] }"""

///|
pub async fn handle(
  request : @types.Request,
  background_group : @async-core.TaskGroup[Unit],
) -> Result[@types.Response, @types.ErrorCode] {
  guard request.get_method() is @types.Method::Post else {
    request.drop()
    return Err(@types.ErrorCode::HttpRequestMethodInvalid)
  }
  guard request.get_path_with_query() == Some("/hooks/build") else {
    request.drop()
    return Err(@types.ErrorCode::HttpRequestUriInvalid)
  }

  let (handling_result, handling_promise) = @async-core.Future::new()
  let (request_body, request_trailers) = request.consume_body(handling_result)
  let payload = @buffer.Buffer()
  for ;; {
    match request_body.read(4096) {
      Some(chunk) => payload.write_iter(chunk.iter())
      None => break
    }
  }
  request_body.drop()
  match request_trailers.get() {
    Ok(Some(fields)) => fields.drop()
    Ok(None) => ()
    Err(error) => {
      let _ = handling_promise.complete(Err(error))
      return Err(error)
    }
  }
  let payload = payload.to_bytes()

  let (body_done, body_done_promise) = @async-core.Future::new()
  let response_body = @async-core.Stream::produce(async fn(sink) {
    guard sink.write_all_bytes(b"accepted"[:]) else {
      abort("response body closed early")
    }
    sink.close()
    let _ = body_done_promise.complete(())
  })
  let (transmitted_done, transmitted_done_promise) = @async-core.Future::new()
  let response_trailers = @async-core.Future::from(async fn() {
    body_done.get()
    transmitted_done.get()
    Ok(Some(@types.Fields::fields()))
  })
  let (response, response_transmitted) = @types.Response::new(
    @types.Fields::fields(),
    Some(response_body),
    response_trailers,
  )
  guard response.set_status_code(202U) is Ok(_) else {
    let error = @types.ErrorCode::InternalError(
      Some("failed to set hook response status"),
    )
    let _ = handling_promise.complete(Err(error))
    response.drop()
    return Err(error)
  }

  background_group.spawn_bg(async fn() {
    let result = (async fn() -> Result[Unit, @types.ErrorCode] {
      let transmission_result = response_transmitted.get()
      let _ = transmitted_done_promise.complete(())
      match transmission_result {
        Err(error) => return Err(error)
        Ok(_) => ()
      }
      let expected = b"build=release"
      guard payload.length() == expected.length() else {
        return Err(
          @types.ErrorCode::InternalError(Some("unexpected hook payload")),
        )
      }
      for i in 0..<expected.length() {
        guard payload[i] == expected[i] else {
          return Err(
            @types.ErrorCode::InternalError(Some("unexpected hook payload")),
          )
        }
      }
      Ok(())
    })() catch {
      _ => Err(
        @types.ErrorCode::InternalError(Some("background hook task failed")),
      )
    }
    let _ = handling_promise.complete(result)
  })
  Ok(response)
}