1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//! # kanin
//!
//! A framework for AMQP built on top of [lapin](https://github.com/amqp-rs/lapin).
//!
//! kanin makes it easy to create RPC microservices using protobuf in Rust with minimal boilerplate.
//!
//! # Example
//! ```no_run
//! # mod protobuf {
//! # #[derive(kanin::FromError)]
//! # #[derive(Clone, PartialEq, ::prost::Message)]
//! # pub struct InvalidRequest {
//! # #[prost(string, tag="1")]
//! # pub error: ::prost::alloc::string::String,
//! # }
//! # #[derive(Clone, PartialEq, ::prost::Message)]
//! # pub struct InternalError {
//! # #[prost(string, tag="1")]
//! # pub source: ::prost::alloc::string::String,
//! # #[prost(string, tag="2")]
//! # pub error: ::prost::alloc::string::String,
//! # }
//! # #[derive(Clone, PartialEq, ::prost::Message)]
//! # pub struct EchoRequest {
//! # #[prost(string, tag="1")]
//! # pub value: ::prost::alloc::string::String,
//! # }
//! # #[derive(kanin::FromError)]
//! # #[derive(Clone, PartialEq, ::prost::Message)]
//! # pub struct EchoResponse {
//! # #[prost(oneof="echo_response::Response", tags="1, 2, 3")]
//! # pub response: ::core::option::Option<echo_response::Response>,
//! # }
//! # /// Nested message and enum types in `EchoResponse`.
//! # pub mod echo_response {
//! # #[derive(Clone, PartialEq, ::prost::Message)]
//! # pub struct Success {
//! # #[prost(string, tag="1")]
//! # pub value: ::prost::alloc::string::String,
//! # }
//! # #[derive(kanin::FromError)]
//! # #[derive(Clone, PartialEq, ::prost::Oneof)]
//! # pub enum Response {
//! # #[prost(message, tag="1")]
//! # Success(Success),
//! # #[prost(message, tag="2")]
//! # InternalError(super::InternalError),
//! # #[prost(message, tag="3")]
//! # InvalidRequest(super::InvalidRequest),
//! # }
//! # }
//! #
//! # impl EchoResponse {
//! # pub fn success(value: String) -> Self {
//! # Self { response: Some(echo_response::Response::Success(echo_response::Success { value })) }
//! # }
//! # }
//! # }
//! # use kanin::{extract::{Msg, State}, App, AppState};
//! # use protobuf::{EchoRequest, EchoResponse};
//! #
//! // EchoRequest and EchoResponse are protobuf messages as generated by prost_build: https://docs.rs/prost-build/latest/prost_build/index.html
//! async fn echo(Msg(request): Msg<EchoRequest>, State(num): State<u8>) -> EchoResponse {
//! assert_eq!(42, num);
//!
//! EchoResponse::success(request.value)
//! }
//!
//! #[derive(AppState)]
//! struct MyState {
//! num: u8
//! }
//!
//! #[tokio::main]
//! async fn main() -> kanin::Result<()> {
//! App::new(MyState { num: 42 })
//! .handler("my_routing_key", echo)
//! .run("amqp://localhost")
//! .await
//! }
//! ```
//!
//! # Help, why is my handler rejected by kanin?
//! There can be several reasons.
//!
//! Firstly, ensure that all parameters implement [`Extract`].
//! Especially for [`Msg`](extract::Msg), ensure the version of the `prost` crate used for the inner type is the same as the prost type used by `kanin`.
//! You can remove parameters one by one until the function is accepted to find out which parameter is the problem.
//! You can see if you have multiple `prost` versions by checking your `Cargo.lock` file.
//!
//! Secondly, ensure that the response type implements [`Respond`]. Once again, Protobuf messages automatically implement this but your `prost` version must match.
//!
//! If you're sure these things are handled, try to replace the body of the handler with `todo!()`.
//! If this causes the handler to work, then it's likely that the future your async function is creating is not [`Send`].
//! Your future must be [`Send`]. It is probably not [`Send`] because you're holding on to a type that is not [`Send`] across an await point.
//! For instance, holding a [`std::sync::MutexGuard`] across an await point will cause your future to not be [`Send`].
// kanin is 100% Safe Rust.
// Re-exporting underlying lapin version so you don't have to add the same version as a dependency.
pub use lapin;
// Also re-exporting connection for easy access.
pub use Connection;
// pub-using every name::Name to avoid having to have kanin::name::Name repetition.
// This way you can just do kanin::Name.
pub use App;
pub use Error;
pub use HandlerError;
pub use Extract;
pub use Handler;
pub use HandlerConfig;
pub use AppState;
pub use FromError;
pub use Request;
pub use Respond;
/// Convenience type for a result with `kanin`'s error.
pub type Result<T> = Result;