|
|
@@ -32,24 +32,26 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|
|
#include "Device.h"
|
|
|
#include "ProxyAllocator.h"
|
|
|
#include "LuaEnvironment.h"
|
|
|
+#include "File.h"
|
|
|
+#include "Filesystem.h"
|
|
|
+#include "MathUtils.h"
|
|
|
|
|
|
namespace crown
|
|
|
{
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-ConsoleServer::ConsoleServer()
|
|
|
- : m_num_clients(0)
|
|
|
+ConsoleServer::ConsoleServer(uint16_t port)
|
|
|
+ : m_port(port)
|
|
|
+ , m_num_clients(0)
|
|
|
, m_receive_buffer(default_allocator())
|
|
|
- , m_send_buffer(default_allocator())
|
|
|
, m_receive_callbacks(default_allocator())
|
|
|
- , m_send_callbacks(default_allocator())
|
|
|
{
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
void ConsoleServer::init(bool wait)
|
|
|
{
|
|
|
- m_listener.open(10001);
|
|
|
+ m_listener.open(m_port);
|
|
|
|
|
|
if (wait)
|
|
|
{
|
|
|
@@ -98,14 +100,9 @@ void ConsoleServer::log_to_all(const char* message, LogSeverity::Enum severity)
|
|
|
//-----------------------------------------------------------------------------
|
|
|
void ConsoleServer::send_message_to(ClientId client, const char* message)
|
|
|
{
|
|
|
- RPCCallback cb;
|
|
|
- cb.client = client;
|
|
|
- cb.message_index = m_send_buffer.size();
|
|
|
-
|
|
|
- m_send_buffer.push(message, string::strlen(message));
|
|
|
- m_send_buffer.push_back('\0');
|
|
|
-
|
|
|
- m_send_callbacks.push_back(cb);
|
|
|
+ uint32_t msg_len = string::strlen(message);
|
|
|
+ m_clients[client.index].write((const char*) &msg_len, 4);
|
|
|
+ m_clients[client.index].write(message, msg_len);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -141,6 +138,9 @@ void ConsoleServer::update()
|
|
|
update_client(id);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // Process all requests
|
|
|
+ process_requests();
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -154,72 +154,43 @@ void ConsoleServer::process_requests()
|
|
|
const char* request = &m_receive_buffer[cb.message_index];
|
|
|
JSONParser parser(request);
|
|
|
JSONElement request_type = parser.root().key("type");
|
|
|
- const char* type = request_type.string_value();
|
|
|
+ DynamicString type;
|
|
|
+ request_type.string_value(type);
|
|
|
|
|
|
// Determine request type
|
|
|
- if (string::strcmp("ping", type) == 0) process_ping(cb.client, request);
|
|
|
- else if (string::strcmp("script", type) == 0) process_script(cb.client, request);
|
|
|
- else if (string::strcmp("stats", type) == 0) process_stats(cb.client, request);
|
|
|
- else if (string::strcmp("command", type) == 0) process_command(cb.client, request);
|
|
|
+ if (type == "ping") process_ping(cb.client, request);
|
|
|
+ else if (type == "script") process_script(cb.client, request);
|
|
|
+ else if (type == "stats") process_stats(cb.client, request);
|
|
|
+ else if (type == "command") process_command(cb.client, request);
|
|
|
+ else if (type == "filesystem") processs_filesystem(cb.client, request);
|
|
|
else continue;
|
|
|
}
|
|
|
|
|
|
m_receive_callbacks.clear();
|
|
|
m_receive_buffer.clear();
|
|
|
-
|
|
|
- for (uint32_t i = 0; i < m_send_callbacks.size(); i++)
|
|
|
- {
|
|
|
- RPCCallback cb = m_send_callbacks.front();
|
|
|
- m_send_callbacks.pop_front();
|
|
|
-
|
|
|
- m_clients[cb.client.index].write(&m_send_buffer[cb.message_index], string::strlen(&m_send_buffer[cb.message_index]));
|
|
|
- }
|
|
|
-
|
|
|
- m_send_callbacks.clear();
|
|
|
- m_send_buffer.clear();
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
void ConsoleServer::update_client(ClientId id)
|
|
|
{
|
|
|
- size_t total_read = 0;
|
|
|
- uint32_t message_index = m_receive_buffer.size();
|
|
|
-
|
|
|
TCPSocket& client = m_clients[id.index];
|
|
|
|
|
|
- char buf[1024];
|
|
|
- while (true)
|
|
|
- {
|
|
|
- ReadResult result = client.read(buf, 32);
|
|
|
+ uint32_t msg_len = 0;
|
|
|
+ ReadResult rr = client.read_nonblock(&msg_len, 4);
|
|
|
|
|
|
- if (result.error == ReadResult::NO_RESULT_ERROR)
|
|
|
- {
|
|
|
- if (result.received_bytes > 0)
|
|
|
- {
|
|
|
- m_receive_buffer.push(buf, result.received_bytes);
|
|
|
- total_read += result.received_bytes;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Close remote connection
|
|
|
- client.close();
|
|
|
- remove_client(id);
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
+ // If no data received, return
|
|
|
+ if (rr.error == ReadResult::NO_ERROR && rr.received_bytes == 0) return;
|
|
|
+ if (rr.error == ReadResult::REMOTE_CLOSED) return;
|
|
|
|
|
|
- // Ensure NUL-terminated
|
|
|
+ // Else read the message
|
|
|
+ List<char> msg_buf(default_allocator());
|
|
|
+ msg_buf.resize(msg_len);
|
|
|
+ ReadResult msg_result = client.read(msg_buf.begin(), msg_len);
|
|
|
+
|
|
|
+ uint32_t message_index = m_receive_buffer.size();
|
|
|
+ m_receive_buffer.push(msg_buf.begin(), msg_result.received_bytes);
|
|
|
m_receive_buffer.push_back('\0');
|
|
|
-
|
|
|
- // Process only if received something
|
|
|
- if (total_read > 0)
|
|
|
- {
|
|
|
- add_request(id, message_index);
|
|
|
- }
|
|
|
+ add_request(id, message_index);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -268,8 +239,9 @@ void ConsoleServer::process_script(ClientId /*client*/, const char* msg)
|
|
|
JSONParser parser(msg);
|
|
|
JSONElement root = parser.root();
|
|
|
|
|
|
- const char* script = root.key("script").string_value();
|
|
|
- device()->lua_environment()->execute_string(script);
|
|
|
+ DynamicString script;
|
|
|
+ root.key("script").string_value(script);
|
|
|
+ device()->lua_environment()->execute_string(script.c_str());
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -305,27 +277,92 @@ void ConsoleServer::process_command(ClientId /*client*/, const char* msg)
|
|
|
JSONElement root = parser.root();
|
|
|
JSONElement command = root.key("command");
|
|
|
|
|
|
- const char* cmd = command.string_value();
|
|
|
+ DynamicString cmd;
|
|
|
+ command.string_value(cmd);
|
|
|
|
|
|
- if (string::strcmp("reload", cmd) == 0)
|
|
|
+ if (cmd == "reload")
|
|
|
{
|
|
|
- JSONElement resource_type = root.key_or_nil("resource_type");
|
|
|
- JSONElement resource_name = root.key_or_nil("resource_name");
|
|
|
+ JSONElement type = root.key_or_nil("resource_type");
|
|
|
+ JSONElement name = root.key_or_nil("resource_name");
|
|
|
+
|
|
|
+ DynamicString resource_type;
|
|
|
+ DynamicString resource_name;
|
|
|
+ type.string_value(resource_type);
|
|
|
+ name.string_value(resource_name);
|
|
|
|
|
|
char t[256];
|
|
|
char n[256];
|
|
|
- string::strncpy(t, resource_type.string_value(), 256);
|
|
|
- string::strncpy(n, resource_name.string_value(), 256);
|
|
|
+ string::strncpy(t, resource_type.c_str(), 256);
|
|
|
+ string::strncpy(n, resource_name.c_str(), 256);
|
|
|
device()->reload(t, n);
|
|
|
}
|
|
|
- else if (string::strcmp("pause", cmd) == 0)
|
|
|
+ else if (cmd == "pause")
|
|
|
{
|
|
|
device()->pause();
|
|
|
}
|
|
|
- else if (string::strcmp("unpause", cmd) == 0)
|
|
|
+ else if (cmd == "unpause")
|
|
|
{
|
|
|
device()->unpause();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ConsoleServer::processs_filesystem(ClientId client, const char* msg)
|
|
|
+{
|
|
|
+ JSONParser parser(msg);
|
|
|
+ JSONElement root = parser.root();
|
|
|
+ JSONElement filesystem = root.key("filesystem");
|
|
|
+
|
|
|
+ DynamicString cmd;
|
|
|
+ filesystem.string_value(cmd);
|
|
|
+
|
|
|
+ if (cmd == "size")
|
|
|
+ {
|
|
|
+ DynamicString file_name;
|
|
|
+ root.key("file").string_value(file_name);
|
|
|
+
|
|
|
+ File* file = device()->filesystem()->open(file_name.c_str(), FOM_READ);
|
|
|
+ size_t file_size = file->size();
|
|
|
+ device()->filesystem()->close(file);
|
|
|
+
|
|
|
+ TempAllocator64 alloc;
|
|
|
+ StringStream response(alloc);
|
|
|
+ response << "{\"type\":\"file\",\"size\":" << file_size << "}";
|
|
|
+
|
|
|
+ send_message_to(client, response.c_str());
|
|
|
+ }
|
|
|
+ else if (cmd == "read")
|
|
|
+ {
|
|
|
+ JSONElement file_position = root.key("position");
|
|
|
+ JSONElement file_size = root.key("size");
|
|
|
+
|
|
|
+ DynamicString file_name;
|
|
|
+ root.key("file").string_value(file_name);
|
|
|
+
|
|
|
+ // Read the file data
|
|
|
+ File* file = device()->filesystem()->open(file_name.c_str(), FOM_READ);
|
|
|
+ char* bytes = (char*) default_allocator().allocate((size_t) file_size.int_value());
|
|
|
+ file->seek((size_t) file_position.int_value());
|
|
|
+ file->read(bytes, (size_t) file_size.int_value());
|
|
|
+ device()->filesystem()->close(file);
|
|
|
+
|
|
|
+ // Encode data to base64
|
|
|
+ size_t dummy;
|
|
|
+ char* bytes_encoded = math::base64_encode((unsigned char*) bytes, (size_t) file_size.int_value(), &dummy);
|
|
|
+
|
|
|
+ // Send data
|
|
|
+ TempAllocator4096 alloc;
|
|
|
+ StringStream response(alloc);
|
|
|
+
|
|
|
+ response << "{\"type\":\"file\",";
|
|
|
+ response << "\"data\":\"" << bytes_encoded << "\"}";
|
|
|
+
|
|
|
+ send_message_to(client, response.c_str());
|
|
|
+
|
|
|
+ // Cleanup
|
|
|
+ default_allocator().deallocate(bytes_encoded);
|
|
|
+ default_allocator().deallocate(bytes);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
} // namespace crown
|