diff --git a/README.md b/README.md index 6c35950da8..fb1b0c8692 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ you likely had Cmake generate Xcode project files and have not run `cmake ..` in Then, launch the static components - a domain-server and a voxel-server. All of the targets will run in the foreground, so you'll either want to background it yourself or open a seperate terminal window per target. - cd domain-server && ./domain-server --local + cd domain-server && ./domain-server ./voxel-server/voxel-server --local > /tmp/voxel-server.log 2>&1 & Then, run an assignment-client with 2 forks to fulfill the avatar-mixer and audio-mixer assignments. It uses localhost as its assignment-server and talks to it on port 40102 (the default domain-server port). diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 07ab486296..32959139d9 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -51,27 +51,45 @@ unsigned char* addNodeToBroadcastPacket(unsigned char* currentPosition, Node* no return currentPosition; } +static int mongooseRequestHandler(struct mg_connection *conn) { + const struct mg_request_info *ri = mg_get_request_info(conn); + + if (strcmp(ri->uri, "/assignment") == 0 && strcmp(ri->request_method, "POST") == 0) { + // return a 200 + mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n"); + // upload the file + mg_upload(conn, "/tmp"); + + return 1; + } else { + // have mongoose process this request from the document_root + return 0; + } +} + +const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "web/assignment"; + +static void mongooseUploadHandler(struct mg_connection *conn, const char *path) { + // create an assignment for this saved script + Assignment scriptAssignment(Assignment::CreateCommand, Assignment::AgentType); + + QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION); + newPath += "/"; + // append the UUID for this script as the new filename, remove the curly braces + newPath += scriptAssignment.getUUID().toString().mid(1, scriptAssignment.getUUID().toString().length() - 2); + + // rename the saved script to the GUID of the assignment and move it to the script host locaiton + rename(path, newPath.toStdString().c_str()); + + qDebug("Saved a script for assignment at %s\n", newPath.toStdString().c_str()); +} + int main(int argc, const char* argv[]) { qInstallMessageHandler(Logging::verboseMessageHandler); NodeList* nodeList = NodeList::createInstance(NODE_TYPE_DOMAIN, DOMAIN_LISTEN_PORT); - // If user asks to run in "local" mode then we do NOT replace the IP - // with the EC2 IP. Otherwise, we will replace the IP like we used to - // this allows developers to run a local domain without recompiling the - // domain server - bool isLocalMode = cmdOptionExists(argc, (const char**) argv, "--local"); - if (isLocalMode) { - printf("NOTE: Running in local mode!\n"); - } else { - printf("--------------------------------------------------\n"); - printf("NOTE: Not running in local mode. \n"); - printf("If you're a developer testing a local system, you\n"); - printf("probably want to include --local on command line.\n"); - printf("--------------------------------------------------\n"); - } - setvbuf(stdout, NULL, _IOLBF, 0); ssize_t receivedBytes = 0; @@ -82,7 +100,7 @@ int main(int argc, const char* argv[]) { unsigned char* currentBufferPos; unsigned char* startPointer; - sockaddr_in nodePublicAddress, nodeLocalAddress; + sockaddr_in nodePublicAddress, nodeLocalAddress, replyDestinationSocket; nodeLocalAddress.sin_family = AF_INET; in_addr_t serverLocalAddress = getLocalAddress(); @@ -128,7 +146,10 @@ int main(int argc, const char* argv[]) { // list of options. Last element must be NULL. const char *options[] = {"listening_ports", "8080", - "document_root", "./web", NULL}; + "document_root", "./web", NULL}; + + callbacks.begin_request = mongooseRequestHandler; + callbacks.upload = mongooseUploadHandler; // Start the web server. ctx = mg_start(&callbacks, NULL, options); @@ -161,19 +182,15 @@ int main(int argc, const char* argv[]) { int numBytesSocket = unpackSocket(packetData + numBytesSenderHeader + sizeof(NODE_TYPE), (sockaddr*) &nodeLocalAddress); - sockaddr* destinationSocket = (sockaddr*) &nodePublicAddress; + replyDestinationSocket = nodePublicAddress; // check the node public address - // if it matches our local address we're on the same box - // so hardcode the EC2 public address for now - if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress) { - // If we're not running "local" then we do replace the IP - // with 0. This designates to clients that the server is reachable - // at the same IP address - if (!isLocalMode) { - nodePublicAddress.sin_addr.s_addr = 0; - destinationSocket = (sockaddr*) &nodeLocalAddress; - } + // if it matches our local address + // or if it's the loopback address we're on the same box + if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress || + nodePublicAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + + nodePublicAddress.sin_addr.s_addr = 0; } Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress, @@ -244,7 +261,7 @@ int main(int argc, const char* argv[]) { currentBufferPos += packNodeId(currentBufferPos, newNode->getNodeID()); // send the constructed list back to this node - nodeList->getNodeSocket()->send(destinationSocket, + nodeList->getNodeSocket()->send((sockaddr*)&replyDestinationSocket, broadcastPacket, (currentBufferPos - startPointer) + numHeaderBytes); } diff --git a/domain-server/src/web/assignment/js/assignment.js b/domain-server/src/web/assignment/js/assignment.js index 69864575e9..fd153edcce 100644 --- a/domain-server/src/web/assignment/js/assignment.js +++ b/domain-server/src/web/assignment/js/assignment.js @@ -12,20 +12,28 @@ $(document).ready(function(){ $('#deploy-button').click(function(){ script = editor.getValue(); - // store the script on S3 using filepicker - filepicker.store(script, {mimetype: 'application/javascript'}, function(blob){ - console.log(JSON.stringify(blob)); - - s3_filename = blob["key"]; - - $.post('/assignment', {s3_filename: s3_filename}, function(response){ - // the response is the assignment ID, if successful - console.log(response); - }, function(error) { - console.log(error); - }); - }, function(FPError){ - console.log(FPError); + // setup our boundary - this is "highfidelity" in hex + var boundary = "----68696768666964656c697479"; + var body = '--' + boundary + '\r\n' + // parameter name is "file" and local filename is "temp.txt" + + 'Content-Disposition:form-data; name="file"; ' + + 'filename="script.js"\r\n' + // add the javascript mime-type + + 'Content-type: application/javascript\r\n\r\n' + // add the script + + script + '\r\n' + + '--' + boundary + '--'; + + // post form to assignment in order to create an assignment + $.ajax({ + contentType: "multipart/form-data; boundary=" + boundary, + data: body, + type: "POST", + url: "/assignment", + success: function (data, status) { + console.log(data); + console.log(status); + } }); }); }); diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 0f7b59aeab..c0e1f3af09 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -7,12 +7,15 @@ // #include "PacketHeaders.h" +#include "SharedUtil.h" #include "Assignment.h" const char IPv4_ADDRESS_DESIGNATOR = 4; const char IPv6_ADDRESS_DESIGNATOR = 6; +const int NUM_BYTES_RFC4122_UUID = 16; + Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assignment::Location location) : _command(command), _type(type), @@ -22,6 +25,11 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assig { // set the create time on this assignment gettimeofday(&_time, NULL); + + if (_command == Assignment::CreateCommand) { + // this is a newly created assignment, generate a random UUID + _uuid = QUuid::createUuid(); + } } Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) : @@ -44,6 +52,12 @@ Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) : numBytesRead += numBytesForPacketHeader(dataBuffer); + if (dataBuffer[0] != PACKET_TYPE_REQUEST_ASSIGNMENT) { + // read the GUID for this assignment + _uuid = QUuid::fromRfc4122(QByteArray((const char*) dataBuffer + numBytesRead, NUM_BYTES_RFC4122_UUID)); + numBytesRead += NUM_BYTES_RFC4122_UUID; + } + memcpy(&_type, dataBuffer + numBytesRead, sizeof(Assignment::Type)); numBytesRead += sizeof(Assignment::Type); @@ -102,6 +116,12 @@ void Assignment::setAttachedLocalSocket(const sockaddr* attachedLocalSocket) { int Assignment::packToBuffer(unsigned char* buffer) { int numPackedBytes = 0; + // pack the UUID for this assignment, if this is an assignment create or deploy + if (_command != Assignment::RequestCommand) { + memcpy(buffer, _uuid.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + numPackedBytes += NUM_BYTES_RFC4122_UUID; + } + memcpy(buffer + numPackedBytes, &_type, sizeof(_type)); numPackedBytes += sizeof(_type); diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 99d22b791e..d34c436a6c 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -11,6 +11,8 @@ #include +#include + #include "NodeList.h" /// Holds information used for request, creation, and deployment of assignments @@ -20,6 +22,7 @@ public: enum Type { AudioMixerType, AvatarMixerType, + AgentType, AllTypes }; @@ -45,6 +48,7 @@ public: ~Assignment(); + const QUuid& getUUID() const { return _uuid; } Assignment::Command getCommand() const { return _command; } Assignment::Type getType() const { return _type; } Assignment::Location getLocation() const { return _location; } @@ -65,6 +69,7 @@ public: void setCreateTimeToNow() { gettimeofday(&_time, NULL); } private: + QUuid _uuid; /// the 16 byte UUID for this assignment Assignment::Command _command; /// the command for this assignment (Create, Deploy, Request) Assignment::Type _type; /// the type of the assignment, defines what the assignee will do Assignment::Location _location; /// the location of the assignment, allows a domain to preferentially use local ACs