xuzhenbao opened a new issue, #775:
URL: https://github.com/apache/celix/issues/775
In some service usage scenarios, the result may not be returned immediately
after the service call is completed, it may be returned through a callback
function at some time after the service call is completed. How should we use
callback functions in celix services (it includes remote services and local
services)?
In my opinion, it is unsafe to design function pointers directly in the
service method parameters, because the service provider may have been destroyed
after the service call is completed. At this time, if the callback function is
called again, problems will occur. In addition, designing callback function
pointers in the service method may make the implementation of RSA complex.
Therefore, I think the callback function can be designed as a celix service.
If a service method needs a callback function, the service method's input
parameters should include the service identifier of the callback function
(Maybe the service identifier is a string composed of `framework uuid` and
`service id`). When calling the service method, the service caller needs to
register the callback function service first, and then pass the callback
function service identifier to the service method. The service provider can
invoke the callback function through the callback function service. The example
is as follows:
```c
//provider api
#define MY_SERVICE_NAME "my_service"
#define MY_SERVICE_VERSION "1.0.0"
typedef struct my_service {
void* handle;
void (*doSomething)(void *handle, const char *input, const char
*callbackServiceUUID);
} my_service_t;
#define MY_SERVICE_CALLBACK_SERVICE_NAME "my_service_callback"
#define MY_SERVICE_CALLBACK_SERVICE_VERSION "1.0.0"
typedef struct callback_service {
void* handle;
void (*callback)(void *handle, const char *result);
} callback_service_t;
```
```c
//provider impl
typedef struct provider {
celix_bundle_context_t *context;
my_service_t service;
long svcId;
long trkId;
} provider_t;
typedef struct use_callback_data {
provider_t *provider;
const char *input;
const char *callbackServiceUUID;
}use_callback_data_t;
void useCallback(void *handle, void *svc) {
use_callback_data_t *data = handle;
callback_service_t *callback = svc;
callback->callback(callback->handle, "result");
}
void my_service_doSomething(void *handle, const char *input, const char
*callbackServiceUUID) {
provider_t *provider = handle;
// invoke callback service
use_callback_data_t data = {provider, input, callbackServiceUUID};
celix_bundleContext_useTrackedServices(provider->context,
provider->trkId, &data, useCallback);
}
void provider_init(celix_bundle_context_t *context, provider_t *provider) {
provider->context = context;
provider->service.handle = provider;
provider->service.doSomething = my_service_doSomething;
provider->svcId = celix_bundleContext_registerService(context,
&provider->service, MY_SERVICE_NAME, MY_SERVICE_VERSION, NULL);
//track callback service
celix_service_tracking_options_t opts =
CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
opts.filter.serviceName = MY_SERVICE_CALLBACK_SERVICE_NAME;
provider->trkId = celix_bundleContext_trackServicesWithOptions(ctx,
&opts);
}
```
```c
//consumer impl
typedef struct consumer {
celix_bundle_context_t *context;
callback_service_t service;
long svcId;
long trkId;
} consumer_t;
void my_service_callback(void *handle, const char *result) {
printf("my_service_callback called with result %s\n", result);
}
void useService(void *handle, void *svc) {
consumer_t *consumer = handle;
my_service_t *service = svc;
service->doSomething(service->handle, "input", "<frameworkUUID>+<service
id>");
}
void consumer_init(celix_bundle_context_t *context, consumer_t *consumer) {
// register callback function service
consumer->context = context;
consumer->service.handle = consumer;
consumer->service.callback = my_service_callback;
consumer->svcId = celix_bundleContext_registerService(context,
&consumer->service, MY_SERVICE_CALLBACK_SERVICE_NAME,
MY_SERVICE_CALLBACK_SERVICE_VERSION, NULL);
//use target service
celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
opts.filter.serviceName = MY_SERVICE_NAME;
celix_bundleContext_useServiceWithOptions(context, &opts, consumer,
useService);
}
```
@pnoltes
Do you have any suggestions for the design of callback function?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]