From cd1dfca2f5b93cdac50b100a0431b08eb2498e3b Mon Sep 17 00:00:00 2001 From: ykiko Date: Tue, 19 Nov 2024 17:10:47 +0800 Subject: [PATCH] Some update for server. --- include/Server/Async.h | 242 --------------------------- include/Server/CDBWatcher.h | 8 - include/Server/CacheManager.h | 19 --- include/Server/Config.h | 2 +- include/Server/FileScheduler.h | 15 -- include/Server/Scheduler.h | 26 --- include/Server/Server.h | 31 +--- include/Server/SymbolIndex.h | 6 - src/Server/Scheduler.cpp | 33 ---- src/Server/Server.cpp | 296 +++++++++++---------------------- src/Server/Server2.cpp | 131 +++++++++++++++ src/Server/Transport.cpp | 165 ++++++++++++++++++ src/main.cpp | 20 +-- 13 files changed, 398 insertions(+), 596 deletions(-) delete mode 100644 include/Server/Async.h delete mode 100644 include/Server/CDBWatcher.h delete mode 100644 include/Server/CacheManager.h delete mode 100644 include/Server/FileScheduler.h delete mode 100644 include/Server/Scheduler.h delete mode 100644 include/Server/SymbolIndex.h delete mode 100644 src/Server/Scheduler.cpp create mode 100644 src/Server/Server2.cpp create mode 100644 src/Server/Transport.cpp diff --git a/include/Server/Async.h b/include/Server/Async.h deleted file mode 100644 index 115df029..00000000 --- a/include/Server/Async.h +++ /dev/null @@ -1,242 +0,0 @@ -#include -#include -#include -#include -#include - -namespace clice {} // namespace clice - -namespace clice::asyncio { - -/// Unique loop instance. -inline uv_loop_t* loop = uv_default_loop(); - -template -struct result { - union { - Value value; - }; - - result() = default; - - result(const result&) = delete; - - result& operator= (const result&) = delete; - - bool await_ready() noexcept { - return false; - } - - decltype(auto) await_resume() { - return std::move(value); - } -}; - -template -auto schedule(Task&& task) { - using R = std::invoke_result_t; - - struct awaiter : result { - Task task; - uv_work_t request; - std::coroutine_handle<> h; - - void await_suspend(std::coroutine_handle<> caller) noexcept { - h = caller; - request.data = this; - uv_queue_work( - loop, - &request, - [](uv_work_t* req) { - auto* self = static_cast(req->data); - new (&self->value) R(self->task()); - }, - [](uv_work_t* req, int status) { - auto* self = static_cast(req->data); - /// FIXME: resolve status and handle errors. - if(!self->h.done()) { - self->h.resume(); - } - }); - } - }; - - return awaiter{{}, std::forward(task)}; -} - -auto sleep(std::size_t milliseconds) { - struct awaiter { - uv_timer_t timer; - std::size_t milliseconds; - std::coroutine_handle<> h; - - bool await_ready() noexcept { - return false; - } - - void await_suspend(std::coroutine_handle<> caller) noexcept { - h = caller; - timer.data = this; - uv_timer_init(loop, &timer); - uv_timer_start( - &timer, - [](uv_timer_t* handle) { - auto* self = static_cast(handle->data); - if(!self->h.done()) { - self->h.resume(); - } - uv_close(reinterpret_cast(handle), nullptr); - }, - milliseconds, - 0); - } - - void await_resume() noexcept {} - }; - - return awaiter{{}, milliseconds}; -} - -struct final_awaiter { - std::coroutine_handle<> caller; - - bool await_ready() noexcept { - return false; - } - - void await_suspend(std::coroutine_handle<> h) noexcept { - h.destroy(); - if(caller && !caller.done()) { - caller.resume(); - } - } - - void await_resume() noexcept {} -}; - -template -class promise { -public: - struct promise_type { - union { - T value; - }; - - std::coroutine_handle<> caller; - - auto get_return_object() noexcept { - return handle::from_promise(*this); - }; - - std::suspend_always initial_suspend() noexcept { - return {}; - } - - auto final_suspend() noexcept { - return final_awaiter{caller}; - } - - void unhandled_exception() noexcept { - std::terminate(); - } - - template - void return_value(Value&& value) noexcept { - new (&this->value) Value(std::forward(value)); - } - }; - - using handle = std::coroutine_handle; - - promise(handle h) : h(h) {} - - bool await_ready() noexcept { - return false; - } - - void await_suspend(std::coroutine_handle<> caller) noexcept { - h.promise().caller = caller; - if(!h.done()) { - h.resume(); - } - } - - decltype(auto) await_resume() { - return std::move(h.promise().value); - } - - void resume() { - if(!h.done()) { - h.resume(); - } - } - -private: - handle h; -}; - -template <> -class promise { -public: - struct promise_type { - std::coroutine_handle<> caller; - - auto get_return_object() noexcept { - return handle::from_promise(*this); - }; - - std::suspend_always initial_suspend() noexcept { - return {}; - } - - auto final_suspend() noexcept { - return final_awaiter{caller}; - } - - void unhandled_exception() noexcept { - std::terminate(); - } - - void return_void() noexcept {} - }; - - using handle = std::coroutine_handle; - - promise(handle h) : h(h) {} - - bool await_ready() noexcept { - return false; - } - - void await_suspend(std::coroutine_handle<> caller) noexcept { - h.promise().caller = caller; - if(!h.done()) { - h.resume(); - } - } - - void await_resume() {} - -private: - handle h; -}; - -template -T& uv_cast(Handle handle) { - return *reinterpret_cast(handle->data); -} - -} // namespace clice::asyncio - -using namespace clice; -using namespace clice::asyncio; - -promise test() { - co_await asyncio::sleep(1000); - int result = co_await asyncio::schedule([]() -> int { - printf("Hello from async task!\n"); - return 42; - }); - co_return result; -} - diff --git a/include/Server/CDBWatcher.h b/include/Server/CDBWatcher.h deleted file mode 100644 index 418ce34d..00000000 --- a/include/Server/CDBWatcher.h +++ /dev/null @@ -1,8 +0,0 @@ -namespace clice { - -/// responsible for: -/// - watch and incrementally update compliation database -/// - scan module dependencies -class CDBWatcher {}; - -} // namespace clice diff --git a/include/Server/CacheManager.h b/include/Server/CacheManager.h deleted file mode 100644 index bc499ed8..00000000 --- a/include/Server/CacheManager.h +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -namespace clice { - -/// responsible for: -/// - build PCH and PCM for specific file -/// - update PCH and PCM -class CacheManager { -public: - -private: - // file -> dependencies files - // check modification time of file and dependencies files to decide whether to rebuild PCH and - // PCM - llvm::StringMap> caches; -}; - -} // namespace clice diff --git a/include/Server/Config.h b/include/Server/Config.h index 3dcce6ad..cbf42c2e 100644 --- a/include/Server/Config.h +++ b/include/Server/Config.h @@ -13,7 +13,7 @@ int parse(int argc, const char** argv); void init(std::string_view workplace); struct ServerOption { - std::string mode; + std::string mode = "pipe"; unsigned int port; std::string address; }; diff --git a/include/Server/FileScheduler.h b/include/Server/FileScheduler.h deleted file mode 100644 index 162f85fc..00000000 --- a/include/Server/FileScheduler.h +++ /dev/null @@ -1,15 +0,0 @@ -namespace clice { - -/// Header file, use specific TU as context. -struct Header {}; - -/// A simple TU file. -struct TranslationUnit {}; - -/// responsible for: -/// - manage the compiler instance for active files -class FileScheduler { - // TODO: -}; - -} // namespace clice diff --git a/include/Server/Scheduler.h b/include/Server/Scheduler.h deleted file mode 100644 index 03850af4..00000000 --- a/include/Server/Scheduler.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -namespace clice { - -/// responsible for file management and scheduling tasks. -class Scheduler { -private: - struct TU { - // using message = llvm::unique_function; - // std::string content; - // std::deque messages; - // std::unique_ptr ast; - // std::unique_ptr preamble; - }; - -public: - void dispatch(json::Value id, std::string_view method, json::Value value); - -private: - llvm::StringMap files; -}; - -} // namespace clice diff --git a/include/Server/Server.h b/include/Server/Server.h index 0b6777fd..7487f7eb 100644 --- a/include/Server/Server.h +++ b/include/Server/Server.h @@ -1,8 +1,6 @@ #pragma once -#include -#include -#include +#include "Basic/Basic.h" namespace clice::proto { @@ -72,29 +70,6 @@ struct InitializedParams {}; namespace clice { -struct Server { - using Handler = llvm::unique_function; - Scheduler scheduler; - llvm::StringMap handlers; +int run(int argc, const char** argv); - static Server instance; - - Server(); - - int run(int argc, const char** argv); - - void handleMessage(std::string_view message); - - void notify(); - - void response(json::Value id, json::Value result); - -public: - // LSP methods, if the return type is void, the method is used for notification. - // otherwise, the method is used for request. - auto initialize(proto::InitializeParams params) -> proto::InitializeResult; - - void initialized(proto::InitializedParams params); -}; - -} // namespace clice +} diff --git a/include/Server/SymbolIndex.h b/include/Server/SymbolIndex.h deleted file mode 100644 index 189a2fc9..00000000 --- a/include/Server/SymbolIndex.h +++ /dev/null @@ -1,6 +0,0 @@ -namespace clice { - -/// responsible for loading and update symbol from index file. -class SymbolIndex {}; - -} // namespace clice diff --git a/src/Server/Scheduler.cpp b/src/Server/Scheduler.cpp deleted file mode 100644 index 904276d6..00000000 --- a/src/Server/Scheduler.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include -#include - -namespace clice { - -void Scheduler::dispatch(json::Value id, std::string_view method, json::Value value) { - std::vector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir=/home/ykiko/C++/clice2/build/lib/clang/20", - }; - if(method == "textDocument/didOpen") { - // auto params = json::deserialize(value); - // auto AST = ParsedAST::build("main.cpp", params.textDocument.text, compileArgs); - // files[params.textDocument.uri].ast = std::move(AST); - } else if(method == "textDocument/didChange") { - // auto params = json::deserialize(value); - // auto AST = ParsedAST::build("main.cpp", params.contentChanges.back().text, compileArgs); - // files[params.textDocument.uri].ast = std::move(AST); - } else if(method == "textDocument/semanticTokens/full") { - // auto params = json::deserialize(value); - // auto AST = files[params.textDocument.uri].ast.get(); - // auto semanticTokens = feature::semanticTokens(*AST, "main.cpp"); - // Server::instance.response(std::move(id), json::serialize(semanticTokens)); - } else { - spdlog::error("unknown method: {}", method); - } -} - -} // namespace clice diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index c4581979..fd3f86c5 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -1,226 +1,120 @@ -#include -#include -#include -#include -#include -#include +#include "uv.h" +#include "Server/Config.h" +#include "Server/Server.h" +#include "Basic/Location.h" +#include "llvm/Support/raw_ostream.h" namespace clice { -Server Server::instance; +static uv_loop_t* loop; +static uv_idle_t idle; +static uv_stream_t* writer; -namespace { +void schedule() {} -class MessageBuffer { - std::vector buffer; - std::size_t max = 0; - -public: - void write(std::string_view message) { - buffer.insert(buffer.end(), message.begin(), message.end()); - } - - std::string_view read() { - std::string_view view = std::string_view(buffer.data(), buffer.size()); - auto start = view.find("Content-Length: ") + 16; - auto end = view.find("\r\n\r\n"); - - if(start != std::string_view::npos && end != std::string_view::npos) { - std::size_t length = std::stoul(std::string(view.substr(start, end - start))); - if(view.size() >= length + end + 4) { - this->max = length + end + 4; - return view.substr(end + 4, length); - } - } - - return {}; - } - - void clear() { - if(max != 0) { - buffer.erase(buffer.begin(), buffer.begin() + max); - max = 0; - } - } -}; - -uv_loop_t* unique_loop; -uv_idle_t idle; - -static llvm::SmallVector buffer; - -void alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { - buffer.resize(size); +void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + static llvm::SmallString<4096> buffer; + buffer.resize_for_overwrite(suggested_size); buf->base = buffer.data(); - buf->len = buffer.size(); + buf->len = suggested_size; } -MessageBuffer messageBuffer; - -void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { +void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if(nread > 0) { - messageBuffer.write(std::string_view(buf->base, nread)); + llvm::outs() << "Received from stdin: " << llvm::StringRef(buf->base, nread); } else if(nread < 0) { - logger::error("Read error: {}", uv_strerror(nread)); - } -} - -struct Pipe { - inline static uv_pipe_t stdin; - inline static uv_pipe_t stdout; - - static void initialize() { - uv_pipe_init(unique_loop, &stdin, 0); - uv_pipe_open(&stdin, 0); - - uv_pipe_init(unique_loop, &stdout, 0); - uv_pipe_open(&stdout, 1); - - uv_read_start(reinterpret_cast(&stdin), alloc, onRead); - } - - inline static uv_buf_t buf; - inline static uv_write_t req; - - static void write(std::string_view message) { - buf.base = const_cast(message.data()); - buf.len = message.size(); - int state = uv_write(&req, reinterpret_cast(&stdout), &buf, 1, nullptr); - if(state < 0) { - logger::error("Error writing to client: {}", uv_strerror(state)); + if(nread != UV_EOF) { + fprintf(stderr, "Error reading from stdin: %s\n", uv_strerror(nread)); } - } -}; - -struct Socket { - inline static uv_tcp_t server; - inline static uv_tcp_t client; - - static void initialize(const char* ip, int port) { - uv_tcp_init(unique_loop, &server); - - sockaddr_in addr; - uv_ip4_addr(ip, port, &addr); - - uv_tcp_bind(&server, reinterpret_cast(&addr), 0); - uv_listen(reinterpret_cast(&server), 1, [](uv_stream_t* server, int status) { - if(status < 0) { - logger::error("Listen error: {}", uv_strerror(status)); - return; - } - - uv_tcp_init(unique_loop, &client); - uv_accept(server, reinterpret_cast(&client)); - uv_read_start(reinterpret_cast(&client), alloc, onRead); - }); - } - - inline static uv_buf_t buf; - inline static uv_write_t req; - - static void write(std::string_view message) { - buf.base = const_cast(message.data()); - buf.len = message.size(); - int state = uv_write(&req, reinterpret_cast(&client), &buf, 1, nullptr); - if(state < 0) { - logger::error("Error writing to client: {}", uv_strerror(state)); - } - } -}; - -} // namespace - -Server::Server() { - - handlers.try_emplace("initialize", [](json::Value id, json::Value value) { - auto result = instance.initialize(json::deserialize(value)); - instance.response(std::move(id), json::serialize(result)); - }); -} - -void eventloop(uv_idle_t* handle) { - if(auto message = messageBuffer.read(); !message.empty()) { - Server::instance.handleMessage(message); - messageBuffer.clear(); + uv_close((uv_handle_t*)stream, NULL); } } -auto Server::initialize(proto::InitializeParams params) -> proto::InitializeResult { - config::init(URI::resolve(params.workspaceFolders[0].uri)); - - // TODO: sacn module: - - // TODO: load index result - - // TODO: initialize dependencies - - return proto::InitializeResult(); -} - -int Server::run(int argc, const char** argv) { - std::this_thread::sleep_for(std::chrono::seconds(2)); - - logger::init("console", argv[0]); - - if(auto err = config::parse(argc, argv); err < 0) { - return err; - }; - - unique_loop = uv_default_loop(); - Socket::initialize("127.0.0.1", 50505); - - uv_idle_init(unique_loop, &idle); - uv_idle_start(&idle, eventloop); - - uv_run(unique_loop, UV_RUN_DEFAULT); - - uv_loop_close(unique_loop); - - return 0; -} - -void Server::handleMessage(std::string_view message) { - auto result = json::parse(message); - if(!result) { - logger::error("Error parsing JSON: {}", llvm::toString(result.takeError())); - } - - logger::info("Received message: {}", message); - auto input = result->getAsObject(); - auto id = input->get("id"); - std::string_view method = input->get("method")->getAsString().value(); - auto params = input->get("params"); - - if(auto handler = handlers.find(method); handler != handlers.end()) { - handler->second(*id, *params); +void on_write(uv_write_t* req, int status) { + if(status < 0) { + fprintf(stderr, "Write error: %s\n", uv_strerror(status)); } else { - // FIXME: notify do not have a ID. - if(id) { - scheduler.dispatch(std::move(*id), method, *params); - } else { - scheduler.dispatch(nullptr, method, *params); - } + printf("Write completed successfully.\n"); } + free(req); } -void Server::response(json::Value id, json::Value result) { - json::Object response; - response.try_emplace("jsonrpc", "2.0"); - response.try_emplace("id", std::move(id)); - response.try_emplace("result", result); +void write(llvm::StringRef message) { + /// FIXME: + static uv_write_t write_req; + uv_buf_t buf = uv_buf_init((char*)message.data(), message.size()); + uv_write(&write_req, writer, &buf, 1, on_write); +} - json::Value responseValue = std::move(response); +uv_stream_t* init_socket(const char* address, unsigned int port) { + static uv_tcp_t server; + static uv_tcp_t client; - std::string s; - llvm::raw_string_ostream stream(s); - stream << responseValue; - stream.flush(); + uv_tcp_init(loop, &server); + uv_tcp_init(loop, &client); - s = "Content-Length: " + std::to_string(s.size()) + "\r\n\r\n" + s; + struct sockaddr_in addr; + uv_ip4_addr(address, port, &addr); - // FIXME: use more flexible way to do this. - Socket::write(s); - logger::info("Response: {}", s); + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + + int r = uv_listen((uv_stream_t*)&server, 128, [](uv_stream_t* server, int status) { + if(status < 0) { + fprintf(stderr, "New connection error\n"); + return; + } + + if(uv_accept(server, (uv_stream_t*)&client) == 0) { + printf("Client connected.\n"); + uv_read_start((uv_stream_t*)&client, on_alloc_buffer, on_read); + } else { + uv_close((uv_handle_t*)&client, NULL); + } + }); + + if(r) { + fprintf(stderr, "Listen error: %s\n", uv_strerror(r)); + } + + return (uv_stream_t*)&client; +} + +uv_stream_t* init_pipe() { + static uv_pipe_t stdin_pipe; + static uv_pipe_t stdout_pipe; + + uv_pipe_init(loop, &stdin_pipe, 0); + uv_pipe_init(loop, &stdout_pipe, 0); + + uv_pipe_open(&stdin_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + uv_read_start((uv_stream_t*)&stdin_pipe, on_alloc_buffer, on_read); + + return (uv_stream_t*)&stdout_pipe; +} + +int run(int argc, const char** argv) { + loop = uv_default_loop(); + + uv_idle_init(loop, &idle); + uv_idle_start(&idle, [](uv_idle_t* handle) { schedule(); }); + + /// read config file. + config::parse(argc, argv); + + /// init writer. + const auto& option = config::server(); + if(option.mode == "socket") { + writer = init_socket(option.address.c_str(), option.port); + } else if(option.mode == "pipe") { + writer = init_pipe(); + } else { + llvm::errs() << "Unknown mode: " << option.mode << "\n"; + return 1; + } + + return uv_run(loop, UV_RUN_DEFAULT); } } // namespace clice diff --git a/src/Server/Server2.cpp b/src/Server/Server2.cpp new file mode 100644 index 00000000..0388289d --- /dev/null +++ b/src/Server/Server2.cpp @@ -0,0 +1,131 @@ +#include "llvm/ADT/SmallVector.h" +#include +#include +#include +#include +#include +#include + +namespace clice { + +uv_loop_t* loop = uv_default_loop(); + +template +struct awaiter { + + awaiter(Func&& func) : func(std::forward(func)) {} + + bool await_ready() noexcept { + return false; + } + + void await_suspend(std::coroutine_handle<> h) noexcept { + request.data = this; + uv_queue_work( + loop, + &request, + [](uv_work_t* req) { + auto* self = static_cast(req->data); + self->result = self->func(); + }, + [](uv_work_t* req, int status) { + auto* self = static_cast(req->data); + self->coro.resume(); + }); + } + + decltype(auto) await_resume() { + return std::move(*result); + } + + Func func; + uv_work_t request; + std::coroutine_handle<> coro; + std::optional result; +}; + +template +struct Result { + template + void return_value(T&& value) noexcept {} +}; + +template <> +struct Result { + void return_void() noexcept {} +}; + +template +struct Task { + struct promise_type; + + using handle = std::coroutine_handle; + + struct promise_type : Result { + auto get_return_object() noexcept { + return Task{handle::from_promise(*this)}; + } + + std::suspend_always initial_suspend() noexcept { + return {}; + } + + auto final_suspend() noexcept { + struct final_awaiter { + std::coroutine_handle<> caller; + + bool await_ready() noexcept { + return false; + } + + void await_suspend(std::coroutine_handle<> h) noexcept { + h.destroy(); + caller.resume(); + } + + void await_resume() noexcept {} + }; + + return final_awaiter{caller}; + } + + void unhandled_exception() noexcept { + std::terminate(); + } + + std::coroutine_handle<> caller; + }; + + bool await_ready() noexcept { + return false; + } + + void await_suspend(std::coroutine_handle<> caller) noexcept { + h.promise().caller = caller; + h.resume(); + } + + decltype(auto) await_resume() {} + + handle h; +}; + +template +auto run(Func&& func) { + return awaiter{std::forward(func)}; +} + +Task<> test() { + co_await run([] { + printf("Hello from thread pool.\n"); + return 1; + }); + printf("Thread pool work completed.\n"); +} + +Task<> test2() { + co_await test(); +} + +} // namespace clice + diff --git a/src/Server/Transport.cpp b/src/Server/Transport.cpp new file mode 100644 index 00000000..9243a485 --- /dev/null +++ b/src/Server/Transport.cpp @@ -0,0 +1,165 @@ + +#include +#include +#include + +#include +#include +#include + +namespace clice { + +void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + static llvm::SmallString<4096> buffer; + buffer.resize_for_overwrite(suggested_size); + buf->base = buffer.data(); + buf->len = suggested_size; +} + +void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + if(nread > 0) { + printf("Received from stdin: %.*s", (int)nread, buf->base); + } else if(nread < 0) { + if(nread != UV_EOF) { + fprintf(stderr, "Error reading from stdin: %s\n", uv_strerror(nread)); + } + uv_close((uv_handle_t*)stream, NULL); + } +} + +void on_write(uv_write_t* req, int status) { + if(status < 0) { + fprintf(stderr, "Write error: %s\n", uv_strerror(status)); + } else { + printf("Write completed successfully.\n"); + } + free(req); +} + +void test_pipe(const char* data) { + static uv_pipe_t stdin_pipe; + static uv_pipe_t stdout_pipe; + + auto loop = uv_default_loop(); + uv_pipe_init(loop, &stdin_pipe, 0); + uv_pipe_open(&stdin_pipe, 0); + + uv_pipe_init(loop, &stdout_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + uv_read_start((uv_stream_t*)&stdin_pipe, on_alloc_buffer, on_read); + + uv_buf_t buf = uv_buf_init((char*)data, strlen(data)); + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + uv_write(write_req, (uv_stream_t*)&stdout_pipe, &buf, 1, on_write); +} + +void test_socket(const char* data) { + static uv_loop_t* loop = uv_default_loop(); + static uv_tcp_t server; + static uv_tcp_t client; + + uv_tcp_init(loop, &server); + uv_tcp_init(loop, &client); + + sockaddr_in addr; + uv_ip4_addr("0.0.0.0", 7000, &addr); + uv_tcp_bind(&server, (const sockaddr*)&addr, 0); + + int r = uv_listen((uv_stream_t*)&server, 128, [](uv_stream_t* server, int status) { + if(status < 0) { + fprintf(stderr, "New connection error\n"); + return; + } + + if(uv_accept(server, (uv_stream_t*)&client) == 0) { + printf("Client connected.\n"); + uv_read_start((uv_stream_t*)&client, on_alloc_buffer, on_read); + } else { + uv_close((uv_handle_t*)&client, NULL); + } + }); + + if(r) { + fprintf(stderr, "Listen error: %s\n", uv_strerror(r)); + } + + uv_buf_t buf = uv_buf_init((char*)data, strlen(data)); + uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + uv_write(write_req, (uv_stream_t*)&client, &buf, 1, on_write); +} + +void test_thread_pool() { + uv_loop_t* loop = uv_default_loop(); + uv_work_t* work = new uv_work_t(); + auto work_cb = [](uv_work_t* req) { + // in thread pool + printf("Hello from thread pool.\n"); + }; + auto after_work_cb = [](uv_work_t* req, int status) { + /// in main thread + printf("Thread pool work completed.\n"); + free(req); + }; + uv_queue_work(loop, work, work_cb, after_work_cb); +} + +void test_fs_event() { + uv_loop_t* loop = uv_default_loop(); + uv_fs_event_t fs_event; + uv_fs_event_init(loop, &fs_event); + auto on_fs_event = [](uv_fs_event_t* handle, const char* filename, int events, int status) { + if(status < 0) { + fprintf(stderr, "Error: %s\n", uv_strerror(status)); + return; + } + + char path[1024]; + size_t size = sizeof(path); + int ret = uv_fs_event_getpath(handle, path, &size); + + if(ret == 0) { + path[size] = '\0'; + printf("File change detected in: %s\n", path); + } else { + fprintf(stderr, "Failed to get path: %s\n", uv_strerror(ret)); + } + + if(filename) { + printf(" Affected file: %s\n", filename); + } + + if(events & UV_RENAME) { + printf(" Event: File renamed\n"); + } + if(events & UV_CHANGE) { + printf(" Event: File changed\n"); + } + }; + + const char* path = "./watched_dir"; + int ret = uv_fs_event_start(&fs_event, on_fs_event, path, 0); + if(ret < 0) { + fprintf(stderr, "Failed to start file watcher: %s\n", uv_strerror(ret)); + } +} + +void test_event_loop() { + auto on_prepare = [](uv_prepare_t* handle) { + static int count = 0; + printf("Prepare callback: count = %d\n", count++); + if(count >= 5) { + uv_prepare_stop(handle); + } + }; + + uv_loop_t* loop = uv_default_loop(); + uv_prepare_t prepare_handle; + uv_prepare_init(loop, &prepare_handle); + + uv_prepare_start(&prepare_handle, on_prepare); +} + +} // namespace clice + + diff --git a/src/main.cpp b/src/main.cpp index ac71d8c4..ef1b8aa8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,6 @@ -#include - - -int main() { - promise p = test(); - - uv_idle_t idle; - uv_idle_init(loop, &idle); - idle.data = &p; - - uv_idle_start(&idle, [](uv_idle_t* handle) { - auto& p = uv_cast>(handle); - p.resume(); - uv_idle_stop(handle); - }); - - uv_run(loop, UV_RUN_DEFAULT); +#include "Server/Server.h" +int main(int argc, const char** argv) { + clice::run(argc, argv); return 0; }