Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,246 @@
|
||||
use dever_runtime::api;
|
||||
use dever_runtime::application::Session;
|
||||
use dever_runtime::auth;
|
||||
use dever_runtime::config::RuntimeProfile;
|
||||
use dever_runtime::http::{Request, Response};
|
||||
use dever_runtime::wire::decode::{self, Fields, Reader};
|
||||
use dever_runtime::wire::{Encoded, Encoder};
|
||||
use dever_runtime::{lifecycle, task};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Row {
|
||||
id: i64,
|
||||
text: String,
|
||||
weight: f64,
|
||||
note: Option<String>,
|
||||
}
|
||||
|
||||
impl Fields for Row {
|
||||
fn count(&self) -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn index(&self, name: &str) -> Result<usize, String> {
|
||||
match name {
|
||||
"id" => Ok(0),
|
||||
"text" => Ok(1),
|
||||
"weight" => Ok(2),
|
||||
"note" => Ok(3),
|
||||
_ => Err("unknown wire record field".into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn required(&self, index: usize) -> bool {
|
||||
index != 3
|
||||
}
|
||||
|
||||
fn read(&mut self, index: usize, reader: &mut Reader<'_, '_>) -> Result<(), String> {
|
||||
match index {
|
||||
0 => self.id = reader.int()?,
|
||||
1 => self.text = reader.text()?.into_owned(),
|
||||
2 => self.weight = reader.float()?,
|
||||
3 => {
|
||||
reader.nullable(&mut |reader| {
|
||||
self.note = Some(reader.text()?.into_owned());
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
_ => return Err("invalid wire field index".into()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Payload {
|
||||
rows: Vec<Row>,
|
||||
raw: Option<Encoded>,
|
||||
}
|
||||
|
||||
impl Fields for Payload {
|
||||
fn count(&self) -> usize {
|
||||
2
|
||||
}
|
||||
|
||||
fn index(&self, name: &str) -> Result<usize, String> {
|
||||
match name {
|
||||
"rows" => Ok(0),
|
||||
"raw" => Ok(1),
|
||||
_ => Err("unknown wire record field".into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn required(&self, _: usize) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn read(&mut self, index: usize, reader: &mut Reader<'_, '_>) -> Result<(), String> {
|
||||
match index {
|
||||
0 => reader.list(&mut |reader| {
|
||||
let mut row = Row::default();
|
||||
reader.record(&mut row)?;
|
||||
self.rows.push(row);
|
||||
Ok(())
|
||||
}),
|
||||
1 => {
|
||||
self.raw = Some(reader.json()?);
|
||||
Ok(())
|
||||
}
|
||||
_ => Err("invalid wire field index".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Payload {
|
||||
fn encode(self) -> Result<Encoded, String> {
|
||||
let mut encoder = Encoder::default();
|
||||
encoder.compiled_record(2, |encoder| {
|
||||
encoder.compiled_key("\"rows\":")?;
|
||||
encoder.begin_array()?;
|
||||
for row in self.rows {
|
||||
encoder.compiled_record(4, |encoder| {
|
||||
encoder.compiled_key("\"id\":")?;
|
||||
encoder.int(row.id)?;
|
||||
encoder.compiled_key(",\"text\":")?;
|
||||
encoder.text(&row.text)?;
|
||||
encoder.compiled_key(",\"weight\":")?;
|
||||
encoder.float(row.weight)?;
|
||||
encoder.compiled_key(",\"note\":")?;
|
||||
match row.note {
|
||||
Some(note) => encoder.text(¬e),
|
||||
None => encoder.null(),
|
||||
}
|
||||
})?;
|
||||
}
|
||||
encoder.end()?;
|
||||
encoder.compiled_key(",\"raw\":")?;
|
||||
encoder.encoded(&self.raw.ok_or("missing required wire field")?)
|
||||
})?;
|
||||
encoder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
enum Value {
|
||||
Typed(Payload),
|
||||
Raw(Encoded),
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
typed: bool,
|
||||
value: Option<Value>,
|
||||
}
|
||||
|
||||
impl Fields for Arguments {
|
||||
fn count(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn index(&self, name: &str) -> Result<usize, String> {
|
||||
if name == if self.typed { "payload" } else { "source" } {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err("unknown wire record field".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn required(&self, _: usize) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn read(&mut self, _: usize, reader: &mut Reader<'_, '_>) -> Result<(), String> {
|
||||
self.value = Some(if self.typed {
|
||||
let mut payload = Payload::default();
|
||||
reader.record(&mut payload)?;
|
||||
Value::Typed(payload)
|
||||
} else {
|
||||
Value::Raw(reader.json()?)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn call(mut request: Request, typed: bool) -> Response {
|
||||
if let Err(error) = auth::require_components(&[], &[]).await {
|
||||
return api::auth_error(error);
|
||||
}
|
||||
if let Err(error) = api::upload::read_body(&mut request).await {
|
||||
return api::invalid_input(error);
|
||||
}
|
||||
let body = match api::Inputs::json_body(&request) {
|
||||
Ok(body) => body,
|
||||
Err(error) => return api::invalid_input(error),
|
||||
};
|
||||
let mut arguments = Arguments { typed, value: None };
|
||||
if let Err(error) = decode::read(body, &mut |reader| reader.record(&mut arguments)) {
|
||||
return api::invalid_input(api::InputError(error));
|
||||
}
|
||||
let encoded = match arguments.value {
|
||||
Some(Value::Typed(payload)) => payload.encode(),
|
||||
Some(Value::Raw(value)) => Ok(value),
|
||||
None => Err("missing required wire field".into()),
|
||||
};
|
||||
match encoded {
|
||||
Ok(value) => {
|
||||
if api::commit_response_metadata().is_err() {
|
||||
return api::internal_error();
|
||||
}
|
||||
api::success(value)
|
||||
}
|
||||
Err(_) => api::internal_error(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn route(request: Request) -> Result<Response, String> {
|
||||
let typed = match request.target.split('?').next().unwrap_or("") {
|
||||
"/benchmark/echo/echo" => true,
|
||||
"/benchmark/echo/raw" => false,
|
||||
_ => return Ok(api::not_found()),
|
||||
};
|
||||
if request.method != "POST" {
|
||||
return Ok(api::method_not_allowed(&["POST"]));
|
||||
}
|
||||
let prepared = match auth::prepare(&[], &request, true) {
|
||||
Ok(prepared) => prepared,
|
||||
Err(error) => return Ok(api::auth_error(error)),
|
||||
};
|
||||
let identity = prepared.claims().map(|claims| auth::Identity {
|
||||
id: claims.subject.clone(),
|
||||
user_id: None,
|
||||
tenant_id: None,
|
||||
});
|
||||
Ok(
|
||||
match auth::scope(prepared, identity, call(request, typed)).await {
|
||||
Ok(response) => response,
|
||||
Err(error) => api::auth_error(error),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let session = Session::load(
|
||||
RuntimeProfile {
|
||||
sqlite: true,
|
||||
postgres: false,
|
||||
},
|
||||
&[(None, "benchmark", false)],
|
||||
&[],
|
||||
)?;
|
||||
session.initialize_authorization(false)?;
|
||||
let cleanup = session.clone();
|
||||
task::run_entry_with_typed_cleanup(
|
||||
task::RuntimeConfig::default(),
|
||||
session.clone().scope(async move {
|
||||
session
|
||||
.databases()
|
||||
.prepare()
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
lifecycle::configure(true, false)?;
|
||||
lifecycle::run(api::serve(route)).await
|
||||
}),
|
||||
|result| async move {
|
||||
let closed = cleanup.close().await;
|
||||
result.and(closed)
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user