diff options
Diffstat (limited to 'Userland/Services/WebSocket/ConnectionFromClient.cpp')
-rw-r--r-- | Userland/Services/WebSocket/ConnectionFromClient.cpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/Userland/Services/WebSocket/ConnectionFromClient.cpp b/Userland/Services/WebSocket/ConnectionFromClient.cpp new file mode 100644 index 0000000000..52ee645895 --- /dev/null +++ b/Userland/Services/WebSocket/ConnectionFromClient.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2021, Dexβͺ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWebSocket/ConnectionInfo.h> +#include <LibWebSocket/Message.h> +#include <WebSocket/ConnectionFromClient.h> +#include <WebSocket/WebSocketClientEndpoint.h> + +namespace WebSocket { + +static HashMap<int, RefPtr<ConnectionFromClient>> s_connections; + +ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket) + : IPC::ConnectionFromClient<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), 1) +{ + s_connections.set(1, *this); +} + +ConnectionFromClient::~ConnectionFromClient() +{ +} + +void ConnectionFromClient::die() +{ + s_connections.remove(client_id()); + if (s_connections.is_empty()) + Core::EventLoop::current().quit(0); +} + +Messages::WebSocketServer::ConnectResponse ConnectionFromClient::connect(URL const& url, String const& origin, + Vector<String> const& protocols, Vector<String> const& extensions, IPC::Dictionary const& additional_request_headers) +{ + if (!url.is_valid()) { + dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url); + return -1; + } + + ConnectionInfo connection_info(url); + connection_info.set_origin(origin); + connection_info.set_protocols(protocols); + connection_info.set_extensions(extensions); + + Vector<ConnectionInfo::Header> headers; + for (auto const& header : additional_request_headers.entries()) { + headers.append({ header.key, header.value }); + } + connection_info.set_headers(headers); + + VERIFY(m_connection_ids < NumericLimits<i32>::max()); + auto id = ++m_connection_ids; + auto connection = WebSocket::create(move(connection_info)); + connection->on_open = [this, id]() { + did_connect(id); + }; + connection->on_message = [this, id](auto message) { + did_receive_message(id, move(message)); + }; + connection->on_error = [this, id](auto message) { + did_error(id, (i32)message); + }; + connection->on_close = [this, id](u16 code, String reason, bool was_clean) { + did_close(id, code, move(reason), was_clean); + }; + + connection->start(); + m_connections.set(id, move(connection)); + return id; +} + +Messages::WebSocketServer::ReadyStateResponse ConnectionFromClient::ready_state(i32 connection_id) +{ + RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({}); + if (connection) { + return (u32)connection->ready_state(); + } + return (u32)ReadyState::Closed; +} + +void ConnectionFromClient::send(i32 connection_id, bool is_text, ByteBuffer const& data) +{ + RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({}); + if (connection && connection->ready_state() == ReadyState::Open) { + Message websocket_message(data, is_text); + connection->send(websocket_message); + } +} + +void ConnectionFromClient::close(i32 connection_id, u16 code, String const& reason) +{ + RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({}); + if (connection && connection->ready_state() == ReadyState::Open) + connection->close(code, reason); +} + +Messages::WebSocketServer::SetCertificateResponse ConnectionFromClient::set_certificate(i32 connection_id, + [[maybe_unused]] String const& certificate, [[maybe_unused]] String const& key) +{ + RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({}); + bool success = false; + if (connection) { + // NO OP here + // connection->set_certificate(certificate, key); + success = true; + } + return success; +} + +void ConnectionFromClient::did_connect(i32 connection_id) +{ + async_connected(connection_id); +} + +void ConnectionFromClient::did_receive_message(i32 connection_id, Message message) +{ + async_received(connection_id, message.is_text(), message.data()); +} + +void ConnectionFromClient::did_error(i32 connection_id, i32 message) +{ + async_errored(connection_id, message); +} + +void ConnectionFromClient::did_close(i32 connection_id, u16 code, String reason, bool was_clean) +{ + async_closed(connection_id, code, reason, was_clean); + deferred_invoke([this, connection_id] { + m_connections.remove(connection_id); + }); +} + +void ConnectionFromClient::did_request_certificates(i32 connection_id) +{ + async_certificate_requested(connection_id); +} + +} |