forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTransport.h
182 lines (148 loc) · 4.54 KB
/
Transport.h
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <libsolutil/Exceptions.h>
#include <libsolutil/JSON.h>
#include <functional>
#include <iosfwd>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <variant>
namespace solidity::lsp
{
using MessageID = Json;
enum class TraceValue
{
Off,
Messages,
Verbose
};
enum class ErrorCode
{
// Defined by JSON RPC
ParseError = -32700,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
// Defined by the protocol.
ServerNotInitialized = -32002,
RequestFailed = -32803
};
/**
* Error exception used to bail out on errors in the LSP function-call handlers.
*/
class RequestError: public util::Exception
{
public:
explicit RequestError(ErrorCode _code):
m_code{_code}
{
}
ErrorCode code() const noexcept { return m_code; }
private:
ErrorCode m_code;
};
/**
* Ensures precondition check is valid.
* This is supposed to be a recoverable error, that means, if the condition fails to be valid,
* an exception is being raised to be thrown out of the current request handlers
* of the current LSP's client RPC call and this will cause the current request to fail
* with the given error code - but subsequent calls shall be able to continue.
*/
#define lspRequire(condition, errorCode, errorMessage) \
if (!(condition)) \
{ \
BOOST_THROW_EXCEPTION( \
RequestError(errorCode) << \
util::errinfo_comment(errorMessage) \
); \
}
/**
* Transport layer API
*
* The transport layer API is abstracted to make LSP more testable as well as
* this way it could be possible to support other transports (HTTP for example) easily.
*/
class Transport
{
public:
virtual ~Transport() = default;
std::optional<Json> receive();
void notify(std::string _method, Json _params);
void reply(MessageID _id, Json _result);
void error(MessageID _id, ErrorCode _code, std::string _message);
virtual bool closed() const noexcept = 0;
void trace(std::string _message, Json _extra = Json{});
TraceValue traceValue() const noexcept { return m_logTrace; }
void setTrace(TraceValue _value) noexcept { m_logTrace = _value; }
private:
TraceValue m_logTrace = TraceValue::Off;
protected:
/// Reads from the transport and parses the headers until the beginning
/// of the contents.
std::optional<std::map<std::string, std::string>> parseHeaders();
/// Consumes exactly @p _byteCount bytes, as needed for consuming
/// the message body from the transport line.
virtual std::string readBytes(size_t _byteCount) = 0;
// Mimics std::getline() on this Transport API.
virtual std::string getline() = 0;
/// Writes the given payload @p _data to transport.
/// This call may or may not buffer.
virtual void writeBytes(std::string_view _data) = 0;
/// Ensures transport output is flushed.
virtual void flushOutput() = 0;
/// Sends an arbitrary raw message to the client.
///
/// Used by the notify/reply/error function family.
virtual void send(Json _message, MessageID _id = Json{});
};
/**
* LSP Transport using JSON-RPC over iostreams.
*/
class IOStreamTransport: public Transport
{
public:
/// Constructs a standard stream transport layer.
///
/// @param _in for example std::cin (stdin)
/// @param _out for example std::cout (stdout)
IOStreamTransport(std::istream& _in, std::ostream& _out);
bool closed() const noexcept override;
protected:
std::string readBytes(size_t _byteCount) override;
std::string getline() override;
void writeBytes(std::string_view _data) override;
void flushOutput() override;
private:
std::istream& m_input;
std::ostream& m_output;
};
/**
* Standard I/O transport Layer utilizing stdin/stdout for communication.
*/
class StdioTransport: public Transport
{
public:
StdioTransport();
bool closed() const noexcept override;
protected:
std::string readBytes(size_t _byteCount) override;
std::string getline() override;
void writeBytes(std::string_view _data) override;
void flushOutput() override;
};
}