ابدأ بأمثلة وتجول على موقعنا!
ليس لديك الوقت لقراءة المستندات؟ الدفع
✅ يعمل في مستقر ✅ يعمل بسرعة ✅ لا يستخدم غير آمن
الوثائق
Trouster هو إطار عمل على شبكة الإنترنت يهدف إلى أن يكون المطورون مثمرًا ومتسقًا عبر المشاريع والفرق. أهدافها هي أن تكون:
ثقل أيضا
unsafeيمكن تشغيل Troster مع خلفية خادم مختلفة ويمثل طبقة معبأة بشكل جيد عليها. هذا يعني أنه يمكنه مواكبة أحدث وأكبر التغييرات من أمثال Hyper أو Actix أو حتى Thrusterserver ، وهو محرك HTTP الذي ينمو محليًا.
استنادًا إلى أطر مثل KOA ، و Express ، يهدف Trouster إلى أن يكون من دواعي سروري التطور مع.
لتشغيل مثال cargo run --example <example-name> . على سبيل المثال ، cargo run --example hello_world وفتح http: // localhost: 4321/
تقوم الأجزاء الأساسية التي تجعل أعمال الرمز Async الجديد بتعيين وظائف الوسيطة مع سمة #[middleware_fn] (التي تمثل البرامج الوسيطة بحيث تكون متوافقة مع الإصدار المستقبلي المستقر الذي تم بناؤه على ذلك ،) ثم m! الماكرو في الطرق الفعلية.
مثال بسيط لاستخدام Async في انتظار:
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 ;
}هذا مثال لطيف
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 ;
} يوفر Trouster مجموعة اختبار سهلة لاختبار نقاط النهاية الخاصة بك ، ببساطة تضمين وحدة testing على النحو التالي:
let mut app = App :: < Request , Ctx , ( ) > :: new_basic ( ) ;
.. .
app . get ( "/plaintext" , m ! [ plaintext ] ) ;
.. .
let result = testing :: get ( app , "/plaintext" ) ;
assert ! ( result . body == "Hello, World!" ) ; الوسيطة سهلة للغاية! ببساطة إنشاء وظيفة وتصديرها على مستوى الوحدة النمطية. أدناه ، سترى قطعة من الوسيطة تسمح بتوصيف الطلبات:
# [ 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 )
}قد تجد أنك تريد السماح بتخزين المزيد من البيانات المحددة في السياق ، على سبيل المثال ، ربما تريد أن تكون قادرًا على ترطيب معلمات الاستعلام في hashmap لاستخدامها لاحقًا بواسطة الأدوات الوسطى الأخرى. من أجل القيام بذلك ، يمكنك إنشاء سمة إضافية للسياق الذي يجب أن تلتزم به Middlewares في اتجاه مجرى النهر. تحقق من البرامج الوسيطة Query_Params المقدمة للحصول على مثال.
Trouster قادر على توفير طبقة التوجيه أعلى خادم من نوع ما ، على سبيل المثال ، في المقتطف المفرط أعلاه. يمكن تطبيق ذلك على نطاق واسع على أي واجهات خلفية ، طالما أن الخادم ينفذ 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 ) ;
}يجب أن يكون هناك:
ضمن وظيفة build ، ينبغي أن يلفت تنفيذ الخادم:
let matched = app.resolve_from_method_and_path(<some method>, <some path>); (هذا يوفر التوجيه الفعلي.)app.resolve(<incoming request>, matched) (هذا يدير الوسيطة المتسلسلة.) 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 ) ;
.. .هنا غاز:
# [ 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 ] ) ;
.. .أكثر مباشرة قليلا هو لطيف!
إذا وصلت إلى هذا الحد ، شكرًا على القراءة! لا تتردد دائمًا في التواصل.