diff options
Diffstat (limited to 'Build/source/utils/asymptote/LspCpp/examples/WebsocketExample.cpp')
-rwxr-xr-x | Build/source/utils/asymptote/LspCpp/examples/WebsocketExample.cpp | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/LspCpp/examples/WebsocketExample.cpp b/Build/source/utils/asymptote/LspCpp/examples/WebsocketExample.cpp new file mode 100755 index 00000000000..40d920ac001 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/examples/WebsocketExample.cpp @@ -0,0 +1,296 @@ + +#include "LibLsp/JsonRpc/WebSocketServer.h" +#include "LibLsp/lsp/textDocument/signature_help.h" +#include "LibLsp/lsp/general/initialize.h" +#include "LibLsp/lsp/ProtocolJsonHandler.h" +#include "LibLsp/lsp/textDocument/typeHierarchy.h" +#include "LibLsp/lsp/AbsolutePath.h" +#include "LibLsp/lsp/textDocument/resolveCompletionItem.h" +#include <network/uri.hpp> + + +#include "LibLsp/JsonRpc/Endpoint.h" +#include "LibLsp/JsonRpc/stream.h" +#include "LibLsp/JsonRpc/TcpServer.h" +#include "LibLsp/lsp/textDocument/document_symbol.h" +#include "LibLsp/lsp/workspace/execute_command.h" + +#include <boost/filesystem.hpp> +#include <boost/asio.hpp> +#include <iostream> +#include <boost/beast/core.hpp> +#include <boost/beast/websocket.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/strand.hpp> +#include <algorithm> +#include <cstdlib> +#include <functional> +#include <iostream> +#include <memory> +#include <string> +#include <thread> +#include <vector> + +#include <boost/beast/version.hpp> +#include <boost/beast/websocket.hpp> +#include <boost/asio/dispatch.hpp> +#include "LibLsp/JsonRpc/Endpoint.h" +#include "LibLsp/JsonRpc/RemoteEndPoint.h" +#include "LibLsp/JsonRpc/stream.h" +#include "LibLsp/lsp/ProtocolJsonHandler.h" + +namespace beast = boost::beast; // from <boost/beast.hpp> +namespace http = beast::http; // from <boost/beast/http.hpp> +namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp> +namespace net = boost::asio; // from <boost/asio.hpp> +using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> + +//------------------------------------------------------------------------------ + +std::string _address = "127.0.0.1"; +std::string _port = "9333"; + + + + +using namespace std; +class DummyLog :public lsp::Log +{ +public: + + void log(Level level, std::wstring&& msg) + { + std::wcout << msg << std::endl; + }; + void log(Level level, const std::wstring& msg) + { + std::wcout << msg << std::endl; + }; + void log(Level level, std::string&& msg) + { + std::cout << msg << std::endl; + }; + void log(Level level, const std::string& msg) + { + std::cout << msg << std::endl; + }; +}; + + + +// Sends a WebSocket message and prints the response +class Client : public std::enable_shared_from_this<Client> +{ + net::io_context ioc; + tcp::resolver resolver_; + websocket::stream<beast::tcp_stream> ws_; + beast::flat_buffer buffer_; + std::string host_; + std::string user_agent_; + std::shared_ptr < lsp::ProtocolJsonHandler > protocol_json_handler = std::make_shared< lsp::ProtocolJsonHandler>(); + DummyLog _log; + + std::shared_ptr<GenericEndpoint> endpoint = std::make_shared<GenericEndpoint>(_log); + + std::shared_ptr<lsp::websocket_stream_wrapper> proxy_; +public: + RemoteEndPoint point; + +public: + // Resolver and socket require an io_context + explicit + Client() + : resolver_(net::make_strand(ioc)) + , ws_(net::make_strand(ioc)),point(protocol_json_handler, endpoint, _log) + { + proxy_ = std::make_shared<lsp::websocket_stream_wrapper>(ws_); + + } + + // Start the asynchronous operation + void + run( + char const* host, + char const* port, char const* user_agent) + { + // Save these for later + host_ = host; + user_agent_ = user_agent; + // Look up the domain name + resolver_.async_resolve( + host, + port, + beast::bind_front_handler( + &Client::on_resolve, + shared_from_this())); + std::thread([&] + { + ioc.run(); + }).detach(); + while (!point.IsWorking()) + { + std::this_thread::sleep_for(std::chrono::milliseconds (50)); + } + } + + void + on_resolve( + beast::error_code ec, + tcp::resolver::results_type results) + { + if (ec) + return; + + // Set the timeout for the operation + beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30)); + + // Make the connection on the IP address we get from a lookup + beast::get_lowest_layer(ws_).async_connect( + results, + beast::bind_front_handler( + &Client::on_connect, + shared_from_this())); + } + + void + on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type) + { + if (ec) + return; + + // Turn off the timeout on the tcp_stream, because + // the websocket stream has its own timeout system. + beast::get_lowest_layer(ws_).expires_never(); + + // Set suggested timeout settings for the websocket + ws_.set_option( + websocket::stream_base::timeout::suggested( + beast::role_type::client)); + + // Set a decorator to change the User-Agent of the handshake + ws_.set_option(websocket::stream_base::decorator( + [=](websocket::request_type& req) + { + req.set(http::field::user_agent, + user_agent_.c_str()); + })); + + // Perform the websocket handshake + ws_.async_handshake(host_, "/", + beast::bind_front_handler( + &Client::on_handshake, + shared_from_this())); + } + + void + on_handshake(beast::error_code ec) + { + if (ec) + return; + + // Send the message + + + point.startProcessingMessages(proxy_, proxy_); + // Read a message into our buffer + ws_.async_read( + buffer_, + beast::bind_front_handler( + &Client::on_read, + shared_from_this())); + } + + + void + on_read( + beast::error_code ec, + std::size_t bytes_transferred) + { + boost::ignore_unused(bytes_transferred); + + if (ec) + return; + + char* data = reinterpret_cast<char*>(buffer_.data().data()); + std::vector<char> elements(data, data + bytes_transferred); + buffer_.clear(); + proxy_->on_request.EnqueueAll(std::move(elements), false); + + ws_.async_read( + buffer_, + beast::bind_front_handler( + &Client::on_read, + shared_from_this())); + } + + void + on_close(beast::error_code ec) + { + if (ec) + return; + + // If we get here then the connection is closed gracefully + + // The make_printable() function helps print a ConstBufferSequence + std::cout << beast::make_printable(buffer_.data()) << std::endl; + } +}; + +class Server +{ +public: + Server(const std::string& user_agent) : server(user_agent,_address, _port, protocol_json_handler, endpoint, _log) + { + server.point.registerHandler( + [&](const td_initialize::request& req) + { + td_initialize::response rsp; + CodeLensOptions code_lens_options; + code_lens_options.resolveProvider = true; + rsp.result.capabilities.codeLensProvider = code_lens_options; + return rsp; + }); + std::thread([&]() + { + server.run(); + }).detach(); + } + ~Server() + { + server.stop(); + } + std::shared_ptr < lsp::ProtocolJsonHandler > protocol_json_handler = std::make_shared < lsp::ProtocolJsonHandler >(); + DummyLog _log; + + std::shared_ptr < GenericEndpoint > endpoint = std::make_shared<GenericEndpoint>(_log); + lsp::WebSocketServer server; + +}; + +int main() +{ + std::string user_agent = std::string(BOOST_BEAST_VERSION_STRING) +" websocket-server-async"; + Server server(user_agent); + + auto client = std::make_shared<Client>(); + user_agent = std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-async"; + client->run(_address.c_str(), _port.c_str(), user_agent.c_str()); + + td_initialize::request req; + + auto rsp = client->point.waitResponse(req); + if (rsp) + { + std::cout << rsp->ToJson() << std::endl; + } + return 0; +} + + + + + + + + + |