Comece com exemplos e passo a passo em nosso site!
Não tem tempo para ler os documentos? Confira
✅ Runções em estábulo ✅ RUNS RÁPIDO ✅ não usa inseguro
Documentação
O Thruster é uma estrutura da web que visa que os desenvolvedores sejam produtivos e consistentes em projetos e equipes. Seus objetivos são ser:
Propulsor também
unsafeO propulsor pode ser executado com back -ends de servidor diferentes e representa uma camada bem embalada sobre eles. Isso significa que ele pode acompanhar as melhores e mais recentes alterações de artistas como Hyper, Actix ou mesmo ThraterServer, um motor HTTP caseiro.
Com base em estruturas como Koa e Express, o propulsor pretende ser um prazer desenvolver.
Para executar o exemplo cargo run --example <example-name> . Por exemplo, cargo run --example hello_world e aberto http: // localhost: 4321/
As partes principais que fazem com que o novo trabalho de código assíncrono aguarda está designando funções de middleware com o atributo #[middleware_fn] (que marca o middleware para que seja compatível com a versão futura estável na qual o propulsor é construído) e depois o m! Macro nas rotas reais.
Um exemplo simples para usar o Async Wait é:
use std :: boxed :: Box ;
use std :: future :: Future ;
use std :: pin :: Pin ;
use std :: time :: Instant ;
use thruster :: { App , BasicContext as Ctx , Request } ;
use thruster :: { m , middleware_fn , MiddlewareNext , MiddlewareResult , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn profile ( context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ;
let elapsed_time = start_time . elapsed ( ) ;
println ! (
"[{}μs] {} -- {}" ,
elapsed_time . as_micros ( ) ,
context . request . method ( ) ,
context . request . path ( )
) ;
Ok ( context )
}
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn four_oh_four ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . status ( 404 ) ;
context . body ( "Whoops! That route doesn't exist!" ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
app . get ( "/plaintext" , m ! [ profile , plaintext ] ) ;
app . set404 ( m ! [ four_oh_four ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
}Aqui está um bom exemplo
use thruster :: errors :: ThrusterError as Error ;
use thruster :: proc :: { m , middleware_fn } ;
use thruster :: { map_try , App , BasicContext as Ctx , Request } ;
use thruster :: { MiddlewareNext , MiddlewareResult , MiddlewareReturnValue , Server , ThrusterServer } ;
# [ middleware_fn ]
async fn plaintext ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let val = "Hello, World!" ;
context . body ( val ) ;
Ok ( context )
}
# [ middleware_fn ]
async fn error ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
let res = "Hello, world" . parse :: < u32 > ( )
. map_err ( |_| {
let mut context = Ctx :: default ( ) ;
context . status ( 400 ) ;
ThrusterError {
context ,
message : "Custom error message" . to_string ( ) ,
cause : None ,
}
} ? ;
context . body ( & format ! ( "{}" , non_existent_param ) ) ;
Ok ( context )
}
# [ tokio :: main ]
fn main ( ) {
println ! ( "Starting server..." ) ;
let app = App :: < Request , Ctx , ( ) > :: new_basic ( )
. get ( "/plaintext" , m ! [ plaintext ] )
. get ( "/error" , m ! [ error ] ) ;
let server = Server :: new ( app ) ;
server . build ( "0.0.0.0" , 4321 ) . await ;
} O Thruster fornece uma suíte de teste fácil para testar seus terminais, basta incluir o módulo testing como abaixo:
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
.. .
app . get ( "/plaintext" , m ! [ plaintext ] ) ;
.. .
let result = testing :: get ( app , "/plaintext" ) ;
assert ! ( result . body == "Hello, World!" ) ; O middleware é super fácil de fazer! Basta criar uma função e exportá -la em um nível de módulo. Abaixo, você verá um pedaço de middleware que permite o perfil de solicitações:
# [ middleware_fn ]
async fn profiling < C : ' static + Context + Send > (
mut context : C ,
next : MiddlewareNext < C > ,
) -> MiddlewareResult < C > {
let start_time = Instant :: now ( ) ;
context = next ( context ) . await ? ;
let elapsed_time = start_time . elapsed ( ) ;
info ! ( "[{}μs] {}" , elapsed_time . as_micros ( ) , context . route ( ) ) ;
Ok ( context )
}Você pode achar que deseja permitir dados mais específicos armazenados no contexto, por exemplo, talvez você queira hidratar parâmetros de consulta em um hashmap para uso posterior por outros middlewares. Para fazer isso, você pode criar uma característica adicional para o contexto para o qual o Middlewares a jusante deve aderir. Confira o middleware query_params fornecido para um exemplo.
O propulsor é capaz de apenas fornecer a camada de roteamento em cima de um servidor de algum tipo, por exemplo, no snippet hiper acima. Isso pode ser aplicado amplamente a qualquer back -end, desde que o servidor implemente ThrusterServer .
use async_trait :: async_trait ;
# [ async_trait ]
pub trait ThrusterServer {
type Context : Context + Send ;
type Response : Send ;
type Request : RequestWithParams + Send ;
fn new ( App < Self :: Request , Self :: Context > ) -> Self ;
async fn build ( self , host : & str , port : u16 ) ;
}Precisa haver:
Dentro da função build , a implementação do servidor deve:
let matched = app.resolve_from_method_and_path(<some method>, <some path>); (Isso está fornecendo o roteamento real.)app.resolve(<incoming request>, matched) (isso executa o middleware encadeado.) fn ip_guard ( head : & RequestHead ) -> bool {
// Check for the cloudflare IP header
let ip = if let Some ( val ) = head . headers ( ) . get ( CF_IP_HEADER ) {
val . to_str ( ) . unwrap_or ( "" ) . to_owned ( )
} else if let Some ( val ) = head . peer_addr {
val . to_string ( )
} else {
return false ;
} ;
"1.2.3.4" . contains ( & ip )
}
# [ actix_web :: post ( "/ping" ) ]
async fn ping ( ) -> Result < HttpResponse , UserPersonalError > {
Ok ( HttpResponse :: Ok ( ) . body ( "pong" ) )
}
.. .
web :: scope ( "/*" )
// This is confusing, but we catch all routes that _aren't_
// ip guarded and return an error.
. guard ( guard :: Not ( ip_guard ) )
. route ( "/*" , web :: to ( HttpResponse :: Forbidden ) ) ,
)
. service ( ping ) ;
.. .Aqui está o propulsor:
# [ middleware_fn ]
async fn ip_guard ( mut context : Ctx , next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
if "1.2.3.4" . contains ( & context . headers ( ) . get ( "Auth-Token" ) . unwrap_or ( "" ) ) {
context = next ( context ) . await ? ;
Ok ( context )
} else {
Err ( Error :: unauthorized_error ( context ) )
}
}
# [ middleware_fn ]
async fn ping ( mut context : Ctx , _next : MiddlewareNext < Ctx > ) -> MiddlewareResult < Ctx > {
context . body ( "pong" ) ;
Ok ( context )
}
.. .
app . get ( "/ping" , m ! [ ip_guard , plaintext ] ) ;
.. .Um pouco mais direto é bom!
Se você chegou tão longe, obrigado por ler! Sempre fique à vontade para alcançar.