Future<Unit> wangle fixup
[folly.git] / folly / wangle / service / Service.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17
18 #include <folly/futures/Future.h>
19 #include <folly/Memory.h>
20
21 #include <folly/wangle/bootstrap/ServerBootstrap.h>
22 #include <folly/wangle/bootstrap/ClientBootstrap.h>
23 #include <folly/wangle/channel/Pipeline.h>
24 #include <folly/wangle/channel/AsyncSocketHandler.h>
25
26 namespace folly {
27
28 /**
29  * A Service is an asynchronous function from Request to
30  * Future<Response>. It is the basic unit of the RPC interface.
31  */
32 template <typename Req, typename Resp = Req>
33 class Service {
34  public:
35   virtual Future<Resp> operator()(Req request) = 0;
36   virtual ~Service() = default;
37   virtual Future<Unit> close() {
38     return makeFuture();
39   }
40   virtual bool isAvailable() {
41     return true;
42   }
43 };
44
45 /**
46  * A Filter acts as a decorator/transformer of a service. It may apply
47  * transformations to the input and output of that service:
48  *
49  *          class MyService
50  *
51  * ReqA  -> |
52  *          | -> ReqB
53  *          | <- RespB
54  * RespA <- |
55  *
56  * For example, you may have a service that takes Strings and parses
57  * them as Ints.  If you want to expose this as a Network Service via
58  * Thrift, it is nice to isolate the protocol handling from the
59  * business rules. Hence you might have a Filter that converts back
60  * and forth between Thrift structs:
61  *
62  * [ThriftIn -> (String  ->  Int) -> ThriftOut]
63  */
64 template <typename ReqA, typename RespA,
65           typename ReqB = ReqA, typename RespB = RespA>
66 class ServiceFilter : public Service<ReqA, RespA> {
67   public:
68   explicit ServiceFilter(std::shared_ptr<Service<ReqB, RespB>> service)
69       : service_(service) {}
70   virtual ~ServiceFilter() = default;
71
72   virtual Future<Unit> close() override {
73     return service_->close();
74   }
75
76   virtual bool isAvailable() override {
77     return service_->isAvailable();
78   }
79
80  protected:
81   std::shared_ptr<Service<ReqB, RespB>> service_;
82 };
83
84 /**
85  * A factory that creates services, given a client.  This lets you
86  * make RPC calls on the Service interface over a client's pipeline.
87  *
88  * Clients can be reused after you are done using the service.
89  */
90 template <typename Pipeline, typename Req, typename Resp>
91 class ServiceFactory {
92  public:
93   virtual Future<std::shared_ptr<Service<Req, Resp>>> operator()(
94     std::shared_ptr<ClientBootstrap<Pipeline>> client) = 0;
95
96   virtual ~ServiceFactory() = default;
97
98 };
99
100
101 template <typename Pipeline, typename Req, typename Resp>
102 class ConstFactory : public ServiceFactory<Pipeline, Req, Resp> {
103  public:
104   explicit ConstFactory(std::shared_ptr<Service<Req, Resp>> service)
105       : service_(service) {}
106
107   virtual Future<std::shared_ptr<Service<Req, Resp>>> operator()(
108     std::shared_ptr<ClientBootstrap<Pipeline>> client) {
109     return service_;
110   }
111  private:
112   std::shared_ptr<Service<Req, Resp>> service_;
113 };
114
115 template <typename Pipeline, typename ReqA, typename RespA,
116           typename ReqB = ReqA, typename RespB = RespA>
117 class ServiceFactoryFilter : public ServiceFactory<Pipeline, ReqA, RespA> {
118  public:
119   explicit ServiceFactoryFilter(
120     std::shared_ptr<ServiceFactory<Pipeline, ReqB, RespB>> serviceFactory)
121       : serviceFactory_(std::move(serviceFactory)) {}
122
123   virtual ~ServiceFactoryFilter() = default;
124
125  protected:
126   std::shared_ptr<ServiceFactory<Pipeline, ReqB, RespB>> serviceFactory_;
127 };
128
129 template <typename Pipeline, typename Req, typename Resp = Req>
130 class FactoryToService : public Service<Req, Resp> {
131  public:
132   explicit FactoryToService(
133     std::shared_ptr<ServiceFactory<Pipeline, Req, Resp>> factory)
134       : factory_(factory) {}
135   virtual ~FactoryToService() = default;
136
137   virtual Future<Resp> operator()(Req request) override {
138     DCHECK(factory_);
139     return ((*factory_)(nullptr)).then(
140       [=](std::shared_ptr<Service<Req, Resp>> service)
141       {
142         return (*service)(std::move(request)).ensure(
143           [this]() {
144             this->close();
145           });
146       });
147   }
148
149  private:
150   std::shared_ptr<ServiceFactory<Pipeline, Req, Resp>> factory_;
151 };
152
153
154 } // namespace