MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Lila.cpp
Go to the documentation of this file.
1#include "Lila.hpp"
2
4#include "Server.hpp"
5
6#include "Commentator.hpp"
7
8#ifdef MAYAFLUX_PLATFORM_MACOS
9#include <CoreFoundation/CoreFoundation.h>
10#endif
11
12#ifdef MAYAFLUX_PLATFORM_WINDOWS
14#endif
15
16namespace Lila {
17
19 : m_interpreter(std::make_unique<ClangInterpreter>())
20 , m_current_mode(OperationMode::Direct)
21 , server_loop_rate(0.1F)
22{
23 LILA_DEBUG(Emitter::SYSTEM, "Lila instance created");
24}
25
27{
28 stop_server();
29 LILA_DEBUG(Emitter::SYSTEM, "Lila instance destroyed");
30}
31
32bool Lila::initialize(OperationMode mode, int server_port) noexcept
33{
34 LILA_INFO(Emitter::SYSTEM, "Initializing Lila");
35 m_current_mode = mode;
36
37 if (!initialize_interpreter()) {
38 LILA_ERROR(Emitter::SYSTEM, "Failed to initialize interpreter");
39 return false;
40 }
41
42 if (mode == OperationMode::Server || mode == OperationMode::Both) {
43 if (!initialize_server(server_port)) {
44 LILA_ERROR(Emitter::SYSTEM, "Failed to initialize server");
45 return false;
46 }
47 }
48
49 LILA_INFO(Emitter::SYSTEM, "Lila initialized successfully");
50 return true;
51}
52
54{
55 LILA_DEBUG(Emitter::SYSTEM, "Initializing interpreter subsystem");
56 return m_interpreter->initialize();
57}
58
60{
61 if (m_server && m_server->is_running()) {
62 LILA_WARN(Emitter::SYSTEM, "Stopping existing server before starting new one");
63 stop_server();
64 }
65
66 LILA_DEBUG(Emitter::SYSTEM,
67 std::string("Initializing server on port ") + std::to_string(port));
68
69 m_server = std::make_unique<Server>(port);
70
71 m_server->set_message_handler([this](std::string_view message) {
72 return this->handle_server_message(message);
73 });
74
75 return m_server->start();
76}
77
78std::expected<std::string, std::string> Lila::handle_server_message(std::string_view message)
79{
80 if (message.empty()) {
81 return R"({"status":"error","message":"Empty message"})";
82 }
83
84 auto result = m_interpreter->eval(std::string(message));
85
86 if (result.success) {
87 if (m_success_callback) {
88 m_success_callback();
89 }
90 return "";
91 }
92
93 if (m_error_callback) {
94 m_error_callback(result.error);
95 }
96
97 return std::unexpected(escape_json(result.error));
98}
99
100bool Lila::eval(const std::string& code)
101{
102 if (!m_interpreter) {
103 LILA_ERROR(Emitter::SYSTEM, "Cannot eval: interpreter not initialized");
104 return false;
105 }
106
107 auto result = m_interpreter->eval(code);
108
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);
113 }
114
115 return result.success;
116}
117
118bool Lila::eval_file(const std::string& filepath)
119{
120 if (!m_interpreter) {
121 LILA_ERROR(Emitter::SYSTEM, "Cannot eval file: interpreter not initialized");
122 return false;
123 }
124
125 auto result = m_interpreter->eval_file(filepath);
126 return result.success;
127}
128
129void Lila::start_server(int port)
130{
131 LILA_INFO(Emitter::SYSTEM,
132 std::string("Starting server on port ") + std::to_string(port));
133
134 initialize_server(port);
135}
136
138{
139 if (m_server) {
140 LILA_INFO(Emitter::SYSTEM, "Stopping server");
141 m_server->stop();
142 m_server.reset();
143 }
144}
145
147{
148 return m_server && m_server->is_running();
149}
150
151void* Lila::get_symbol_address(const std::string& name)
152{
153 return m_interpreter ? m_interpreter->get_symbol_address(name) : nullptr;
154}
155
156std::vector<std::string> Lila::get_defined_symbols()
157{
158 return m_interpreter ? m_interpreter->get_defined_symbols() : std::vector<std::string> {};
159}
160
161void Lila::add_include_path(const std::string& path)
162{
163 if (m_interpreter) {
164 m_interpreter->add_include_path(path);
165 }
166}
167
168void Lila::add_compile_flag(const std::string& flag)
169{
170 if (m_interpreter) {
171 m_interpreter->add_compile_flag(flag);
172 }
173}
174
175void Lila::on_success(std::function<void()> callback)
176{
177 m_success_callback = std::move(callback);
178 LILA_DEBUG(Emitter::SYSTEM, "Success callback registered");
179}
180
181void Lila::on_error(std::function<void(const std::string&)> callback)
182{
183 m_error_callback = std::move(callback);
184 LILA_DEBUG(Emitter::SYSTEM, "Error callback registered");
185}
186
187void Lila::on_server_started(std::function<void()> callback)
188{
189 if (m_server) {
190 m_server->on_server_started(std::move(callback));
191 LILA_DEBUG(Emitter::SYSTEM, "Server started callback registered");
192 }
193}
194
195void Lila::on_server_client_connected(std::function<void(const ClientInfo&)> callback)
196{
197 if (m_server) {
198 m_server->on_client_connected(std::move(callback));
199 LILA_DEBUG(Emitter::SYSTEM, "Client connected callback registered");
200 }
201}
202
203void Lila::on_server_client_disconnected(std::function<void(const ClientInfo&)> callback)
204{
205 if (m_server) {
206 m_server->on_client_disconnected(std::move(callback));
207 LILA_DEBUG(Emitter::SYSTEM, "Client disconnected callback registered");
208 }
209}
210
211std::string Lila::get_last_error() const
212{
213 return m_interpreter ? m_interpreter->get_last_error() : "Interpreter not initialized";
214}
215
216OperationMode Lila::get_current_mode() const
217{
218 return m_current_mode;
219}
220
221void Lila::await_shutdown(const std::atomic<bool>* external_flag)
222{
223 LILA_INFO(Emitter::SYSTEM, "Entering main event loop");
224
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");
229 break;
230 }
231 CFRunLoopRunInMode(kCFRunLoopDefaultMode, server_loop_rate, false);
232 }
233
234#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
235 if (MayaFlux::Parallel::g_MainThreadId == 0) {
236 MayaFlux::Parallel::g_MainThreadId = GetCurrentThreadId();
237 }
238
239 MSG msg;
240 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
241
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");
246 break;
247 }
248
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);
252 break;
253 }
254
255 if (msg.message == MAYAFLUX_WM_DISPATCH) {
256 auto* task = reinterpret_cast<std::function<void()>*>(msg.lParam);
257 if (task) {
258 (*task)();
259 delete task;
260 }
261 } else {
262 TranslateMessage(&msg);
263 DispatchMessage(&msg);
264 }
265 }
266
267 std::this_thread::sleep_for(
268 std::chrono::milliseconds(static_cast<int>(server_loop_rate * 1000.0F)));
269 }
270
271#else
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");
275 break;
276 }
277 std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(server_loop_rate * 1000)));
278 }
279#endif
280
281 LILA_INFO(Emitter::SYSTEM, "Exiting main event loop");
282}
283
285{
286 m_shutdown_requested.store(true, std::memory_order_release);
287
288#ifdef MAYAFLUX_PLATFORM_MACOS
289 CFRunLoopStop(CFRunLoopGetMain());
290#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
291 PostThreadMessage(MayaFlux::Parallel::g_MainThreadId, WM_QUIT, 0, 0);
292#endif
293}
294
295std::string Lila::escape_json(const std::string& str)
296{
297 std::string escaped;
298 escaped.reserve(str.size());
299
300 for (char c : str) {
301 switch (c) {
302 case '"':
303 escaped += "\\\"";
304 break;
305 case '\\':
306 escaped += "\\\\";
307 break;
308 case '\n':
309 escaped += "\\n";
310 break;
311 case '\r':
312 escaped += "\\r";
313 break;
314 case '\t':
315 escaped += "\\t";
316 break;
317 default:
318 if (c >= 0x20) {
319 escaped += c;
320 }
321 }
322 }
323 return escaped;
324}
325
326} // namespace Lila
#define LILA_WARN(emitter, msg)
#define LILA_ERROR(emitter, msg)
#define LILA_DEBUG(emitter, msg)
#define LILA_INFO(emitter, msg)
Embedded Clang interpreter for live code evaluation in MayaFlux.
std::vector< std::string > get_defined_symbols()
Gets a list of all defined symbols.
Definition Lila.cpp:156
static std::string escape_json(const std::string &str)
Escapes a string for safe JSON encoding.
Definition Lila.cpp:295
bool eval(const std::string &code)
Evaluates a C++ code snippet directly.
Definition Lila.cpp:100
void on_error(std::function< void(const std::string &)> callback)
Registers a callback for code evaluation errors.
Definition Lila.cpp:181
std::expected< std::string, std::string > handle_server_message(std::string_view message)
Definition Lila.cpp:78
void stop_server()
Stops the TCP server and disconnects all clients.
Definition Lila.cpp:137
OperationMode get_current_mode() const
Gets the current operation mode.
Definition Lila.cpp:216
void * get_symbol_address(const std::string &name)
Gets the address of a symbol defined in the interpreter.
Definition Lila.cpp:151
bool initialize_interpreter()
Definition Lila.cpp:53
void on_server_client_disconnected(std::function< void(const ClientInfo &)> callback)
Registers a callback for client disconnections (server mode)
Definition Lila.cpp:203
bool initialize_server(int port)
Definition Lila.cpp:59
bool initialize(OperationMode mode=OperationMode::Direct, int server_port=9090) noexcept
Initializes the live coding environment.
Definition Lila.cpp:32
void request_shutdown()
Request shutdown from any thread.
Definition Lila.cpp:284
void on_server_client_connected(std::function< void(const ClientInfo &)> callback)
Registers a callback for new client connections (server mode)
Definition Lila.cpp:195
void add_compile_flag(const std::string &flag)
Adds a compile flag for code evaluation.
Definition Lila.cpp:168
void add_include_path(const std::string &path)
Adds an include path for code evaluation.
Definition Lila.cpp:161
~Lila()
Destructor; cleans up interpreter and server resources.
Definition Lila.cpp:26
void start_server(int port=9090)
Starts the TCP server for remote live coding.
Definition Lila.cpp:129
bool eval_file(const std::string &filepath)
Evaluates a C++ code file directly.
Definition Lila.cpp:118
std::string get_last_error() const
Gets the last error message.
Definition Lila.cpp:211
bool is_server_running() const
Checks if the server is currently running.
Definition Lila.cpp:146
void await_shutdown(const std::atomic< bool > *external_flag)
Blocks until server shutdown (main thread event loop)
Definition Lila.cpp:221
Lila()
Constructs a Lila instance.
Definition Lila.cpp:18
void on_success(std::function< void()> callback)
Registers a callback for successful code evaluation.
Definition Lila.cpp:175
void on_server_started(std::function< void()> callback)
Registers a callback for server start events.
Definition Lila.cpp:187
Information about a connected client.
Definition EventBus.hpp:58