Branch data Line data Source code
1 : : /* Copyright 2006-2013 Savarese Software Research Corporation.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at
6 : : *
7 : : * http://www.savarese.com/software/ApacheLicense-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : /**
17 : : * @file
18 : : * This header defines the Service class.
19 : : */
20 : :
21 : : #ifndef __SSRC_WISP_SERVICE_SERVICE_H
22 : : #define __SSRC_WISP_SERVICE_SERVICE_H
23 : :
24 : : #include <ssrc/wisp/protocol/ContinuationCaller.h>
25 : : #include <ssrc/wisp/service/EventLoop.h>
26 : :
27 : : #include <functional>
28 : :
29 : : #ifdef WISP_DEBUG
30 : : #include <iostream>
31 : : #endif
32 : :
33 : : __BEGIN_NS_SSRC_WISP_SERVICE
34 : :
35 : : using NS_SSRC_SPREAD::MembershipInfo;
36 : : using NS_SSRC_SPREAD::Message;
37 : : using NS_SSRC_SPREAD::GroupList;
38 : : using NS_SSRC_WISP_PROTOCOL::MessageInfo;
39 : : using NS_SSRC_WISP_PROTOCOL::message_info_ptr;
40 : : using NS_SSRC_WISP_PROTOCOL::CallException;
41 : : using NS_SSRC_WISP_PROTOCOL::GroupMembershipDisable;
42 : : using NS_SSRC_WISP_PROTOCOL::wisp_message_protocol;
43 : : using NS_SSRC_WISP_PROTOCOL::wisp_message_id;
44 : : using NS_SSRC_WISP_UTILITY::make_smart_ptr;
45 : :
46 : : #define WISP_SERVICE_REQUEST(MessageType) \
47 : : set_request_handler<MessageType>(*this)
48 : : #define WISP_SERVICE_RESPONSE(MessageType) \
49 : : set_response_handler<MessageType>(*this)
50 : : #define WISP_SERVICE_REQUEST_T(MessageType) \
51 : : this->template set_request_handler<MessageType>(*this)
52 : : #define WISP_SERVICE_RESPONSE_T(MessageType) \
53 : : this->template set_response_handler<MessageType>(*this)
54 : :
55 : : #define WISP_SERVICE_REQUEST_BUFFERED(MessageType, msg) \
56 : : set_request_handler<MessageType>(*this, msg)
57 : : #define WISP_SERVICE_RESPONSE_BUFFERED(MessageType, msg) \
58 : : set_response_handler<MessageType>(*this, msg)
59 : : #define WISP_SERVICE_REQUEST_BUFFERED_T(MessageType, msg) \
60 : : this->template set_request_handler<MessageType>(*this, msg)
61 : : #define WISP_SERVICE_RESPONSE_BUFFERED_T(MessageType, msg) \
62 : : this->template set_response_handler<MessageType>(*this, msg)
63 : :
64 : :
65 : : typedef std::function<void (const EventInfo &)> timeout_handler;
66 : : // We expose message_handler_type, message_handler_entry, and
67 : : // message_handler_map specifically to support dynamically loaded handlers.
68 : : typedef std::function<void (MessageInfo &)> message_handler_type;
69 : :
70 : 18 : struct message_handler_entry {
71 : : wisp_message_protocol protocol;
72 : : wisp_message_id id;
73 : : message_handler_type handle_message;
74 : :
75 : 6 : message_handler_entry(const wisp_message_protocol protocol,
76 : : const wisp_message_id id,
77 : 6 : const message_handler_type & message_handler) :
78 : 6 : protocol(protocol), id(id), handle_message(message_handler)
79 : 6 : { }
80 : : };
81 : :
82 : : typedef boost::multi_index_container<
83 : : message_handler_entry,
84 : : boost::multi_index::indexed_by<
85 : : boost::multi_index::hashed_unique<
86 : : boost::multi_index::composite_key<
87 : : message_handler_entry,
88 : : boost::multi_index::member<message_handler_entry,
89 : : wisp_message_protocol,
90 : : &message_handler_entry::protocol>,
91 : : boost::multi_index::member<message_handler_entry, wisp_message_id,
92 : : &message_handler_entry::id> >
93 : : >
94 : : > > message_handler_map;
95 : :
96 : : /* BEGIN EXPERIMENTAL CODE */
97 : : // TODO: This is all one big kluge and should be re-implemented, but it works..
98 : 9 : class ServiceContext {
99 : : public:
100 : : class TimeoutHandler : public EventHandler {
101 : : ServiceContext & _context;
102 : : bool _once;
103 : : timeout_handler _handler;
104 : :
105 : : public:
106 : :
107 : : TimeoutHandler(ServiceContext & context,
108 : : const timeout_handler & handler, bool once) :
109 : : _context(context), _once(once), _handler(handler)
110 : : { }
111 : :
112 : : virtual ~TimeoutHandler() = default;
113 : :
114 : : virtual void handle_timeout(const EventInfo & info) {
115 : : _handler(info);
116 : : // TODO: WARNING: This could blow up because the current object
117 : : // may be deleted on the call to remove_timeout. This works only
118 : : // because the removal happens at the end of the function and we
119 : : // don't access 'this' again. Seek an alternative solution.
120 : : if(_once)
121 : : _context.remove_timeout(this);
122 : : }
123 : :
124 : : void execute() {
125 : : handle_timeout(EventInfo(_context.event_loop(), EventLoop::None, false));
126 : : }
127 : :
128 : : bool once() {
129 : : return _once;
130 : : }
131 : :
132 : 0 : const TimeoutHandler *address() const {
133 : 0 : return this;
134 : : }
135 : : };
136 : :
137 : : typedef std::shared_ptr<TimeoutHandler> timeout_handler_ptr;
138 : :
139 : : typedef boost::multi_index_container<
140 : : timeout_handler_ptr,
141 : : boost::multi_index::indexed_by<
142 : : boost::multi_index::hashed_unique<
143 : : boost::multi_index::const_mem_fun<TimeoutHandler,
144 : : const TimeoutHandler *,
145 : : &TimeoutHandler::address> >
146 : : > > timeout_map;
147 : :
148 : : private:
149 : : EventLoop *loop;
150 : : timeout_map _timeouts;
151 : :
152 : : public:
153 : :
154 [ + - + - ]: 6 : explicit ServiceContext(EventLoop * loop = 0) : loop(loop) { }
155 : :
156 : : timeout_map::size_type count_timeouts() const {
157 : : return _timeouts.size();
158 : : }
159 : :
160 : 3 : void clear_timeouts() {
161 [ + - - + : 3 : for(timeout_map::iterator it = _timeouts.begin(), end = _timeouts.end();
# # ]
162 : : it != end; ++it)
163 [ # # # # ]: 0 : remove_timeout(it->get());
164 : 3 : }
165 : :
166 : : timeout_handler_ptr add_timeout(const timeout_handler & handler_fun,
167 : : const TimeValue & timeout,
168 : : const bool once)
169 : : {
170 : : timeout_handler_ptr handler(make_smart_ptr<timeout_handler_ptr>(*this, handler_fun, once));
171 : : _timeouts.insert(handler);
172 : : loop->add_handler(*handler, EventLoop::None, timeout);
173 : : return handler;
174 : : }
175 : :
176 : 0 : void remove_timeout(TimeoutHandler *timeout) {
177 : : // must remove from loop first or we lose pointer!!!
178 : 0 : loop->remove_handler(*timeout);
179 : 0 : _timeouts.erase(timeout);
180 : 0 : }
181 : :
182 : : EventLoop & event_loop() { return *loop; }
183 : : };
184 : :
185 : :
186 : : typedef ServiceContext::timeout_handler_ptr timeout_ptr;
187 : :
188 : : /* END EXPERIMENTAL CODE */
189 : :
190 : : template<typename PackingTraits = BinaryPackingTraits>
191 : : class ServiceProtocolProcessor {
192 : : public:
193 : : typedef PackingTraits packing_traits;
194 : : typedef typename protocol::ContinuationCaller<packing_traits> caller_type;
195 : :
196 : : enum State { Starting, Started, Stopping, Stopped };
197 : :
198 : : /**
199 : : * Subclasses should redefine this variable to override behavior.
200 : : * We don't reference the template parameter so that you can subclass a
201 : : * protocol processor that is a concrete class that disables group
202 : : * membership and enable it in the subclass. Otherwise, every
203 : : * protocol processor would have to be a template class. The variable
204 : : * is used only by the Service template to initialize _caller.
205 : : */
206 : : static const bool GroupMembership = GroupMembershipDisable;
207 : :
208 : : private:
209 : : State _state;
210 : :
211 : : private:
212 : :
213 : : message_handler_map _request_handlers;
214 : : message_handler_map _response_handlers;
215 : :
216 : : protected:
217 : : caller_type & _caller;
218 : :
219 : : // WARNING!! This is highly experimental and only made available so
220 : : // a subclass may add handlers to the event loop for I/O on other
221 : : // descriptors. The context is only valid in the Starting and
222 : : // Started states.
223 : : ServiceContext & context() { return _context; };
224 : :
225 : 0 : virtual void process_membership_message(const MessageInfo & msginfo,
226 : : const MembershipInfo & meminfo)
227 : 0 : { }
228 : :
229 : : // So you can reuse message types that are expensive to create on each call.
230 : : template<typename MessageType, typename Impl>
231 : 6 : void request(Impl & impl, MessageType & msg, MessageInfo & msginfo)
232 : : SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure,
233 : : CallException)
234 : : {
235 : 6 : _caller.unpack(msg, msginfo);
236 : : // Cast forces msginfo to be const arg in process_request
237 : 6 : impl.process_request(msg, static_cast<const MessageInfo &>(msginfo));
238 : 6 : }
239 : :
240 : : template<typename MessageType, typename Impl>
241 : 6 : void request(Impl & impl, MessageInfo & msginfo)
242 : : SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
243 : : {
244 : 6 : MessageType msg;
245 [ + - + - ]: 6 : request(impl, msg, msginfo);
246 : 6 : }
247 : :
248 : : template<typename MessageType, typename Impl>
249 : : void respond(Impl & impl, MessageType & msg, MessageInfo & msginfo)
250 : : SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure,
251 : : CallException)
252 : : {
253 : : _caller.unpack(msg, msginfo);
254 : : // Cast forces msginfo to be const arg in process_response
255 : : impl.process_response(msg, static_cast<const MessageInfo &>(msginfo));
256 : : }
257 : :
258 : : template<typename MessageType, typename Impl>
259 : : void respond(Impl & impl, MessageInfo & msginfo)
260 : : SSRC_DECL_THROW(boost::archive::archive_exception, std::ios_base::failure)
261 : : {
262 : : MessageType msg;
263 : : respond(impl, msg, msginfo);
264 : : }
265 : :
266 : 6 : bool set_request_handler(const message_handler_entry & handler) {
267 : 6 : return _request_handlers.insert(handler).second;
268 : : }
269 : :
270 : : message_handler_map::size_type
271 : : remove_request_handler(const message_handler_entry & handler) {
272 : : return
273 : : _request_handlers.erase(_request_handlers.key_extractor()((handler)));
274 : : }
275 : :
276 : : void clear_request_handlers() {
277 : : _request_handlers.clear();
278 : : }
279 : :
280 : : template<typename MessageType, typename Impl>
281 : 6 : bool set_request_handler(Impl & impl) {
282 : : constexpr void (ServiceProtocolProcessor::*handler)(Impl &, MessageInfo &) =
283 : 6 : &ServiceProtocolProcessor::template request<MessageType, Impl>;
284 [ + - + - : 12 : return set_request_handler(message_handler_entry(MessageType::protocol,
+ - + - +
- + - ]
285 : : MessageType::id,
286 [ + - + - ]: 18 : std::bind(handler, this, std::ref(impl), std::placeholders::_1)));
287 : : }
288 : :
289 : : template<typename MessageType, typename Impl>
290 : : bool set_request_handler(Impl & impl, MessageType & buffer) {
291 : : constexpr void (ServiceProtocolProcessor::*handler)
292 : : (Impl &, MessageType &, MessageInfo &) =
293 : : &ServiceProtocolProcessor::template request<MessageType, Impl>;
294 : : return set_request_handler(message_handler_entry(MessageType::protocol,
295 : : MessageType::id,
296 : : std::bind(handler, this, std::ref(impl), std::ref(buffer), std::placeholders::_1)));
297 : : }
298 : :
299 : : bool set_response_handler(const message_handler_entry & handler) {
300 : : return _response_handlers.insert(handler).second;
301 : : }
302 : :
303 : : message_handler_map::size_type
304 : : remove_response_handler(const message_handler_entry & handler) {
305 : : return
306 : : _response_handlers.erase(_response_handlers.key_extractor()((handler)));
307 : : }
308 : :
309 : : void clear_response_handlers() {
310 : : _response_handlers.clear();
311 : : }
312 : :
313 : : template<typename MessageType, typename Impl>
314 : : bool set_response_handler(Impl & impl) {
315 : : constexpr void (ServiceProtocolProcessor::*handler)(Impl &, MessageInfo &) =
316 : : &ServiceProtocolProcessor::template respond<MessageType, Impl>;
317 : : return set_response_handler(message_handler_entry(MessageType::protocol,
318 : : MessageType::id,
319 : : std::bind(handler, this, std::ref(impl), std::placeholders::_1))); }
320 : :
321 : : template<typename MessageType, typename Impl>
322 : : bool set_response_handler(Impl & impl, MessageType & buffer) {
323 : : constexpr void (ServiceProtocolProcessor::*handler)
324 : : (Impl &, MessageType &, MessageInfo &) =
325 : : &ServiceProtocolProcessor::template respond<MessageType, Impl>;
326 : : return set_response_handler(message_handler_entry(MessageType::protocol,
327 : : MessageType::id,
328 : : std::bind(handler, this, std::ref(impl), std::ref(buffer), std::placeholders::_1)));
329 : : }
330 : :
331 : 6 : virtual void transition(State state) {
332 : 6 : _state = state;
333 : 6 : }
334 : :
335 : : public:
336 : :
337 : 3 : explicit ServiceProtocolProcessor(caller_type & caller) :
338 : : _state(Stopped),
339 [ + - + - : 3 : _request_handlers(), _response_handlers(), _caller(caller)
+ - + - +
- ]
340 : 3 : { }
341 : :
342 : 3 : virtual ~ServiceProtocolProcessor() = default;
343 : :
344 : 0 : std::string name() const {
345 : 0 : return _caller.name();
346 : : }
347 : :
348 : 21 : State state() const {
349 : 21 : return _state;
350 : : }
351 : :
352 : 3 : void start() {
353 : 3 : transition(Starting);
354 : 3 : }
355 : :
356 : : // Services listening for membership messages should wait for self-leave
357 : : // before transitioning to Stopped.
358 : 3 : void stop() {
359 : 3 : transition(Stopping);
360 : 3 : }
361 : :
362 : 0 : void membership(const MessageInfo & msginfo,
363 : : const MembershipInfo & meminfo)
364 : : {
365 : 0 : process_membership_message(msginfo, meminfo);
366 : 0 : }
367 : :
368 : 6 : void request(MessageInfo & msginfo) {
369 : : message_handler_map::iterator it =
370 [ + - ]: 6 : _request_handlers.find(std::make_tuple(msginfo.protocol(), msginfo.id()));
371 [ + - + - ]: 6 : if(it != _request_handlers.end()) {
372 [ + - + - ]: 6 : it->handle_message(msginfo);
373 : : }
374 : : // TODO: add an else log unhandled message
375 : 6 : }
376 : :
377 : : /**
378 : : *
379 : : */
380 : 0 : void response(MessageInfo & msginfo) {
381 [ # # ]: 0 : if(!_caller.resume(msginfo)) {
382 : : message_handler_map::iterator it =
383 : 0 : _response_handlers.find(std::make_tuple(msginfo.protocol(),
384 [ # # ]: 0 : msginfo.id()));
385 [ # # # # ]: 0 : if(it != _response_handlers.end()) {
386 [ # # # # ]: 0 : it->handle_message(msginfo);
387 : : }
388 : : // TODO: add an else log unhandled message
389 : : }
390 : 0 : }
391 : :
392 : : /* BEGIN EXPERIMENTAL CODE */
393 : : // TODO: This is all one big kluge and should be re-implemented (which
394 : : // is why this is stuffed at the end of the class), but it works.
395 : :
396 : : timeout_ptr schedule_timeout(const timeout_handler & handler,
397 : : const TimeValue & timeout,
398 : : const bool once = EventLoop::Persist)
399 : : {
400 : : return _context.add_timeout(handler, timeout, once);
401 : : }
402 : :
403 : : void cancel_timeout(const timeout_ptr & timeout) {
404 : : _context.remove_timeout(timeout.get());
405 : : }
406 : :
407 : 3 : void clear_timeouts() {
408 : 3 : _context.clear_timeouts();
409 : 3 : }
410 : :
411 : : ServiceContext::timeout_map::size_type count_timeouts() const {
412 : : return _context.count_timeouts();
413 : : }
414 : :
415 : : private:
416 : : template<typename PP> friend class ServiceEventHandler;
417 : :
418 : : ServiceContext _context;
419 : :
420 : 3 : void set_service_context(const ServiceContext & context) {
421 : 3 : _context = context;
422 : 3 : }
423 : :
424 : : /* END EXPERIMENTAL CODE */
425 : : };
426 : :
427 : : template<typename PP>
428 : : class ServiceEventHandler : public EventHandler {
429 : : public:
430 : : typedef PP protocol_processor;
431 : : WISP_IMPORT_T(protocol_processor, caller_type);
432 : :
433 : : private:
434 : : caller_type & _caller;
435 : : protocol_processor _protocol;
436 : : // Scratch variables for handle_event().
437 : : message_info_ptr _message_info;
438 : : MembershipInfo _membership_info;
439 : : protocol::wisp_call_token _min_token, _max_token;
440 : : std::vector<typename caller_type::jumbo_message_key_type> _jumbo_message_keys;
441 : :
442 : : protected:
443 : :
444 : 3 : virtual void remove_handler(EventLoop & loop) {
445 : : /* BEGIN EXPERIMENTAL CODE */
446 : : // TODO: This is a kluge and should be re-implemented, but it works.
447 : 3 : _protocol.clear_timeouts();
448 : : /* END EXPERIMENTAL CODE */
449 : 3 : loop.remove_handler(*this);
450 : 3 : _caller.cancel_all();
451 : 3 : }
452 : :
453 : : public:
454 : :
455 : 3 : explicit ServiceEventHandler(caller_type & caller) :
456 : : _caller(caller), _protocol(caller),
457 : 6 : _message_info(make_smart_ptr<message_info_ptr>(caller.message_capacity_receive())),
458 : : _membership_info(),
459 : : _min_token(0), _max_token(0),
460 [ + - + - : 9 : _jumbo_message_keys(4)
+ - + - ]
461 : 3 : { }
462 : :
463 : : template<typename Initializer>
464 : : explicit ServiceEventHandler(caller_type & caller,
465 : : const Initializer & initializer) :
466 : : _caller(caller), _protocol(caller, initializer),
467 : : _message_info(),
468 : : _membership_info(),
469 : : _min_token(0), _max_token(0),
470 : : _jumbo_message_keys(4)
471 : : { }
472 : :
473 : 3 : virtual ~ServiceEventHandler() = default;
474 : :
475 : 12 : typename protocol_processor::State state() const {
476 : 12 : return _protocol.state();
477 : : }
478 : :
479 : 12 : virtual int event_descriptor() const {
480 : 12 : return _caller.mbox().descriptor();
481 : : }
482 : :
483 : 6 : virtual void handle_read(const EventInfo & info) {
484 : : try {
485 [ + - ]: 6 : if(state() != protocol_processor::Stopped) {
486 [ + - ]: 6 : _caller.receive(_message_info);
487 : :
488 [ + - + - : 12 : if(_message_info->message.is_regular() &&
+ - ]
489 : 6 : _protocol.state() < protocol_processor::Stopping)
490 : : {
491 [ - + ]: 6 : if(_message_info->role() == protocol::TwoWayResponse)
492 [ # # ]: 0 : _protocol.response(*_message_info);
493 : : else
494 [ + - ]: 6 : _protocol.request(*_message_info);
495 [ # # ]: 0 : } else if(_message_info->message.is_membership()) {
496 [ # # ]: 0 : _message_info->message.get_membership_info(_membership_info);
497 [ # # ]: 0 : _protocol.membership(*_message_info, _membership_info);
498 : : }
499 : :
500 [ + + ]: 6 : if(state() == protocol_processor::Stopped)
501 [ + - ]: 3 : remove_handler(info.event_loop());
502 : : }
503 : 0 : } catch(const boost::archive::archive_exception & ae) {
504 : : // TODO: log
505 : : #ifdef WISP_DEBUG
506 [ # # ]: 0 : std::cerr << _protocol.name()
507 : : << ": Caught boost::archive::archive_exception: "
508 [ # # # # : 0 : << ae.what() << "\nContinuing.";
# # # # ]
509 : : #endif
510 : 0 : } catch(const std::ios_base::failure & iof) {
511 : : // TODO: log. probably don't want to try again
512 : : #ifdef WISP_DEBUG
513 [ # # ]: 0 : std::cerr << _protocol.name() << ": Caught std::ios_base::failure: "
514 [ # # # # : 0 : << iof.what() << "\nContinuing.";
# # # # ]
515 : : #endif
516 : : }
517 [ # # # ]: 6 : }
518 : :
519 : 0 : virtual void handle_timeout(const EventInfo & info) {
520 : : // Cancel continuations
521 : 0 : _caller.cancel_range(_min_token, _max_token);
522 : 0 : _min_token = _max_token;
523 : 0 : _max_token = _caller.call_token();
524 : :
525 : : // Clear out incomplete jumbo messages
526 [ # # ]: 0 : if(!_jumbo_message_keys.empty()) {
527 [ # # ]: 0 : if(_caller.count_jumbo_messages() > 0) {
528 [ # # ]: 0 : _caller.erase_jumbo_messages(_jumbo_message_keys.begin(),
529 : : _jumbo_message_keys.end());
530 : : }
531 : 0 : _jumbo_message_keys.clear();
532 : : }
533 : :
534 [ # # ]: 0 : if(_caller.count_jumbo_messages() > 0) {
535 : 0 : _caller.collect_jumbo_message_keys(_jumbo_message_keys);
536 : : }
537 : 0 : }
538 : :
539 : 3 : protocol_processor & protocol() {
540 : 3 : return _protocol;
541 : : }
542 : :
543 : 3 : void start(EventLoop & loop, const unsigned int call_timeout) {
544 : 3 : _min_token = _max_token = _caller.call_token();
545 [ + - ]: 3 : loop.add_handler(*this, EventLoop::Read, TimeValue(call_timeout, 0));
546 : : /* BEGIN EXPERIMENTAL CODE */
547 : : // TODO: This is a kluge and should be re-implemented, but it works.
548 [ + - ]: 3 : _protocol.set_service_context(ServiceContext(&loop));
549 : : /* END EXPERIMENTAL CODE */
550 : 3 : _protocol.start();
551 : 3 : }
552 : :
553 : : void stop() {
554 : : _protocol.stop();
555 : : }
556 : : };
557 : :
558 : :
559 : : /**
560 : : *
561 : : */
562 : : template<typename EH>
563 : 3 : class Service {
564 : : public:
565 : : typedef EH event_handler;
566 : : WISP_IMPORT_T(event_handler, caller_type);
567 : : WISP_IMPORT_T(event_handler, protocol_processor);
568 : :
569 : : private:
570 : : caller_type _caller;
571 : : event_handler _handler;
572 : :
573 : : protected:
574 : :
575 : 3 : protocol_processor & protocol() {
576 : 3 : return _handler.protocol();
577 : : }
578 : :
579 : : public:
580 : :
581 : 3 : explicit Service(const std::string & connection = "",
582 : : const std::string & name = "",
583 : : const unsigned int message_capacity =
584 : : Message::DefaultCapacity) :
585 : : _caller(connection, name, message_capacity,
586 : : protocol_processor::GroupMembership),
587 [ + - ]: 3 : _handler(_caller)
588 : 3 : { }
589 : :
590 : : template<typename Initializer>
591 : : explicit Service(const Initializer & initializer,
592 : : const std::string & connection = "",
593 : : const std::string & name = "",
594 : : const unsigned int message_capacity =
595 : : Message::DefaultCapacity) :
596 : : _caller(connection, name, message_capacity,
597 : : protocol_processor::GroupMembership),
598 : : _handler(_caller, initializer)
599 : : { }
600 : :
601 : 6 : const std::string & name() const {
602 : 6 : return _caller.name();
603 : : }
604 : :
605 : 3 : typename protocol_processor::State state() {
606 : 3 : return protocol().state();
607 : : }
608 : :
609 : 3 : void start(EventLoop & loop, unsigned int call_timeout) {
610 : 3 : _handler.start(loop, call_timeout);
611 : 3 : }
612 : :
613 : : void stop() {
614 : : _handler.stop();
615 : : }
616 : : };
617 : :
618 : : __END_NS_SSRC_WISP_SERVICE
619 : :
620 : : #endif
|