feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+289
View File
@@ -0,0 +1,289 @@
use std::future::Future;
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use hyper::service::service_fn;
use hyper_util::rt::TokioIo;
use tokio::sync::Mutex;
use super::reply::{HttpReply, LiveLimits, Outgoing, Session};
use super::write_timeout::WriteTimeout;
use super::{Budget, Limits, Request, RequestContext, read_request, reject};
use crate::{net, task};
/// HTTP/1 每条连接最多一个活跃 handler;升级后仍占用同一个连接和任务名额。
pub async fn serve_live<F, Fut>(
route: F,
listener: net::Listener,
limits: Limits,
live: LiveLimits,
) -> Result<(), String>
where
F: Fn(Request, HttpReply) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
serve_transport(route, listener, limits, live, None).await
}
pub async fn serve_live_tls<F, Fut>(
route: F,
listener: net::Listener,
limits: Limits,
live: LiveLimits,
tls: crate::tls::ServerTls,
) -> Result<(), String>
where
F: Fn(Request, HttpReply) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
serve_transport(route, listener, limits, live, Some(tls)).await
}
async fn serve_transport<F, Fut>(
route: F,
listener: net::Listener,
limits: Limits,
live: LiveLimits,
tls: Option<crate::tls::ServerTls>,
) -> Result<(), String>
where
F: Fn(Request, HttpReply) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
let budget = limits.check()?;
live.check()?;
let tls = tls.map(|tls| super::protocol::server_tls(tls, budget.http2));
task::parallel_each_stream(
net::incoming(listener.clone(), true),
limits.connections,
move |connection| {
let route = route.clone();
let tls = tls.clone();
let listener = listener.clone();
async move {
let stream = connection?;
let stream = match crate::tls::accept(stream, tls.as_ref(), limits.timeout_ms).await
{
Ok(stream) => stream,
Err(_) => return Ok(()),
};
if super::protocol::check_alpn(&stream, budget.http2).is_err() {
return Ok(());
}
if let Some(http2) = budget.http2 {
return serve_http2(route, listener, stream, budget, live, http2).await;
}
let handlers = Arc::new(Mutex::new(Some(task::Group::new(1)?)));
let upgraded = Arc::new(AtomicBool::new(false));
let service = {
let handlers = handlers.clone();
let upgraded = upgraded.clone();
service_fn(move |request| {
dispatch(
request,
route.clone(),
budget,
live,
handlers.clone(),
upgraded.clone(),
)
})
};
let connection = super::server_builder(budget)
.serve_connection(
TokioIo::new(WriteTimeout::new(stream, budget.timeout)),
service,
)
.with_upgrades();
tokio::pin!(connection);
let result = tokio::select! {
result = &mut connection => result,
_ = listener.closed() => {
connection.as_mut().graceful_shutdown();
connection.await
}
};
let group = handlers
.lock()
.await
.take()
.expect("connection owns handlers");
if result.is_ok() && upgraded.load(Ordering::Acquire) {
group.wait().await?;
} else {
group.stop().await?;
}
super::connection_result(result)
}
},
)
.await
}
async fn serve_http2<F, Fut>(
route: F,
listener: net::Listener,
stream: crate::transport::Transport,
budget: Budget,
live: LiveLimits,
http2: super::Http2Limits,
) -> Result<(), String>
where
F: Fn(Request, HttpReply) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
let (mut owner, spawner, fault) = task::scoped_owner(())?;
let first_request = super::server_h2::FirstRequest::new();
let service = {
let first_request = first_request.clone();
service_fn(move |request| {
first_request.mark();
let route = route.clone();
dispatch_http2(request, route, budget, live)
})
};
let mut builder = http2.server_builder(super::executor::Http2Executor(spawner), budget.headers);
super::server_h2::configure_liveness(&mut builder, budget.timeout);
let connection = builder.serve_connection(
hyper_util::rt::TokioIo::new(WriteTimeout::new(stream, budget.timeout)),
service,
);
let result = owner
.enter(super::server_h2::drive(
connection,
&listener,
&first_request,
budget.timeout,
&fault,
|connection| connection.graceful_shutdown(),
))
.await;
super::server_h2::complete(owner, result).await
}
async fn dispatch<F, Fut>(
mut request: hyper::Request<hyper::body::Incoming>,
route: F,
budget: Budget,
live: LiveLimits,
handlers: Arc<Mutex<Option<task::Group>>>,
upgraded: Arc<AtomicBool>,
) -> Result<hyper::Response<Outgoing>, std::convert::Infallible>
where
F: Fn(Request, HttpReply) -> Fut + Send + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
let upgrade = if request.headers().contains_key(hyper::header::UPGRADE) {
let upgrade = hyper::upgrade::on(&mut request);
let mut handshake = hyper::Request::new(());
*handshake.method_mut() = request.method().clone();
*handshake.uri_mut() = request.uri().clone();
*handshake.version_mut() = request.version();
*handshake.headers_mut() = request.headers().clone();
Some((handshake, upgrade))
} else {
None
};
let request = match read_request(request, budget).await {
Ok(request) => request,
Err(status) => return Ok(reject(status, budget).map(Outgoing::Full)),
};
let context = RequestContext::new("http/1.1", request.target.clone(), None);
let (session, head) = Session::new(budget, live, upgrade, upgraded);
let reply = session.reply();
let state = reply.clone();
let handler_context = context.clone();
let started = handlers
.lock()
.await
.as_mut()
.expect("active connection")
.run(async move {
let result = session.run(route(request, reply)).await;
if let Err(error) = result {
handler_context.report(error);
}
Ok(())
})
.await;
if let Err(error) = started {
context.report(error);
return Ok(reject(hyper::StatusCode::INTERNAL_SERVER_ERROR, budget).map(Outgoing::Full));
}
match tokio::time::timeout(budget.timeout, head).await {
Ok(Ok(response)) => Ok(response),
Ok(Err(_)) => {
if state.fault().is_none() {
context.report("HTTP live handler ended without a response");
}
Ok(reject(hyper::StatusCode::INTERNAL_SERVER_ERROR, budget).map(Outgoing::Full))
}
Err(_) => Ok(reject(hyper::StatusCode::GATEWAY_TIMEOUT, budget).map(Outgoing::Full)),
}
}
async fn dispatch_http2<F, Fut>(
request: hyper::Request<hyper::body::Incoming>,
route: F,
budget: Budget,
live: LiveLimits,
) -> Result<hyper::Response<Outgoing>, std::convert::Infallible>
where
F: Fn(Request, HttpReply) -> Fut + Send + 'static,
Fut: Future<Output = Result<(), String>> + Send + 'static,
{
if request.method() == hyper::Method::CONNECT
|| request.headers().contains_key(hyper::header::UPGRADE)
{
return Ok(reject(hyper::StatusCode::NOT_IMPLEMENTED, budget).map(Outgoing::Full));
}
let request = match read_request(request, budget).await {
Ok(request) => request,
Err(status) => return Ok(reject(status, budget).map(Outgoing::Full)),
};
let context = RequestContext::new("http/2", request.target.clone(), None);
let (session, head) = Session::new(budget, live, None, Arc::new(AtomicBool::new(false)));
let reply = session.reply();
let state = reply.clone();
let mut handler = match task::Group::new(1) {
Ok(handler) => handler,
Err(error) => {
context.report(error);
return Ok(reject(hyper::StatusCode::INTERNAL_SERVER_ERROR, budget).map(Outgoing::Full));
}
};
let handler_context = context.clone();
let started = handler
.run(async move {
let result = session.run(route(request, reply)).await;
if let Err(error) = result {
handler_context.report(error);
}
Ok(())
})
.await;
if let Err(error) = started {
context.report(error);
return Ok(reject(hyper::StatusCode::INTERNAL_SERVER_ERROR, budget).map(Outgoing::Full));
}
match tokio::time::timeout(budget.timeout, head).await {
Ok(Ok(response)) => Ok(response.map(|body| body.with_handler(handler))),
Ok(Err(_)) => {
if let Err(error) = handler.wait().await {
context.report(error);
} else if state.fault().is_none() {
context.report("HTTP live handler ended without a response");
}
Ok(reject(hyper::StatusCode::INTERNAL_SERVER_ERROR, budget).map(Outgoing::Full))
}
Err(_) => match handler.stop().await {
Ok(()) => Ok(reject(hyper::StatusCode::GATEWAY_TIMEOUT, budget).map(Outgoing::Full)),
Err(error) => {
context.report(error);
Ok(reject(hyper::StatusCode::GATEWAY_TIMEOUT, budget).map(Outgoing::Full))
}
},
}
}