Client.cpp
4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//===--- Client.cpp ----------------------------------------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <grpc++/grpc++.h>
#include "Client.h"
#include "Index.grpc.pb.h"
#include "index/Index.h"
#include "index/Serialization.h"
#include "marshalling/Marshalling.h"
#include "support/Logger.h"
#include "support/Trace.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <chrono>
namespace clang {
namespace clangd {
namespace remote {
namespace {
class IndexClient : public clangd::SymbolIndex {
template <typename RequestT, typename ReplyT>
using StreamingCall = std::unique_ptr<grpc::ClientReader<ReplyT>> (
remote::SymbolIndex::Stub::*)(grpc::ClientContext *, const RequestT &);
template <typename RequestT, typename ReplyT, typename ClangdRequestT,
typename CallbackT>
bool streamRPC(ClangdRequestT Request,
StreamingCall<RequestT, ReplyT> RPCCall,
CallbackT Callback) const {
bool FinalResult = false;
trace::Span Tracer(RequestT::descriptor()->name());
const auto RPCRequest = ProtobufMarshaller->toProtobuf(Request);
SPAN_ATTACH(Tracer, "Request", RPCRequest.DebugString());
grpc::ClientContext Context;
std::chrono::system_clock::time_point Deadline =
std::chrono::system_clock::now() + DeadlineWaitingTime;
Context.set_deadline(Deadline);
auto Reader = (Stub.get()->*RPCCall)(&Context, RPCRequest);
ReplyT Reply;
unsigned Successful = 0;
unsigned FailedToParse = 0;
while (Reader->Read(&Reply)) {
if (!Reply.has_stream_result()) {
FinalResult = Reply.final_result();
continue;
}
auto Response = ProtobufMarshaller->fromProtobuf(Reply.stream_result());
if (!Response) {
elog("Received invalid {0}: {1}. Reason: {2}",
ReplyT::descriptor()->name(), Reply.stream_result().DebugString(),
Response.takeError());
++FailedToParse;
continue;
}
Callback(*Response);
++Successful;
}
SPAN_ATTACH(Tracer, "Status", Reader->Finish().ok());
SPAN_ATTACH(Tracer, "Successful", Successful);
SPAN_ATTACH(Tracer, "Failed to parse", FailedToParse);
return FinalResult;
}
public:
IndexClient(
std::shared_ptr<grpc::Channel> Channel, llvm::StringRef ProjectRoot,
std::chrono::milliseconds DeadlineTime = std::chrono::milliseconds(1000))
: Stub(remote::SymbolIndex::NewStub(Channel)),
ProtobufMarshaller(new Marshaller(/*RemoteIndexRoot=*/"",
/*LocalIndexRoot=*/ProjectRoot)),
DeadlineWaitingTime(DeadlineTime) {
assert(!ProjectRoot.empty());
}
void lookup(const clangd::LookupRequest &Request,
llvm::function_ref<void(const clangd::Symbol &)> Callback) const {
streamRPC(Request, &remote::SymbolIndex::Stub::Lookup, Callback);
}
bool
fuzzyFind(const clangd::FuzzyFindRequest &Request,
llvm::function_ref<void(const clangd::Symbol &)> Callback) const {
return streamRPC(Request, &remote::SymbolIndex::Stub::FuzzyFind, Callback);
}
bool refs(const clangd::RefsRequest &Request,
llvm::function_ref<void(const clangd::Ref &)> Callback) const {
return streamRPC(Request, &remote::SymbolIndex::Stub::Refs, Callback);
}
void
relations(const clangd::RelationsRequest &Request,
llvm::function_ref<void(const SymbolID &, const clangd::Symbol &)>
Callback) const {
streamRPC(Request, &remote::SymbolIndex::Stub::Relations,
// Unpack protobuf Relation.
[&](std::pair<SymbolID, clangd::Symbol> SubjectAndObject) {
Callback(SubjectAndObject.first, SubjectAndObject.second);
});
}
// IndexClient does not take any space since the data is stored on the
// server.
size_t estimateMemoryUsage() const { return 0; }
private:
std::unique_ptr<remote::SymbolIndex::Stub> Stub;
std::unique_ptr<Marshaller> ProtobufMarshaller;
// Each request will be terminated if it takes too long.
std::chrono::milliseconds DeadlineWaitingTime;
};
} // namespace
std::unique_ptr<clangd::SymbolIndex> getClient(llvm::StringRef Address,
llvm::StringRef ProjectRoot) {
const auto Channel =
grpc::CreateChannel(Address.str(), grpc::InsecureChannelCredentials());
Channel->GetState(true);
return std::unique_ptr<clangd::SymbolIndex>(
new IndexClient(Channel, ProjectRoot));
}
} // namespace remote
} // namespace clangd
} // namespace clang