1+ use crate :: dapr:: proto:: runtime:: v1:: app_callback_alpha_server:: AppCallbackAlpha ;
12use crate :: dapr:: proto:: runtime:: v1:: app_callback_server:: AppCallback ;
23use crate :: dapr:: proto:: { common, runtime} ;
34use std:: collections:: HashMap ;
@@ -40,6 +41,12 @@ pub type TopicEventBulkRequest = runtime::v1::TopicEventBulkRequest;
4041/// It includes the result for each event in the request.
4142pub type TopicEventBulkResponse = runtime:: v1:: TopicEventBulkResponse ;
4243
44+ /// JobEventRequest is the request message for a job event callback.
45+ pub type JobEventRequest = runtime:: v1:: JobEventRequest ;
46+
47+ /// JobEventResponse is the response from the app when a job is triggered.
48+ pub type JobEventResponse = runtime:: v1:: JobEventResponse ;
49+
4350impl ListTopicSubscriptionsResponse {
4451 /// Create `ListTopicSubscriptionsResponse` with a topic.
4552 pub fn topic ( pubsub_name : String , topic : String ) -> Self {
@@ -82,6 +89,7 @@ impl ListInputBindingsResponse {
8289
8390pub struct AppCallbackService {
8491 handlers : Vec < Handler > ,
92+ job_handlers : HashMap < String , Box < dyn JobHandlerMethod + Send + Sync + ' static > > ,
8593}
8694
8795pub struct Handler {
@@ -156,6 +164,52 @@ impl AppCallback for AppCallbackService {
156164 ) -> Result < Response < TopicEventBulkResponse > , Status > {
157165 todo ! ( "on_bulk_topic_event is not implemented yet" )
158166 }
167+
168+ async fn on_job_event (
169+ & self ,
170+ request : Request < runtime:: v1:: JobEventRequest > ,
171+ ) -> Result < Response < runtime:: v1:: JobEventResponse > , Status > {
172+ let request_inner = request. into_inner ( ) ;
173+ let job_name = if !request_inner. name . is_empty ( ) {
174+ request_inner. name . clone ( )
175+ } else if let Some ( stripped) = request_inner. method . strip_prefix ( "job/" ) {
176+ stripped. to_string ( )
177+ } else {
178+ return Err ( Status :: invalid_argument ( format ! (
179+ "cannot determine job name from request (method={:?})" ,
180+ request_inner. method,
181+ ) ) ) ;
182+ } ;
183+
184+ if let Some ( handler) = self . job_handlers . get ( & job_name) {
185+ let handle_response = handler. handler ( request_inner) . await ;
186+ handle_response. map ( Response :: new)
187+ } else {
188+ Err ( Status :: not_found ( format ! (
189+ "no handler registered for job {:?}" ,
190+ job_name,
191+ ) ) )
192+ }
193+ }
194+ }
195+
196+ // Also implement AppCallbackAlpha so the same service handles
197+ // Dapr ≤ 1.17 runtimes that call OnJobEventAlpha1 / OnBulkTopicEventAlpha1.
198+ #[ tonic:: async_trait]
199+ impl AppCallbackAlpha for AppCallbackService {
200+ async fn on_bulk_topic_event_alpha1 (
201+ & self ,
202+ request : Request < runtime:: v1:: TopicEventBulkRequest > ,
203+ ) -> Result < Response < runtime:: v1:: TopicEventBulkResponse > , Status > {
204+ self . on_bulk_topic_event ( request) . await
205+ }
206+
207+ async fn on_job_event_alpha1 (
208+ & self ,
209+ request : Request < runtime:: v1:: JobEventRequest > ,
210+ ) -> Result < Response < runtime:: v1:: JobEventResponse > , Status > {
211+ self . on_job_event ( request) . await
212+ }
159213}
160214
161215impl Default for AppCallbackService {
@@ -192,12 +246,19 @@ impl AppCallbackService {
192246 /// The actor HTTP server ([`crate::server::DaprHttpServer`]) installs
193247 /// the layer automatically.
194248 pub fn new ( ) -> AppCallbackService {
195- AppCallbackService { handlers : vec ! [ ] }
249+ AppCallbackService {
250+ handlers : vec ! [ ] ,
251+ job_handlers : HashMap :: new ( ) ,
252+ }
196253 }
197254
198255 pub fn add_handler ( & mut self , handler : Handler ) {
199256 self . handlers . push ( handler)
200257 }
258+
259+ pub fn add_job_handler ( & mut self , job_name : String , handler : Box < dyn JobHandlerMethod > ) {
260+ self . job_handlers . insert ( job_name, handler) ;
261+ }
201262}
202263
203264#[ tonic:: async_trait]
@@ -207,3 +268,39 @@ pub trait HandlerMethod: Send + Sync + 'static {
207268 request : runtime:: v1:: TopicEventRequest ,
208269 ) -> Result < Response < runtime:: v1:: TopicEventResponse > , Status > ;
209270}
271+
272+ #[ tonic:: async_trait]
273+ pub trait JobHandlerMethod : Send + Sync + ' static {
274+ async fn handler (
275+ & self ,
276+ request : runtime:: v1:: JobEventRequest ,
277+ ) -> Result < runtime:: v1:: JobEventResponse , Status > ;
278+ }
279+
280+ #[ macro_export]
281+ macro_rules! add_job_handler {
282+ ( $app_callback_service: expr, $handler_name: ident, $handler_fn: expr) => {
283+ pub struct $handler_name { }
284+
285+ #[ $crate:: reexport:: async_trait]
286+ impl $crate:: appcallback:: JobHandlerMethod for $handler_name {
287+ async fn handler(
288+ & self ,
289+ request: $crate:: appcallback:: JobEventRequest ,
290+ ) -> :: std:: result:: Result <$crate:: appcallback:: JobEventResponse , :: tonic:: Status >
291+ {
292+ $handler_fn( request) . await
293+ }
294+ }
295+
296+ impl $handler_name {
297+ pub fn new( ) -> Self {
298+ $handler_name { }
299+ }
300+ }
301+
302+ let handler_name = $handler_name. to_string( ) ;
303+
304+ $app_callback_service. add_job_handler( handler_name, Box :: new( $handler_name:: new( ) ) ) ;
305+ } ;
306+ }
0 commit comments