From 09783d07a4c774a3ec5088d7e394ca2211896e24 Mon Sep 17 00:00:00 2001 From: Alexander Polyakov Date: Wed, 23 Oct 2024 17:47:43 +0300 Subject: [PATCH] K2: initial support for http queries (#1124) --- runtime-light/component/component.cpp | 31 ++- runtime-light/component/component.h | 5 +- runtime-light/component/init-functions.cpp | 27 +-- .../core/globals/php-script-globals.h | 33 +++ runtime-light/runtime-light.cmake | 2 + .../server/http/http-server-context.cpp | 12 ++ .../server/http/http-server-context.h | 18 ++ runtime-light/server/http/init-functions.cpp | 191 ++++++++++++++++++ runtime-light/server/http/init-functions.h | 9 + runtime-light/server/init-functions.h | 47 +++++ .../server/job-worker/init-functions.h | 25 +++ .../job-worker/job-worker-server-context.cpp} | 6 +- .../job-worker/job-worker-server-context.h} | 6 - runtime-light/server/server.cmake | 2 + .../stdlib/job-worker/job-worker-api.cpp | 3 +- .../job-worker/job-worker-client-context.cpp | 12 ++ .../job-worker/job-worker-client-context.h | 16 ++ runtime-light/stdlib/stdlib.cmake | 2 +- 18 files changed, 414 insertions(+), 33 deletions(-) create mode 100644 runtime-light/server/http/http-server-context.cpp create mode 100644 runtime-light/server/http/http-server-context.h create mode 100644 runtime-light/server/http/init-functions.cpp create mode 100644 runtime-light/server/http/init-functions.h create mode 100644 runtime-light/server/init-functions.h create mode 100644 runtime-light/server/job-worker/init-functions.h rename runtime-light/{stdlib/job-worker/job-worker-context.cpp => server/job-worker/job-worker-server-context.cpp} (63%) rename runtime-light/{stdlib/job-worker/job-worker-context.h => server/job-worker/job-worker-server-context.h} (77%) create mode 100644 runtime-light/server/server.cmake create mode 100644 runtime-light/stdlib/job-worker/job-worker-client-context.cpp create mode 100644 runtime-light/stdlib/job-worker/job-worker-client-context.h diff --git a/runtime-light/component/component.cpp b/runtime-light/component/component.cpp index 527b8d887a..34f864eb57 100644 --- a/runtime-light/component/component.cpp +++ b/runtime-light/component/component.cpp @@ -7,16 +7,19 @@ #include #include #include +#include #include #include +#include "runtime-core/runtime-core.h" #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/init-functions.h" #include "runtime-light/core/globals/php-init-scripts.h" +#include "runtime-light/core/globals/php-script-globals.h" #include "runtime-light/coroutine/task.h" #include "runtime-light/header.h" #include "runtime-light/scheduler/scheduler.h" -#include "runtime-light/stdlib/job-worker/job-worker-context.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" #include "runtime-light/streams/streams.h" #include "runtime-light/utils/context.h" @@ -48,8 +51,30 @@ void ComponentState::init_script_execution() noexcept { template task_t ComponentState::run_component_prologue() noexcept { static_assert(kind != ComponentKind::Invalid); - component_kind_ = kind; + + // common initialization + auto &superglobals{php_script_mutable_globals_singleton.get_superglobals()}; + superglobals.v$argc = static_cast(0); // TODO + superglobals.v$argv = array{}; // TODO + { + const auto &platform_ctx{*get_platform_context()}; + + SystemTime sys_time{}; + platform_ctx.get_system_time(std::addressof(sys_time)); + const auto time_mcs{std::chrono::duration_cast(std::chrono::nanoseconds{sys_time.since_epoch_ns}).count()}; + + using namespace PhpServerSuperGlobalIndices; + superglobals.v$_SERVER.set_value(string{ARGC, std::char_traits::length(ARGC)}, superglobals.v$argc); + superglobals.v$_SERVER.set_value(string{ARGV, std::char_traits::length(ARGV)}, superglobals.v$argv); + superglobals.v$_SERVER.set_value(string{PHP_SELF, std::char_traits::length(PHP_SELF)}, string{}); // TODO: script name + superglobals.v$_SERVER.set_value(string{SCRIPT_NAME, std::char_traits::length(SCRIPT_NAME)}, string{}); + superglobals.v$_SERVER.set_value(string{REQUEST_TIME, std::char_traits::length(REQUEST_TIME)}, static_cast(sys_time.since_epoch_ns)); + superglobals.v$_SERVER.set_value(string{REQUEST_TIME_FLOAT, std::char_traits::length(REQUEST_TIME_FLOAT)}, static_cast(time_mcs)); + } + // TODO sapi, env + + // specific initialization if constexpr (kind == ComponentKind::CLI) { standard_stream_ = co_await init_kphp_cli_component(); } else if constexpr (kind == ComponentKind::Server) { @@ -67,7 +92,7 @@ task_t ComponentState::run_component_epilogue() noexcept { co_return; } // do not flush output buffers if we are in job worker - if (JobWorkerServerComponentContext::get().kind != JobWorkerServerComponentContext::Kind::Invalid) { + if (job_worker_server_component_context.kind != JobWorkerServerComponentContext::Kind::Invalid) { co_return; } if (standard_stream() == INVALID_PLATFORM_DESCRIPTOR) { diff --git a/runtime-light/component/component.h b/runtime-light/component/component.h index 95c8f59e57..aee1bc1299 100644 --- a/runtime-light/component/component.h +++ b/runtime-light/component/component.h @@ -17,10 +17,12 @@ #include "runtime-light/coroutine/task.h" #include "runtime-light/header.h" #include "runtime-light/scheduler/scheduler.h" +#include "runtime-light/server/http/http-server-context.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" #include "runtime-light/stdlib/curl/curl-context.h" #include "runtime-light/stdlib/file/file-stream-context.h" #include "runtime-light/stdlib/fork/fork-context.h" -#include "runtime-light/stdlib/job-worker/job-worker-context.h" +#include "runtime-light/stdlib/job-worker/job-worker-client-context.h" #include "runtime-light/stdlib/output/output-buffer.h" #include "runtime-light/stdlib/regex/regex-context.h" #include "runtime-light/stdlib/rpc/rpc-context.h" @@ -107,6 +109,7 @@ struct ComponentState { KphpCoreContext kphp_core_context; RpcComponentContext rpc_component_context; + HttpServerComponentContext http_server_component_context{}; JobWorkerClientComponentContext job_worker_client_component_context{}; JobWorkerServerComponentContext job_worker_server_component_context{}; diff --git a/runtime-light/component/init-functions.cpp b/runtime-light/component/init-functions.cpp index 3bb01557bd..87a785d19e 100644 --- a/runtime-light/component/init-functions.cpp +++ b/runtime-light/component/init-functions.cpp @@ -6,13 +6,13 @@ #include -#include "runtime-core/runtime-core.h" #include "runtime-core/utils/kphp-assert-core.h" #include "runtime-light/component/component.h" #include "runtime-light/coroutine/awaitable.h" #include "runtime-light/coroutine/task.h" #include "runtime-light/header.h" -#include "runtime-light/stdlib/job-worker/job-worker-context.h" +#include "runtime-light/server/init-functions.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" #include "runtime-light/streams/streams.h" #include "runtime-light/tl/tl-core.h" #include "runtime-light/tl/tl-functions.h" @@ -20,26 +20,21 @@ namespace { +void process_k2_invoke_http(tl::TLBuffer &tlb) noexcept { + tl::K2InvokeHttp invoke_http{}; + if (!invoke_http.fetch(tlb)) { + php_error("erroneous http request"); + } + init_server(ServerQuery{std::move(invoke_http)}); +} + void process_k2_invoke_job_worker(tl::TLBuffer &tlb) noexcept { tl::K2InvokeJobWorker invoke_jw{}; if (!invoke_jw.fetch(tlb)) { php_error("erroneous job worker request"); } php_assert(invoke_jw.image_id == vk_k2_describe()->build_timestamp); // ensure that we got the request from ourselves - - auto &jw_server_ctx{JobWorkerServerComponentContext::get()}; - jw_server_ctx.kind = invoke_jw.ignore_answer ? JobWorkerServerComponentContext::Kind::NoReply : JobWorkerServerComponentContext::Kind::Regular; - jw_server_ctx.state = JobWorkerServerComponentContext::State::Working; - jw_server_ctx.job_id = invoke_jw.job_id; - jw_server_ctx.body = std::move(invoke_jw.body); - get_component_context()->php_script_mutable_globals_singleton.get_superglobals().v$_SERVER.set_value(string{"JOB_ID"}, invoke_jw.job_id); -} - -void process_k2_invoke_http(tl::TLBuffer &tlb) noexcept { - tl::K2InvokeHttp invoke_http{}; - if (!invoke_http.fetch(tlb)) { - php_error("erroneous http request"); - } + init_server(ServerQuery{std::move(invoke_jw)}); } } // namespace diff --git a/runtime-light/core/globals/php-script-globals.h b/runtime-light/core/globals/php-script-globals.h index a1a45b08d4..305d5c7f2f 100644 --- a/runtime-light/core/globals/php-script-globals.h +++ b/runtime-light/core/globals/php-script-globals.h @@ -8,7 +8,40 @@ #include "runtime-core/memory-resource/unsynchronized_pool_resource.h" #include "runtime-core/runtime-core.h" +namespace PhpServerSuperGlobalIndices { + +inline constexpr auto *ARGC = "argc"; +inline constexpr auto *ARGV = "argv"; + +inline constexpr auto *PHP_SELF = "PHP_SELF"; +inline constexpr auto *SCRIPT_URL = "SCRIPT_URL"; +inline constexpr auto *SCRIPT_URI = "SCRIPT_URI"; +inline constexpr auto *SCRIPT_NAME = "SCRIPT_NAME"; + +inline constexpr auto *REQUEST_URI = "REQUEST_URI"; +inline constexpr auto *REQUEST_TIME = "REQUEST_TIME"; +inline constexpr auto *REQUEST_METHOD = "REQUEST_METHOD"; +inline constexpr auto *REQUEST_TIME_FLOAT = "REQUEST_TIME_FLOAT"; + +inline constexpr auto *JOB_ID = "JOB_ID"; + +inline constexpr auto *SERVER_NAME = "SERVER_NAME"; +inline constexpr auto *SERVER_ADDR = "SERVER_ADDR"; +inline constexpr auto *SERVER_PORT = "SERVER_PORT"; +inline constexpr auto *SERVER_PROTOCOL = "SERVER_PROTOCOL"; +inline constexpr auto *SERVER_SOFTWARE = "SERVER_SOFTWARE"; +inline constexpr auto *SERVER_SIGNATURE = "SERVER_SIGNATURE"; + +inline constexpr auto *REMOTE_ADDR = "REMOTE_ADDR"; +inline constexpr auto *REMOTE_PORT = "REMOTE_PORT"; + +inline constexpr auto *QUERY_STRING = "QUERY_STRING"; +inline constexpr auto *GATEWAY_INTERFACE = "GATEWAY_INTERFACE"; + +}; // namespace PhpServerSuperGlobalIndices + struct PhpScriptBuiltInSuperGlobals { + // variables below are PHP language superglobals mixed v$_SERVER; mixed v$_GET; diff --git a/runtime-light/runtime-light.cmake b/runtime-light/runtime-light.cmake index debf858e2e..39a82b2ca2 100644 --- a/runtime-light/runtime-light.cmake +++ b/runtime-light/runtime-light.cmake @@ -1,6 +1,7 @@ include(${RUNTIME_LIGHT_DIR}/allocator/allocator.cmake) include(${RUNTIME_LIGHT_DIR}/core/core.cmake) include(${RUNTIME_LIGHT_DIR}/scheduler/scheduler.cmake) +include(${RUNTIME_LIGHT_DIR}/server/server.cmake) include(${RUNTIME_LIGHT_DIR}/stdlib/stdlib.cmake) include(${RUNTIME_LIGHT_DIR}/streams/streams.cmake) include(${RUNTIME_LIGHT_DIR}/tl/tl.cmake) @@ -12,6 +13,7 @@ set(RUNTIME_LIGHT_SRC ${RUNTIME_CORE_SRC} ${RUNTIME_STDLIB_SRC} ${RUNTIME_SCHEDULER_SRC} + ${RUNTIME_SERVER_SRC} ${RUNTIME_ALLOCATOR_SRC} ${RUNTIME_COROUTINE_SRC} ${RUNTIME_COMPONENT_SRC} diff --git a/runtime-light/server/http/http-server-context.cpp b/runtime-light/server/http/http-server-context.cpp new file mode 100644 index 0000000000..03126e1e87 --- /dev/null +++ b/runtime-light/server/http/http-server-context.cpp @@ -0,0 +1,12 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime-light/server/http/http-server-context.h" + +#include "runtime-light/component/component.h" +#include "runtime-light/utils/context.h" + +HttpServerComponentContext &HttpServerComponentContext::get() noexcept { + return get_component_context()->http_server_component_context; +} diff --git a/runtime-light/server/http/http-server-context.h b/runtime-light/server/http/http-server-context.h new file mode 100644 index 0000000000..72bd5b3694 --- /dev/null +++ b/runtime-light/server/http/http-server-context.h @@ -0,0 +1,18 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include + +#include "common/mixin/not_copyable.h" + +struct HttpServerComponentContext final : private vk::not_copyable { + static constexpr auto ENCODING_GZIP = static_cast(1U << 0U); + static constexpr auto ENCODING_DEFLATE = static_cast(1U << 1U); + + uint32_t encoding{}; + + static HttpServerComponentContext &get() noexcept; +}; diff --git a/runtime-light/server/http/init-functions.cpp b/runtime-light/server/http/init-functions.cpp new file mode 100644 index 0000000000..8489264642 --- /dev/null +++ b/runtime-light/server/http/init-functions.cpp @@ -0,0 +1,191 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime-light/server/http/init-functions.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "runtime-core/runtime-core.h" +#include "runtime-core/utils/kphp-assert-core.h" +#include "runtime-light/component/component.h" +#include "runtime-light/core/globals/php-script-globals.h" +#include "runtime-light/server/http/http-server-context.h" +#include "runtime-light/tl/tl-functions.h" +#include "runtime-light/tl/tl-types.h" +#include "runtime-light/utils/context.h" + +namespace { + +enum class HttpConnectionKind : uint8_t { KeepAlive, Close }; + +enum class HttpMethod : uint8_t { GET, POST, HEAD, OTHER }; + +constexpr auto *HTTPS = "HTTPS"; +constexpr auto *HTTPS_SCHEME = "https"; +constexpr auto *HTTP_HEADER_PREFIX = "HTTP_"; +constexpr auto *HTTP_X_REAL_HOST = "HTTP_X_REAL_HOST"; +constexpr auto *HTTP_X_REAL_SCHEME = "HTTP_X_REAL_SCHEME"; +constexpr auto *HTTP_X_REAL_REQUEST = "HTTP_X_REAL_REQUEST"; + +constexpr auto *SCHEME_SUFFIX = "://"; +constexpr auto *GATEWAY_INTERFACE_VALUE = "CGI/1.1"; + +constexpr auto *HEADER_HOST = "host"; +constexpr auto *HEADER_COOKIE = "cookie"; +constexpr auto *HEADER_AUTHORIZATION = "authorization"; +constexpr auto *HEADER_ACCEPT_ENCODING = "accept-encoding"; + +constexpr auto *GET_METHOD = "GET"; +constexpr auto *POST_METHOD = "POST"; +constexpr auto *HEAD_METHOD = "HEAD"; + +constexpr auto *ENCODING_GZIP = "gzip"; +constexpr auto *ENCODING_DEFLATE = "deflate"; + +[[maybe_unused]] constexpr auto *CONTENT_TYPE = "CONTENT_TYPE"; + +string get_server_protocol([[maybe_unused]] tl::HttpVersion http_version, [[maybe_unused]] const std::optional &opt_scheme) noexcept { + return string{"HTTP/1.1"}; // TODO +} + +void process_cookie_header(const string &header, PhpScriptBuiltInSuperGlobals &superglobals) noexcept { + // *** be careful here *** + auto *cookie_start{const_cast(header.c_str())}; + auto *cookie_list_end{const_cast(header.c_str() + header.size())}; + do { + auto *cookie_end{std::find(cookie_start, cookie_list_end, ';')}; + char *cookie_domain_end{std::find(cookie_start, cookie_end, '=')}; + if (cookie_domain_end != cookie_end) [[likely]] { + char *cookie_value_start{std::next(cookie_domain_end)}; + const auto cookie_domain_size{static_cast(std::distance(cookie_start, cookie_domain_end))}; + const auto cookie_value_size{static_cast(std::distance(cookie_value_start, cookie_end))}; + string cookie_domain{cookie_start, cookie_domain_size}; + string cookie_value{cookie_value_start, cookie_value_size}; + superglobals.v$_COOKIE.set_value(cookie_domain, std::move(cookie_value)); // TODO use proper setter + } + // skip ';' if possible + cookie_start = cookie_end == cookie_list_end ? cookie_list_end : std::next(cookie_end); + // skip whitespaces + while (cookie_start != cookie_list_end && *cookie_start == ' ') { + cookie_start = std::next(cookie_start); + } + } while (cookie_start != cookie_list_end); +} + +void process_headers(tl::dictionary &&headers, PhpScriptBuiltInSuperGlobals &superglobals) noexcept { + auto &server{superglobals.v$_SERVER}; + auto &http_server_ctx{HttpServerComponentContext::get()}; + using namespace PhpServerSuperGlobalIndices; + + // platform provides headers that are already in lowercase + for (auto &[header_name, header] : headers) { + if (std::strcmp(header_name.c_str(), HEADER_ACCEPT_ENCODING) == 0) { + if (std::strstr(header.value.c_str(), ENCODING_GZIP) != nullptr) { + http_server_ctx.encoding |= HttpServerComponentContext::ENCODING_GZIP; + } + if (std::strstr(header.value.c_str(), ENCODING_DEFLATE) != nullptr) { + http_server_ctx.encoding |= HttpServerComponentContext::ENCODING_DEFLATE; + } + } else if (std::strcmp(header_name.c_str(), HEADER_COOKIE) == 0) { + process_cookie_header(header.value, superglobals); + } else if (std::strcmp(header_name.c_str(), HEADER_HOST) == 0) { + server.set_value(string{SERVER_NAME, std::char_traits::length(SERVER_NAME)}, header.value); + } else if (std::strcmp(header_name.c_str(), HEADER_AUTHORIZATION) == 0) { + php_warning("authorization not implemented"); // TODO parse authorization + } + // add header entries + string key{}; + key.reserve_at_least(std::char_traits::length(HTTP_HEADER_PREFIX) + header_name.size()); + key.append(HTTP_HEADER_PREFIX); + key.append(header_name.c_str()); + // to uppercase inplace + for (int64_t i = std::char_traits::length(HTTP_HEADER_PREFIX); i < key.size(); ++i) { + key[i] = key[i] != '-' ? std::toupper(key[i]) : '_'; + } + server.set_value(key, std::move(header.value)); + } +} + +} // namespace + +void init_http_server(tl::K2InvokeHttp &&invoke_http) noexcept { + auto &superglobals{get_component_context()->php_script_mutable_globals_singleton.get_superglobals()}; + auto &server{superglobals.v$_SERVER}; + + HttpMethod http_method{HttpMethod::OTHER}; + if (std::strcmp(invoke_http.method.c_str(), GET_METHOD) == 0) { + http_method = HttpMethod::GET; + } else if (std::strcmp(invoke_http.method.c_str(), POST_METHOD) == 0) { + http_method = HttpMethod::POST; + } else if (std::strcmp(invoke_http.method.c_str(), HEAD_METHOD) == 0) { + http_method = HttpMethod::HEAD; + } + + using namespace PhpServerSuperGlobalIndices; + if (http_method == HttpMethod::GET) { + server.set_value(string{ARGC, std::char_traits::length(ARGC)}, static_cast(1)); + server.set_value(string{ARGV, std::char_traits::length(ARGV)}, invoke_http.uri.opt_query.value_or(string{})); + } + server.set_value(string{PHP_SELF, std::char_traits::length(PHP_SELF)}, invoke_http.uri.path); + server.set_value(string{SCRIPT_NAME, std::char_traits::length(SCRIPT_NAME)}, invoke_http.uri.path); + server.set_value(string{SCRIPT_URL, std::char_traits::length(SCRIPT_URL)}, invoke_http.uri.path); + + server.set_value(string{SERVER_ADDR, std::char_traits::length(SERVER_ADDR)}, invoke_http.connection.server_addr); + server.set_value(string{SERVER_PORT, std::char_traits::length(SERVER_PORT)}, static_cast(invoke_http.connection.server_port)); + server.set_value(string{SERVER_PROTOCOL, std::char_traits::length(SERVER_PROTOCOL)}, + get_server_protocol(invoke_http.version, invoke_http.uri.opt_scheme)); + server.set_value(string{REMOTE_ADDR, std::char_traits::length(REMOTE_ADDR)}, invoke_http.connection.remote_addr); + server.set_value(string{REMOTE_PORT, std::char_traits::length(REMOTE_PORT)}, static_cast(invoke_http.connection.remote_port)); + + server.set_value(string{REQUEST_METHOD, std::char_traits::length(REQUEST_METHOD)}, invoke_http.method); + server.set_value(string{GATEWAY_INTERFACE, std::char_traits::length(GATEWAY_INTERFACE)}, + string{GATEWAY_INTERFACE_VALUE, std::char_traits::length(GATEWAY_INTERFACE_VALUE)}); + + if (invoke_http.uri.opt_scheme.has_value() && std::strcmp((*invoke_http.uri.opt_scheme).c_str(), HTTPS_SCHEME) == 0) { + server.set_value(string{HTTPS, std::char_traits::length(HTTPS)}, true); + } + + if (invoke_http.uri.opt_query.has_value()) { + // TODO v_GET + php_warning("v_GET not implemented"); + server.set_value(string{QUERY_STRING, std::char_traits::length(QUERY_STRING)}, *invoke_http.uri.opt_query); + + string uri_string{}; + uri_string.reserve_at_least((invoke_http.uri.path.size()) + (*invoke_http.uri.opt_query).size() + 1); // +1 for '?' + uri_string.append(invoke_http.uri.path); + uri_string.append(1, '?'); + uri_string.append(*invoke_http.uri.opt_query); + server.set_value(string{REQUEST_URI, std::char_traits::length(REQUEST_URI)}, uri_string); + } else { + server.set_value(string{REQUEST_URI, std::char_traits::length(REQUEST_URI)}, invoke_http.uri.path); + } + + process_headers(std::move(invoke_http.headers), superglobals); + // TODO connection_kind, CONTENT_TYPE, is_head_query, _REQUEST, v_POST + php_warning("conncetion kind, content type, post and head methods, _REQUEST superglobal are not supported yet"); + + string real_scheme_header{HTTP_X_REAL_SCHEME, std::char_traits::length(HTTP_X_REAL_SCHEME)}; + string real_host_header{HTTP_X_REAL_HOST, std::char_traits::length(HTTP_X_REAL_HOST)}; + string real_request_header{HTTP_X_REAL_REQUEST, std::char_traits::length(HTTP_X_REAL_REQUEST)}; + if (server.isset(real_scheme_header) && server.isset(real_host_header) && server.isset(real_request_header)) { + string real_scheme{server.get_value(real_request_header).to_string()}; + string real_host{server.get_value(real_host_header).to_string()}; + string real_request{server.get_value(real_request_header).to_string()}; + + string script_uri{}; + script_uri.reserve_at_least(real_scheme.size() + std::char_traits::length(SCHEME_SUFFIX) + real_host.size() + real_request.size()); + script_uri.append(real_scheme); + script_uri.append(SCHEME_SUFFIX, std::char_traits::length(SCHEME_SUFFIX)); + script_uri.append(real_host); + script_uri.append(real_request); + server.set_value(string{SCRIPT_URI, std::char_traits::length(SCRIPT_URI)}, script_uri); + } +} diff --git a/runtime-light/server/http/init-functions.h b/runtime-light/server/http/init-functions.h new file mode 100644 index 0000000000..cf73a1f04c --- /dev/null +++ b/runtime-light/server/http/init-functions.h @@ -0,0 +1,9 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include "runtime-light/tl/tl-functions.h" + +void init_http_server(tl::K2InvokeHttp &&invoke_http) noexcept; diff --git a/runtime-light/server/init-functions.h b/runtime-light/server/init-functions.h new file mode 100644 index 0000000000..afc88d61d5 --- /dev/null +++ b/runtime-light/server/init-functions.h @@ -0,0 +1,47 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include +#include +#include +#include + +#include "runtime-light/component/component.h" +#include "runtime-light/server/http/init-functions.h" +#include "runtime-light/server/job-worker/init-functions.h" +#include "runtime-light/tl/tl-functions.h" +#include "runtime-light/utils/context.h" + +using ServerQuery = std::variant; + +inline void init_server(ServerQuery &&query) noexcept { + static constexpr auto *SERVER_SOFTWARE_VALUE = "K2/KPHP"; + static constexpr auto *SERVER_SIGNATURE_VALUE = "K2/KPHP Server v0.0.0"; + + // common initialization + { + using namespace PhpServerSuperGlobalIndices; + auto &server{get_component_context()->php_script_mutable_globals_singleton.get_superglobals().v$_SERVER}; + server.set_value(string{SERVER_SOFTWARE, std::char_traits::length(SERVER_SOFTWARE)}, + string{SERVER_SOFTWARE_VALUE, std::char_traits::length(SERVER_SOFTWARE_VALUE)}); + server.set_value(string{SERVER_SIGNATURE, std::char_traits::length(SERVER_SIGNATURE)}, + string{SERVER_SIGNATURE_VALUE, std::char_traits::length(SERVER_SIGNATURE_VALUE)}); + } + // specific initialization + std::visit( + [](auto &&query) noexcept { + using query_t = std::remove_cvref_t; + + if constexpr (std::same_as) { + init_http_server(std::forward(query)); + } else if constexpr (std::same_as) { + init_job_server(std::forward(query)); + } else { + static_assert(false, "non-exhaustive visitor!"); + } + }, + std::move(query)); +} diff --git a/runtime-light/server/job-worker/init-functions.h b/runtime-light/server/job-worker/init-functions.h new file mode 100644 index 0000000000..3f97141640 --- /dev/null +++ b/runtime-light/server/job-worker/init-functions.h @@ -0,0 +1,25 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include "runtime-light/component/component.h" +#include "runtime-light/core/globals/php-script-globals.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" +#include "runtime-light/tl/tl-functions.h" +#include "runtime-light/utils/context.h" + +inline void init_job_server(tl::K2InvokeJobWorker &&invoke_jw) noexcept { + auto &jw_server_ctx{JobWorkerServerComponentContext::get()}; + jw_server_ctx.kind = invoke_jw.ignore_answer ? JobWorkerServerComponentContext::Kind::NoReply : JobWorkerServerComponentContext::Kind::Regular; + jw_server_ctx.state = JobWorkerServerComponentContext::State::Working; + jw_server_ctx.job_id = invoke_jw.job_id; + jw_server_ctx.body = std::move(invoke_jw.body); + + { + using namespace PhpServerSuperGlobalIndices; + auto &server{get_component_context()->php_script_mutable_globals_singleton.get_superglobals().v$_SERVER}; + server.set_value(string{JOB_ID, std::char_traits::length(JOB_ID)}, invoke_jw.job_id); + } +} diff --git a/runtime-light/stdlib/job-worker/job-worker-context.cpp b/runtime-light/server/job-worker/job-worker-server-context.cpp similarity index 63% rename from runtime-light/stdlib/job-worker/job-worker-context.cpp rename to runtime-light/server/job-worker/job-worker-server-context.cpp index 35b3db42d6..8f18c8712f 100644 --- a/runtime-light/stdlib/job-worker/job-worker-context.cpp +++ b/runtime-light/server/job-worker/job-worker-server-context.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2024 LLC «V Kontakte» // Distributed under the GPL v3 License, see LICENSE.notice.txt -#include "runtime-light/stdlib/job-worker/job-worker-context.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" #include "runtime-light/component/component.h" #include "runtime-light/utils/context.h" @@ -10,7 +10,3 @@ JobWorkerServerComponentContext &JobWorkerServerComponentContext::get() noexcept { return get_component_context()->job_worker_server_component_context; } - -JobWorkerClientComponentContext &JobWorkerClientComponentContext::get() noexcept { - return get_component_context()->job_worker_client_component_context; -} diff --git a/runtime-light/stdlib/job-worker/job-worker-context.h b/runtime-light/server/job-worker/job-worker-server-context.h similarity index 77% rename from runtime-light/stdlib/job-worker/job-worker-context.h rename to runtime-light/server/job-worker/job-worker-server-context.h index f0f27aa79c..fcb87f5763 100644 --- a/runtime-light/stdlib/job-worker/job-worker-context.h +++ b/runtime-light/server/job-worker/job-worker-server-context.h @@ -21,9 +21,3 @@ struct JobWorkerServerComponentContext final : private vk::not_copyable { static JobWorkerServerComponentContext &get() noexcept; }; - -struct JobWorkerClientComponentContext final : private vk::not_copyable { - int64_t current_job_id{JOB_WORKER_VALID_JOB_ID_RANGE_START}; - - static JobWorkerClientComponentContext &get() noexcept; -}; diff --git a/runtime-light/server/server.cmake b/runtime-light/server/server.cmake new file mode 100644 index 0000000000..5e43e0780f --- /dev/null +++ b/runtime-light/server/server.cmake @@ -0,0 +1,2 @@ +prepend(RUNTIME_SERVER_SRC server/ http/init-functions.cpp + http/http-server-context.cpp job-worker/job-worker-server-context.cpp) diff --git a/runtime-light/stdlib/job-worker/job-worker-api.cpp b/runtime-light/stdlib/job-worker/job-worker-api.cpp index 08639fdd5f..7edb18affa 100644 --- a/runtime-light/stdlib/job-worker/job-worker-api.cpp +++ b/runtime-light/stdlib/job-worker/job-worker-api.cpp @@ -16,9 +16,10 @@ #include "runtime-light/coroutine/awaitable.h" #include "runtime-light/coroutine/task.h" #include "runtime-light/header.h" +#include "runtime-light/server/job-worker/job-worker-server-context.h" #include "runtime-light/stdlib/component/component-api.h" #include "runtime-light/stdlib/fork/fork-context.h" -#include "runtime-light/stdlib/job-worker/job-worker-context.h" +#include "runtime-light/stdlib/job-worker/job-worker-client-context.h" #include "runtime-light/stdlib/job-worker/job-worker.h" #include "runtime-light/streams/streams.h" #include "runtime-light/tl/tl-core.h" diff --git a/runtime-light/stdlib/job-worker/job-worker-client-context.cpp b/runtime-light/stdlib/job-worker/job-worker-client-context.cpp new file mode 100644 index 0000000000..b06ee7735d --- /dev/null +++ b/runtime-light/stdlib/job-worker/job-worker-client-context.cpp @@ -0,0 +1,12 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#include "runtime-light/stdlib/job-worker/job-worker-client-context.h" + +#include "runtime-light/component/component.h" +#include "runtime-light/utils/context.h" + +JobWorkerClientComponentContext &JobWorkerClientComponentContext::get() noexcept { + return get_component_context()->job_worker_client_component_context; +} diff --git a/runtime-light/stdlib/job-worker/job-worker-client-context.h b/runtime-light/stdlib/job-worker/job-worker-client-context.h new file mode 100644 index 0000000000..394f797685 --- /dev/null +++ b/runtime-light/stdlib/job-worker/job-worker-client-context.h @@ -0,0 +1,16 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2024 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include + +#include "common/mixin/not_copyable.h" +#include "runtime-light/stdlib/job-worker/job-worker.h" + +struct JobWorkerClientComponentContext final : private vk::not_copyable { + int64_t current_job_id{JOB_WORKER_VALID_JOB_ID_RANGE_START}; + + static JobWorkerClientComponentContext &get() noexcept; +}; diff --git a/runtime-light/stdlib/stdlib.cmake b/runtime-light/stdlib/stdlib.cmake index aec14c620b..6a3c0d366e 100644 --- a/runtime-light/stdlib/stdlib.cmake +++ b/runtime-light/stdlib/stdlib.cmake @@ -9,7 +9,7 @@ prepend( fork/fork-context.cpp hash/hash-functions.cpp job-worker/job-worker-api.cpp - job-worker/job-worker-context.cpp + job-worker/job-worker-client-context.cpp output/output-buffer.cpp output/print-functions.cpp regex/regex-context.cpp