MayaFlux 0.4.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, bool skip_host_library_load) noexcept
33{
34 LILA_INFO(Emitter::SYSTEM, "Initializing Lila");
35 m_current_mode = mode;
36
37 if (!initialize_interpreter(skip_host_library_load)) {
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
53bool Lila::initialize_interpreter(bool skip_host_library_load)
54{
55 LILA_DEBUG(Emitter::SYSTEM, "Initializing interpreter subsystem");
56 return m_interpreter->initialize(skip_host_library_load);
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::load_library(const std::string& path)
176{
177 if (m_interpreter) {
178 m_interpreter->load_library(path);
179 }
180}
181
182void Lila::on_success(std::function<void()> callback)
183{
184 m_success_callback = std::move(callback);
185 LILA_DEBUG(Emitter::SYSTEM, "Success callback registered");
186}
187
188void Lila::on_error(std::function<void(const std::string&)> callback)
189{
190 m_error_callback = std::move(callback);
191 LILA_DEBUG(Emitter::SYSTEM, "Error callback registered");
192}
193
194void Lila::on_server_started(std::function<void()> callback)
195{
196 if (m_server) {
197 m_server->on_server_started(std::move(callback));
198 LILA_DEBUG(Emitter::SYSTEM, "Server started callback registered");
199 }
200}
201
202void Lila::on_server_client_connected(std::function<void(const ClientInfo&)> callback)
203{
204 if (m_server) {
205 m_server->on_client_connected(std::move(callback));
206 LILA_DEBUG(Emitter::SYSTEM, "Client connected callback registered");
207 }
208}
209
210void Lila::on_server_client_disconnected(std::function<void(const ClientInfo&)> callback)
211{
212 if (m_server) {
213 m_server->on_client_disconnected(std::move(callback));
214 LILA_DEBUG(Emitter::SYSTEM, "Client disconnected callback registered");
215 }
216}
217
218std::string Lila::get_last_error() const
219{
220 return m_interpreter ? m_interpreter->get_last_error() : "Interpreter not initialized";
221}
222
223OperationMode Lila::get_current_mode() const
224{
225 return m_current_mode;
226}
227
228void Lila::await_shutdown(const std::atomic<bool>* external_flag)
229{
230 LILA_INFO(Emitter::SYSTEM, "Entering main event loop");
231
232#ifdef MAYAFLUX_PLATFORM_MACOS
233 while (!m_shutdown_requested.load(std::memory_order_acquire) && (!external_flag || external_flag->load(std::memory_order_acquire))) {
234 if (!is_server_running()) {
235 LILA_ERROR(Emitter::SYSTEM, "Server stopped unexpectedly");
236 break;
237 }
238 CFRunLoopRunInMode(kCFRunLoopDefaultMode, server_loop_rate, false);
239 }
240
241#else
242 while (!m_shutdown_requested.load(std::memory_order_acquire) && (!external_flag || external_flag->load(std::memory_order_acquire))) {
243 if (!is_server_running()) {
244 LILA_ERROR(Emitter::SYSTEM, "Server stopped unexpectedly");
245 break;
246 }
247 std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(server_loop_rate * 1000)));
248 }
249#endif
250
251 LILA_INFO(Emitter::SYSTEM, "Exiting main event loop");
252}
253
255{
256 m_shutdown_requested.store(true, std::memory_order_release);
257
258#ifdef MAYAFLUX_PLATFORM_MACOS
259 CFRunLoopStop(CFRunLoopGetMain());
260#endif
261}
262
263std::string Lila::escape_json(const std::string& str)
264{
265 std::string escaped;
266 escaped.reserve(str.size());
267
268 for (char c : str) {
269 switch (c) {
270 case '"':
271 escaped += "\\\"";
272 break;
273 case '\\':
274 escaped += "\\\\";
275 break;
276 case '\n':
277 escaped += "\\n";
278 break;
279 case '\r':
280 escaped += "\\r";
281 break;
282 case '\t':
283 escaped += "\\t";
284 break;
285 default:
286 if (c >= 0x20) {
287 escaped += c;
288 }
289 }
290 }
291 return escaped;
292}
293
294} // 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:263
bool initialize(OperationMode mode=OperationMode::Direct, int server_port=9090, bool skip_host_library_load=false) noexcept
Initializes the live coding environment.
Definition Lila.cpp:32
bool initialize_interpreter(bool skip_host_library_load)
Definition Lila.cpp:53
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:188
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:223
void * get_symbol_address(const std::string &name)
Gets the address of a symbol defined in the interpreter.
Definition Lila.cpp:151
void load_library(const std::string &path)
Load a shared library into the JIT symbol table.
Definition Lila.cpp:175
void on_server_client_disconnected(std::function< void(const ClientInfo &)> callback)
Registers a callback for client disconnections (server mode)
Definition Lila.cpp:210
bool initialize_server(int port)
Definition Lila.cpp:59
void request_shutdown()
Request shutdown from any thread.
Definition Lila.cpp:254
void on_server_client_connected(std::function< void(const ClientInfo &)> callback)
Registers a callback for new client connections (server mode)
Definition Lila.cpp:202
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:218
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:228
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:182
void on_server_started(std::function< void()> callback)
Registers a callback for server start events.
Definition Lila.cpp:194
Information about a connected client.
Definition EventBus.hpp:58