Serenity Operating System
at master 149 lines 5.2 kB view raw
1/* 2 * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Base64.h> 8#include <AK/Format.h> 9#include <AK/URL.h> 10#include <LibCore/ArgsParser.h> 11#include <LibCore/EventLoop.h> 12#include <LibCore/System.h> 13#include <LibLine/Editor.h> 14#include <LibMain/Main.h> 15#include <LibProtocol/WebSocket.h> 16#include <LibProtocol/WebSocketClient.h> 17 18ErrorOr<int> serenity_main(Main::Arguments arguments) 19{ 20 TRY(Core::System::pledge("stdio unix inet accept rpath wpath cpath fattr tty sigaction")); 21 22 Core::ArgsParser args_parser; 23 24 DeprecatedString origin; 25 DeprecatedString url_string; 26 27 args_parser.add_positional_argument(url_string, "URL to connect to", "url", Core::ArgsParser::Required::Yes); 28 args_parser.add_option(origin, "URL to use as origin", "origin", 'o', "origin"); 29 30 args_parser.parse(arguments); 31 32 URL url(url_string); 33 34 if (!url.is_valid()) { 35 warnln("The given URL is not valid"); 36 return 1; 37 } 38 39 Core::EventLoop loop; 40 41 auto maybe_websocket_client = Protocol::WebSocketClient::try_create(); 42 if (maybe_websocket_client.is_error()) { 43 warnln("Failed to connect to the websocket server: {}\n", maybe_websocket_client.error()); 44 return maybe_websocket_client.release_error(); 45 } 46 auto websocket_client = maybe_websocket_client.release_value(); 47 48 RefPtr<Line::Editor> editor = Line::Editor::construct(); 49 bool should_quit = false; 50 auto socket = websocket_client->connect(url, origin); 51 if (!socket) { 52 warnln("Failed to start socket for '{}'\n", url); 53 return 1; 54 } 55 socket->on_open = [&]() { 56 outln("[WebSocket opened]"sv); 57 }; 58 socket->on_error = [&](auto error) { 59 outln("[WebSocket Error : {}]", (unsigned)error); 60 }; 61 socket->on_message = [&](auto message) { 62 if (!message.is_text) { 63 outln("[Received binary data : {} bytes]", message.data.size()); 64 return; 65 } 66 outln("[Received utf8 text] {}", DeprecatedString(ReadonlyBytes(message.data))); 67 }; 68 socket->on_close = [&](auto code, auto message, bool was_clean) { 69 outln("[Server {} closed connection : '{}' (code {})]", 70 was_clean ? "cleanly" : "dirtily", 71 message, 72 code); 73 should_quit = true; 74 Core::EventLoop::current().quit(0); 75 }; 76 77 TRY(Core::System::pledge("stdio unix inet accept rpath wpath tty sigaction")); 78 79 TRY(Core::System::unveil(nullptr, nullptr)); 80 81 outln("Started server. Commands :"); 82 outln("- '<text>' send the text as message"); 83 outln("- '.text <data>' send the text as message"); 84 outln("- '.base64 <data>' send the binary data from a base64-encoded string as message"); 85 outln("- '.exit' Ask to exit the server"); 86 outln("- '.forceexit' Exit the server"); 87 while (!should_quit) { 88 auto line_or_error = editor->get_line(">"); 89 if (line_or_error.is_error()) { 90 continue; 91 } 92 auto line = line_or_error.value(); 93 if (line.is_empty()) 94 continue; 95 96 if (line.starts_with('.')) { 97 if (line.starts_with(".text "sv)) { 98 editor->add_to_history(line); 99 if (socket->ready_state() != Protocol::WebSocket::ReadyState::Open) { 100 outln("Could not send message : socket is not open."); 101 continue; 102 } 103 socket->send(line.substring(6)); 104 continue; 105 } 106 if (line.starts_with(".base64 "sv)) { 107 editor->add_to_history(line); 108 if (socket->ready_state() != Protocol::WebSocket::ReadyState::Open) { 109 outln("Could not send message : socket is not open."); 110 continue; 111 } 112 auto base64_data = line.substring(8); 113 auto buffer = decode_base64(base64_data); 114 if (buffer.is_error()) { 115 outln("Could not send message : {}", buffer.error().string_literal()); 116 } else { 117 socket->send(buffer.value(), false); 118 } 119 continue; 120 } 121 if (line == ".exit") { 122 editor->add_to_history(line); 123 if (socket->ready_state() != Protocol::WebSocket::ReadyState::Open) { 124 outln("Socket is not open. Exiting."); 125 should_quit = true; 126 continue; 127 } 128 socket->close(); 129 continue; 130 } 131 if (line == ".forceexit") { 132 editor->add_to_history(line); 133 if (socket->ready_state() == Protocol::WebSocket::ReadyState::Open) 134 socket->close(); 135 return 1; 136 } 137 outln("Unknown command : {}", line); 138 continue; 139 } 140 editor->add_to_history(line); 141 if (socket->ready_state() != Protocol::WebSocket::ReadyState::Open) { 142 outln("Could not send message : socket is not open."); 143 continue; 144 } 145 socket->send(line); 146 } 147 148 return 0; 149}