8#ifdef MAYAFLUX_PLATFORM_MACOS
9#include <CoreFoundation/CoreFoundation.h>
12#ifdef MAYAFLUX_PLATFORM_WINDOWS
20 , m_current_mode(OperationMode::Direct)
21 , server_loop_rate(0.1F)
23 LILA_DEBUG(Emitter::SYSTEM,
"Lila instance created");
29 LILA_DEBUG(Emitter::SYSTEM,
"Lila instance destroyed");
34 LILA_INFO(Emitter::SYSTEM,
"Initializing Lila");
35 m_current_mode = mode;
37 if (!initialize_interpreter()) {
38 LILA_ERROR(Emitter::SYSTEM,
"Failed to initialize interpreter");
42 if (mode == OperationMode::Server || mode == OperationMode::Both) {
43 if (!initialize_server(server_port)) {
44 LILA_ERROR(Emitter::SYSTEM,
"Failed to initialize server");
49 LILA_INFO(Emitter::SYSTEM,
"Lila initialized successfully");
55 LILA_DEBUG(Emitter::SYSTEM,
"Initializing interpreter subsystem");
56 return m_interpreter->initialize();
61 if (m_server && m_server->is_running()) {
62 LILA_WARN(Emitter::SYSTEM,
"Stopping existing server before starting new one");
67 std::string(
"Initializing server on port ") + std::to_string(port));
69 m_server = std::make_unique<Server>(port);
71 m_server->set_message_handler([
this](std::string_view message) {
72 return this->handle_server_message(message);
75 return m_server->start();
80 if (message.empty()) {
81 return R
"({"status":"error","message":"Empty message"})";
84 auto result = m_interpreter->eval(std::string(message));
87 if (m_success_callback) {
93 if (m_error_callback) {
94 m_error_callback(result.error);
97 return std::unexpected(escape_json(result.error));
102 if (!m_interpreter) {
103 LILA_ERROR(Emitter::SYSTEM,
"Cannot eval: interpreter not initialized");
107 auto result = m_interpreter->eval(code);
109 if (result.success && m_success_callback) {
110 m_success_callback();
111 }
else if (!result.success && m_error_callback) {
112 m_error_callback(result.error);
115 return result.success;
120 if (!m_interpreter) {
121 LILA_ERROR(Emitter::SYSTEM,
"Cannot eval file: interpreter not initialized");
125 auto result = m_interpreter->eval_file(filepath);
126 return result.success;
132 std::string(
"Starting server on port ") + std::to_string(port));
134 initialize_server(port);
140 LILA_INFO(Emitter::SYSTEM,
"Stopping server");
148 return m_server && m_server->is_running();
153 return m_interpreter ? m_interpreter->get_symbol_address(name) :
nullptr;
158 return m_interpreter ? m_interpreter->get_defined_symbols() : std::vector<std::string> {};
164 m_interpreter->add_include_path(path);
171 m_interpreter->add_compile_flag(flag);
177 m_success_callback = std::move(callback);
178 LILA_DEBUG(Emitter::SYSTEM,
"Success callback registered");
183 m_error_callback = std::move(callback);
184 LILA_DEBUG(Emitter::SYSTEM,
"Error callback registered");
190 m_server->on_server_started(std::move(callback));
191 LILA_DEBUG(Emitter::SYSTEM,
"Server started callback registered");
198 m_server->on_client_connected(std::move(callback));
199 LILA_DEBUG(Emitter::SYSTEM,
"Client connected callback registered");
206 m_server->on_client_disconnected(std::move(callback));
207 LILA_DEBUG(Emitter::SYSTEM,
"Client disconnected callback registered");
213 return m_interpreter ? m_interpreter->get_last_error() :
"Interpreter not initialized";
218 return m_current_mode;
223 LILA_INFO(Emitter::SYSTEM,
"Entering main event loop");
225#ifdef MAYAFLUX_PLATFORM_MACOS
226 while (!m_shutdown_requested.load(std::memory_order_acquire) && (!external_flag || external_flag->load(std::memory_order_acquire))) {
227 if (!is_server_running()) {
228 LILA_ERROR(Emitter::SYSTEM,
"Server stopped unexpectedly");
231 CFRunLoopRunInMode(kCFRunLoopDefaultMode, server_loop_rate,
false);
234#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
235 if (MayaFlux::Parallel::g_MainThreadId == 0) {
236 MayaFlux::Parallel::g_MainThreadId = GetCurrentThreadId();
240 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
242 while (!m_shutdown_requested.load(std::memory_order_acquire)
243 && (!external_flag || external_flag->load(std::memory_order_acquire))) {
244 if (!is_server_running()) {
245 LILA_ERROR(Emitter::SYSTEM,
"Server stopped unexpectedly");
249 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
250 if (msg.message == WM_QUIT) {
251 m_shutdown_requested.store(
true, std::memory_order_release);
255 if (msg.message == MAYAFLUX_WM_DISPATCH) {
256 auto* task =
reinterpret_cast<std::function<
void()
>*>(msg.lParam);
262 TranslateMessage(&msg);
263 DispatchMessage(&msg);
267 std::this_thread::sleep_for(
268 std::chrono::milliseconds(
static_cast<int>(server_loop_rate * 1000.0F)));
272 while (!m_shutdown_requested.load(std::memory_order_acquire) && (!external_flag || external_flag->load(std::memory_order_acquire))) {
273 if (!is_server_running()) {
274 LILA_ERROR(Emitter::SYSTEM,
"Server stopped unexpectedly");
277 std::this_thread::sleep_for(std::chrono::milliseconds(
static_cast<int>(server_loop_rate * 1000)));
281 LILA_INFO(Emitter::SYSTEM,
"Exiting main event loop");
286 m_shutdown_requested.store(
true, std::memory_order_release);
288#ifdef MAYAFLUX_PLATFORM_MACOS
289 CFRunLoopStop(CFRunLoopGetMain());
290#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
291 PostThreadMessage(MayaFlux::Parallel::g_MainThreadId, WM_QUIT, 0, 0);
298 escaped.reserve(str.size());
Embedded Clang interpreter for live code evaluation in MayaFlux.
std::vector< std::string > get_defined_symbols()
Gets a list of all defined symbols.
static std::string escape_json(const std::string &str)
Escapes a string for safe JSON encoding.
bool eval(const std::string &code)
Evaluates a C++ code snippet directly.
void on_error(std::function< void(const std::string &)> callback)
Registers a callback for code evaluation errors.
std::expected< std::string, std::string > handle_server_message(std::string_view message)
void stop_server()
Stops the TCP server and disconnects all clients.
OperationMode get_current_mode() const
Gets the current operation mode.
void * get_symbol_address(const std::string &name)
Gets the address of a symbol defined in the interpreter.
bool initialize_interpreter()
void on_server_client_disconnected(std::function< void(const ClientInfo &)> callback)
Registers a callback for client disconnections (server mode)
bool initialize_server(int port)
bool initialize(OperationMode mode=OperationMode::Direct, int server_port=9090) noexcept
Initializes the live coding environment.
void request_shutdown()
Request shutdown from any thread.
void on_server_client_connected(std::function< void(const ClientInfo &)> callback)
Registers a callback for new client connections (server mode)
void add_compile_flag(const std::string &flag)
Adds a compile flag for code evaluation.
void add_include_path(const std::string &path)
Adds an include path for code evaluation.
~Lila()
Destructor; cleans up interpreter and server resources.
void start_server(int port=9090)
Starts the TCP server for remote live coding.
bool eval_file(const std::string &filepath)
Evaluates a C++ code file directly.
std::string get_last_error() const
Gets the last error message.
bool is_server_running() const
Checks if the server is currently running.
void await_shutdown(const std::atomic< bool > *external_flag)
Blocks until server shutdown (main thread event loop)
Lila()
Constructs a Lila instance.
void on_success(std::function< void()> callback)
Registers a callback for successful code evaluation.
void on_server_started(std::function< void()> callback)
Registers a callback for server start events.
Information about a connected client.