summaryrefslogtreecommitdiff
path: root/editor/fileserver
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2017-03-05 14:21:25 +0100
committerRémi Verschelde <rverschelde@gmail.com>2017-03-05 14:21:25 +0100
commit49c065d29ca07040c3fd810026121164ad86b247 (patch)
tree285176e0c80a41c22c3e8f171024472cfdc7d765 /editor/fileserver
parent532f6d4b431f940432e82b7fc7826652b7a4520d (diff)
Refactoring: rename tools/editor/ to editor/
The other subfolders of tools/ had already been moved to either editor/, misc/ or thirdparty/, so the hiding the editor code that deep was no longer meaningful.
Diffstat (limited to 'editor/fileserver')
-rw-r--r--editor/fileserver/SCsub5
-rw-r--r--editor/fileserver/editor_file_server.cpp361
-rw-r--r--editor/fileserver/editor_file_server.h87
3 files changed, 453 insertions, 0 deletions
diff --git a/editor/fileserver/SCsub b/editor/fileserver/SCsub
new file mode 100644
index 0000000000..f1fa50148f
--- /dev/null
+++ b/editor/fileserver/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import('env')
+Export('env')
+env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp
new file mode 100644
index 0000000000..2e5dbf6248
--- /dev/null
+++ b/editor/fileserver/editor_file_server.cpp
@@ -0,0 +1,361 @@
+/*************************************************************************/
+/* editor_file_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "editor_file_server.h"
+
+#include "io/marshalls.h"
+#include "io/marshalls.h"
+#include "../editor_settings.h"
+
+//#define DEBUG_PRINT(m_p) print_line(m_p)
+#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec());
+
+//#define DEBUG_TIME(m_what)
+
+void EditorFileServer::_close_client(ClientData *cd) {
+
+ cd->connection->disconnect_from_host();
+ cd->efs->wait_mutex->lock();
+ cd->efs->to_wait.insert(cd->thread);
+ cd->efs->wait_mutex->unlock();
+ while(cd->files.size()) {
+ memdelete(cd->files.front()->get());
+ cd->files.erase(cd->files.front());
+ }
+ memdelete(cd);
+
+}
+
+void EditorFileServer::_subthread_start(void*s) {
+
+ ClientData *cd = (ClientData*)s;
+
+
+ cd->connection->set_nodelay(true);
+ uint8_t buf4[8];
+ Error err = cd->connection->get_data(buf4,4);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+
+
+
+ int passlen=decode_uint32(buf4);
+
+ if (passlen>512) {
+
+ _close_client(cd);
+ ERR_FAIL_COND(passlen>512);
+ } else if (passlen>0) {
+
+ Vector<char> passutf8;
+ passutf8.resize(passlen+1);
+ err = cd->connection->get_data((uint8_t*)passutf8.ptr(),passlen);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+ passutf8[passlen]=0;
+ String s;
+ s.parse_utf8(passutf8.ptr());
+ if (s!=cd->efs->password) {
+ encode_uint32(ERR_INVALID_DATA,buf4);
+ cd->connection->put_data(buf4,4);
+ OS::get_singleton()->delay_usec(1000000);
+ _close_client(cd);
+ ERR_PRINT("CLIENT PASSWORD MISMATCH");
+ ERR_FAIL();
+ }
+ } else {
+ if (cd->efs->password!="") {
+ encode_uint32(ERR_INVALID_DATA,buf4);
+ cd->connection->put_data(buf4,4);
+ OS::get_singleton()->delay_usec(1000000);
+ _close_client(cd);
+ ERR_PRINT("CLIENT PASSWORD MISMATCH (should be empty!)");
+ ERR_FAIL();
+ }
+ }
+
+ encode_uint32(OK,buf4);
+ cd->connection->put_data(buf4,4);
+
+ while(!cd->quit) {
+
+ //wait for ID
+ err = cd->connection->get_data(buf4,4);
+ //#define DEBUG_PRINT(m_p) print_line(m_p)
+ DEBUG_TIME("get_data")
+
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+ int id=decode_uint32(buf4);
+
+ //wait for command
+ err = cd->connection->get_data(buf4,4);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+ int cmd=decode_uint32(buf4);
+
+ switch(cmd) {
+
+ case FileAccessNetwork::COMMAND_FILE_EXISTS:
+ case FileAccessNetwork::COMMAND_GET_MODTIME:
+ case FileAccessNetwork::COMMAND_OPEN_FILE: {
+
+ DEBUG_TIME("open_file")
+ err = cd->connection->get_data(buf4,4);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+
+ int namelen=decode_uint32(buf4);
+ Vector<char> fileutf8;
+ fileutf8.resize(namelen+1);
+ err = cd->connection->get_data((uint8_t*)fileutf8.ptr(),namelen);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+ fileutf8[namelen]=0;
+ String s;
+ s.parse_utf8(fileutf8.ptr());
+
+ if (cmd==FileAccessNetwork::COMMAND_FILE_EXISTS) {
+ print_line("FILE EXISTS: "+s);
+ }
+ if (cmd==FileAccessNetwork::COMMAND_GET_MODTIME) {
+ print_line("MOD TIME: "+s);
+ }
+ if (cmd==FileAccessNetwork::COMMAND_OPEN_FILE) {
+ print_line("OPEN: "+s);
+ }
+
+ if ( !s.begins_with("res://")) {
+
+ _close_client(cd);
+ ERR_FAIL_COND(!s.begins_with("res://"));
+ }
+ ERR_CONTINUE(cd->files.has(id));
+
+ if (cmd==FileAccessNetwork::COMMAND_FILE_EXISTS) {
+
+ encode_uint32(id,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccessNetwork::RESPONSE_FILE_EXISTS,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccess::exists(s),buf4);
+ cd->connection->put_data(buf4,4);
+ DEBUG_TIME("open_file_end")
+ break;
+ }
+
+ if (cmd==FileAccessNetwork::COMMAND_GET_MODTIME) {
+
+ encode_uint32(id,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccessNetwork::RESPONSE_GET_MODTIME,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint64(FileAccess::get_modified_time(s),buf4);
+ cd->connection->put_data(buf4,8);
+ DEBUG_TIME("open_file_end")
+ break;
+ }
+
+ FileAccess *fa = FileAccess::open(s,FileAccess::READ);
+ if (!fa) {
+ //not found, continue
+ encode_uint32(id,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccessNetwork::RESPONSE_OPEN,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(ERR_FILE_NOT_FOUND,buf4);
+ cd->connection->put_data(buf4,4);
+ DEBUG_TIME("open_file_end")
+ break;
+
+ }
+
+ encode_uint32(id,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccessNetwork::RESPONSE_OPEN,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(OK,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint64(fa->get_len(),buf4);
+ cd->connection->put_data(buf4,8);
+
+ cd->files[id]=fa;
+ DEBUG_TIME("open_file_end")
+
+ } break;
+ case FileAccessNetwork::COMMAND_READ_BLOCK: {
+
+ err = cd->connection->get_data(buf4,8);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+
+ ERR_CONTINUE(!cd->files.has(id));
+
+ uint64_t offset = decode_uint64(buf4);
+
+ err = cd->connection->get_data(buf4,4);
+ if (err!=OK) {
+ _close_client(cd);
+ ERR_FAIL_COND(err!=OK);
+ }
+
+ int blocklen=decode_uint32(buf4);
+ ERR_CONTINUE(blocklen > (16*1024*1024));
+
+ cd->files[id]->seek(offset);
+ Vector<uint8_t> buf;
+ buf.resize(blocklen);
+ int read = cd->files[id]->get_buffer(buf.ptr(),blocklen);
+ ERR_CONTINUE(read<0);
+
+ print_line("GET BLOCK - offset: "+itos(offset)+", blocklen: "+itos(blocklen));
+
+ //not found, continue
+ encode_uint32(id,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint32(FileAccessNetwork::RESPONSE_DATA,buf4);
+ cd->connection->put_data(buf4,4);
+ encode_uint64(offset,buf4);
+ cd->connection->put_data(buf4,8);
+ encode_uint32(read,buf4);
+ cd->connection->put_data(buf4,4);
+ cd->connection->put_data(buf.ptr(),read);
+
+
+ } break;
+ case FileAccessNetwork::COMMAND_CLOSE: {
+
+ print_line("CLOSED");
+ ERR_CONTINUE(!cd->files.has(id));
+ memdelete(cd->files[id]);
+ cd->files.erase(id);
+ } break;
+ }
+ }
+
+ _close_client(cd);
+
+}
+
+void EditorFileServer::_thread_start(void*s) {
+
+ EditorFileServer *self=(EditorFileServer*)s;
+ while(!self->quit) {
+
+ if (self->cmd==CMD_ACTIVATE) {
+ self->server->listen(self->port);
+ self->active=true;
+ self->cmd=CMD_NONE;
+ } else if (self->cmd==CMD_STOP) {
+ self->server->stop();
+ self->active=false;
+ self->cmd=CMD_NONE;
+ }
+
+ if (self->active) {
+ if (self->server->is_connection_available()) {
+ ClientData *cd = memnew( ClientData);
+ cd->connection=self->server->take_connection();
+ cd->efs=self;
+ cd->quit=false;
+ cd->thread=Thread::create(_subthread_start,cd);
+ }
+ }
+
+ self->wait_mutex->lock();
+ while (self->to_wait.size()) {
+ Thread *w = self->to_wait.front()->get();
+ self->to_wait.erase(w);
+ self->wait_mutex->unlock();
+ Thread::wait_to_finish(w);
+ memdelete(w);
+ self->wait_mutex->lock();
+ }
+ self->wait_mutex->unlock();
+
+ OS::get_singleton()->delay_usec(100000);
+ }
+
+
+}
+
+void EditorFileServer::start() {
+
+
+ stop();
+ port=EDITOR_DEF("filesystem/file_server/port",6010);
+ password=EDITOR_DEF("filesystem/file_server/password","");
+ cmd=CMD_ACTIVATE;
+
+}
+
+bool EditorFileServer::is_active() const {
+
+ return active;
+}
+
+void EditorFileServer::stop(){
+
+ cmd=CMD_STOP;
+}
+
+EditorFileServer::EditorFileServer() {
+
+ server = TCP_Server::create_ref();
+ wait_mutex = Mutex::create();
+ quit=false;
+ active=false;
+ cmd=CMD_NONE;
+ thread=Thread::create(_thread_start,this);
+
+ EDITOR_DEF("filesystem/file_server/port",6010);
+ EDITOR_DEF("filesystem/file_server/password","");
+}
+
+EditorFileServer::~EditorFileServer() {
+
+
+ quit=true;
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+ memdelete(wait_mutex);
+}
diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h
new file mode 100644
index 0000000000..31f8ae84b8
--- /dev/null
+++ b/editor/fileserver/editor_file_server.h
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* editor_file_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef EDITOR_FILE_SERVER_H
+#define EDITOR_FILE_SERVER_H
+
+#include "object.h"
+#include "os/thread.h"
+#include "io/tcp_server.h"
+#include "io/packet_peer.h"
+#include "io/file_access_network.h"
+
+class EditorFileServer : public Object {
+
+ GDCLASS(EditorFileServer,Object);
+
+ enum Command {
+ CMD_NONE,
+ CMD_ACTIVATE,
+ CMD_STOP,
+ };
+
+
+ struct ClientData {
+
+ Thread *thread;
+ Ref<StreamPeerTCP> connection;
+ Map<int,FileAccess*> files;
+ EditorFileServer *efs;
+ bool quit;
+
+ };
+
+ Ref<TCP_Server> server;
+ Set<Thread*> to_wait;
+
+ static void _close_client(ClientData *cd);
+ static void _subthread_start(void*s);
+
+ Mutex *wait_mutex;
+ Thread *thread;
+ static void _thread_start(void*);
+ bool quit;
+ Command cmd;
+
+ String password;
+ int port;
+ bool active;
+
+
+public:
+
+ void start();
+ void stop();
+
+ bool is_active() const;
+
+ EditorFileServer();
+ ~EditorFileServer();
+};
+
+#endif // EDITOR_FILE_SERVER_H