capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

json-rpc.h (3916B)


      1 // Copyright (c) 2018 Kenton Varda and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #pragma once
     23 
     24 #include "json.h"
     25 #include <kj/async-io.h>
     26 #include <capnp/capability.h>
     27 #include <kj/map.h>
     28 
     29 namespace kj { class HttpInputStream; }
     30 
     31 namespace capnp {
     32 
     33 class JsonRpc: private kj::TaskSet::ErrorHandler {
     34   // An implementation of JSON-RPC 2.0: https://www.jsonrpc.org/specification
     35   //
     36   // This allows you to use Cap'n Proto interface declarations to implement JSON-RPC protocols.
     37   // Of course, JSON-RPC does not support capabilities. So, the client and server each expose
     38   // exactly one object to the other.
     39 
     40 public:
     41   class Transport;
     42   class ContentLengthTransport;
     43 
     44   JsonRpc(Transport& transport, DynamicCapability::Client interface = {});
     45   KJ_DISALLOW_COPY(JsonRpc);
     46 
     47   DynamicCapability::Client getPeer(InterfaceSchema schema);
     48 
     49   template <typename T>
     50   typename T::Client getPeer() {
     51     return getPeer(Schema::from<T>()).template castAs<T>();
     52   }
     53 
     54   kj::Promise<void> onError() { return errorPromise.addBranch(); }
     55 
     56 private:
     57   JsonCodec codec;
     58   Transport& transport;
     59   DynamicCapability::Client interface;
     60   kj::HashMap<kj::StringPtr, InterfaceSchema::Method> methodMap;
     61   uint callCount = 0;
     62   kj::Promise<void> writeQueue = kj::READY_NOW;
     63   kj::ForkedPromise<void> errorPromise;
     64   kj::Own<kj::PromiseFulfiller<void>> errorFulfiller;
     65   kj::Promise<void> readTask;
     66 
     67   struct AwaitedResponse {
     68     CallContext<DynamicStruct, DynamicStruct> context;
     69     kj::Own<kj::PromiseFulfiller<void>> fulfiller;
     70   };
     71   kj::HashMap<uint, AwaitedResponse> awaitedResponses;
     72 
     73   kj::TaskSet tasks;
     74 
     75   class CapabilityImpl;
     76 
     77   kj::Promise<void> queueWrite(kj::String text);
     78   void queueError(kj::Maybe<json::Value::Reader> id, int code, kj::StringPtr message);
     79 
     80   kj::Promise<void> readLoop();
     81 
     82   void taskFailed(kj::Exception&& exception) override;
     83 
     84   JsonRpc(Transport& transport, DynamicCapability::Client interface,
     85           kj::PromiseFulfillerPair<void> paf);
     86 };
     87 
     88 class JsonRpc::Transport {
     89 public:
     90   virtual kj::Promise<void> send(kj::StringPtr text) = 0;
     91   virtual kj::Promise<kj::String> receive() = 0;
     92 };
     93 
     94 class JsonRpc::ContentLengthTransport: public Transport {
     95   // The transport used by Visual Studio Code: Each message is composed like an HTTP message
     96   // without the first line. That is, a list of headers, followed by a blank line, followed by the
     97   // content whose length is determined by the content-length header.
     98 public:
     99   explicit ContentLengthTransport(kj::AsyncIoStream& stream);
    100   ~ContentLengthTransport() noexcept(false);
    101   KJ_DISALLOW_COPY(ContentLengthTransport);
    102 
    103   kj::Promise<void> send(kj::StringPtr text) override;
    104   kj::Promise<kj::String> receive() override;
    105 
    106 private:
    107   kj::AsyncIoStream& stream;
    108   kj::Own<kj::HttpInputStream> input;
    109   kj::ArrayPtr<const byte> parts[2];
    110 };
    111 
    112 }  // namespace capnp