From 2f9da176b194975a6b3ecb322213e8ea4e286820 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 25 Dec 2012 16:06:23 +0900 Subject: [PATCH 001/477] initial commit of mujin controller client library --- .../mujincontrollerclient.h | 153 ++++++++++++++++++ src/mujincontrollerclient.cpp | 24 +++ 2 files changed, 177 insertions(+) create mode 100644 include/mujincontrollerclient/mujincontrollerclient.h create mode 100644 src/mujincontrollerclient.cpp diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h new file mode 100644 index 00000000..3f3a8e74 --- /dev/null +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -0,0 +1,153 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** \file mujincontrollerclient.h + \brief Defines the public headers of the MUJIN Controller Client + */ +#ifndef MUJINCLIENT_H +#define MUJINCLIENT_H + +#ifndef MUJINCLIENT_DISABLE_ASSERT_HANDLER +#define BOOST_ENABLE_ASSERT_HANDLER +#endif + +#define BOOST_FILESYSTEM_VERSION 3 // use boost filesystem v3 + +#include +#include +#include +#include + +#include + +#ifdef _MSC_VER + +#pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class +#pragma warning(disable:4190) // C-linkage specified, but returns UDT 'boost::shared_ptr' which is incompatible with C +#pragma warning(disable:4819) //The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss using native typeof + +#ifndef __PRETTY_FUNCTION__ +#define __PRETTY_FUNCTION__ __FUNCDNAME__ +#endif + +#else +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace mujinclient { + +#include + +enum MujinErrorCode { + ORE_Failed=0, + ORE_InvalidArguments=1, ///< passed in input arguments are not valid + ORE_EnvironmentNotLocked=2, + ORE_CommandNotSupported=3, ///< string command could not be parsed or is not supported + ORE_Assert=4, + ORE_NotInitialized=9, ///< when object is used without it getting fully initialized + ORE_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. + ORE_Timeout=11, ///< process timed out +}; + +inline const char* GetErrorCodeString(MujinErrorCode error) +{ + switch(error) { + case ORE_Failed: return "Failed"; + case ORE_InvalidArguments: return "InvalidArguments"; + case ORE_EnvironmentNotLocked: return "EnvironmentNotLocked"; + case ORE_CommandNotSupported: return "CommandNotSupported"; + case ORE_Assert: return "Assert"; + case ORE_NotInitialized: return "NotInitialized"; + case ORE_InvalidState: return "InvalidState"; + case ORE_Timeout: return "Timeout"; + } + // should throw an exception? + return ""; +} + + +/// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. +class MUJINCLIENT_API mujin_exception : public std::exception +{ +public: + mujin_exception() : std::exception(), _s("unknown exception"), _error(ORE_Failed) { + } + mujin_exception(const std::string& s, MujinErrorCode error=ORE_Failed) : std::exception() { + _error = error; + _s = "mujin ("; + _s += GetErrorCodeString(_error); + _s += "): "; + _s += s; + } + virtual ~mujin_exception() throw() { + } + char const* what() const throw() { + return _s.c_str(); + } + const std::string& message() const { + return _s; + } + MujinErrorCode GetCode() const { + return _error; + } +private: + std::string _s; + MujinErrorCode _error; +}; + + +MUJINCLIENT_API void testfn(); + +} + +#if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) +/// Modifications controlling %boost library behavior. +namespace boost +{ +inline void assertion_failed(char const * expr, char const * function, char const * file, long line) +{ + throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::ORE_Assert); +} + +#if BOOST_VERSION>104600 +inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) +{ + throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::ORE_Assert); +} +#endif + +} +#endif + +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MAJOR>=0&&MUJINCLIENT_VERSION_MAJOR<=255); +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MINOR>=0&&MUJINCLIENT_VERSION_MINOR<=255); +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_PATCH>=0&&MUJINCLIENT_VERSION_PATCH<=255); + +#endif diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp new file mode 100644 index 00000000..3cb20b2c --- /dev/null +++ b/src/mujincontrollerclient.cpp @@ -0,0 +1,24 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include + +#include + +namespace mujinclient { +void testfn() +{ + printf("yo\n"); +} + +} From da44f2ded6f4b9364114276c2c9312f8b2114d99 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 25 Dec 2012 22:44:49 +0900 Subject: [PATCH 002/477] initial test with https --- src/mujincontrollerclient.cpp | 67 ++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3cb20b2c..dc007824 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -14,11 +14,76 @@ #include #include +#include + namespace mujinclient { + +static int _writer(char *data, size_t size, size_t nmemb, std::string *writerData) +{ + if (writerData == NULL) { + return 0; + } + writerData->append(data, size*nmemb); + return size * nmemb; +} + void testfn() { - printf("yo\n"); + + std::string buffer; + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://controller.mujin.co.jp/"); + +//#ifdef SKIP_PEER_VERIFICATION +// /* +// * If you want to connect to a site who isn't using a certificate that is +// * signed by one of the certs in the CA bundle you have, you can skip the +// * verification of the server's certificate. This makes the connection +// * A LOT LESS SECURE. +// * +// * If you have a CA cert for the server stored someplace else than in the +// * default bundle, then the CURLOPT_CAPATH option might come handy for +// * you. +// */ +// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); +//#endif +// +//#ifdef SKIP_HOSTNAME_VERIFICATION +// /* +// * If the site you're connecting to uses a different host name that what +// * they have mentioned in their server certificate's commonName (or +// * subjectAltName) fields, libcurl will refuse to connect. You can skip +// * this check, but this will make the connection less secure. +// */ +// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); +//#endif + + res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _writer); + if (res != CURLE_OK) { + //fprintf(stderr, "Failed to set writer [%s]\n", errorBuffer); + return; // false; + } + + res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + if (res != CURLE_OK) { + //fprintf(stderr, "Failed to set write data [%s]\n", errorBuffer); + return; // false; + } + + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + printf("buffer: %s\n", buffer.c_str()); + /* always cleanup */ + curl_easy_cleanup(curl); + } } + + } From b9df01d8a638509d8959da336d9b2eeeafc0072e Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 25 Dec 2012 23:26:25 +0900 Subject: [PATCH 003/477] link with libcurl for initial http comm --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index dc007824..91fa35e7 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -36,7 +36,7 @@ void testfn() CURLcode res; curl = curl_easy_init(); if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, "https://controller.mujin.co.jp/"); + curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com/");//"https://controller.mujin.co.jp/"); //#ifdef SKIP_PEER_VERIFICATION // /* From d2ecc585bce8117472c8cb08f31e718af97f521e Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 26 Dec 2012 17:52:47 +0900 Subject: [PATCH 004/477] client now prints environments --- .../mujincontrollerclient.h | 5 ++++- src/mujincontrollerclient.cpp | 17 ++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3f3a8e74..bc0241c1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -123,7 +123,10 @@ class MUJINCLIENT_API mujin_exception : public std::exception }; -MUJINCLIENT_API void testfn(); +/// \brief returns raw environment data +/// +/// \param usernamepassword user:password +MUJINCLIENT_API std::string ListAllEnvironmentsRaw(const std::string& usernamepassword); } diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 91fa35e7..fbea3697 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -28,7 +28,7 @@ static int _writer(char *data, size_t size, size_t nmemb, std::string *writerDat return size * nmemb; } -void testfn() +std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) { std::string buffer; @@ -36,7 +36,7 @@ void testfn() CURLcode res; curl = curl_easy_init(); if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com/");//"https://controller.mujin.co.jp/"); + curl_easy_setopt(curl, CURLOPT_URL, "https://controller.mujin.co.jp/api/v1/scene/?format=json"); //#ifdef SKIP_PEER_VERIFICATION // /* @@ -62,26 +62,29 @@ void testfn() // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); //#endif + res = curl_easy_setopt(curl, CURLOPT_USERPWD, usernamepassword.c_str()); + if (res != CURLE_OK) { + throw mujin_exception("failed to set userpw"); + } + //densowave:Debpawm8 res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _writer); if (res != CURLE_OK) { - //fprintf(stderr, "Failed to set writer [%s]\n", errorBuffer); - return; // false; + throw mujin_exception("failed to set writer"); } res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); if (res != CURLE_OK) { - //fprintf(stderr, "Failed to set write data [%s]\n", errorBuffer); - return; // false; + throw mujin_exception("failed to set write data"); } res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } - printf("buffer: %s\n", buffer.c_str()); /* always cleanup */ curl_easy_cleanup(curl); } + return buffer; } From fb89f566941e889bc4ebb0e0e60202716783799b Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 27 Dec 2012 00:39:06 +0900 Subject: [PATCH 005/477] added visual studio 2005 binaries --- include/mujincontrollerclient/mujincontrollerclient.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index bc0241c1..2a319316 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -28,8 +28,6 @@ #include #include -#include - #ifdef _MSC_VER #pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class From 0ef654fa1fb40789c4bb301589c680bc7338eacd Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 27 Dec 2012 00:51:02 +0900 Subject: [PATCH 006/477] skip peer validation --- src/mujincontrollerclient.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index fbea3697..666b228c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -28,6 +28,8 @@ static int _writer(char *data, size_t size, size_t nmemb, std::string *writerDat return size * nmemb; } +#define SKIP_PEER_VERIFICATION // temporary + std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) { @@ -38,20 +40,20 @@ std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://controller.mujin.co.jp/api/v1/scene/?format=json"); -//#ifdef SKIP_PEER_VERIFICATION -// /* -// * If you want to connect to a site who isn't using a certificate that is -// * signed by one of the certs in the CA bundle you have, you can skip the -// * verification of the server's certificate. This makes the connection -// * A LOT LESS SECURE. -// * -// * If you have a CA cert for the server stored someplace else than in the -// * default bundle, then the CURLOPT_CAPATH option might come handy for -// * you. -// */ -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); -//#endif -// +#ifdef SKIP_PEER_VERIFICATION + /* + * if you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the ca bundle you have, you can skip the + * verification of the server's certificate. this makes the connection + * a lot less secure. + * + * if you have a ca cert for the server stored someplace else than in the + * default bundle, then the curlopt_capath option might come handy for + * you. + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0l); +#endif + //#ifdef SKIP_HOSTNAME_VERIFICATION // /* // * If the site you're connecting to uses a different host name that what From 064c918937d0409931a706f3b4b47d7aae720bfe Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 9 Jan 2013 03:29:12 +0900 Subject: [PATCH 007/477] modified test example to do more complex mujin controller quering --- .../mujincontrollerclient.h | 158 ++++++++++++--- src/mujincontrollerclient.cpp | 187 +++++++++++++++--- 2 files changed, 292 insertions(+), 53 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2a319316..9dd85298 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -23,10 +23,10 @@ #define BOOST_FILESYSTEM_VERSION 3 // use boost filesystem v3 -#include -#include +//#include +//#include #include -#include +//#include #ifdef _MSC_VER @@ -64,27 +64,27 @@ namespace mujinclient { #include enum MujinErrorCode { - ORE_Failed=0, - ORE_InvalidArguments=1, ///< passed in input arguments are not valid - ORE_EnvironmentNotLocked=2, - ORE_CommandNotSupported=3, ///< string command could not be parsed or is not supported - ORE_Assert=4, - ORE_NotInitialized=9, ///< when object is used without it getting fully initialized - ORE_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. - ORE_Timeout=11, ///< process timed out + MEC_Failed=0, + MEC_InvalidArguments=1, ///< passed in input arguments are not valid + MEC_EnvironmentNotLocked=2, + MEC_CommandNotSupported=3, ///< string command could not be parsed or is not supported + MEC_Assert=4, + MEC_NotInitialized=9, ///< when object is used without it getting fully initialized + MEC_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. + MEC_Timeout=11, ///< process timed out }; inline const char* GetErrorCodeString(MujinErrorCode error) { switch(error) { - case ORE_Failed: return "Failed"; - case ORE_InvalidArguments: return "InvalidArguments"; - case ORE_EnvironmentNotLocked: return "EnvironmentNotLocked"; - case ORE_CommandNotSupported: return "CommandNotSupported"; - case ORE_Assert: return "Assert"; - case ORE_NotInitialized: return "NotInitialized"; - case ORE_InvalidState: return "InvalidState"; - case ORE_Timeout: return "Timeout"; + case MEC_Failed: return "Failed"; + case MEC_InvalidArguments: return "InvalidArguments"; + case MEC_EnvironmentNotLocked: return "EnvironmentNotLocked"; + case MEC_CommandNotSupported: return "CommandNotSupported"; + case MEC_Assert: return "Assert"; + case MEC_NotInitialized: return "NotInitialized"; + case MEC_InvalidState: return "InvalidState"; + case MEC_Timeout: return "Timeout"; } // should throw an exception? return ""; @@ -95,9 +95,9 @@ inline const char* GetErrorCodeString(MujinErrorCode error) class MUJINCLIENT_API mujin_exception : public std::exception { public: - mujin_exception() : std::exception(), _s("unknown exception"), _error(ORE_Failed) { + mujin_exception() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { } - mujin_exception(const std::string& s, MujinErrorCode error=ORE_Failed) : std::exception() { + mujin_exception(const std::string& s, MujinErrorCode error=MEC_Failed) : std::exception() { _error = error; _s = "mujin ("; _s += GetErrorCodeString(_error); @@ -120,11 +120,119 @@ class MUJINCLIENT_API mujin_exception : public std::exception MujinErrorCode _error; }; +class ControllerClient; +class SceneResource; +class TaskResource; +class PlanningResultResource; -/// \brief returns raw environment data +typedef boost::shared_ptr ControllerClientPtr; +typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr SceneResourcePtr; +typedef boost::weak_ptr SceneResourceWeakPtr; +typedef boost::shared_ptr TaskResourcePtr; +typedef boost::weak_ptr TaskResourceWeakPtr; +typedef boost::shared_ptr PlanningResultResourcePtr; +typedef boost::weak_ptr PlanningResultResourceWeakPtr; +typedef double Real; + +/// \brief Creates on MUJIN Controller instance. +/// +/// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. +class MUJINCLIENT_API ControllerClient +{ +public: + virtual ~ControllerClient() { + } + + /** \brief Returns a list of filenames in the user system of a particular type + + \param scenetype the type of scene possible values are: + - mujincollada + - wincaps + - rttoolbox + - cecvirfitxml + - stl + - x + - vrml + - stl + */ + virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; + + /// \brief gets a list of all the scene primary keys currently available to the user + virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; + + //virtual SceneResourcePtr GetScene(const std::string& pk); +}; + +class MUJINCLIENT_API WebResource +{ +public: + WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk); + virtual ~WebResource() { + } + + inline ControllerClientPtr GetController() const { + return __controller; + } + inline const std::string& GetResourceName() const { + return __resourcename; + } + inline const std::string& GetPrimaryKey() const { + return __pk; + } + + /// \brief gets an attribute of this web resource + std::string Get(const std::string& field); + +private: + ControllerClientPtr __controller; + std::string __resourcename, __pk; +}; + +class MUJINCLIENT_API SceneResource : public WebResource +{ +public: + SceneResource(ControllerClientPtr controller, const std::string& pk); + virtual ~SceneResource() { + } + + TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname); + + /// \brief gets a list of all the scene primary keys currently available to the user + //virtual void GetTaskPrimaryKeys(std::vector& task) = 0; +}; + +class MUJINCLIENT_API TaskResource : public WebResource +{ +public: + TaskResource(ControllerClientPtr controller, const std::string& pk); + virtual ~TaskResource() { + } + + /// \brief execute the task + virtual void Execute(); + + /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. + virtual PlanningResultResourcePtr GetTaskResult(); +}; + +class MUJINCLIENT_API PlanningResultResource : public WebResource +{ +public: + PlanningResultResource(ControllerClientPtr controller, const std::string& pk); + virtual ~PlanningResultResource() { + } +}; + + +/// \brief creates the controller with an account. /// /// \param usernamepassword user:password -MUJINCLIENT_API std::string ListAllEnvironmentsRaw(const std::string& usernamepassword); +/// This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword); + +/// \brief called at the very end of an application to safely destroy all controller client resources +MUJINCLIENT_API void ControllerClientDestroy(); } @@ -134,13 +242,13 @@ namespace boost { inline void assertion_failed(char const * expr, char const * function, char const * file, long line) { - throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::ORE_Assert); + throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::MEC_Assert); } #if BOOST_VERSION>104600 inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) { - throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::ORE_Assert); + throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::MEC_Assert); } #endif diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 666b228c..d6b83404 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -13,33 +13,48 @@ // limitations under the License. #include -#include +#include +#include +#include +#include +#include + +#include #include +#define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); -namespace mujinclient { +#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) -static int _writer(char *data, size_t size, size_t nmemb, std::string *writerData) -{ - if (writerData == NULL) { - return 0; - } - writerData->append(data, size*nmemb); - return size * nmemb; -} +/// adds the function name and line number to an exception +#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) + +#define MUJIN_ASSERT_FORMAT(testexpr, s, args, errorcode) { if( !(testexpr) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)%args),errorcode); } } + +#define MUJIN_ASSERT_FORMAT0(testexpr, s, errorcode) { if( !(testexpr) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)),errorcode); } } + +// note that expr1 and expr2 will be evaluated twice if not equal +#define MUJIN_ASSERT_OP_FORMAT(expr1,op,expr2,s, args, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)%args),errorcode); } } + +#define MUJIN_ASSERT_OP_FORMAT0(expr1,op,expr2,s, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),errorcode); } } + +#define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } + +namespace mujinclient { #define SKIP_PEER_VERIFICATION // temporary -std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) +class ControllerClientImpl : public ControllerClient { +public: + ControllerClientImpl(const std::string& usernamepassword) + { + _baseuri = "https://controller.mujin.co.jp/api/v1/"; + //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); + _curl = curl_easy_init(); + BOOST_ASSERT(!!_curl); - std::string buffer; - CURL *curl; - CURLcode res; - curl = curl_easy_init(); - if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, "https://controller.mujin.co.jp/api/v1/scene/?format=json"); - + CURLcode res; #ifdef SKIP_PEER_VERIFICATION /* * if you want to connect to a site who isn't using a certificate that is @@ -51,7 +66,7 @@ std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) * default bundle, then the curlopt_capath option might come handy for * you. */ - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0l); + curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0l); #endif //#ifdef SKIP_HOSTNAME_VERIFICATION @@ -64,31 +79,147 @@ std::string ListAllEnvironmentsRaw(const std::string& usernamepassword) // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); //#endif - res = curl_easy_setopt(curl, CURLOPT_USERPWD, usernamepassword.c_str()); + res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); if (res != CURLE_OK) { throw mujin_exception("failed to set userpw"); } //densowave:Debpawm8 - res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _writer); + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); if (res != CURLE_OK) { throw mujin_exception("failed to set writer"); } - res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); if (res != CURLE_OK) { throw mujin_exception("failed to set write data"); } - res = curl_easy_perform(curl); - if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + virtual ~ControllerClientImpl() { + curl_easy_cleanup(_curl); + } + + virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) + { + } + + virtual void GetScenePrimaryKeys(std::vector& scenekeys) + { + _Call("scene/?format=json&limit=0&fields=pk"); + boost::property_tree::ptree pt; + boost::property_tree::read_json(_buffer, pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + scenekeys.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + scenekeys[i++] = v.second.get("pk"); + } + } + + void _Call(const std::string& relativeuri) { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + CURLcode res = curl_easy_perform(_curl); + if (res != CURLE_OK) { + throw mujin_exception("curl_easy_perform failed"); } - /* always cleanup */ - curl_easy_cleanup(curl); } - return buffer; + + std::stringstream& GetBuffer() { + return _buffer; + } + +protected: + + static int _writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) + { + if (writerData == NULL) { + return 0; + } + writerData->write(data, size*nmemb); + return size * nmemb; + } + + CURL *_curl; + boost::mutex _mutex; + std::stringstream _buffer; + std::string _baseuri, _uri; +}; + +typedef boost::shared_ptr ControllerClientImplPtr; + +WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) +{ +} + +std::string WebResource::Get(const std::string& field) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field)); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + std::string fieldvalue = pt.get(field); + return fieldvalue; } +SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) +{ +} +TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskname) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%taskname)); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + if( objects.size() == 0 ) { + throw MUJIN_EXCEPTION_FORMAT("failed to get task %s", taskname, MEC_InvalidArguments); + } + std::string pk = objects.begin()->second.get("pk"); + TaskResourcePtr task(new TaskResource(GetController(), pk)); + return task; +} + +TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) +{ +} + +void TaskResource::Execute() +{ + throw mujin_exception("not implemented yet"); +} + +PlanningResultResourcePtr TaskResource::GetTaskResult() +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey())); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + if( objects.size() == 0 ) { + return PlanningResultResourcePtr(); + } + std::string pk = objects.begin()->second.get("pk"); + PlanningResultResourcePtr result(new PlanningResultResource(GetController(), pk)); + return result; +} + +PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) +{ +} + +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword) +{ + return ControllerClientPtr(new ControllerClientImpl(usernamepassword)); +} + +void ControllerClientDestroy() +{ +} } From 4f5b7ba9005566abf5c99344b9030c24a6a9a840 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 9 Jan 2013 09:50:39 +0900 Subject: [PATCH 008/477] added optimizations and ability to see results --- .../mujincontrollerclient.h | 83 ++++++++++- src/mujincontrollerclient.cpp | 138 +++++++++++++++++- 2 files changed, 212 insertions(+), 9 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9dd85298..1e099710 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -23,11 +23,6 @@ #define BOOST_FILESYSTEM_VERSION 3 // use boost filesystem v3 -//#include -//#include -#include -//#include - #ifdef _MSC_VER #pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class @@ -123,6 +118,7 @@ class MUJINCLIENT_API mujin_exception : public std::exception class ControllerClient; class SceneResource; class TaskResource; +class OptimizationResource; class PlanningResultResource; typedef boost::shared_ptr ControllerClientPtr; @@ -131,10 +127,31 @@ typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; +typedef boost::shared_ptr OptimizationResourcePtr; +typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; typedef boost::weak_ptr PlanningResultResourceWeakPtr; typedef double Real; +struct JobStatus +{ + JobStatus() : code(0) { + } + int code; ///< if 3, succeeded + std::string message; +}; + +/// \brief an affine transform +struct Transform +{ + Transform() { + quat[0] = 1; quat[1] = 0; quat[2] = 0; quat[3] = 0; + translation[0] = 0; translation[1] = 0; translation[2] = 0; + } + Real quat[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] + Real translation[3]; ///< translation x,y,z +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -196,7 +213,10 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~SceneResource() { } - TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname); + /// \brief Gets or creates the a task part of the scene + /// + /// \param taskname the name of the task to search for or create + virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname); /// \brief gets a list of all the scene primary keys currently available to the user //virtual void GetTaskPrimaryKeys(std::vector& task) = 0; @@ -212,8 +232,35 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief execute the task virtual void Execute(); + /// \brief get the run-time status of the executed task + virtual JobStatus GetRunTimeStatus(); + + /// \brief Gets or creates the a optimization part of the scene + /// + /// \param optimizationname the name of the optimization to search for or create + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName(const std::string& optimizationname); + /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. - virtual PlanningResultResourcePtr GetTaskResult(); + virtual PlanningResultResourcePtr GetResult(); +}; + +class MUJINCLIENT_API OptimizationResource : public WebResource +{ +public: + OptimizationResource(ControllerClientPtr controller, const std::string& pk); + virtual ~OptimizationResource() { + } + + /// \brief execute the optimization + virtual void Execute(); + + /// \brief get the run-time status of the executed optimization + virtual JobStatus GetRunTimeStatus(); + + /// \brief gets the fastest results of the optimization execution. + /// + /// \param fastestnum The number of results to get starting with the fastest task_time. If 0, will return ALL results. + virtual void GetResults(int fastestnum, std::vector& results); }; class MUJINCLIENT_API PlanningResultResource : public WebResource @@ -222,6 +269,9 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource PlanningResultResource(ControllerClientPtr controller, const std::string& pk); virtual ~PlanningResultResource() { } + + /// \brief Get all the transforms the results are storing. Depending on the optimization, can be more than just the robot + virtual void GetTransforms(std::map& transforms); }; @@ -234,6 +284,25 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); +/// \brief Compute a 3x4 matrix from a Transform +MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); + +/** \brief Compute Euler angles in ZXY order (T = Z*X*Y) from a 3x4 matrix + + Rx = Matrix(3,3,[1,0,0,0,cos(x),-sin(x),0,sin(x),cos(x)]) + Ry = Matrix(3,3,[cos(y),0,sin(y),0,1,0,-sin(y),0,cos(y)]) + Rz = Matrix(3,3,[cos(z),-sin(z),0,sin(z),cos(z),0,0,0,1]) + Rz*Rx*Ry + + [-sin(x)*sin(y)*sin(z) + cos(y)*cos(z), -sin(z)*cos(x), sin(x)*sin(z)*cos(y) + sin(y)*cos(z)] + [ sin(x)*sin(y)*cos(z) + sin(z)*cos(y), cos(x)*cos(z), -sin(x)*cos(y)*cos(z) + sin(y)*sin(z)] + [ -sin(y)*cos(x), sin(x), cos(x)*cos(y)] + + */ +MUJINCLIENT_API void ComputeZXYFromMatrix(Real ZXY[3], const Real matrix[12]); + +MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &transform); + } #if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d6b83404..7d0d7429 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -178,7 +180,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna boost::property_tree::read_json(controller->GetBuffer(), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() == 0 ) { - throw MUJIN_EXCEPTION_FORMAT("failed to get task %s", taskname, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to get task %s from scene pk %s", taskname%GetPrimaryKey(), MEC_InvalidArguments); } std::string pk = objects.begin()->second.get("pk"); TaskResourcePtr task(new TaskResource(GetController(), pk)); @@ -194,7 +196,26 @@ void TaskResource::Execute() throw mujin_exception("not implemented yet"); } -PlanningResultResourcePtr TaskResource::GetTaskResult() +JobStatus TaskResource::GetRunTimeStatus() { + throw mujin_exception("not implemented yet"); +} + +OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%optimizationname)); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + if( objects.size() == 0 ) { + throw MUJIN_EXCEPTION_FORMAT("failed to get optimization %s from task pk", optimizationname%GetPrimaryKey(), MEC_InvalidArguments); + } + std::string pk = objects.begin()->second.get("pk"); + OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); + return optimization; +} + +PlanningResultResourcePtr TaskResource::GetResult() { GETCONTROLLERIMPL(); controller->_Call(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey())); @@ -209,10 +230,78 @@ PlanningResultResourcePtr TaskResource::GetTaskResult() return result; } +OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) +{ +} + +void OptimizationResource::Execute() +{ + throw mujin_exception("not implemented yet"); +} + +JobStatus OptimizationResource::GetRunTimeStatus() { + throw mujin_exception("not implemented yet"); +} + +void OptimizationResource::GetResults(int fastestnum, std::vector& results) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("optimization/%s/result/?format=json&limit=%d&fields=pk&order_by=task_time")%GetPrimaryKey()%fastestnum)); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + results.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + results[i++].reset(new PlanningResultResource(controller, v.second.get("pk"))); + } +} + PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) { } +void PlanningResultResource::GetTransforms(std::map& transforms) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("%s/%s/?format=json&fields=transformxml")%GetResourceName()%GetPrimaryKey())); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + std::stringstream sstrans(pt.get("transformxml")); + boost::property_tree::ptree pttrans; + boost::property_tree::read_xml(sstrans, pttrans); + boost::property_tree::ptree& objects = pttrans.get_child("root"); + transforms.clear(); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + if( v.first == "transforms_" ) { + Transform t; + std::string name; + int itranslation=0, iquat=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtrans, v.second) { + if( vtrans.first == "name" ) { + name = vtrans.second.data(); + } + else if( vtrans.first == "translation_" && itranslation < 3 ) { + t.translation[itranslation++] = boost::lexical_cast(vtrans.second.data()); + } + else if( vtrans.first == "quat_" && iquat < 4 ) { + t.quat[iquat++] = boost::lexical_cast(vtrans.second.data()); + } + } + // normalize the quaternion + Real dist2 = t.quat[0]*t.quat[0] + t.quat[1]*t.quat[1] + t.quat[2]*t.quat[2] + t.quat[3]*t.quat[3]; + if( dist2 > 0 ) { + Real fnorm =1/std::sqrt(dist2); + t.quat[0] *= fnorm; t.quat[1] *= fnorm; t.quat[2] *= fnorm; t.quat[3] *= fnorm; + } + transforms[name] = t; + } + } + //std::string fieldvalue = pt.get(field); + //return fieldvalue; +} + +// transformxml ControllerClientPtr CreateControllerClient(const std::string& usernamepassword) { return ControllerClientPtr(new ControllerClientImpl(usernamepassword)); @@ -222,4 +311,49 @@ void ControllerClientDestroy() { } +void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) +{ + throw mujin_exception("not implemented yet"); +// length2 = numpy.sum(quat**2) +// ilength2 = 2.0/length2 +// qq1 = ilength2*quat[1]*quat[1] +// qq2 = ilength2*quat[2]*quat[2] +// qq3 = ilength2*quat[3]*quat[3] +// T = numpy.eye(4) +// T[0,0] = 1 - qq2 - qq3 +// T[0,1] = ilength2*(quat[1]*quat[2] - quat[0]*quat[3]) +// T[0,2] = ilength2*(quat[1]*quat[3] + quat[0]*quat[2]) +// T[1,0] = ilength2*(quat[1]*quat[2] + quat[0]*quat[3]) +// T[1,1] = 1 - qq1 - qq3 +// T[1,2] = ilength2*(quat[2]*quat[3] - quat[0]*quat[1]) +// T[2,0] = ilength2*(quat[1]*quat[3] - quat[0]*quat[2]) +// T[2,1] = ilength2*(quat[2]*quat[3] + quat[0]*quat[1]) +// T[2,2] = 1 - qq1 - qq2 +} + +void ComputeZXYFromMatrix(Real ZXY[3], Real matrix[12]) +{ + throw mujin_exception("not implemented yet"); +// if abs(T[2][0]) < 1e-10 and abs(T[2][2]) < 1e-10: +// sinx = T[2][1] +// x = numpy.pi/2 if sinx > 0 else -numpy.pi/2 +// z = 0.0 +// y = numpy.arctan2(sinx*T[1][0],T[0][0]) +// else: +// y = numpy.arctan2(-T[2][0],T[2][2]) +// siny = numpy.sin(y) +// cosy = numpy.cos(y) +// Ryinv = numpy.array([[cosy,0,-siny],[0,1,0],[siny,0,cosy]]) +// Rzx = numpy.dot(T[0:3,0:3],Ryinv) +// x = numpy.arctan2(Rzx[2][1],Rzx[2][2]) +// z = numpy.arctan2(Rzx[1][0],Rzx[0][0]) +// return numpy.array([x,y,z]) +} + +void ComputeZXYFromTransform(Real ZXY[3], const Transform& transform) +{ + throw mujin_exception("not implemented yet"); + //zxyFromMatrix(matrixFromTransform()) +} + } From 573baaf1c0de756c60f94e89a80b6afb15d181d0 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 9 Jan 2013 10:22:38 +0900 Subject: [PATCH 009/477] fixed visual studio 2005 compilation, updated to v0.1.1 --- src/mujincontrollerclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 7d0d7429..bc10ac55 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#define WIN32_LEAN_AND_MEAN #include #include From 105cde4ad3b4ec36804fb09bae749f20cf37f9ab Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 9 Jan 2013 22:14:08 +0900 Subject: [PATCH 010/477] added more get functions to api --- .../mujincontrollerclient.h | 7 +++-- src/mujincontrollerclient.cpp | 30 ++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1e099710..267075a2 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -1,5 +1,5 @@ // -*- coding: utf-8 -*- -// Copyright (C) 2012 MUJIN Inc. +// Copyright (C) 2012-2013 MUJIN Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -219,7 +219,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname); /// \brief gets a list of all the scene primary keys currently available to the user - //virtual void GetTaskPrimaryKeys(std::vector& task) = 0; + virtual void GetTaskPrimaryKeys(std::vector& taskkeys); }; class MUJINCLIENT_API TaskResource : public WebResource @@ -240,6 +240,9 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \param optimizationname the name of the optimization to search for or create virtual OptimizationResourcePtr GetOrCreateOptimizationFromName(const std::string& optimizationname); + /// \brief gets a list of all the scene primary keys currently available to the user + virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); + /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. virtual PlanningResultResourcePtr GetResult(); }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index bc10ac55..79c63fff 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1,5 +1,5 @@ // -*- coding: utf-8 -*- -// Copyright (C) 2012 MUJIN Inc. +// Copyright (C) 2012-2013 MUJIN Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -188,6 +188,20 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna return task; } +void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey())); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + taskkeys.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + taskkeys[i++] = v.second.get("pk"); + } +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } @@ -216,6 +230,20 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std: return optimization; } +void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) +{ + GETCONTROLLERIMPL(); + controller->_Call(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey())); + boost::property_tree::ptree pt; + boost::property_tree::read_json(controller->GetBuffer(), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + optimizationkeys.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + optimizationkeys[i++] = v.second.get("pk"); + } +} + PlanningResultResourcePtr TaskResource::GetResult() { GETCONTROLLERIMPL(); From 0eb1bec2a4e0e4418e01e4455f13a0a2535f29cb Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 11 Jan 2013 18:07:35 +0900 Subject: [PATCH 011/477] api updates, started on post commands --- .../mujincontrollerclient.h | 73 ++++++-- src/mujincontrollerclient.cpp | 161 ++++++++++++++---- 2 files changed, 183 insertions(+), 51 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 267075a2..59cd4004 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -49,7 +49,6 @@ #include #include -#include #include #include #include @@ -67,6 +66,8 @@ enum MujinErrorCode { MEC_NotInitialized=9, ///< when object is used without it getting fully initialized MEC_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. MEC_Timeout=11, ///< process timed out + MEC_HTTPClient=12, ///< HTTP client error + MEC_HTTPStatus=13, ///< http error status code }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -80,6 +81,8 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_NotInitialized: return "NotInitialized"; case MEC_InvalidState: return "InvalidState"; case MEC_Timeout: return "Timeout"; + case MEC_HTTPClient: return "HTTPClient"; + case MEC_HTTPStatus: return "HTTPStatus"; } // should throw an exception? return ""; @@ -152,6 +155,14 @@ struct Transform Real translation[3]; ///< translation x,y,z }; +struct SceneInformation +{ + std::string pk; ///< primary key + std::string uri; ///< uri of the file pointed to + std::string datemodified; ///< late date modified + std::string name; +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -161,24 +172,47 @@ class MUJINCLIENT_API ControllerClient virtual ~ControllerClient() { } - /** \brief Returns a list of filenames in the user system of a particular type +// /** \brief Returns a list of filenames in the user system of a particular type +// +// \param scenetype the type of scene possible values are: +// - mujincollada +// - wincaps +// - rttoolbox +// - cecvirfitxml +// - stl +// - x +// - vrml +// - stl +// */ +// virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; + + /// \brief sets the character encoding for all strings that are being input and output from the resources + /// + /// The default character encoding is utf-8, can also set it to Shift_JIS for windows japanese unicode, iso-2022-jp + /// List of possible sets: http://www.iana.org/assignments/character-sets/character-sets.xml + virtual void SetCharacterEncoding(const std::string& newencoding) = 0; - \param scenetype the type of scene possible values are: - - mujincollada - - wincaps - - rttoolbox - - cecvirfitxml - - stl - - x - - vrml - - stl - */ - virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; + /// \brief sets the language code for all output + /// + /// Checkout http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + virtual void SetLanguage(const std::string& language) = 0; /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; - //virtual SceneResourcePtr GetScene(const std::string& pk); + /** \brief import a scene using from scene identified by a URI + + \param importuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext + \param importformat The format of the imported file. Can be: + - mujincollada + - **wincaps** (DensoWave WINCAPS III) + - **rttoolbox** (Mitsubishi RT ToolBox) + - **x** (DirectX) + - **vrml** + - **stl** + \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae + */ + virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) = 0; }; class MUJINCLIENT_API WebResource @@ -199,7 +233,13 @@ class MUJINCLIENT_API WebResource } /// \brief gets an attribute of this web resource - std::string Get(const std::string& field); + virtual std::string Get(const std::string& field); + + /// \brief delete the resource and all its child resources + virtual void Delete(); + + /// \brief copy the resource and all its child resources to a new name + virtual void Copy(const std::string& newname, int options); private: ControllerClientPtr __controller; @@ -282,7 +322,8 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource /// /// \param usernamepassword user:password /// This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword); +/// \param url the URL of controller API, it needs to have a trailing slash +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/api/v1/"); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 79c63fff..ff7e999f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -46,13 +48,14 @@ namespace mujinclient { #define SKIP_PEER_VERIFICATION // temporary +//#define SKIP_HOSTNAME_VERIFICATION -class ControllerClientImpl : public ControllerClient +class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this { public: - ControllerClientImpl(const std::string& usernamepassword) + ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri) { - _baseuri = "https://controller.mujin.co.jp/api/v1/"; + _baseuri = baseuri; //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); @@ -72,15 +75,15 @@ class ControllerClientImpl : public ControllerClient curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0l); #endif -//#ifdef SKIP_HOSTNAME_VERIFICATION -// /* -// * If the site you're connecting to uses a different host name that what -// * they have mentioned in their server certificate's commonName (or -// * subjectAltName) fields, libcurl will refuse to connect. You can skip -// * this check, but this will make the connection less secure. -// */ -// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); -//#endif +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); if (res != CURLE_OK) { @@ -97,20 +100,37 @@ class ControllerClientImpl : public ControllerClient throw mujin_exception("failed to set write data"); } + // need to set the following? + //CURLOPT_COOKIE, CURLOPT_USERAGENT and CURLOPT_REFERER. + + _charset = "utf-8"; + _language = "en-us"; + _SetHTTPHeaders(); } + virtual ~ControllerClientImpl() { + //curl_slist_free_all(slist); // free the list again curl_easy_cleanup(_curl); } - virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) + virtual void SetCharacterEncoding(const std::string& newencoding) { + boost::mutex::scoped_lock lock(_mutex); + _charset = newencoding; + _SetHTTPHeaders(); + } + + virtual void SetLanguage(const std::string& language) + { + boost::mutex::scoped_lock lock(_mutex); + _language = language; + _SetHTTPHeaders(); } virtual void GetScenePrimaryKeys(std::vector& scenekeys) { - _Call("scene/?format=json&limit=0&fields=pk"); boost::property_tree::ptree pt; - boost::property_tree::read_json(_buffer, pt); + CallGet("scene/?format=json&limit=0&fields=pk", pt); boost::property_tree::ptree& objects = pt.get_child("objects"); scenekeys.resize(objects.size()); size_t i = 0; @@ -119,20 +139,69 @@ class ControllerClientImpl : public ControllerClient } } - void _Call(const std::string& relativeuri) { + virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) + { + boost::property_tree::ptree pt; + CallPost("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; + } + + void CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt) + { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + if (res != CURLE_OK) { + throw mujin_exception("curl_easy_perform failed"); + } + long http_code = 0; + curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if (res != CURLE_OK) { + throw mujin_exception("curl_easy_getinfo failed", MEC_HTTPClient); + } + if( http_code != 200 ) { + throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); + } + boost::property_tree::read_json(_buffer, pt); + } + + void CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt) + { boost::mutex::scoped_lock lock(_mutex); _uri = _baseuri; _uri += relativeuri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); _buffer.clear(); _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); CURLcode res = curl_easy_perform(_curl); if (res != CURLE_OK) { throw mujin_exception("curl_easy_perform failed"); } + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if (res != CURLE_OK) { + throw mujin_exception("curl_easy_getinfo failed", MEC_HTTPClient); + } + if( http_code != 200 ) { + throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); + } + std::string temp = _buffer.str(); + boost::property_tree::read_json(_buffer, pt); + // check if an error } - std::stringstream& GetBuffer() { + std::stringstream& GetBuffer() + { return _buffer; } @@ -147,28 +216,56 @@ class ControllerClientImpl : public ControllerClient return size * nmemb; } + void _SetHTTPHeaders() + { + _httpheaders = curl_slist_append(NULL, "Accept:"); + // set the header to only send json + std::string s = std::string("Content-Type: application/json; charset=") + _charset; + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); + s = str(boost::format("Accept-Language: %s,en-us")%_language); + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") + // test on windows first + //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); + } + + int _lastmode; CURL *_curl; boost::mutex _mutex; std::stringstream _buffer; std::string _baseuri, _uri; + + curl_slist *_httpheaders; + std::string _charset, _language; }; typedef boost::shared_ptr ControllerClientImplPtr; WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) { + BOOST_ASSERT(__pk.size()>0); } std::string WebResource::Get(const std::string& field) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field)); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt); + //boost::property_tree::read_json(controller->GetBuffer(), pt); std::string fieldvalue = pt.get(field); return fieldvalue; } +void WebResource::Delete() +{ + throw mujin_exception("not implemented yet"); +} + +void WebResource::Copy(const std::string& newname, int options) +{ + throw mujin_exception("not implemented yet"); +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { } @@ -176,9 +273,8 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskname) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%taskname)); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%taskname), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() == 0 ) { throw MUJIN_EXCEPTION_FORMAT("failed to get task %s from scene pk %s", taskname%GetPrimaryKey(), MEC_InvalidArguments); @@ -191,9 +287,9 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey())); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); + //boost::property_tree::read_json(controller->GetBuffer(), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); taskkeys.resize(objects.size()); size_t i = 0; @@ -218,9 +314,8 @@ JobStatus TaskResource::GetRunTimeStatus() { OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%optimizationname)); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%optimizationname), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() == 0 ) { throw MUJIN_EXCEPTION_FORMAT("failed to get optimization %s from task pk", optimizationname%GetPrimaryKey(), MEC_InvalidArguments); @@ -233,9 +328,8 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std: void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey())); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); optimizationkeys.resize(objects.size()); size_t i = 0; @@ -247,9 +341,8 @@ void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimiza PlanningResultResourcePtr TaskResource::GetResult() { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey())); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() == 0 ) { return PlanningResultResourcePtr(); @@ -275,9 +368,8 @@ JobStatus OptimizationResource::GetRunTimeStatus() { void OptimizationResource::GetResults(int fastestnum, std::vector& results) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("optimization/%s/result/?format=json&limit=%d&fields=pk&order_by=task_time")%GetPrimaryKey()%fastestnum)); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("optimization/%s/result/?format=json&limit=%d&fields=pk&order_by=task_time")%GetPrimaryKey()%fastestnum), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); results.resize(objects.size()); size_t i = 0; @@ -293,9 +385,8 @@ PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, c void PlanningResultResource::GetTransforms(std::map& transforms) { GETCONTROLLERIMPL(); - controller->_Call(str(boost::format("%s/%s/?format=json&fields=transformxml")%GetResourceName()%GetPrimaryKey())); boost::property_tree::ptree pt; - boost::property_tree::read_json(controller->GetBuffer(), pt); + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=transformxml")%GetResourceName()%GetPrimaryKey()), pt); std::stringstream sstrans(pt.get("transformxml")); boost::property_tree::ptree pttrans; boost::property_tree::read_xml(sstrans, pttrans); @@ -331,9 +422,9 @@ void PlanningResultResource::GetTransforms(std::map& tra } // transformxml -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl)); } void ControllerClientDestroy() From f23de3de89beaaf42fb92f2c04b848c6be155721 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 12 Jan 2013 15:36:56 +0900 Subject: [PATCH 012/477] better error checking --- src/mujincontrollerclient.cpp | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index ff7e999f..e1d5d255 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -27,7 +27,16 @@ #include #include +#ifdef _MSC_VER +#ifndef __PRETTY_FUNCTION__ +#define __PRETTY_FUNCTION__ __FUNCDNAME__ +#endif +#endif + #define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); +#define CHECKCURLCODE(code, msg) if (code != CURLE_OK) { \ + throw mujin_exception(str(boost::format("[%s:%d] curl function failed with error '%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%curl_easy_strerror(code)%(msg)), MEC_HTTPClient); \ +} #define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) @@ -48,7 +57,7 @@ namespace mujinclient { #define SKIP_PEER_VERIFICATION // temporary -//#define SKIP_HOSTNAME_VERIFICATION +#define SKIP_HOSTNAME_VERIFICATION class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this { @@ -86,19 +95,13 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share #endif res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); - if (res != CURLE_OK) { - throw mujin_exception("failed to set userpw"); - } - //densowave:Debpawm8 + CHECKCURLCODE(res, "failed to set userpw"); + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); - if (res != CURLE_OK) { - throw mujin_exception("failed to set writer"); - } + CHECKCURLCODE(res, "failed to set writer"); res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); - if (res != CURLE_OK) { - throw mujin_exception("failed to set write data"); - } + CHECKCURLCODE(res, "failed to set write data"); // need to set the following? //CURLOPT_COOKIE, CURLOPT_USERAGENT and CURLOPT_REFERER. @@ -158,14 +161,11 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _buffer.str(""); curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); CURLcode res = curl_easy_perform(_curl); - if (res != CURLE_OK) { - throw mujin_exception("curl_easy_perform failed"); - } + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; - curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - if (res != CURLE_OK) { - throw mujin_exception("curl_easy_getinfo failed", MEC_HTTPClient); - } + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); if( http_code != 200 ) { throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); } @@ -184,14 +184,10 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); CURLcode res = curl_easy_perform(_curl); - if (res != CURLE_OK) { - throw mujin_exception("curl_easy_perform failed"); - } + CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - if (res != CURLE_OK) { - throw mujin_exception("curl_easy_getinfo failed", MEC_HTTPClient); - } + CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( http_code != 200 ) { throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); } @@ -218,12 +214,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share void _SetHTTPHeaders() { - _httpheaders = curl_slist_append(NULL, "Accept:"); // set the header to only send json std::string s = std::string("Content-Type: application/json; charset=") + _charset; - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); + _httpheaders = curl_slist_append(NULL, s.c_str()); s = str(boost::format("Accept-Language: %s,en-us")%_language); _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") + //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // test on windows first //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); From e3cc9ac1ee0cd2d0bee59f9f319191652bce2bc9 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 12 Jan 2013 20:11:18 +0900 Subject: [PATCH 013/477] importing/deleting scenes now works --- .../mujincontrollerclient.h | 29 ++- src/mujincontrollerclient.cpp | 198 +++++++++++++++--- 2 files changed, 196 insertions(+), 31 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 59cd4004..1f5d7ef7 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -67,7 +67,7 @@ enum MujinErrorCode { MEC_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. MEC_Timeout=11, ///< process timed out MEC_HTTPClient=12, ///< HTTP client error - MEC_HTTPStatus=13, ///< http error status code + MEC_HTTPServer=13, ///< HTTP server error }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -82,7 +82,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_InvalidState: return "InvalidState"; case MEC_Timeout: return "Timeout"; case MEC_HTTPClient: return "HTTPClient"; - case MEC_HTTPStatus: return "HTTPStatus"; + case MEC_HTTPServer: return "HTTPServer"; } // should throw an exception? return ""; @@ -249,6 +249,23 @@ class MUJINCLIENT_API WebResource class MUJINCLIENT_API SceneResource : public WebResource { public: + /// \brief nested resource in the scene describe an object in the scene + class MUJINCLIENT_API InstObject : public WebResource + { +public: + InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk); + virtual ~InstObject() { + } + + std::vector dofvalues; + std::string name; + std::string object_pk; + std::string reference_uri; + Real rotate[4]; // quaternion + Real translate[3]; + }; + typedef boost::shared_ptr InstObjectPtr; + SceneResource(ControllerClientPtr controller, const std::string& pk); virtual ~SceneResource() { } @@ -260,6 +277,9 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); + + /// \brief gets a list of all the instance objects of the scene + virtual void GetInstObjects(std::vector& instobjects); }; class MUJINCLIENT_API TaskResource : public WebResource @@ -322,8 +342,9 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource /// /// \param usernamepassword user:password /// This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. -/// \param url the URL of controller API, it needs to have a trailing slash -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/api/v1/"); +/// \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. +/// \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/", int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index e1d5d255..5f066b55 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #ifdef _MSC_VER @@ -57,18 +58,23 @@ namespace mujinclient { #define SKIP_PEER_VERIFICATION // temporary -#define SKIP_HOSTNAME_VERIFICATION +//#define SKIP_HOSTNAME_VERIFICATION class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this { public: - ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri) + ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, int options) { _baseuri = baseuri; + _baseapiuri = baseuri + std::string("api/v1/"); //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); +#ifdef _DEBUG + curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); +#endif + CURLcode res; #ifdef SKIP_PEER_VERIFICATION /* @@ -94,21 +100,60 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif + res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + CHECKCURLCODE(res, "failed to set auth"); res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); CHECKCURLCODE(res, "failed to set userpw"); - res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); - CHECKCURLCODE(res, "failed to set writer"); - - res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); - CHECKCURLCODE(res, "failed to set write data"); - // need to set the following? - //CURLOPT_COOKIE, CURLOPT_USERAGENT and CURLOPT_REFERER. - + //CURLOPT_USERAGENT + //CURLOPT_TCP_KEEPIDLE + //CURLOPT_TCP_KEEPALIVE + //CURLOPT_TCP_KEEPINTVL + + curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine + + if( !(options & 1) ) { + size_t index = usernamepassword.find_first_of(':'); + BOOST_ASSERT(index != std::string::npos ); + + // make an initial GET call to get the CSRF token + std::string loginuri = _baseuri + "login/"; + curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( http_code != 200 ) { + throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%loginuri%http_code), MEC_HTTPServer); + } + _csrfmiddlewaretoken = _GetCSRFFromCookies(); + + std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); + //curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); + curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); + std::cout << "---performing post---" << std::endl; + res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 && http_code != 302) { + throw mujin_exception(str(boost::format("HTTP POST %s returned HTTP error code %s")%loginuri%http_code), MEC_HTTPServer); + } + } _charset = "utf-8"; _language = "en-us"; _SetHTTPHeaders(); + + // save everything to _buffer + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); + CHECKCURLCODE(res, "failed to set writer"); + res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); + CHECKCURLCODE(res, "failed to set write data"); } virtual ~ControllerClientImpl() { @@ -154,7 +199,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share void CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt) { boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri; + _uri = _baseapiuri; _uri += relativeuri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); _buffer.clear(); @@ -162,20 +207,23 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); - + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( http_code != 200 ) { - throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); + std::string error_message = pt.get("error_message"); + std::string traceback = pt.get("traceback"); + throw mujin_exception(str(boost::format("HTTP GET to '%s' returned HTTP status %s: %s")%relativeuri%http_code%error_message), MEC_HTTPServer); } - boost::property_tree::read_json(_buffer, pt); } void CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt) { boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri; + _uri = _baseapiuri; _uri += relativeuri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); _buffer.clear(); @@ -185,15 +233,34 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 ) { - throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%relativeuri%http_code), MEC_HTTPStatus); + if( http_code != 201 ) { // or 200 or 202 or 204? + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw mujin_exception(str(boost::format("HTTP POST to '%s' returned HTTP status %s: %s")%relativeuri%http_code%error_message), MEC_HTTPServer); + } + } + + void CallDelete(const std::string& relativeuri) { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + CURLcode res = curl_easy_perform(_curl); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 204 ) { // or 200 or 202 or 201? + throw mujin_exception(str(boost::format("HTTP DELETE to '%s' returned HTTP status %s")%relativeuri%http_code), MEC_HTTPServer); } - std::string temp = _buffer.str(); - boost::property_tree::read_json(_buffer, pt); - // check if an error } std::stringstream& GetBuffer() @@ -201,6 +268,17 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return _buffer; } + /* webdav operations + const char *postdata = + "" + "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" + " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " + "WHERE \"DAV:isfolder\" = True\r\n"; + + CURLOPT_UPLOAD + + */ + protected: static int _writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) @@ -219,20 +297,46 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _httpheaders = curl_slist_append(NULL, s.c_str()); s = str(boost::format("Accept-Language: %s,en-us")%_language); _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") - //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); + //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // necessary? + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); + _httpheaders = curl_slist_append(_httpheaders, "Connection: Keep-Alive"); + _httpheaders = curl_slist_append(_httpheaders, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); } + std::string _GetCSRFFromCookies() { + struct curl_slist *cookies; + CURLcode res = curl_easy_getinfo(_curl, CURLINFO_COOKIELIST, &cookies); + CHECKCURLCODE(res, "curl_easy_getinfo CURLINFO_COOKIELIST"); + struct curl_slist *nc = cookies; + int i = 1; + std::string csrfmiddlewaretoken; + while (nc) { + std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; + char* csrftokenstart = strstr(nc->data, "csrftoken"); + if( !!csrftokenstart ) { + std::stringstream ss(csrftokenstart+10); + ss >> csrfmiddlewaretoken; + } + nc = nc->next; + i++; + } + curl_slist_free_all(cookies); + return csrfmiddlewaretoken; + } + int _lastmode; CURL *_curl; boost::mutex _mutex; std::stringstream _buffer; - std::string _baseuri, _uri; + std::string _baseuri, _baseapiuri, _uri; curl_slist *_httpheaders; std::string _charset, _language; + std::string _csrfmiddlewaretoken; }; typedef boost::shared_ptr ControllerClientImplPtr; @@ -247,14 +351,14 @@ std::string WebResource::Get(const std::string& field) GETCONTROLLERIMPL(); boost::property_tree::ptree pt; controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt); - //boost::property_tree::read_json(controller->GetBuffer(), pt); std::string fieldvalue = pt.get(field); return fieldvalue; } void WebResource::Delete() { - throw mujin_exception("not implemented yet"); + GETCONTROLLERIMPL(); + controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey())); } void WebResource::Copy(const std::string& newname, int options) @@ -262,6 +366,10 @@ void WebResource::Copy(const std::string& newname, int options) throw mujin_exception("not implemented yet"); } +SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) +{ +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { } @@ -285,7 +393,6 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) GETCONTROLLERIMPL(); boost::property_tree::ptree pt; controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - //boost::property_tree::read_json(controller->GetBuffer(), pt); boost::property_tree::ptree& objects = pt.get_child("objects"); taskkeys.resize(objects.size()); size_t i = 0; @@ -294,6 +401,43 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) } } +void SceneResource::GetInstObjects(std::vector& instobjects) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("instobjects"); + instobjects.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); + //instobject->dofvalues + instobject->name = v.second.get("name"); + instobject->object_pk = v.second.get("object_pk"); + instobject->reference_uri = v.second.get("reference_uri"); + + boost::property_tree::ptree& jsondofvalues = v.second.get_child("dofvalues"); + instobject->dofvalues.resize(jsondofvalues.size()); + size_t idof = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vdof, jsondofvalues) { + instobject->dofvalues[idof++] = boost::lexical_cast(vdof.second.data()); + } + + size_t irotate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vrotate, v.second.get_child("rotate")) { + BOOST_ASSERT( irotate < 4 ); + instobject->rotate[irotate++] = boost::lexical_cast(vrotate.second.data()); + } + size_t itranslate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + instobject->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + } + + instobjects[i++] = instobject; + } +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } @@ -418,9 +562,9 @@ void PlanningResultResource::GetTransforms(std::map& tra } // transformxml -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, int options) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, options)); } void ControllerClientDestroy() From f948b436e68556a8fe4a5fab8891a98f3e7da945 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 12 Jan 2013 20:35:02 +0900 Subject: [PATCH 014/477] moved samples --- src/mujincontrollerclient.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5f066b55..9c8064fc 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -113,12 +113,18 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine + // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); + CHECKCURLCODE(res, "failed to set writer"); + res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); + CHECKCURLCODE(res, "failed to set write data"); + if( !(options & 1) ) { size_t index = usernamepassword.find_first_of(':'); BOOST_ASSERT(index != std::string::npos ); // make an initial GET call to get the CSRF token - std::string loginuri = _baseuri + "login/"; + std::string loginuri = _baseuri + "api/v1/"; //"login/"; curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); CURLcode res = curl_easy_perform(_curl); @@ -126,7 +132,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code != 200 ) { + if( http_code != 200 && http_code != 302 ) { throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%loginuri%http_code), MEC_HTTPServer); } _csrfmiddlewaretoken = _GetCSRFFromCookies(); @@ -135,7 +141,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share //curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); - std::cout << "---performing post---" << std::endl; + //std::cout << "---performing post---" << std::endl; res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); http_code = 0; @@ -148,12 +154,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _charset = "utf-8"; _language = "en-us"; _SetHTTPHeaders(); - - // save everything to _buffer - res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); - CHECKCURLCODE(res, "failed to set writer"); - res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); - CHECKCURLCODE(res, "failed to set write data"); } virtual ~ControllerClientImpl() { @@ -315,7 +315,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share int i = 1; std::string csrfmiddlewaretoken; while (nc) { - std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; + //std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; char* csrftokenstart = strstr(nc->data, "csrftoken"); if( !!csrftokenstart ) { std::stringstream ss(csrftokenstart+10); From 779466e50488143e59f206dd161552e73e2bf66b Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 13 Jan 2013 15:09:45 +0900 Subject: [PATCH 015/477] changed result test --- include/mujincontrollerclient/mujincontrollerclient.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1f5d7ef7..fcacf1ae 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -204,12 +204,13 @@ class MUJINCLIENT_API ControllerClient \param importuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext \param importformat The format of the imported file. Can be: - - mujincollada + - **mujincollada** - **wincaps** (DensoWave WINCAPS III) - **rttoolbox** (Mitsubishi RT ToolBox) - **x** (DirectX) - **vrml** - **stl** + - **cecvirfitxml** (CEC Virfit XML environments) \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) = 0; From 4f5b957abe373329490d52f4b905c719e61a1762 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 13 Jan 2013 19:22:11 +0900 Subject: [PATCH 016/477] work towards api to execute tasks --- .../mujincontrollerclient.h | 121 +++++++++++---- src/mujincontrollerclient.cpp | 141 +++++++++++++----- 2 files changed, 203 insertions(+), 59 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index fcacf1ae..0671a539 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -60,7 +60,6 @@ namespace mujinclient { enum MujinErrorCode { MEC_Failed=0, MEC_InvalidArguments=1, ///< passed in input arguments are not valid - MEC_EnvironmentNotLocked=2, MEC_CommandNotSupported=3, ///< string command could not be parsed or is not supported MEC_Assert=4, MEC_NotInitialized=9, ///< when object is used without it getting fully initialized @@ -75,7 +74,6 @@ inline const char* GetErrorCodeString(MujinErrorCode error) switch(error) { case MEC_Failed: return "Failed"; case MEC_InvalidArguments: return "InvalidArguments"; - case MEC_EnvironmentNotLocked: return "EnvironmentNotLocked"; case MEC_CommandNotSupported: return "CommandNotSupported"; case MEC_Assert: return "Assert"; case MEC_NotInitialized: return "NotInitialized"; @@ -90,19 +88,19 @@ inline const char* GetErrorCodeString(MujinErrorCode error) /// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. -class MUJINCLIENT_API mujin_exception : public std::exception +class MUJINCLIENT_API MujinException : public std::exception { public: - mujin_exception() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { + MujinException() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { } - mujin_exception(const std::string& s, MujinErrorCode error=MEC_Failed) : std::exception() { + MujinException(const std::string& s, MujinErrorCode error=MEC_Failed) : std::exception() { _error = error; _s = "mujin ("; _s += GetErrorCodeString(_error); _s += "): "; _s += s; } - virtual ~mujin_exception() throw() { + virtual ~MujinException() throw() { } char const* what() const throw() { return _s.c_str(); @@ -136,11 +134,28 @@ typedef boost::shared_ptr PlanningResultResourcePtr; typedef boost::weak_ptr PlanningResultResourceWeakPtr; typedef double Real; +/// \brief status code for a job +/// +/// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html +enum JobStatusCode { + JSC_Pending = 0, ///< The goal has yet to be processed + JSC_Active = 1, ///< The goal is currently being processed + JSC_Preempted = 2, ///< The goal received a cancel request after it started executing and has since completed its execution. + JSC_Succeeded = 3, ///< The goal was achieved successfully. + JSC_Aborted = 4, ///< The goal was aborted during execution due to some failure + JSC_Rejected = 5, ///< The goal was rejected without being processed, because the goal was unattainable or invalid. + JSC_Preempting = 6, ///< The goal received a cancel request after it started executing and has not yet completed execution + JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. + JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled + JSC_Lost = 9, ///< An unknokwn error happened and the job stopped being tracked. + JSC_Unknown = 0xffffffff, +}; + struct JobStatus { - JobStatus() : code(0) { + JobStatus() : code(JSC_Unknown) { } - int code; ///< if 3, succeeded + JobStatusCode code; std::string message; }; @@ -163,6 +178,29 @@ struct SceneInformation std::string name; }; +/// \brief holds information about the itlplanning task goal +struct ITLPlanningTaskInfo +{ + ITLPlanningTaskInfo() { + SetDefaults(); + } + inline void SetDefaults() { + startfromcurrent = 0; + returntostart = 1; + usevrc = 1; + unit = "mm"; + outputtrajtype = "robotmaker"; + optimizationvalue = 1; + } + int startfromcurrent; + int returntostart; + int usevrc; + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + std::string outputtrajtype; ///< what format to output the trajectory in. + Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) + std::string program; ///< itl program +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -197,6 +235,17 @@ class MUJINCLIENT_API ControllerClient /// Checkout http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; + /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. + /// + /// If the server is not responding, call this method to clear the server state and initialize everything. + /// The method is blocking, when it returns the MUJIN Controller would have been restarted. + virtual void RestartServer() = 0; + + /// \brief sends the cancel message to all jobs. + /// + /// The method is non-blocking + virtual void CancelAllJobs() = 0; + /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; @@ -236,6 +285,9 @@ class MUJINCLIENT_API WebResource /// \brief gets an attribute of this web resource virtual std::string Get(const std::string& field); + /// \brief sets an attribute of this web resource + virtual void Set(const std::string& field, const std::string& newvalue); + /// \brief delete the resource and all its child resources virtual void Delete(); @@ -271,10 +323,13 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~SceneResource() { } - /// \brief Gets or creates the a task part of the scene - /// - /// \param taskname the name of the task to search for or create - virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname); + /** \brief Gets or creates the a task part of the scene + + \param taskname the name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown + \param tasktype The type of task to create. Supported types are: + - itlplanning + */ + virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype=std::string("itlplanning")); /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); @@ -290,11 +345,13 @@ class MUJINCLIENT_API TaskResource : public WebResource virtual ~TaskResource() { } - /// \brief execute the task + /// \brief execute the task. + /// + /// This operation is non-blocking and will return immediately after the execution is started. In order to check if the task is running or is complete, use \ref GetRunTimeStatus() and \ref GetResult() virtual void Execute(); - /// \brief get the run-time status of the executed task - virtual JobStatus GetRunTimeStatus(); + /// \brief get the run-time status of the executed task. + virtual void GetRunTimeStatus(JobStatus& status); /// \brief Gets or creates the a optimization part of the scene /// @@ -304,6 +361,12 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); + /// \brief Get the task info for tasks of type itlplanning + virtual void GetTaskInfo(ITLPlanningTaskInfo& taskinfo); + + /// \brief Set new task info for tasks of type itlplanning + virtual void SetTaskInfo(const ITLPlanningTaskInfo& taskinfo); + /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. virtual PlanningResultResourcePtr GetResult(); }; @@ -318,8 +381,8 @@ class MUJINCLIENT_API OptimizationResource : public WebResource /// \brief execute the optimization virtual void Execute(); - /// \brief get the run-time status of the executed optimization - virtual JobStatus GetRunTimeStatus(); + /// \brief get the run-time status of the executed optimization. + virtual void GetRunTimeStatus(JobStatus& status); /// \brief gets the fastest results of the optimization execution. /// @@ -339,12 +402,20 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource }; -/// \brief creates the controller with an account. -/// -/// \param usernamepassword user:password -/// This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. -/// \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. -/// \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls +/** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + */ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/", int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources @@ -377,13 +448,13 @@ namespace boost { inline void assertion_failed(char const * expr, char const * function, char const * file, long line) { - throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::MEC_Assert); + throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::MEC_Assert); } #if BOOST_VERSION>104600 inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) { - throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::MEC_Assert); + throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::MEC_Assert); } #endif diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9c8064fc..28c9df2d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -36,24 +36,24 @@ #define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); #define CHECKCURLCODE(code, msg) if (code != CURLE_OK) { \ - throw mujin_exception(str(boost::format("[%s:%d] curl function failed with error '%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%curl_easy_strerror(code)%(msg)), MEC_HTTPClient); \ + throw MujinException(str(boost::format("[%s:%d] curl function failed with error '%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%curl_easy_strerror(code)%(msg)), MEC_HTTPClient); \ } -#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) +#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) /// adds the function name and line number to an exception -#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) +#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) -#define MUJIN_ASSERT_FORMAT(testexpr, s, args, errorcode) { if( !(testexpr) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)%args),errorcode); } } +#define MUJIN_ASSERT_FORMAT(testexpr, s, args, errorcode) { if( !(testexpr) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)%args),errorcode); } } -#define MUJIN_ASSERT_FORMAT0(testexpr, s, errorcode) { if( !(testexpr) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)),errorcode); } } +#define MUJIN_ASSERT_FORMAT0(testexpr, s, errorcode) { if( !(testexpr) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)),errorcode); } } // note that expr1 and expr2 will be evaluated twice if not equal -#define MUJIN_ASSERT_OP_FORMAT(expr1,op,expr2,s, args, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)%args),errorcode); } } +#define MUJIN_ASSERT_OP_FORMAT(expr1,op,expr2,s, args, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)%args),errorcode); } } -#define MUJIN_ASSERT_OP_FORMAT0(expr1,op,expr2,s, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),errorcode); } } +#define MUJIN_ASSERT_OP_FORMAT0(expr1,op,expr2,s, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),errorcode); } } -#define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::mujin_exception(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } +#define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } namespace mujinclient { @@ -133,7 +133,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( http_code != 200 && http_code != 302 ) { - throw mujin_exception(str(boost::format("HTTP GET %s returned HTTP error code %s")%loginuri%http_code), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); } _csrfmiddlewaretoken = _GetCSRFFromCookies(); @@ -148,7 +148,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( http_code != 200 && http_code != 302) { - throw mujin_exception(str(boost::format("HTTP POST %s returned HTTP error code %s")%loginuri%http_code), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); } } _charset = "utf-8"; @@ -175,6 +175,16 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _SetHTTPHeaders(); } + virtual void RestartServer() + { + throw MujinException("not implemented"); + } + + virtual void CancelAllJobs() + { + throw MujinException("not implemented"); + } + virtual void GetScenePrimaryKeys(std::vector& scenekeys) { boost::property_tree::ptree pt; @@ -196,7 +206,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return scene; } - void CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt) + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode=200) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -213,14 +224,16 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code != 200 ) { + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message"); std::string traceback = pt.get("traceback"); - throw mujin_exception(str(boost::format("HTTP GET to '%s' returned HTTP status %s: %s")%relativeuri%http_code%error_message), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } + return http_code; } - void CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt) + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode=201) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -239,14 +252,16 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 201 ) { // or 200 or 202 or 204? + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); - throw mujin_exception(str(boost::format("HTTP POST to '%s' returned HTTP status %s: %s")%relativeuri%http_code%error_message), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } + return http_code; } - void CallDelete(const std::string& relativeuri) { + void CallDelete(const std::string& relativeuri) + { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; @@ -259,7 +274,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( http_code != 204 ) { // or 200 or 202 or 201? - throw mujin_exception(str(boost::format("HTTP DELETE to '%s' returned HTTP status %s")%relativeuri%http_code), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); } } @@ -355,6 +370,11 @@ std::string WebResource::Get(const std::string& field) return fieldvalue; } +void WebResource::Set(const std::string& field, const std::string& newvalue) +{ + throw MujinException("not implemented"); +} + void WebResource::Delete() { GETCONTROLLERIMPL(); @@ -363,7 +383,7 @@ void WebResource::Delete() void WebResource::Copy(const std::string& newname, int options) { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); } SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) @@ -374,17 +394,25 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& { } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskname) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%taskname), pt); + int http_code = controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); + // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { - throw MUJIN_EXCEPTION_FORMAT("failed to get task %s from scene pk %s", taskname%GetPrimaryKey(), MEC_InvalidArguments); + if( objects.size() > 0 ) { + std::string pk = objects.begin()->second.get("pk"); + std::string currenttasktype = objects.begin()->second.get("tasktype"); + if( currenttasktype != tasktype ) { + throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype, MEC_InvalidState); + } + TaskResourcePtr task(new TaskResource(GetController(), pk)); + return task; } - std::string pk = objects.begin()->second.get("pk"); - TaskResourcePtr task(new TaskResource(GetController(), pk)); + throw MujinException("not implemented"); + // create a new task + TaskResourcePtr task(new TaskResource(GetController(), "")); return task; } @@ -444,11 +472,12 @@ TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk void TaskResource::Execute() { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); } -JobStatus TaskResource::GetRunTimeStatus() { - throw mujin_exception("not implemented yet"); +void TaskResource::GetRunTimeStatus(JobStatus& status) +{ + throw MujinException("not implemented yet"); } OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname) @@ -478,6 +507,50 @@ void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimiza } } +void TaskResource::GetTaskInfo(ITLPlanningTaskInfo& taskinfo) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskgoalxml&tasktype")%GetPrimaryKey()), pt); + std::string tasktype = pt.get("tasktype"); + if( tasktype != "itlplanning" ) { + throw MUJIN_EXCEPTION_FORMAT("task %s is type %s, expected itlplanning", GetPrimaryKey()%tasktype, MEC_InvalidArguments); + } + std::stringstream sstrans(pt.get("taskgoalxml")); + boost::property_tree::ptree pttrans; + boost::property_tree::read_xml(sstrans, pttrans); + boost::property_tree::ptree& objects = pttrans.get_child("root"); + taskinfo.SetDefaults(); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + if( v.first == "startfromcurrent" ) { + taskinfo.startfromcurrent = v.second.data() == std::string("True"); + } + else if( v.first == "returntostart" ) { + taskinfo.returntostart = v.second.data() == std::string("True"); + } + else if( v.first == "usevrc" ) { + taskinfo.usevrc = v.second.data() == std::string("True"); + } + else if( v.first == "unit" ) { + taskinfo.unit = v.second.data(); + } + else if( v.first == "outputtrajtype" ) { + taskinfo.outputtrajtype = v.second.data(); + } + else if( v.first == "optimizationvalue" ) { + taskinfo.optimizationvalue = boost::lexical_cast(v.second.data()); + } + else if( v.first == "program" ) { + taskinfo.program = v.second.data(); + } + } +} + +void TaskResource::SetTaskInfo(const ITLPlanningTaskInfo& taskinfo) +{ + +} + PlanningResultResourcePtr TaskResource::GetResult() { GETCONTROLLERIMPL(); @@ -498,11 +571,11 @@ OptimizationResource::OptimizationResource(ControllerClientPtr controller, const void OptimizationResource::Execute() { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); } -JobStatus OptimizationResource::GetRunTimeStatus() { - throw mujin_exception("not implemented yet"); +void OptimizationResource::GetRunTimeStatus(JobStatus& status) { + throw MujinException("not implemented yet"); } void OptimizationResource::GetResults(int fastestnum, std::vector& results) @@ -573,7 +646,7 @@ void ControllerClientDestroy() void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); // length2 = numpy.sum(quat**2) // ilength2 = 2.0/length2 // qq1 = ilength2*quat[1]*quat[1] @@ -593,7 +666,7 @@ void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) void ComputeZXYFromMatrix(Real ZXY[3], Real matrix[12]) { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); // if abs(T[2][0]) < 1e-10 and abs(T[2][2]) < 1e-10: // sinx = T[2][1] // x = numpy.pi/2 if sinx > 0 else -numpy.pi/2 @@ -612,7 +685,7 @@ void ComputeZXYFromMatrix(Real ZXY[3], Real matrix[12]) void ComputeZXYFromTransform(Real ZXY[3], const Transform& transform) { - throw mujin_exception("not implemented yet"); + throw MujinException("not implemented yet"); //zxyFromMatrix(matrixFromTransform()) } From 5c9a9accecb178553f2b356e374e6a36549c1979 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 15 Jan 2013 02:14:59 +0900 Subject: [PATCH 017/477] implemented task execution --- .../mujincontrollerclient.h | 15 +- src/mujincontrollerclient.cpp | 213 +++++++++++++++--- 2 files changed, 190 insertions(+), 38 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 0671a539..ba332e76 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -67,6 +67,7 @@ enum MujinErrorCode { MEC_Timeout=11, ///< process timed out MEC_HTTPClient=12, ///< HTTP client error MEC_HTTPServer=13, ///< HTTP server error + MEC_UserAuthentication=14, ///< authentication failed }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -81,6 +82,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_Timeout: return "Timeout"; case MEC_HTTPClient: return "HTTPClient"; case MEC_HTTPServer: return "HTTPServer"; + case MEC_UserAuthentication: return "UserAuthentication"; } // should throw an exception? return ""; @@ -147,8 +149,8 @@ enum JobStatusCode { JSC_Preempting = 6, ///< The goal received a cancel request after it started executing and has not yet completed execution JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled - JSC_Lost = 9, ///< An unknokwn error happened and the job stopped being tracked. - JSC_Unknown = 0xffffffff, + JSC_Lost = 9, ///< An error happened and the job stopped being tracked. + JSC_Unknown = 0xffffffff, ///< the job is }; struct JobStatus @@ -192,9 +194,9 @@ struct ITLPlanningTaskInfo outputtrajtype = "robotmaker"; optimizationvalue = 1; } - int startfromcurrent; - int returntostart; - int usevrc; + int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. + int returntostart; ///< Plan the return path of the robot to where the entire trajectory started. Makes it possible to loop the robot motion. + int usevrc; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc std::string outputtrajtype; ///< what format to output the trajectory in. Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) @@ -241,6 +243,9 @@ class MUJINCLIENT_API ControllerClient /// The method is blocking, when it returns the MUJIN Controller would have been restarted. virtual void RestartServer() = 0; + /// \brief returns the mujin controller version + virtual std::string GetVersion() = 0; + /// \brief sends the cancel message to all jobs. /// /// The method is non-blocking diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 28c9df2d..2bb3027a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -57,6 +57,42 @@ namespace mujinclient { +static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) +{ + return p0.first.size() > p1.first.size(); +} + +static std::string& SearchAndReplace(std::string& out, const std::string& in, const std::vector< std::pair >&_pairs) +{ + BOOST_ASSERT(&out != &in); + std::vector< std::pair >::const_iterator itp, itbestp; + for(itp = _pairs.begin(); itp != _pairs.end(); ++itp) { + BOOST_ASSERT(itp->first.size()>0); + } + std::vector< std::pair > pairs = _pairs; + stable_sort(pairs.begin(),pairs.end(),PairStringLengthCompare); + out.resize(0); + size_t startindex = 0; + while(startindex < in.size()) { + size_t nextindex=std::string::npos; + for(itp = pairs.begin(); itp != pairs.end(); ++itp) { + size_t index = in.find(itp->first,startindex); + if((nextindex == std::string::npos)|| ((index != std::string::npos)&&(index < nextindex)) ) { + nextindex = index; + itbestp = itp; + } + } + if( nextindex == std::string::npos ) { + out += in.substr(startindex); + break; + } + out += in.substr(startindex,nextindex-startindex); + out += itbestp->second; + startindex = nextindex+itbestp->first.size(); + } + return out; +} + #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION @@ -65,6 +101,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share public: ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, int options) { + _httpheaders = NULL; _baseuri = baseuri; _baseapiuri = baseuri + std::string("api/v1/"); //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); @@ -119,12 +156,21 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); CHECKCURLCODE(res, "failed to set write data"); + std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; + res = curl_easy_setopt(_curl, CURLOPT_USERAGENT, useragent.c_str()); + CHECKCURLCODE(res, "failed to set user-agent"); + + res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 0); // do not bounce through pages since we need to detect when login sessions expired + CHECKCURLCODE(res, "failed to set follow location"); + res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); + CHECKCURLCODE(res, "failed to max redirs"); + if( !(options & 1) ) { size_t index = usernamepassword.find_first_of(':'); BOOST_ASSERT(index != std::string::npos ); // make an initial GET call to get the CSRF token - std::string loginuri = _baseuri + "api/v1/"; //"login/"; + std::string loginuri = _baseuri + "login/"; curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); CURLcode res = curl_easy_perform(_curl); @@ -132,32 +178,67 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code != 200 && http_code != 302 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); + if( http_code == 302 ) { + // most likely apache2-only authentication and login page isn't needed, however need to send another GET for the csrftoken + std::string loginuri = _baseuri + "api/v1/"; + curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); + } + _csrfmiddlewaretoken = _GetCSRFFromCookies(); } - _csrfmiddlewaretoken = _GetCSRFFromCookies(); - - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); - //curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); - curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); - //std::cout << "---performing post---" << std::endl; - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 && http_code != 302) { - throw MUJIN_EXCEPTION_FORMAT("HTTP POST %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); + else if( http_code == 200 ) { + _csrfmiddlewaretoken = _GetCSRFFromCookies(); + + std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); + //curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); + curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); + //std::cout << "---performing post---" << std::endl; + res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 302 ) { + throw MUJIN_EXCEPTION_FORMAT("User login failed. HTTP POST %s returned HTTP status %s", loginuri%http_code, MEC_UserAuthentication); + } + curl_easy_setopt(_curl, CURLOPT_REFERER, NULL); + } + else { + throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); } } + _charset = "utf-8"; _language = "en-us"; _SetHTTPHeaders(); + + try { + GetProfile(); + } + catch(const MujinException& ex) { + // most likely username or password are + throw MujinException(str(boost::format("failed to get controller profile, check username/password or if controller is active at %s")%_baseuri), MEC_UserAuthentication); + } + } + + std::string GetVersion() + { + return _profile.get("version"); } virtual ~ControllerClientImpl() { - //curl_slist_free_all(slist); // free the list again + if( !!_httpheaders ) { + curl_slist_free_all(_httpheaders); + } curl_easy_cleanup(_curl); } @@ -177,12 +258,24 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share virtual void RestartServer() { - throw MujinException("not implemented"); + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri + std::string("ajax/restartserver/");; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); + } } virtual void CancelAllJobs() { - throw MujinException("not implemented"); + CallDelete("job/?format=json"); } virtual void GetScenePrimaryKeys(std::vector& scenekeys) @@ -218,15 +311,15 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); - if( _buffer.rdbuf()->in_avail() > 0 ) { - boost::property_tree::read_json(_buffer, pt); - } long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message"); - std::string traceback = pt.get("traceback"); + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } return http_code; @@ -242,16 +335,42 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _buffer.clear(); _buffer.str(""); curl_easy_setopt(_curl, CURLOPT_POST, 1); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( _buffer.rdbuf()->in_avail() > 0 ) { boost::property_tree::read_json(_buffer, pt); } + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + return http_code; + } + + int CallPut(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode=202) + { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); + CURLcode res = curl_easy_perform(_curl); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default + CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); @@ -296,6 +415,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share protected: + void GetProfile() + { + _profile.clear(); + CallGet("profile/", _profile); + } + static int _writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) { if (writerData == NULL) { @@ -309,6 +434,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share { // set the header to only send json std::string s = std::string("Content-Type: application/json; charset=") + _charset; + if( !!_httpheaders ) { + curl_slist_free_all(_httpheaders); + } _httpheaders = curl_slist_append(NULL, s.c_str()); s = str(boost::format("Accept-Language: %s,en-us")%_language); _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") @@ -352,6 +480,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_slist *_httpheaders; std::string _charset, _language; std::string _csrfmiddlewaretoken; + + boost::property_tree::ptree _profile; ///< user profile and versioning }; typedef boost::shared_ptr ControllerClientImplPtr; @@ -398,7 +528,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - int http_code = controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() > 0 ) { @@ -410,9 +540,11 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna TaskResourcePtr task(new TaskResource(GetController(), pk)); return task; } - throw MujinException("not implemented"); - // create a new task - TaskResourcePtr task(new TaskResource(GetController(), "")); + + pt.clear(); + controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype%GetPrimaryKey()), pt); + std::string pk = pt.get("pk"); + TaskResourcePtr task(new TaskResource(GetController(), pk)); return task; } @@ -472,7 +604,9 @@ TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk void TaskResource::Execute() { - throw MujinException("not implemented yet"); + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt); } void TaskResource::GetRunTimeStatus(JobStatus& status) @@ -548,7 +682,20 @@ void TaskResource::GetTaskInfo(ITLPlanningTaskInfo& taskinfo) void TaskResource::SetTaskInfo(const ITLPlanningTaskInfo& taskinfo) { - + GETCONTROLLERIMPL(); + std::string startfromcurrent = taskinfo.startfromcurrent ? "True" : "False"; + std::string usevrc = taskinfo.usevrc ? "True" : "False"; + std::string returntostart = taskinfo.returntostart ? "True" : "False"; + + // because program will inside string, encode newlines + std::string program; + std::vector< std::pair > serachpairs(2); + serachpairs[0].first = "\n"; serachpairs[0].second = "\\n"; + serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; + SearchAndReplace(program, taskinfo.program, serachpairs); + std::string taskgoalput = str(boost::format("{\"taskgoalxml\":\"%s%s%s%f%s%s%s\"}")%taskinfo.outputtrajtype%program%taskinfo.unit%taskinfo.optimizationvalue%startfromcurrent%usevrc%returntostart); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } PlanningResultResourcePtr TaskResource::GetResult() From 9b09d8562ee9cd9710bd15ff8274a5cf9f3177c6 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 15 Jan 2013 02:26:12 +0900 Subject: [PATCH 018/477] task execution fixes --- src/mujincontrollerclient.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 2bb3027a..6e9c362d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -198,7 +198,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _csrfmiddlewaretoken = _GetCSRFFromCookies(); std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); - //curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); //std::cout << "---performing post---" << std::endl; @@ -262,6 +262,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _uri = _baseuri + std::string("ajax/restartserver/");; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -335,6 +336,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _buffer.clear(); _buffer.str(""); curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -361,6 +363,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _buffer.clear(); _buffer.str(""); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); CURLcode res = curl_easy_perform(_curl); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default @@ -606,7 +609,7 @@ void TaskResource::Execute() { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt); + controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt, 200); } void TaskResource::GetRunTimeStatus(JobStatus& status) From 8357127fe0fbf16beaa67f30e6213c133bd66b5f Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 15 Jan 2013 02:56:28 +0900 Subject: [PATCH 019/477] fixed using https --- src/mujincontrollerclient.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 6e9c362d..479053cd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -180,23 +180,21 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share CHECKCURLCODE(res, "curl_easy_getinfo"); if( http_code == 302 ) { // most likely apache2-only authentication and login page isn't needed, however need to send another GET for the csrftoken - std::string loginuri = _baseuri + "api/v1/"; + loginuri = _baseuri + "api/v1/"; // pick some neutral page that is easy to load curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( http_code != 200 ) { throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); } _csrfmiddlewaretoken = _GetCSRFFromCookies(); + curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); // necessary for SSL to work } else if( http_code == 200 ) { _csrfmiddlewaretoken = _GetCSRFFromCookies(); - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); @@ -207,10 +205,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 302 ) { + if( http_code != 200 && http_code != 302 ) { throw MUJIN_EXCEPTION_FORMAT("User login failed. HTTP POST %s returned HTTP status %s", loginuri%http_code, MEC_UserAuthentication); } - curl_easy_setopt(_curl, CURLOPT_REFERER, NULL); } else { throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); From b2fb58b0bf34be7fa370b81bd75ab22b0a7b9262 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 15 Jan 2013 03:25:56 +0900 Subject: [PATCH 020/477] added optimization stuff --- .../mujincontrollerclient.h | 35 +++++++++++++++++-- src/mujincontrollerclient.cpp | 35 +++++++++++++++---- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ba332e76..a4a2c19d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -193,6 +193,7 @@ struct ITLPlanningTaskInfo unit = "mm"; outputtrajtype = "robotmaker"; optimizationvalue = 1; + program.clear(); } int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. int returntostart; ///< Plan the return path of the robot to where the entire trajectory started. Makes it possible to loop the robot motion. @@ -203,6 +204,31 @@ struct ITLPlanningTaskInfo std::string program; ///< itl program }; +struct RobotPlacementOptimizationInfo +{ + RobotPlacementOptimizationInfo() { + SetDefaults(); + } + inline void SetDefaults() { + name.clear(); + frame = "0 robot"; + unit = "mm"; + minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; + maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; + stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; + ignorebasecollision = 1; + maxstorecandidates = 0; + } + std::string name; ///< what to optimize + std::string frame; ///< The frame to define the optimization parameters in + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + Real maxrange[4]; ///< X, Y, Z, Angle (deg) + Real minrange[4]; ///< X, Y, Z, Angle (deg) + Real stepsize[4]; ///< X, Y, Z, Angle (deg) + int ignorebasecollision; ///< When moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. + int maxstorecandidates; ///< The candidates are first ordered and then the top N are stored. If 0, then everything is stored +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -361,15 +387,15 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief Gets or creates the a optimization part of the scene /// /// \param optimizationname the name of the optimization to search for or create - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName(const std::string& optimizationname); + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); - /// \brief Get the task info for tasks of type itlplanning + /// \brief Get the task info for tasks of type itlplanning virtual void GetTaskInfo(ITLPlanningTaskInfo& taskinfo); - /// \brief Set new task info for tasks of type itlplanning + /// \brief Set new task info for tasks of type itlplanning virtual void SetTaskInfo(const ITLPlanningTaskInfo& taskinfo); /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. @@ -386,6 +412,9 @@ class MUJINCLIENT_API OptimizationResource : public WebResource /// \brief execute the optimization virtual void Execute(); + /// \brief Set new task info for tasks of type robotplanning + void SetOptimizationInfo(const RobotPlacementOptimizationInfo& optimizationinfo); + /// \brief get the run-time status of the executed optimization. virtual void GetRunTimeStatus(JobStatus& status); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 479053cd..7ca44a23 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -221,7 +221,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share try { GetProfile(); } - catch(const MujinException& ex) { + catch(const MujinException&) { // most likely username or password are throw MujinException(str(boost::format("failed to get controller profile, check username/password or if controller is active at %s")%_baseuri), MEC_UserAuthentication); } @@ -614,16 +614,26 @@ void TaskResource::GetRunTimeStatus(JobStatus& status) throw MujinException("not implemented yet"); } -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname) +OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname, const std::string& optimizationtype) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk")%GetPrimaryKey()%optimizationname), pt); + controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%optimizationname), pt); + // optimization exists boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { - throw MUJIN_EXCEPTION_FORMAT("failed to get optimization %s from task pk", optimizationname%GetPrimaryKey(), MEC_InvalidArguments); + if( objects.size() > 0 ) { + std::string pk = objects.begin()->second.get("pk"); + std::string currentoptimizationtype = objects.begin()->second.get("optimizationtype"); + if( currentoptimizationtype != optimizationtype ) { + throw MUJIN_EXCEPTION_FORMAT("optimization pk %s exists and has type %s, expected is %s", pk%currentoptimizationtype%optimizationtype, MEC_InvalidState); + } + OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); + return optimization; } - std::string pk = objects.begin()->second.get("pk"); + + pt.clear(); + controller->CallPost(str(boost::format("task/%s/optimization/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"optimizationtype\":\"%s\", \"taskpk\":\"%s\"}")%optimizationname%optimizationtype%GetPrimaryKey()), pt); + std::string pk = pt.get("pk"); OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); return optimization; } @@ -718,13 +728,24 @@ OptimizationResource::OptimizationResource(ControllerClientPtr controller, const void OptimizationResource::Execute() { - throw MujinException("not implemented yet"); + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), std::string(), pt, 200); } void OptimizationResource::GetRunTimeStatus(JobStatus& status) { throw MujinException("not implemented yet"); } +void OptimizationResource::SetOptimizationInfo(const RobotPlacementOptimizationInfo& optimizationinfo) +{ + GETCONTROLLERIMPL(); + std::string ignorebasecollision = optimizationinfo.ignorebasecollision ? "True" : "False"; + std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.name%optimizationinfo.maxstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); +} + void OptimizationResource::GetResults(int fastestnum, std::vector& results) { GETCONTROLLERIMPL(); From 498eb7eeb6d845cffcc6366f0ea4fd4f9833786e Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 16 Jan 2013 20:54:17 +0900 Subject: [PATCH 021/477] added ControllerClient::SetProxy --- include/mujincontrollerclient/mujincontrollerclient.h | 6 ++++++ src/mujincontrollerclient.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a4a2c19d..f3fdb95e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -263,6 +263,12 @@ class MUJINCLIENT_API ControllerClient /// Checkout http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; + /// \brief If necessary, sets the proxy to communicate to the controller server + /// + /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + virtual void SetProxy(const std::string& serverport, const std::string& userpw) = 0; + /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. /// /// If the server is not responding, call this method to clear the server state and initialize everything. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 7ca44a23..10e41c7f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -246,6 +246,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _SetHTTPHeaders(); } + virtual void SetProxy(const std::string& serverport, const std::string& userpw) + { + curl_easy_setopt(_curl, CURLOPT_PROXY, serverport.c_str()); + curl_easy_setopt(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); + } + virtual void SetLanguage(const std::string& language) { boost::mutex::scoped_lock lock(_mutex); From 3e8de5a4ea398139f2c0773474dc685a127a5e9f Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 17 Jan 2013 10:24:26 +0900 Subject: [PATCH 022/477] put proxy parameters on the create controller function --- include/mujincontrollerclient/mujincontrollerclient.h | 6 ++++-- src/mujincontrollerclient.cpp | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f3fdb95e..db404258 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -263,7 +263,7 @@ class MUJINCLIENT_API ControllerClient /// Checkout http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; - /// \brief If necessary, sets the proxy to communicate to the controller server + /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. @@ -454,9 +454,11 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 \param usernamepassword ユーザ:パスワード \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/", int options=0); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/", const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 10e41c7f..baa3dc85 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -99,7 +99,7 @@ static std::string& SearchAndReplace(std::string& out, const std::string& in, co class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this { public: - ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, int options) + ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { _httpheaders = NULL; _baseuri = baseuri; @@ -137,6 +137,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif + SetProxy(proxyserverport, proxyuserpw); + res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CHECKCURLCODE(res, "failed to set auth"); res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); @@ -809,9 +811,9 @@ void PlanningResultResource::GetTransforms(std::map& tra } // transformxml -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, int options) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, options)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); } void ControllerClientDestroy() From 1a83956cf252a8d29fd4a8a642fee3f22c2f0f02 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 17 Jan 2013 12:01:00 +0900 Subject: [PATCH 023/477] if uri is empty, will be filled with mujin controller default --- include/mujincontrollerclient/mujincontrollerclient.h | 8 +++++--- src/mujincontrollerclient.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index db404258..c24fb5fe 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -446,19 +446,21 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. \param usernamepassword user:password - \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. If not specified, will use the default mujin controller URL + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。指定されていなければデフォールトのMUJINコントローラURLが使用されます。 \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url="https://controller.mujin.co.jp/", const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index baa3dc85..90bcd846 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -102,7 +102,13 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { _httpheaders = NULL; - _baseuri = baseuri; + if( baseuri.size() > 0 ) { + _baseuri = baseuri; + } + else { + // use the default + _baseuri = "https://controller.mujin.co.jp/"; + } _baseapiuri = baseuri + std::string("api/v1/"); //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); From 636ad6253fbad4889b92d9db785deb9f8c605363 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 18 Jan 2013 11:33:05 +0900 Subject: [PATCH 024/477] fixed bug with autosetting url --- src/mujincontrollerclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 90bcd846..211d81cb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -109,7 +109,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // use the default _baseuri = "https://controller.mujin.co.jp/"; } - _baseapiuri = baseuri + std::string("api/v1/"); + _baseapiuri = _baseuri + std::string("api/v1/"); //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); @@ -143,7 +143,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif - SetProxy(proxyserverport, proxyuserpw); + //SetProxy(proxyserverport, proxyuserpw); res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CHECKCURLCODE(res, "failed to set auth"); From 3dda5cefcbb0c29bed04e926c8452fadc5040774 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 19 Jan 2013 01:09:23 +0900 Subject: [PATCH 025/477] add capability to upgrade controller, add correct dependencies --- .../mujincontrollerclient.h | 3 ++ src/mujincontrollerclient.cpp | 35 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c24fb5fe..0ef4b832 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -275,6 +275,9 @@ class MUJINCLIENT_API ControllerClient /// The method is blocking, when it returns the MUJIN Controller would have been restarted. virtual void RestartServer() = 0; + /// \brief Upgrade the controller with this data + virtual void Upgrade(const std::vector& vdata) = 0; + /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 211d81cb..953f308d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -270,7 +270,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share virtual void RestartServer() { boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri + std::string("ajax/restartserver/");; + _uri = _baseuri + std::string("ajax/restartserver/"); curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); curl_easy_setopt(_curl, CURLOPT_POST, 1); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); @@ -285,6 +285,39 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } + virtual void Upgrade(const std::vector& vdata) + { + BOOST_ASSERT(vdata.size()>0); + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri + std::string("upgrade/"); + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + + // set new headers and remove the Expect: 100-continue + struct curl_slist *headerlist=NULL; + headerlist = curl_slist_append(headerlist, "Expect:"); + std::string s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + headerlist = curl_slist_append(headerlist, s.c_str()); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + + // Fill in the file upload field + struct curl_httppost *formpost=NULL, *lastptr=NULL; + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "mujinpatch", CURLFORM_BUFFERPTR, &vdata[0], CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + CURLcode res = curl_easy_perform(_curl); + curl_formfree(formpost); + // reset the headers before any exceptions are thrown + _SetHTTPHeaders(); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, please try again or contact MUJIN support", MEC_HTTPServer); + } + } + virtual void CancelAllJobs() { CallDelete("job/?format=json"); From afce76b6986f9b7b1ad78ecfea3e5592a3bca769 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 5 Mar 2013 20:01:15 +0900 Subject: [PATCH 026/477] enable SetProxy --- src/mujincontrollerclient.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 953f308d..04133d63 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -143,7 +143,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif - //SetProxy(proxyserverport, proxyuserpw); + if( proxyserverport.size() > 0 ) { + SetProxy(proxyserverport, proxyuserpw); + } res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CHECKCURLCODE(res, "failed to set auth"); From 96e0f583c6edf2077d4c490b03da1e59e8106895 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 12 Mar 2013 23:35:17 +0900 Subject: [PATCH 027/477] added a RegisterScene for direct (fast) execution, added new sample --- .../mujincontrollerclient.h | 21 +++++++++++++++---- src/mujincontrollerclient.cpp | 9 ++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 0ef4b832..1db7ef9a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -289,10 +289,23 @@ class MUJINCLIENT_API ControllerClient /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; - /** \brief import a scene using from scene identified by a URI + /** \brief Register a scene to be used by the MUJIN Controller - \param importuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext - \param importformat The format of the imported file. Can be: + \param format The format of the source file. Can be: + - **mujincollada** + - **wincaps** (DensoWave WINCAPS III) + - **rttoolbox** (Mitsubishi RT ToolBox) + - **x** (DirectX) + - **vrml** + - **stl** + - **cecvirfitxml** (CEC Virfit XML environments) + */ + virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) = 0; + + /** \brief import a scene into COLLADA format using from scene identified by a URI + + \param sourceuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext + \param sourceformat The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) - **rttoolbox** (Mitsubishi RT ToolBox) @@ -302,7 +315,7 @@ class MUJINCLIENT_API ControllerClient - **cecvirfitxml** (CEC Virfit XML environments) \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ - virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) = 0; + virtual SceneResourcePtr ImportScene(const std::string& sourceuri, const std::string& sourceformat, const std::string& newuri) = 0; }; class MUJINCLIENT_API WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 04133d63..6fed15bf 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -337,6 +337,15 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } + virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) + { + boost::property_tree::ptree pt; + CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%format), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; + } + virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) { boost::property_tree::ptree pt; From 3c72e7a87fa52bbc98b471e65b291ae18ff59f9f Mon Sep 17 00:00:00 2001 From: yfukaya Date: Wed, 13 Mar 2013 10:59:02 +0900 Subject: [PATCH 028/477] =?UTF-8?q?Proxy=20=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mujincontrollerclient.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 04133d63..e4db8965 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -143,9 +143,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif - if( proxyserverport.size() > 0 ) { - SetProxy(proxyserverport, proxyuserpw); - } + SetProxy(proxyserverport, proxyuserpw); res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CHECKCURLCODE(res, "failed to set auth"); From f4faf1f6d177ed6210067c93d0c267da3b742c80 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 11:13:28 +0900 Subject: [PATCH 029/477] added run-time status getting --- .../mujincontrollerclient.h | 12 ++++++++++-- src/mujincontrollerclient.cpp | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1db7ef9a..cf6a9c41 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -157,8 +157,11 @@ struct JobStatus { JobStatus() : code(JSC_Unknown) { } - JobStatusCode code; - std::string message; + JobStatusCode code; ///< status code on whether the job is active + std::string type; ///< the type of job running + std::string message; ///< current message of the job + double elapsedtime; ///< how long the job has been running for in seconds + std::string pk; ///< the primary key to differentiate this job }; /// \brief an affine transform @@ -286,6 +289,11 @@ class MUJINCLIENT_API ControllerClient /// The method is non-blocking virtual void CancelAllJobs() = 0; + /// \brief get all the run-time statuses + /// + /// \param options if options is 1, also get the message + virtual void GetRunTimeStatuses(std::vector& statuses, int options=0); + /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 6fed15bf..22b3c9fc 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -325,6 +325,23 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share CallDelete("job/?format=json"); } + virtual void GetRunTimeStatuses(std::vector& statuses, int options) + { + boost::property_tree::ptree pt; + std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; + if( options & 1 ) { + url += std::string(",status_text"); + } + CallGet(url, pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + size_t i = 0; + statuses.resize(objects.size()); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + statuses[i].pk = v.second.get("pk"); + i++; + } + } + virtual void GetScenePrimaryKeys(std::vector& scenekeys) { boost::property_tree::ptree pt; From 8ea266e2a887b572ad289ea2b5d269f04ba1054d Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 11:14:07 +0900 Subject: [PATCH 030/477] fixed SetProxy --- src/mujincontrollerclient.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 797157fc..22b3c9fc 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -143,7 +143,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif - SetProxy(proxyserverport, proxyuserpw); + if( proxyserverport.size() > 0 ) { + SetProxy(proxyserverport, proxyuserpw); + } res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CHECKCURLCODE(res, "failed to set auth"); From ab7a816bc91b6fcfe01ce6f0e687476fd6ec903e Mon Sep 17 00:00:00 2001 From: yfukaya Date: Wed, 13 Mar 2013 11:48:26 +0900 Subject: [PATCH 031/477] commit changes from mujin orin provider --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index cf6a9c41..ef7a237a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -292,7 +292,7 @@ class MUJINCLIENT_API ControllerClient /// \brief get all the run-time statuses /// /// \param options if options is 1, also get the message - virtual void GetRunTimeStatuses(std::vector& statuses, int options=0); + virtual void GetRunTimeStatuses(std::vector& statuses, int options=0) = 0; /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; From ef0e080d03e303182ef1c39e9952c5ba2296ef56 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 13:13:55 +0900 Subject: [PATCH 032/477] implemented GetRunTimeStatus --- .../mujincontrollerclient.h | 13 ++++++-- src/mujincontrollerclient.cpp | 32 +++++++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ef7a237a..b4862f44 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -150,7 +150,7 @@ enum JobStatusCode { JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled JSC_Lost = 9, ///< An error happened and the job stopped being tracked. - JSC_Unknown = 0xffffffff, ///< the job is + JSC_Unknown = 0xffffffff, ///< the job is unknown }; struct JobStatus @@ -409,10 +409,14 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief execute the task. /// /// This operation is non-blocking and will return immediately after the execution is started. In order to check if the task is running or is complete, use \ref GetRunTimeStatus() and \ref GetResult() - virtual void Execute(); + /// \return true if task was executed fine + virtual bool Execute(); /// \brief get the run-time status of the executed task. - virtual void GetRunTimeStatus(JobStatus& status); + /// + /// This will only work if the task has been previously Executed with execute + /// If the task is not currently running, will set status.code to JSC_Unknown + virtual void GetRunTimeStatus(JobStatus& status, int options = 1); /// \brief Gets or creates the a optimization part of the scene /// @@ -430,6 +434,9 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. virtual PlanningResultResourcePtr GetResult(); + +protected: + std::string _jobpk; }; class MUJINCLIENT_API OptimizationResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 22b3c9fc..74020e69 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -338,6 +338,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share statuses.resize(objects.size()); BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { statuses[i].pk = v.second.get("pk"); + statuses[i].code = static_cast(boost::lexical_cast(v.second.get("status"))); + statuses[i].type = v.second.get("fnname"); + statuses[i].elapsedtime = v.second.get("elapsedtime"); + if( options & 1 ) { + statuses[i].message = v.second.get("status_text"); + } i++; } } @@ -677,16 +683,36 @@ TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk { } -void TaskResource::Execute() +bool TaskResource::Execute() { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt, 200); + _jobpk = pt.get("jobpk"); + return true; } -void TaskResource::GetRunTimeStatus(JobStatus& status) +void TaskResource::GetRunTimeStatus(JobStatus& status, int options) { - throw MujinException("not implemented yet"); + if( _jobpk.size() > 0 ) { + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); + if( options & 1 ) { + url += std::string(",status_text"); + } + controller->CallGet(url, pt); + //pt.get("error_message") + status.pk = pt.get("pk"); + status.code = static_cast(boost::lexical_cast(pt.get("status"))); + status.type = pt.get("fnname"); + status.elapsedtime = pt.get("elapsedtime"); + if( options & 1 ) { + status.message = pt.get("status_text"); + } + } + + status.code = JSC_Unknown; } OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname, const std::string& optimizationtype) From e13bb1513203f03419e38226238f4b8b1020bb88 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 15:34:00 +0900 Subject: [PATCH 033/477] added default tasks --- .../mujincontrollerclient.h | 41 ++++++++++++++++++- src/mujincontrollerclient.cpp | 39 ++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b4862f44..349d7c62 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -310,6 +310,12 @@ class MUJINCLIENT_API ControllerClient */ virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) = 0; + /// \brief registers scene with default scene type + virtual SceneResourcePtr RegisterScene(const std::string& uri) + { + return RegisterScene(uri,GetDefaultSceneType()); + } + /** \brief import a scene into COLLADA format using from scene identified by a URI \param sourceuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext @@ -324,6 +330,27 @@ class MUJINCLIENT_API ControllerClient \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ virtual SceneResourcePtr ImportScene(const std::string& sourceuri, const std::string& sourceformat, const std::string& newuri) = 0; + + /** \brief uploads a particular scene's files into the network filesystem. + + \param sourcefilename Local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. + \param destinationdir Destination folder in the network file system. By default use: "mujin:/" + \param scenetype The type of scene uploading. + */ + virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; + + virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir) + { + return SyncUpload(sourcefilename, destinationdir, GetDefaultSceneType()); + } + + virtual void SetDefaultSceneType(const std::string& scenetype) = 0; + + virtual const std::string& GetDefaultSceneType() = 0; + + virtual void SetDefaultTaskType(const std::string& tasktype) = 0; + + virtual const std::string& GetDefaultTaskType() = 0; }; class MUJINCLIENT_API WebResource @@ -390,7 +417,13 @@ class MUJINCLIENT_API SceneResource : public WebResource \param tasktype The type of task to create. Supported types are: - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype=std::string("itlplanning")); + virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype); + + virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname) + { + return GetOrCreateTaskFromName(taskname, GetController()->GetDefaultTaskType()); + } + /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); @@ -496,6 +529,12 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); +// \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) +MUJINCLIENT_API std::string GetPrimaryKeyFromURI_UTF8(const std::string& uri); + +// \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) +MUJINCLIENT_API std::string GetPrimaryKeyFromURI_UTF16(const std::wstring& uri); + /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 74020e69..89a2e47d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -362,6 +362,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) { + BOOST_ASSERT(format.size()>0); boost::property_tree::ptree pt; CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%format), pt); std::string pk = pt.get("pk"); @@ -371,6 +372,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) { + BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; CallPost("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); std::string pk = pt.get("pk"); @@ -378,6 +380,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return scene; } + virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) + { + BOOST_ASSERT(scenetype.size()>0); + throw MujinException("not implemented"); + } + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception int CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode=200) { @@ -494,6 +502,25 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share */ + virtual void SetDefaultSceneType(const std::string& scenetype) + { + _defaultscenetype = scenetype; + } + + virtual const std::string& GetDefaultSceneType() + { + return _defaultscenetype; + } + + virtual void SetDefaultTaskType(const std::string& tasktype) + { + _defaultscenetype = tasktype; + } + + virtual const std::string& GetDefaultTaskType() + { + return _defaulttasktype; + } protected: void GetProfile() @@ -563,6 +590,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::string _csrfmiddlewaretoken; boost::property_tree::ptree _profile; ///< user profile and versioning + + std::string _defaultscenetype, _defaulttasktype; }; typedef boost::shared_ptr ControllerClientImplPtr; @@ -913,6 +942,16 @@ void ControllerClientDestroy() { } +std::string GetPrimaryKeyFromURI_UTF8(const std::string& uri) +{ + throw MujinException("not implemented"); +} + +std::string GetPrimaryKeyFromURI_UTF16(const std::wstring& uri) +{ + throw MujinException("not implemented"); +} + void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) { throw MujinException("not implemented yet"); From 6646ac51643bc5dfb938fbc67ace80cd46e413ec Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 15:39:40 +0900 Subject: [PATCH 034/477] changed to vrcruns --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 349d7c62..a4623fb7 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -192,7 +192,7 @@ struct ITLPlanningTaskInfo inline void SetDefaults() { startfromcurrent = 0; returntostart = 1; - usevrc = 1; + vrcruns = 1; unit = "mm"; outputtrajtype = "robotmaker"; optimizationvalue = 1; @@ -200,7 +200,7 @@ struct ITLPlanningTaskInfo } int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. int returntostart; ///< Plan the return path of the robot to where the entire trajectory started. Makes it possible to loop the robot motion. - int usevrc; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. + int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc std::string outputtrajtype; ///< what format to output the trajectory in. Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 89a2e47d..de52699c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -802,8 +802,8 @@ void TaskResource::GetTaskInfo(ITLPlanningTaskInfo& taskinfo) else if( v.first == "returntostart" ) { taskinfo.returntostart = v.second.data() == std::string("True"); } - else if( v.first == "usevrc" ) { - taskinfo.usevrc = v.second.data() == std::string("True"); + else if( v.first == "vrcruns" ) { + taskinfo.vrcruns = boost::lexical_cast(v.second.data()); } else if( v.first == "unit" ) { taskinfo.unit = v.second.data(); @@ -824,7 +824,7 @@ void TaskResource::SetTaskInfo(const ITLPlanningTaskInfo& taskinfo) { GETCONTROLLERIMPL(); std::string startfromcurrent = taskinfo.startfromcurrent ? "True" : "False"; - std::string usevrc = taskinfo.usevrc ? "True" : "False"; + std::string vrcruns = boost::lexical_cast(taskinfo.vrcruns); std::string returntostart = taskinfo.returntostart ? "True" : "False"; // because program will inside string, encode newlines @@ -833,7 +833,7 @@ void TaskResource::SetTaskInfo(const ITLPlanningTaskInfo& taskinfo) serachpairs[0].first = "\n"; serachpairs[0].second = "\\n"; serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; SearchAndReplace(program, taskinfo.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"taskgoalxml\":\"%s%s%s%f%s%s%s\"}")%taskinfo.outputtrajtype%program%taskinfo.unit%taskinfo.optimizationvalue%startfromcurrent%usevrc%returntostart); + std::string taskgoalput = str(boost::format("{\"taskgoalxml\":\"%s%s%s%f%s%s%s\"}")%taskinfo.outputtrajtype%program%taskinfo.unit%taskinfo.optimizationvalue%startfromcurrent%vrcruns%returntostart); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } From d597c3745c10e1e005eccdd840917d1409e0f0dc Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 15:42:55 +0900 Subject: [PATCH 035/477] fixed target name --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a4623fb7..d1461dc5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -213,7 +213,7 @@ struct RobotPlacementOptimizationInfo SetDefaults(); } inline void SetDefaults() { - name.clear(); + targetname.clear(); frame = "0 robot"; unit = "mm"; minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; @@ -222,7 +222,7 @@ struct RobotPlacementOptimizationInfo ignorebasecollision = 1; maxstorecandidates = 0; } - std::string name; ///< what to optimize + std::string targetname; ///< what target object to optimize for. If blank, will use robot. std::string frame; ///< The frame to define the optimization parameters in std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc Real maxrange[4]; ///< X, Y, Z, Angle (deg) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index de52699c..0e9e9eb1 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -871,7 +871,7 @@ void OptimizationResource::SetOptimizationInfo(const RobotPlacementOptimizationI { GETCONTROLLERIMPL(); std::string ignorebasecollision = optimizationinfo.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.name%optimizationinfo.maxstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); + std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.targetname%optimizationinfo.maxstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } From 7b98d00edf32ef6b0d3618c89e568b335b3f1b50 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 15:47:25 +0900 Subject: [PATCH 036/477] introduced topstore candidates --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index d1461dc5..388d0efd 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -213,6 +213,7 @@ struct RobotPlacementOptimizationInfo SetDefaults(); } inline void SetDefaults() { + topstorecandidates = 20; targetname.clear(); frame = "0 robot"; unit = "mm"; @@ -220,7 +221,6 @@ struct RobotPlacementOptimizationInfo maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; ignorebasecollision = 1; - maxstorecandidates = 0; } std::string targetname; ///< what target object to optimize for. If blank, will use robot. std::string frame; ///< The frame to define the optimization parameters in @@ -229,7 +229,7 @@ struct RobotPlacementOptimizationInfo Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) int ignorebasecollision; ///< When moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. - int maxstorecandidates; ///< The candidates are first ordered and then the top N are stored. If 0, then everything is stored + int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; /// \brief Creates on MUJIN Controller instance. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 0e9e9eb1..5e2d2821 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -871,7 +871,7 @@ void OptimizationResource::SetOptimizationInfo(const RobotPlacementOptimizationI { GETCONTROLLERIMPL(); std::string ignorebasecollision = optimizationinfo.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.targetname%optimizationinfo.maxstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); + std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.targetname%optimizationinfo.topstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } From 402bb9156bdc0ff4c6619dc30c58ddef84080fe5 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Mar 2013 15:55:41 +0900 Subject: [PATCH 037/477] changed name --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 388d0efd..3938bddf 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -530,10 +530,10 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us MUJINCLIENT_API void ControllerClientDestroy(); // \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) -MUJINCLIENT_API std::string GetPrimaryKeyFromURI_UTF8(const std::string& uri); +MUJINCLIENT_API std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); // \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) -MUJINCLIENT_API std::string GetPrimaryKeyFromURI_UTF16(const std::wstring& uri); +MUJINCLIENT_API std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5e2d2821..631eed8a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -942,12 +942,12 @@ void ControllerClientDestroy() { } -std::string GetPrimaryKeyFromURI_UTF8(const std::string& uri) +std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) { throw MujinException("not implemented"); } -std::string GetPrimaryKeyFromURI_UTF16(const std::wstring& uri) +std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) { throw MujinException("not implemented"); } From 49cecede4a5df97cbaf156c958db94c58bbacecd Mon Sep 17 00:00:00 2001 From: yfukaya Date: Sat, 16 Mar 2013 17:51:31 +0900 Subject: [PATCH 038/477] Added encoding functions --- .../mujincontrollerclient.h | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3938bddf..42ee2e6e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -53,6 +53,74 @@ #include #include +#ifdef WIN32 +#include +#endif // WIN32 + +namespace Encoding { + inline std::wstring UTF8toUTF16(const std::string& utf8) { + std::wstring utf16(L""); + + if (!utf8.empty()) { + size_t nLen16 = 0; + if ((nLen16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0)) > 0) { + utf16.resize(nLen16); + ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &utf16[0], nLen16); + } + } + return utf16; + } + + inline std::string UTF16toUTF8(const std::wstring& utf16) { + std::string utf8(""); + + if (!utf16.empty()) { + size_t nLen8 = 0; + if ((nLen8 = ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { + utf8.resize(nLen8); + ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, &utf8[0], nLen8, NULL, NULL); + } + } + return utf8; + } + + inline std::string UTF16toMBS(const std::wstring& utf16) { + std::string mbs(""); + + if (!utf16.empty()) { + size_t nLenA = 0; + if ((nLenA = ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { + mbs.resize(nLenA); + ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, &mbs[0], nLenA, NULL, NULL); + } + } + return mbs; + } + + inline std::wstring MBStoUTF16(const std::string& mbs) { + std::wstring utf16(L""); + + if (!mbs.empty()) { + size_t nLen16 = 0; + if ((nLen16 = ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, NULL, 0)) > 0) { + utf16.resize(nLen16); + ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, &utf16[0], nLen16); + } + } + return utf16; + } + + inline std::string MBStoUTF8(const std::string& mbs) { + // MBS -> UTF16 -> UTF8 + return UTF16toUTF8(MBStoUTF16(mbs)); + } + + inline std::string UTF8toMBS(const std::string& utf8) { + // UTF8 -> UTF16 -> MBS + return UTF16toMBS(UTF8toUTF16(utf8)); + } +} + namespace mujinclient { #include From c248ad264407bbc2857e7570b33fa17bade1ba2c Mon Sep 17 00:00:00 2001 From: yfukaya Date: Sat, 16 Mar 2013 17:55:08 +0900 Subject: [PATCH 039/477] Implemented GetScenePrimaryKeyFromURI_UTF8 --- src/mujincontrollerclient.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 631eed8a..90874382 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -942,13 +942,23 @@ void ControllerClientDestroy() { } +//URI encoded UTF-8 to MultiByte std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) { - throw MujinException("not implemented"); + char *lpa = curl_unescape(uri.c_str(), 0); // URI decoding (UTF-8) + std::string str = Encoding::UTF8toMBS(std::string(lpa)); + curl_free(lpa); + + return str; } std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) { + //WCHAR* lpw = curl_unicode_unescape(uri.c_str(), 0); // URI decoding (UTF-16) + //std::string str = Encoding::UTF16toMBS(std::wstring(lpw)); + //curl_free(lpw); + //return str; + throw MujinException("not implemented"); } From 3b5ff2fb4794aba776ef5c2ba4529ec1aa2933d0 Mon Sep 17 00:00:00 2001 From: yfukaya Date: Sun, 17 Mar 2013 09:16:23 +0900 Subject: [PATCH 040/477] Changed usage of predefined macros to detect windows platform WIN32 -> _WIN32 || _WIN64 --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 42ee2e6e..7d5f8f7c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -53,9 +53,9 @@ #include #include -#ifdef WIN32 +#ifdef _WIN32 || _WIN64 #include -#endif // WIN32 +#endif // _WIN32 || _WIN64 namespace Encoding { inline std::wstring UTF8toUTF16(const std::string& utf8) { From 6881480efbdfd7884c91441dc87bd1f93857f3f5 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 3 Apr 2013 21:26:46 +0900 Subject: [PATCH 041/477] many fixes and api updates for mujin controller v0.4.8 --- .../mujincontrollerclient.h | 206 ++++++++-------- src/mujincontrollerclient.cpp | 222 ++++++++++++------ 2 files changed, 258 insertions(+), 170 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 7d5f8f7c..b7d83357 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -53,74 +53,6 @@ #include #include -#ifdef _WIN32 || _WIN64 -#include -#endif // _WIN32 || _WIN64 - -namespace Encoding { - inline std::wstring UTF8toUTF16(const std::string& utf8) { - std::wstring utf16(L""); - - if (!utf8.empty()) { - size_t nLen16 = 0; - if ((nLen16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0)) > 0) { - utf16.resize(nLen16); - ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &utf16[0], nLen16); - } - } - return utf16; - } - - inline std::string UTF16toUTF8(const std::wstring& utf16) { - std::string utf8(""); - - if (!utf16.empty()) { - size_t nLen8 = 0; - if ((nLen8 = ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { - utf8.resize(nLen8); - ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, &utf8[0], nLen8, NULL, NULL); - } - } - return utf8; - } - - inline std::string UTF16toMBS(const std::wstring& utf16) { - std::string mbs(""); - - if (!utf16.empty()) { - size_t nLenA = 0; - if ((nLenA = ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { - mbs.resize(nLenA); - ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, &mbs[0], nLenA, NULL, NULL); - } - } - return mbs; - } - - inline std::wstring MBStoUTF16(const std::string& mbs) { - std::wstring utf16(L""); - - if (!mbs.empty()) { - size_t nLen16 = 0; - if ((nLen16 = ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, NULL, 0)) > 0) { - utf16.resize(nLen16); - ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, &utf16[0], nLen16); - } - } - return utf16; - } - - inline std::string MBStoUTF8(const std::string& mbs) { - // MBS -> UTF16 -> UTF8 - return UTF16toUTF8(MBStoUTF16(mbs)); - } - - inline std::string UTF8toMBS(const std::string& utf8) { - // UTF8 -> UTF16 -> MBS - return UTF16toMBS(UTF8toUTF16(utf8)); - } -} - namespace mujinclient { #include @@ -156,7 +88,6 @@ inline const char* GetErrorCodeString(MujinErrorCode error) return ""; } - /// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. class MUJINCLIENT_API MujinException : public std::exception { @@ -243,6 +174,14 @@ struct Transform Real translation[3]; ///< translation x,y,z }; +struct InstanceObjectState +{ + Transform transform; ///< the transform of this instance object + std::vector jointvalues; ///< the joint values +}; + +typedef std::map EnvironmentState; + struct SceneInformation { std::string pk; ///< primary key @@ -251,33 +190,48 @@ struct SceneInformation std::string name; }; -/// \brief holds information about the itlplanning task goal -struct ITLPlanningTaskInfo +/// \brief holds information about the itlplanning task parameters +class ITLPlanningTaskParameters { - ITLPlanningTaskInfo() { +public: + ITLPlanningTaskParameters() { SetDefaults(); } - inline void SetDefaults() { + virtual void SetDefaults() { startfromcurrent = 0; returntostart = 1; vrcruns = 1; + ignorefigure = 1; unit = "mm"; - outputtrajtype = "robotmaker"; optimizationvalue = 1; program.clear(); } int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. int returntostart; ///< Plan the return path of the robot to where the entire trajectory started. Makes it possible to loop the robot motion. int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. + int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - std::string outputtrajtype; ///< what format to output the trajectory in. Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) std::string program; ///< itl program }; -struct RobotPlacementOptimizationInfo +/// program is wincaps rc8 pac script +class DensoWaveWincapsTaskParameters : public ITLPlanningTaskParameters { - RobotPlacementOptimizationInfo() { +public: + DensoWaveWincapsTaskParameters() : ITLPlanningTaskParameters() { + SetDefaults(); + } + void SetDefaults() { + ITLPlanningTaskParameters::SetDefaults(); + preservespeedparameters = 0; + } + int preservespeedparameters; ///< if 1, preserves all SPEED/ACCEL commands as best as possible. +}; + +struct RobotPlacementOptimizationParameters +{ + RobotPlacementOptimizationParameters() { SetDefaults(); } inline void SetDefaults() { @@ -300,6 +254,25 @@ struct RobotPlacementOptimizationInfo int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; +/// \brief program data for an individual robot +class RobotProgramData +{ +public: + RobotProgramData() { + } + RobotProgramData(const std::string& programdata, const std::string& type) : programdata(programdata), type(type) { + } + std::string programdata; ///< the program data + std::string type; ///< the type of program +}; + +/// \brief program data for all robots. +class RobotControllerPrograms +{ +public: + std::map programs; ///< the keys are the robot instance primary keys of the scene +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -367,7 +340,7 @@ class MUJINCLIENT_API ControllerClient /** \brief Register a scene to be used by the MUJIN Controller - \param format The format of the source file. Can be: + \param scenetype The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) - **rttoolbox** (Mitsubishi RT ToolBox) @@ -376,7 +349,7 @@ class MUJINCLIENT_API ControllerClient - **stl** - **cecvirfitxml** (CEC Virfit XML environments) */ - virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) = 0; + virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& scenetype) = 0; /// \brief registers scene with default scene type virtual SceneResourcePtr RegisterScene(const std::string& uri) @@ -387,7 +360,7 @@ class MUJINCLIENT_API ControllerClient /** \brief import a scene into COLLADA format using from scene identified by a URI \param sourceuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext - \param sourceformat The format of the source file. Can be: + \param sourcescenetype The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) - **rttoolbox** (Mitsubishi RT ToolBox) @@ -397,7 +370,7 @@ class MUJINCLIENT_API ControllerClient - **cecvirfitxml** (CEC Virfit XML environments) \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ - virtual SceneResourcePtr ImportScene(const std::string& sourceuri, const std::string& sourceformat, const std::string& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; /** \brief uploads a particular scene's files into the network filesystem. @@ -419,6 +392,30 @@ class MUJINCLIENT_API ControllerClient virtual void SetDefaultTaskType(const std::string& tasktype) = 0; virtual const std::string& GetDefaultTaskType() = 0; + + /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) + + For example, the URI + + mujin:/検証動作_121122.mujin.dae + + is represented as: + + "mujin:/\xe6\xa4\x9c\xe8\xa8\xbc\xe5\x8b\x95\xe4\xbd\x9c_121122.mujin.dae" + + Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" + \param uri utf-8 encoded URI + */ + std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); + + /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) + + If input URL is L"mujin:/\u691c\u8a3c\u52d5\u4f5c_121122.mujin.dae" + Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" + + \param uri utf-16 encoded URI + */ + std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); }; class MUJINCLIENT_API WebResource @@ -481,6 +478,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /** \brief Gets or creates the a task part of the scene + If task exists already, validates it with tasktype. \param taskname the name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown \param tasktype The type of task to create. Supported types are: - itlplanning @@ -492,6 +490,7 @@ class MUJINCLIENT_API SceneResource : public WebResource return GetOrCreateTaskFromName(taskname, GetController()->GetDefaultTaskType()); } + virtual TaskResourcePtr GetTaskFromName(const std::string& taskname); /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); @@ -528,10 +527,10 @@ class MUJINCLIENT_API TaskResource : public WebResource virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); /// \brief Get the task info for tasks of type itlplanning - virtual void GetTaskInfo(ITLPlanningTaskInfo& taskinfo); + virtual void GetTaskParameters(ITLPlanningTaskParameters& taskparameters); /// \brief Set new task info for tasks of type itlplanning - virtual void SetTaskInfo(const ITLPlanningTaskInfo& taskinfo); + virtual void SetTaskParameters(const ITLPlanningTaskParameters& taskparameters); /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. virtual PlanningResultResourcePtr GetResult(); @@ -551,7 +550,7 @@ class MUJINCLIENT_API OptimizationResource : public WebResource virtual void Execute(); /// \brief Set new task info for tasks of type robotplanning - void SetOptimizationInfo(const RobotPlacementOptimizationInfo& optimizationinfo); + void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); /// \brief get the run-time status of the executed optimization. virtual void GetRunTimeStatus(JobStatus& status); @@ -570,9 +569,38 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource } /// \brief Get all the transforms the results are storing. Depending on the optimization, can be more than just the robot - virtual void GetTransforms(std::map& transforms); -}; + virtual void GetEnvironmentState(EnvironmentState& envstate); + /** \brief Gets the raw program information + + \param[in] programtype The type of program to return. Possible values are: + - auto - special type that returns the most suited programs + - mujinxml - \b xml + - melfabasicv - \b json with Mitsubishi-specific programs + - densowaverc8pac - \b json with DensoWave-specific programs + - cecvirfitsim - zip file + + If \b auto is set, then the robot-maker specific program is returned if possible. If not possible, then mujin xml is returned. All the programs for all robots planned are returned. + + \param[out] outputdata The raw program data + */ + virtual void GetAllRawProgramData(std::string& outputdata, const std::string& programtype="auto"); + + /** \brief Gets the raw program information of a specific robot, if supported. + + \param[in] programtype The type of program to return. + \param[in] robotpk The primary key of the robot instance in the scene. + \param[out] outputdata The raw program data + \throw mujin_exception If robot program is not supported, will throw an exception + */ + virtual void GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype="auto"); + + /// \brief Gets parsed program information + /// + /// If the robot doesn't have a recognizable controller, then no programs might be returned. + /// \param[out] programs The programs for each robot. The best suited program for each robot is determined from its controller. + virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); +}; /** \en \brief creates the controller with an account. This function is not thread safe. @@ -597,12 +625,6 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void ControllerClientDestroy(); -// \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) -MUJINCLIENT_API std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); - -// \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) -MUJINCLIENT_API std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); - /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 90874382..8862f85c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,8 @@ #include #include +#include "utf8.h" + #ifdef _MSC_VER #ifndef __PRETTY_FUNCTION__ #define __PRETTY_FUNCTION__ __FUNCDNAME__ @@ -115,7 +116,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share BOOST_ASSERT(!!_curl); #ifdef _DEBUG - curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); + //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); #endif CURLcode res; @@ -370,7 +371,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return scene; } - virtual SceneResourcePtr ImportScene(const std::string& importuri, const std::string& importformat, const std::string& newuri) + virtual SceneResourcePtr ImportSceneToCOLLADA(const std::string& importuri, const std::string& importformat, const std::string& newuri) { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; @@ -412,6 +413,35 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return http_code; } + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode=200) + { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + outputdata = _buffer.str(); + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + if( outputdata.size() > 0 ) { + boost::property_tree::ptree pt; + boost::property_tree::read_json(_buffer, pt); + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); + } + return http_code; + } + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception int CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode=201) { @@ -521,6 +551,25 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share { return _defaulttasktype; } + + std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) + { + size_t index = uri.find(":/"); + MUJIN_ASSERT_OP_FORMAT(index,!=,std::string::npos, "bad URI: %s", uri, MEC_InvalidArguments); + uri.substr(index+2); + char* pcurlresult = curl_easy_escape(_curl, uri.c_str()+index+2,uri.size()-index-2); + std::string sresult(pcurlresult); + curl_free(pcurlresult); // have to release the result + return sresult; + } + + std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) + { + std::string utf8line; + utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); + return GetScenePrimaryKeyFromURI_UTF8(utf8line); + } + protected: void GetProfile() @@ -658,6 +707,22 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna return task; } +TaskResourcePtr SceneResource::GetTaskFromName(const std::string& taskname) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); + // task exists + boost::property_tree::ptree& objects = pt.get_child("objects"); + if( objects.size() == 0 ) { + throw MUJIN_EXCEPTION_FORMAT("could not find task with name %s", taskname, MEC_InvalidState); + } + + std::string pk = objects.begin()->second.get("pk"); + TaskResourcePtr task(new TaskResource(GetController(), pk)); + return task; +} + void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) { GETCONTROLLERIMPL(); @@ -781,59 +846,57 @@ void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimiza } } -void TaskResource::GetTaskInfo(ITLPlanningTaskInfo& taskinfo) +void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskgoalxml&tasktype")%GetPrimaryKey()), pt); + controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskparameters,tasktype")%GetPrimaryKey()), pt); std::string tasktype = pt.get("tasktype"); if( tasktype != "itlplanning" ) { throw MUJIN_EXCEPTION_FORMAT("task %s is type %s, expected itlplanning", GetPrimaryKey()%tasktype, MEC_InvalidArguments); } - std::stringstream sstrans(pt.get("taskgoalxml")); - boost::property_tree::ptree pttrans; - boost::property_tree::read_xml(sstrans, pttrans); - boost::property_tree::ptree& objects = pttrans.get_child("root"); - taskinfo.SetDefaults(); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + boost::property_tree::ptree& taskparametersjson = pt.get_child("taskparameters"); + taskparameters.SetDefaults(); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, taskparametersjson) { if( v.first == "startfromcurrent" ) { - taskinfo.startfromcurrent = v.second.data() == std::string("True"); + taskparameters.startfromcurrent = v.second.data() == std::string("True"); } else if( v.first == "returntostart" ) { - taskinfo.returntostart = v.second.data() == std::string("True"); + taskparameters.returntostart = v.second.data() == std::string("True"); + } + else if( v.first == "ignorefigure" ) { + taskparameters.ignorefigure = v.second.data() == std::string("True"); } else if( v.first == "vrcruns" ) { - taskinfo.vrcruns = boost::lexical_cast(v.second.data()); + taskparameters.vrcruns = boost::lexical_cast(v.second.data()); } else if( v.first == "unit" ) { - taskinfo.unit = v.second.data(); - } - else if( v.first == "outputtrajtype" ) { - taskinfo.outputtrajtype = v.second.data(); + taskparameters.unit = v.second.data(); } else if( v.first == "optimizationvalue" ) { - taskinfo.optimizationvalue = boost::lexical_cast(v.second.data()); + taskparameters.optimizationvalue = boost::lexical_cast(v.second.data()); } else if( v.first == "program" ) { - taskinfo.program = v.second.data(); + taskparameters.program = v.second.data(); } } } -void TaskResource::SetTaskInfo(const ITLPlanningTaskInfo& taskinfo) +void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparameters) { GETCONTROLLERIMPL(); - std::string startfromcurrent = taskinfo.startfromcurrent ? "True" : "False"; - std::string vrcruns = boost::lexical_cast(taskinfo.vrcruns); - std::string returntostart = taskinfo.returntostart ? "True" : "False"; + std::string startfromcurrent = taskparameters.startfromcurrent ? "True" : "False"; + std::string returntostart = taskparameters.returntostart ? "True" : "False"; + std::string ignorefigure = taskparameters.ignorefigure ? "True" : "False"; + std::string vrcruns = boost::lexical_cast(taskparameters.vrcruns); // because program will inside string, encode newlines std::string program; std::vector< std::pair > serachpairs(2); serachpairs[0].first = "\n"; serachpairs[0].second = "\\n"; serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; - SearchAndReplace(program, taskinfo.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"taskgoalxml\":\"%s%s%s%f%s%s%s\"}")%taskinfo.outputtrajtype%program%taskinfo.unit%taskinfo.optimizationvalue%startfromcurrent%vrcruns%returntostart); + SearchAndReplace(program, taskparameters.program, serachpairs); + std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returntostart\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d} }")%taskparameters.optimizationvalue%program%taskparameters.unit%returntostart%startfromcurrent%ignorefigure%vrcruns); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } @@ -867,11 +930,11 @@ void OptimizationResource::GetRunTimeStatus(JobStatus& status) { throw MujinException("not implemented yet"); } -void OptimizationResource::SetOptimizationInfo(const RobotPlacementOptimizationInfo& optimizationinfo) +void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams) { GETCONTROLLERIMPL(); - std::string ignorebasecollision = optimizationinfo.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationparametersxml\":\"%s%d%s%s%s%f%f%f%f%f%f%f%f%f%f%f%f\"}")%optimizationinfo.targetname%optimizationinfo.topstorecandidates%optimizationinfo.unit%ignorebasecollision%optimizationinfo.frame%optimizationinfo.maxrange[0]%optimizationinfo.maxrange[1]%optimizationinfo.maxrange[2]%optimizationinfo.maxrange[3]%optimizationinfo.minrange[0]%optimizationinfo.minrange[1]%optimizationinfo.minrange[2]%optimizationinfo.minrange[3]%optimizationinfo.stepsize[0]%optimizationinfo.stepsize[1]%optimizationinfo.stepsize[2]%optimizationinfo.stepsize[3]); + std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; + std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.frame%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } @@ -893,73 +956,76 @@ PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, c { } -void PlanningResultResource::GetTransforms(std::map& transforms) +void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=transformxml")%GetResourceName()%GetPrimaryKey()), pt); - std::stringstream sstrans(pt.get("transformxml")); - boost::property_tree::ptree pttrans; - boost::property_tree::read_xml(sstrans, pttrans); - boost::property_tree::ptree& objects = pttrans.get_child("root"); - transforms.clear(); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - if( v.first == "transforms_" ) { - Transform t; - std::string name; - int itranslation=0, iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vtrans, v.second) { - if( vtrans.first == "name" ) { - name = vtrans.second.data(); - } - else if( vtrans.first == "translation_" && itranslation < 3 ) { - t.translation[itranslation++] = boost::lexical_cast(vtrans.second.data()); - } - else if( vtrans.first == "quat_" && iquat < 4 ) { - t.quat[iquat++] = boost::lexical_cast(vtrans.second.data()); - } - } - // normalize the quaternion - Real dist2 = t.quat[0]*t.quat[0] + t.quat[1]*t.quat[1] + t.quat[2]*t.quat[2] + t.quat[3]*t.quat[3]; - if( dist2 > 0 ) { - Real fnorm =1/std::sqrt(dist2); - t.quat[0] *= fnorm; t.quat[1] *= fnorm; t.quat[2] *= fnorm; t.quat[3] *= fnorm; - } - transforms[name] = t; + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); + boost::property_tree::ptree& envstatejson = pt.get_child("envstate"); + envstate.clear(); + BOOST_FOREACH(boost::property_tree::ptree::value_type &objstatejson, envstatejson) { + InstanceObjectState objstate; + std::string name = objstatejson.second.get("name"); + boost::property_tree::ptree& quatjson = objstatejson.second.get_child("quat_"); + int iquat=0; + Real dist2 = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_ASSERT(iquat<4); + Real f = boost::lexical_cast(v.second.data()); + dist2 += f * f; + objstate.transform.quat[iquat++] = f; } + // normalize the quaternion + if( dist2 > 0 ) { + Real fnorm =1/std::sqrt(dist2); + objstate.transform.quat[0] *= fnorm; + objstate.transform.quat[1] *= fnorm; + objstate.transform.quat[2] *= fnorm; + objstate.transform.quat[3] *= fnorm; + } + boost::property_tree::ptree& translationjson = objstatejson.second.get_child("translation_"); + int itranslation=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, translationjson) { + BOOST_ASSERT(iquat<3); + objstate.transform.translation[itranslation++] = boost::lexical_cast(v.second.data()); + } + envstate[name] = objstate; } - //std::string fieldvalue = pt.get(field); - //return fieldvalue; } -// transformxml -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options) +void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); + GETCONTROLLERIMPL(); + controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), outputdata); } -void ControllerClientDestroy() +void PlanningResultResource::GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype) { + GETCONTROLLERIMPL(); + controller->CallGet(str(boost::format("%s/%s/program/%s/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%robotpk%programtype), outputdata); } -//URI encoded UTF-8 to MultiByte -std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) +void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, const std::string& programtype) { - char *lpa = curl_unescape(uri.c_str(), 0); // URI decoding (UTF-8) - std::string str = Encoding::UTF8toMBS(std::string(lpa)); - curl_free(lpa); - - return str; + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + programs.programs.clear(); + controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), pt); + BOOST_FOREACH(boost::property_tree::ptree::value_type &robotdatajson, pt) { + std::string robotpk = robotdatajson.first; + std::string program = robotdatajson.second.get("program"); + std::string currenttype = robotdatajson.second.get("type"); + programs.programs[robotpk] = RobotProgramData(program, currenttype); + } } -std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { - //WCHAR* lpw = curl_unicode_unescape(uri.c_str(), 0); // URI decoding (UTF-16) - //std::string str = Encoding::UTF16toMBS(std::wstring(lpw)); - //curl_free(lpw); - //return str; + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); +} - throw MujinException("not implemented"); +void ControllerClientDestroy() +{ } void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) From b948c3a7f6c9daf13fa47b5e7a9509a73d0b212a Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 12:07:22 +0900 Subject: [PATCH 042/477] added preliminary syncupload --- .../mujincontrollerclient.h | 12 +- src/mujincontrollerclient.cpp | 232 ++++++++++++++++-- 2 files changed, 217 insertions(+), 27 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b7d83357..9e246a12 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -375,14 +375,16 @@ class MUJINCLIENT_API ControllerClient /** \brief uploads a particular scene's files into the network filesystem. \param sourcefilename Local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. - \param destinationdir Destination folder in the network file system. By default use: "mujin:/" + \param destinationdir Destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" \param scenetype The type of scene uploading. + \throw mujin_exception if the upload fails, will throw an exception */ - virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; + virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; - virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir) + /// \see SyncUpload + virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir) { - return SyncUpload(sourcefilename, destinationdir, GetDefaultSceneType()); + SyncUpload(sourcefilename, destinationdir, GetDefaultSceneType()); } virtual void SetDefaultSceneType(const std::string& scenetype) = 0; @@ -467,7 +469,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string name; std::string object_pk; std::string reference_uri; - Real rotate[4]; // quaternion + Real rotate[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; }; typedef boost::shared_ptr InstObjectPtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 8862f85c..bf3898fc 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -22,11 +22,20 @@ #include #include #include +#include #include #include #include +#if defined(_WIN32) || defined(_WIN64) +// win32 specific includes? +#else +#include +#include +#endif + + #include "utf8.h" #ifdef _MSC_VER @@ -56,6 +65,24 @@ #define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } +#include + +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION <= 2 +namespace boost { +namespace filesystem { +inline path absolute(const path& p) +{ + return complete(p, initial_path()); +} + +inline path absolute(const path& p, const path& base) +{ + return complete(p, base); +} +} +} +#endif + namespace mujinclient { static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) @@ -102,15 +129,33 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share public: ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { + size_t usernameindex = usernamepassword.find_first_of(':'); + BOOST_ASSERT(usernameindex != std::string::npos ); + std::string username = usernamepassword.substr(0,usernameindex); + std::string password = usernamepassword.substr(usernameindex+1); + _httpheaders = NULL; if( baseuri.size() > 0 ) { _baseuri = baseuri; + // ensure trailing slash + if( _baseuri[_baseuri.size()-1] != '/' ) { + _baseuri.push_back('/'); + } } else { // use the default _baseuri = "https://controller.mujin.co.jp/"; } _baseapiuri = _baseuri + std::string("api/v1/"); + // hack for now since webdav server and api server could be running on different ports + if( boost::algorithm::ends_with(_baseuri, ":8000/") ) { + // testing on localhost, however the webdav server is running on port 80... + _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); + } + else { + _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%username); + } + //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); @@ -177,9 +222,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share CHECKCURLCODE(res, "failed to max redirs"); if( !(options & 1) ) { - size_t index = usernamepassword.find_first_of(':'); - BOOST_ASSERT(index != std::string::npos ); - // make an initial GET call to get the CSRF token std::string loginuri = _baseuri + "login/"; curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); @@ -206,7 +248,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } else if( http_code == 200 ) { _csrfmiddlewaretoken = _GetCSRFFromCookies(); - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%usernamepassword.substr(0,index)%usernamepassword.substr(index+1)%_csrfmiddlewaretoken); + std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%username%password%_csrfmiddlewaretoken); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); @@ -361,11 +403,11 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } - virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& format) + virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& scenetype) { - BOOST_ASSERT(format.size()>0); + BOOST_ASSERT(scenetype.size()>0); boost::property_tree::ptree pt; - CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%format), pt); + CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; @@ -381,10 +423,103 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return scene; } - virtual bool SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) + class CustomRequestSetter { - BOOST_ASSERT(scenetype.size()>0); - throw MujinException("not implemented"); +public: + CustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); + } + ~CustomRequestSetter() { + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); + } +protected: + CURL* _curl; + }; + + virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) + { + boost::mutex::scoped_lock lock(_mutex); + std::string baseuploaduri; + if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + baseuploaduri += destinationdir.substr(7); + + // go through every directory + boost::filesystem::path bfpdestinationdir(destinationdir.substr(7)); + std::list listCreateDirs; + while( !bfpdestinationdir.parent_path().empty() ) { + boost::filesystem::path bfpparent = bfpdestinationdir.parent_path(); + listCreateDirs.push_front(bfpparent.string()); + bfpdestinationdir = bfpparent; + } + + CustomRequestSetter setter(_curl, "MKCOL"); + for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { + // first have to create the directory structure up to destinationdir + _uri = _basewebdavuri + *itdir; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + /* creating directories + + Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. + + 201 (Created) - The collection or structured resource was created in its entirety. + + 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. + + 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. + + 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. + + 415 (Unsupported Media Type)- The server does not support the request type of the body. + + 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. + + */ + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d", http_code, MEC_HTTPServer); + } + } + } + else { + baseuploaduri = destinationdir; + } + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + + // tell it to "upload" to the URL + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); + //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); +#if defined(_WIN32) || defined(_WIN64) + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); +#endif + + boost::filesystem::path bfpsourcefilename(sourcefilename); + if( scenetype == "wincaps" ) { + // scenefilenames is the WPJ file, so have to open it up to see what directory it points to + // note that the encoding is utf-16 + // + // .\threegoaltouch\threegoaltouch.WCN; + // + } + + _UploadSingleFile(sourcefilename, baseuploaduri+bfpsourcefilename.filename()); + //std::string = bfpsourcefilename.filename(); + + + /* webdav operations + const char *postdata = + "" + "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" + " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " + "WHERE \"DAV:isfolder\" = True\r\n"; + */ } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception @@ -521,17 +656,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return _buffer; } - /* webdav operations - const char *postdata = - "" - "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" - " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " - "WHERE \"DAV:isfolder\" = True\r\n"; - - CURLOPT_UPLOAD - - */ - virtual void SetDefaultSceneType(const std::string& scenetype) { _defaultscenetype = scenetype; @@ -628,11 +752,75 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return csrfmiddlewaretoken; } + /// \brief uploads a single file, assumes the directory already exists + /// + /// overwrites the file if it already exists + void _UploadSingleFile(const std::string& filename, const std::string& uri) + { + FILE * fd = fopen(filename.c_str(), "rb"); + if(!fd) { + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename, MEC_InvalidArguments); + } + +#if defined(_WIN32) || defined(_WIN64) + fseek(fd,0,SEEK_END); + curl_off_t filesize = ftell(fd); + fseek(fd,0,SEEK_SET); +#else + // to get the file size + struct stat file_info; + if(fstat(fileno(fd), &file_info) != 0) { + fclose(fd); // make sure to close the handle + throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", filename, MEC_InvalidArguments); + } + curl_off_t filesize = (curl_off_t)file_info.st_size; +#endif + + _uri = uri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_READDATA, fd); + curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); + + curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); + + CURLcode res = curl_easy_perform(_curl); + fclose(fd); // make sure to close the handle + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 201 ) { + if( http_code == 400 ) { + throw MUJIN_EXCEPTION_FORMAT("upload failed with HTTP status %s, perhaps file exists already?", http_code, MEC_HTTPServer); + } + else { + throw MUJIN_EXCEPTION_FORMAT("upload failed with HTTP status %s", http_code, MEC_HTTPServer); + } + } + // now extract transfer info + //double speed_upload, total_time; + //curl_easy_getinfo(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); + //curl_easy_getinfo(_curl, CURLINFO_TOTAL_TIME, &total_time); + //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); + } + + /// \brief read upload function for win32. + /// MUST also provide this read callback using CURLOPT_READFUNCTION. Failing to do so will give you a crash since a DLL may not use the variable's memory when passed in to it from an app like this. */ + static size_t _ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) + { + curl_off_t nread; + // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally + size_t retcode = fread(ptr, size, nmemb, (FILE*)stream); + + nread = (curl_off_t)retcode; + //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); + return retcode; + } + int _lastmode; CURL *_curl; boost::mutex _mutex; std::stringstream _buffer; - std::string _baseuri, _baseapiuri, _uri; + std::string _baseuri, _baseapiuri, _basewebdavuri, _uri; curl_slist *_httpheaders; std::string _charset, _language; From ad342c5604c61e3327c46440f4fe1ab854716c0a Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 17:36:13 +0900 Subject: [PATCH 043/477] uploading wincaps directories works --- .../mujincontrollerclient.h | 12 +- src/mujincontrollerclient.cpp | 255 +++++++++++++----- 2 files changed, 199 insertions(+), 68 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9e246a12..bd64d325 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -359,7 +359,7 @@ class MUJINCLIENT_API ControllerClient /** \brief import a scene into COLLADA format using from scene identified by a URI - \param sourceuri The original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext + \param sourceuri URI-encoded original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext \param sourcescenetype The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) @@ -374,17 +374,17 @@ class MUJINCLIENT_API ControllerClient /** \brief uploads a particular scene's files into the network filesystem. - \param sourcefilename Local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. - \param destinationdir Destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. + \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" \param scenetype The type of scene uploading. \throw mujin_exception if the upload fails, will throw an exception */ - virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; + virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; /// \see SyncUpload - virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir) + virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir) { - SyncUpload(sourcefilename, destinationdir, GetDefaultSceneType()); + SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); } virtual void SetDefaultSceneType(const std::string& scenetype) = 0; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index bf3898fc..3f1ec64b 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include #include @@ -46,7 +48,7 @@ #define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); #define CHECKCURLCODE(code, msg) if (code != CURLE_OK) { \ - throw MujinException(str(boost::format("[%s:%d] curl function failed with error '%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%curl_easy_strerror(code)%(msg)), MEC_HTTPClient); \ + throw MujinException(str(boost::format("[%s:%d] curl function %s with error='%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%(msg)%curl_easy_strerror(code)%_errormessage), MEC_HTTPClient); \ } #define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) @@ -163,6 +165,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share #ifdef _DEBUG //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); #endif + _errormessage.resize(CURL_ERROR_SIZE); + curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); CURLcode res; #ifdef SKIP_PEER_VERIFICATION @@ -423,66 +427,42 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return scene; } - class CustomRequestSetter + class CurlCustomRequestSetter { public: - CustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { + CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); } - ~CustomRequestSetter() { + ~CurlCustomRequestSetter() { curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); } protected: CURL* _curl; }; - virtual void SyncUpload(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) + class CurlUploadSetter { +public: + CurlUploadSetter(CURL *curl) : _curl(curl) { + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); + } + ~CurlUploadSetter() { + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); + } +protected: + CURL* _curl; + }; + + virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) + { + // TODO use curl_multi_perform to allow uploading of multiple files simultaneously + // TODO should LOCK with WebDAV repository? boost::mutex::scoped_lock lock(_mutex); std::string baseuploaduri; if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { baseuploaduri = _basewebdavuri; - baseuploaduri += destinationdir.substr(7); - - // go through every directory - boost::filesystem::path bfpdestinationdir(destinationdir.substr(7)); - std::list listCreateDirs; - while( !bfpdestinationdir.parent_path().empty() ) { - boost::filesystem::path bfpparent = bfpdestinationdir.parent_path(); - listCreateDirs.push_front(bfpparent.string()); - bfpdestinationdir = bfpparent; - } - - CustomRequestSetter setter(_curl, "MKCOL"); - for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { - // first have to create the directory structure up to destinationdir - _uri = _basewebdavuri + *itdir; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - /* creating directories - - Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. - - 201 (Created) - The collection or structured resource was created in its entirety. - - 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. - - 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. - - 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. - - 415 (Unsupported Media Type)- The server does not support the request type of the body. - - 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. - - */ - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d", http_code, MEC_HTTPServer); - } - } + baseuploaduri += _EncodeWithoutSeparator(destinationdir.substr(7)); + _EnsureWebDAVDirectories(destinationdir.substr(7)); } else { baseuploaduri = destinationdir; @@ -492,14 +472,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share baseuploaduri.push_back('/'); } - // tell it to "upload" to the URL - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); - //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); -#if defined(_WIN32) || defined(_WIN64) - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); -#endif - boost::filesystem::path bfpsourcefilename(sourcefilename); if( scenetype == "wincaps" ) { // scenefilenames is the WPJ file, so have to open it up to see what directory it points to @@ -507,11 +479,52 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // // .\threegoaltouch\threegoaltouch.WCN; // + // first have to get the raw utf-16 data + std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); + if( !wpjfilestream ) { + throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", sourcefilename, MEC_InvalidArguments); + } + std::stringstream wpjfilestream2; + wpjfilestream2 << wpjfilestream.rdbuf() << '\0'; + std::string wpjfilestreamdata = wpjfilestream2.str(); + uint16_t* pstart = (uint16_t*)wpjfilestreamdata.c_str(); + uint16_t* pend = pstart + wpjfilestreamdata.size()/2; + std::stringstream utf8stream; + utf8::utf16to8(pstart, pend, std::ostream_iterator(utf8stream)); + boost::property_tree::ptree wpj; + boost::property_tree::read_xml(utf8stream, wpj); + boost::property_tree::ptree& clsProject = wpj.get_child("clsProject"); + boost::property_tree::ptree& WCNPath = clsProject.get_child("WCNPath"); + std::string strWCNPath = WCNPath.data(); + if( strWCNPath.size() > 0 ) { + // post process the string to get the real filesystem directory + if( strWCNPath.at(strWCNPath.size()-1) == ';') { + strWCNPath.resize(strWCNPath.size()-1); + } +#if defined(_WIN32) || defined(_WIN64) +#else + // separator are in windows, so have to convert + for(size_t i = 0; i < strWCNPath.size(); ++i) { + if( strWCNPath[i] == '\\' ) { + strWCNPath[i] = '/'; + } + } +#endif + boost::filesystem::path winpath(strWCNPath); + boost::filesystem::path copydir = bfpsourcefilename.parent_path() / winpath.parent_path().normalize(); + std::string winpathdir = winpath.parent_path().string(); + if( winpathdir.size() >= 2 && winpathdir.substr(0,2) == "./" ) { + // don't need the ./ prefix + winpathdir = winpathdir.substr(2); + } + _UploadDirectoryToWebDAV(copydir, baseuploaduri+_EncodeWithoutSeparator(winpathdir)); + } } - _UploadSingleFile(sourcefilename, baseuploaduri+bfpsourcefilename.filename()); - //std::string = bfpsourcefilename.filename(); - + char* pescapeddir = curl_easy_escape(_curl, bfpsourcefilename.filename().c_str(), 0); + std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); + curl_free(pescapeddir); + _UploadFileToWebDAV(sourcefilename, uploadfileuri); /* webdav operations const char *postdata = @@ -752,10 +765,119 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return csrfmiddlewaretoken; } + // encode a URL without the / separator + std::string _EncodeWithoutSeparator(const std::string& raw) + { + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < raw.size(); ++i) { + if( raw[i] == '/' ) { + if( startindex != i ) { + char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, i-startindex); + output += std::string(pescaped); + curl_free(pescaped); + startindex = i+1; + } + output += '/'; + } + } + if( startindex != raw.size() ) { + char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, raw.size()-startindex); + output += std::string(pescaped); + curl_free(pescaped); + } + return output; + } + + /// \param destinationdir the directory inside the user webdav folder + void _EnsureWebDAVDirectories(const std::string& destinationdir) + { + // go through every directory + boost::filesystem::path bfpdestinationdir(destinationdir); + std::list listCreateDirs; + while( !bfpdestinationdir.parent_path().empty() ) { + boost::filesystem::path bfpparent = bfpdestinationdir.parent_path(); + listCreateDirs.push_front(bfpparent.string()); + bfpdestinationdir = bfpparent; + } + + // Check that the directory exists + //curl_easy_setopt(_curl, CURLOPT_URL, buff); + //curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + //res = curl_easy_perform(self->send_handle); + //if(res != 0) { + // // does not exist + //} + + CurlCustomRequestSetter setter(_curl, "MKCOL"); + for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { + // first have to create the directory structure up to destinationdir + char* pescapeddir = curl_easy_escape(_curl, itdir->c_str(), itdir->size()); + _uri = _basewebdavuri + std::string(pescapeddir); + curl_free(pescapeddir); + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + /* creating directories + + Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. + + 201 (Created) - The collection or structured resource was created in its entirety. + + 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. + + 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. + + 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. + + 415 (Unsupported Media Type)- The server does not support the request type of the body. + + 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. + + */ + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); + } + } + } + + /// \brief recursively uploads a directory and creates directories along the way if they don't exist + /// + /// overwrites all the files + void _UploadDirectoryToWebDAV(const boost::filesystem::path& copydir, const std::string& uri) + { + { + // make sure the directory is created + CurlCustomRequestSetter setter(_curl, "MKCOL"); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); + } + } + std::cout << "uploading " << copydir.string() << " -> " << uri << std::endl; + for(boost::filesystem::directory_iterator itdir(copydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { + char* pescapeddir = curl_easy_escape(_curl, itdir->filename().c_str(), itdir->filename().size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + if( boost::filesystem::is_directory(itdir->status()) ) { + _UploadDirectoryToWebDAV(itdir->path(), newuri); + } + else if( boost::filesystem::is_regular_file(itdir->status()) ) { + _UploadFileToWebDAV(itdir->path().string(), newuri); + } + } + } + /// \brief uploads a single file, assumes the directory already exists /// /// overwrites the file if it already exists - void _UploadSingleFile(const std::string& filename, const std::string& uri) + void _UploadFileToWebDAV(const std::string& filename, const std::string& uri) { FILE * fd = fopen(filename.c_str(), "rb"); if(!fd) { @@ -776,19 +898,27 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_off_t filesize = (curl_off_t)file_info.st_size; #endif - _uri = uri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + // tell it to "upload" to the URL + CurlUploadSetter uploadsetter(_curl); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); curl_easy_setopt(_curl, CURLOPT_READDATA, fd); curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); + //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); +#if defined(_WIN32) || defined(_WIN64) + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); +#endif - curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); + + //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); CURLcode res = curl_easy_perform(_curl); fclose(fd); // make sure to close the handle CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 ) { + // 204 is when it overwrites the file? + if( http_code != 201 && http_code != 204 ) { if( http_code == 400 ) { throw MUJIN_EXCEPTION_FORMAT("upload failed with HTTP status %s, perhaps file exists already?", http_code, MEC_HTTPServer); } @@ -827,6 +957,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::string _csrfmiddlewaretoken; boost::property_tree::ptree _profile; ///< user profile and versioning + std::string _errormessage; ///< set when an error occurs in libcurl std::string _defaultscenetype, _defaulttasktype; }; From 206f4abe207bc6f9c014cf46ee0c13a859dee093 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 18:27:49 +0900 Subject: [PATCH 044/477] fixed windows compilation --- .../mujincontrollerclient.h | 9 ++++--- src/mujincontrollerclient.cpp | 24 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index bd64d325..a301e62d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -21,8 +21,6 @@ #define BOOST_ENABLE_ASSERT_HANDLER #endif -#define BOOST_FILESYSTEM_VERSION 3 // use boost filesystem v3 - #ifdef _MSC_VER #pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class @@ -49,6 +47,11 @@ #include #include +#if BOOST_VERSION >= 104400 +// boost filesystem v3 is present after v1.44, so force using it +#define BOOST_FILESYSTEM_VERSION 3 +#endif + #include #include #include @@ -374,7 +377,7 @@ class MUJINCLIENT_API ControllerClient /** \brief uploads a particular scene's files into the network filesystem. - \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. + \param sourcefilename URI-encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" \param scenetype The type of scene uploading. \throw mujin_exception if the upload fails, will throw an exception diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3f1ec64b..aa7b6b8c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ #include #endif - #include "utf8.h" #ifdef _MSC_VER @@ -85,6 +85,8 @@ inline path absolute(const path& p, const path& base) } #endif +BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); // need this for utf-16 reading + namespace mujinclient { static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) @@ -487,8 +489,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::stringstream wpjfilestream2; wpjfilestream2 << wpjfilestream.rdbuf() << '\0'; std::string wpjfilestreamdata = wpjfilestream2.str(); - uint16_t* pstart = (uint16_t*)wpjfilestreamdata.c_str(); - uint16_t* pend = pstart + wpjfilestreamdata.size()/2; + const unsigned short* pstart = reinterpret_cast(wpjfilestreamdata.c_str()); + const unsigned short* pend = pstart + wpjfilestreamdata.size()/2; std::stringstream utf8stream; utf8::utf16to8(pstart, pend, std::ostream_iterator(utf8stream)); boost::property_tree::ptree wpj; @@ -513,7 +515,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share boost::filesystem::path winpath(strWCNPath); boost::filesystem::path copydir = bfpsourcefilename.parent_path() / winpath.parent_path().normalize(); std::string winpathdir = winpath.parent_path().string(); - if( winpathdir.size() >= 2 && winpathdir.substr(0,2) == "./" ) { + if( winpathdir.size() >= 2 && (winpathdir.substr(0,2) == "./" || winpathdir.substr(0,2) == ".\\") ) { // don't need the ./ prefix winpathdir = winpathdir.substr(2); } @@ -521,7 +523,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } - char* pescapeddir = curl_easy_escape(_curl, bfpsourcefilename.filename().c_str(), 0); +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::string sourcefilenamebase = bfpsourcefilename.filename().string(); +#else + std::string sourcefilenamebase = bfpsourcefilename.filename(); +#endif + char* pescapeddir = curl_easy_escape(_curl, sourcefilenamebase.c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); _UploadFileToWebDAV(sourcefilename, uploadfileuri); @@ -862,7 +869,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } std::cout << "uploading " << copydir.string() << " -> " << uri << std::endl; for(boost::filesystem::directory_iterator itdir(copydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { - char* pescapeddir = curl_easy_escape(_curl, itdir->filename().c_str(), itdir->filename().size()); +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::string dirfilename = itdir->path().filename().string(); +#else + std::string dirfilename = itdir->path().filename(); +#endif + char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { From bd57fb1fcfd40b8e1a906abc03f691085e1f55a4 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 18:54:52 +0900 Subject: [PATCH 045/477] fixed creating uploaded dirs --- src/mujincontrollerclient.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index aa7b6b8c..67f65afa 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -796,15 +796,24 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share return output; } - /// \param destinationdir the directory inside the user webdav folder + /// \param destinationdir the directory inside the user webdav folder. has a trailing slash void _EnsureWebDAVDirectories(const std::string& destinationdir) { // go through every directory boost::filesystem::path bfpdestinationdir(destinationdir); std::list listCreateDirs; - while( !bfpdestinationdir.parent_path().empty() ) { + while( !bfpdestinationdir.empty() ) { boost::filesystem::path bfpparent = bfpdestinationdir.parent_path(); - listCreateDirs.push_front(bfpparent.string()); +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::string filename = bfpdestinationdir.filename().string(); +#else + std::string filename = bfpdestinationdir.filename(); +#endif + if( filename != "." ) { + char* pescapedname = curl_easy_escape(_curl, filename.c_str(), filename.size()); + listCreateDirs.push_front(pescapedname); + curl_free(pescapedname); + } bfpdestinationdir = bfpparent; } @@ -817,11 +826,14 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share //} CurlCustomRequestSetter setter(_curl, "MKCOL"); + std::string totaluri = ""; for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { // first have to create the directory structure up to destinationdir - char* pescapeddir = curl_easy_escape(_curl, itdir->c_str(), itdir->size()); - _uri = _basewebdavuri + std::string(pescapeddir); - curl_free(pescapeddir); + if( totaluri.size() > 0 ) { + totaluri += '/'; + } + totaluri += *itdir; + _uri = _basewebdavuri + totaluri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); From fc312ab8451b3f1db048db7c3f3bbf680119b0d0 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 23:06:43 +0900 Subject: [PATCH 046/477] added windows codepage suppot --- src/mujincontrollerclient.cpp | 214 ++++++++++++++++++++++++++++------ 1 file changed, 179 insertions(+), 35 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 67f65afa..33f4157c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -32,11 +32,11 @@ #include #if defined(_WIN32) || defined(_WIN64) -// win32 specific includes? +#include #else #include #include -#endif +#endif // defined(_WIN32) || defined(_WIN64) #include "utf8.h" @@ -89,6 +89,142 @@ BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); // need this for utf-16 readin namespace mujinclient { + +namespace encoding { + +#if defined(_WIN32) || defined(_WIN64) + +// Build a table of the mapping between code pages and web charsets +// It's hack, but at least it doesn't drag in a bunch of unnecessary dependencies +// http://msdn.microsoft.com/en-us/library/aa288104%28v=vs.71%29.aspx +std::map InitializeCodePageMap() +{ + std::map mapCodePageToCharset; + mapCodePageToCharset[866] = "IBM866"; + mapCodePageToCharset[852] = "IBM852"; + mapCodePageToCharset[949] = "KS_C_5601-1987"; + mapCodePageToCharset[50220/*CODE_JPN_JIS*/] = "ISO-2022-JP"; + mapCodePageToCharset[874] = "windows-874"; + mapCodePageToCharset[20866] = "koi8-r"; + mapCodePageToCharset[1251] = "x-cp1251"; + mapCodePageToCharset[50225] = "ISO-2022-KR"; + mapCodePageToCharset[1256] = "windows-1256"; + mapCodePageToCharset[1257] = "windows-1257"; + mapCodePageToCharset[1254] = "windows-1254"; + mapCodePageToCharset[1255] = "windows-1255"; + mapCodePageToCharset[1252] = "windows-1252"; + mapCodePageToCharset[1253] = "windows-1253"; + mapCodePageToCharset[1250] = "x-cp1250"; + mapCodePageToCharset[950] = "x-x-big5"; + mapCodePageToCharset[932] = "Shift_JIS"; + mapCodePageToCharset[51932/*CODE_JPN_EUC*/] = "EUC-JP"; + mapCodePageToCharset[28592] = "latin2"; + mapCodePageToCharset[936] = "ISO-IR-58"; + mapCodePageToCharset[1258] = "windows-1258"; + return mapCodePageToCharset; +} +static std::map s_mapCodePageToCharset = InitializeCodePageMap(); + +inline std::wstring ConvertUTF8toUTF16(const std::string& utf8) +{ + std::wstring utf16(L""); + + if (!utf8.empty()) { + size_t nLen16 = 0; + if ((nLen16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0)) > 0) { + utf16.resize(nLen16); + ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &utf16[0], nLen16); + // remove the null terminated char that was written + utf16.resize(nLen16-1); + } + } + return utf16; +} + +inline std::string ConvertUTF16toUTF8(const std::wstring& utf16) +{ + std::string utf8(""); + + if (!utf16.empty()) { + size_t nLen8 = 0; + if ((nLen8 = ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { + utf8.resize(nLen8); + ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, &utf8[0], nLen8, NULL, NULL); + // remove the null terminated char that was written + utf8.resize(nLen8-1); + } + } + return utf8; +} + +inline std::string ConvertUTF16toMBS(const std::wstring& utf16) +{ + std::string mbs(""); + + if (!utf16.empty()) { + size_t nLenA = 0; + if ((nLenA = ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { + mbs.resize(nLenA); + ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, &mbs[0], nLenA, NULL, NULL); + // remove the null terminated char that was written + mbs.resize(nLenA-1); + } + } + return mbs; +} + +inline std::wstring ConvertMBStoUTF16(const std::string& mbs) +{ + std::wstring utf16(L""); + + if (!mbs.empty()) { + size_t nLen16 = 0; + if ((nLen16 = ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, NULL, 0)) > 0) { + utf16.resize(nLen16); + ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, &utf16[0], nLen16); + // remove the null terminated char that was written + utf16.resize(nLen16-1); + } + } + return utf16; +} + +inline std::string ConvertMBStoUTF8(const std::string& mbs) +{ + return ConvertUTF16toUTF8(ConvertMBStoUTF16(mbs)); +} + +inline std::string ConvertUTF8toMBS(const std::string& utf8) +{ + return ConvertUTF16toMBS(ConvertUTF8toUTF16(utf8)); +} +#endif // defined(_WIN32) || defined(_WIN64) + +/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses +std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) +{ +#if defined(_WIN32) || defined(_WIN64) + return encoding::ConvertUTF8toMBS(utf8); +#else + // most linux systems use utf-8, can use getenv("LANG") to double-check + return utf8; +#endif +} + +/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses +std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) +{ +#if defined(_WIN32) || defined(_WIN64) + return encoding::ConvertMBStoUTF8(fs); +#else + // most linux systems use utf-8, can use getenv("LANG") to double-check + return fs; +#endif +} + +} + + static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) { return p0.first.size() > p1.first.size(); @@ -275,6 +411,13 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _charset = "utf-8"; _language = "en-us"; +#if defined(_WIN32) || defined(_WIN64) + UINT codepage = GetACP(); + if( encoding::s_mapCodePageToCharset.find(codepage) != encoding::s_mapCodePageToCharset.end() ) { + _charset = encoding::s_mapCodePageToCharset[codepage]; + } +#endif + std::cout << "setting character set to " << _charset << std::endl; _SetHTTPHeaders(); try { @@ -474,7 +617,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share baseuploaduri.push_back('/'); } - boost::filesystem::path bfpsourcefilename(sourcefilename); + boost::filesystem::path bfpsourcefilename(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename)); if( scenetype == "wincaps" ) { // scenefilenames is the WPJ file, so have to open it up to see what directory it points to // note that the encoding is utf-16 @@ -482,7 +625,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // .\threegoaltouch\threegoaltouch.WCN; // // first have to get the raw utf-16 data - std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); + std::ifstream wpjfilestream(bfpsourcefilename.string().c_str(), std::ios::binary|std::ios::in); if( !wpjfilestream ) { throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", sourcefilename, MEC_InvalidArguments); } @@ -512,7 +655,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } #endif - boost::filesystem::path winpath(strWCNPath); + boost::filesystem::path winpath(encoding::ConvertUTF8ToFileSystemEncoding(strWCNPath)); boost::filesystem::path copydir = bfpsourcefilename.parent_path() / winpath.parent_path().normalize(); std::string winpathdir = winpath.parent_path().string(); if( winpathdir.size() >= 2 && (winpathdir.substr(0,2) == "./" || winpathdir.substr(0,2) == ".\\") ) { @@ -523,15 +666,16 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } + // sourcefilenamebase is utf-8 #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string sourcefilenamebase = bfpsourcefilename.filename().string(); + std::string sourcefilenamebase = boost::filesystem::path(sourcefilename).filename().string(); #else - std::string sourcefilenamebase = bfpsourcefilename.filename(); + std::string sourcefilenamebase = boost::filesystem::path(sourcefilename).filename(); #endif char* pescapeddir = curl_easy_escape(_curl, sourcefilenamebase.c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); - _UploadFileToWebDAV(sourcefilename, uploadfileuri); + _UploadFileToWebDAV(bfpsourcefilename, uploadfileuri); /* webdav operations const char *postdata = @@ -797,24 +941,25 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } /// \param destinationdir the directory inside the user webdav folder. has a trailing slash - void _EnsureWebDAVDirectories(const std::string& destinationdir) + void _EnsureWebDAVDirectories(const std::string& uriDestinationDir) { - // go through every directory - boost::filesystem::path bfpdestinationdir(destinationdir); - std::list listCreateDirs; - while( !bfpdestinationdir.empty() ) { - boost::filesystem::path bfpparent = bfpdestinationdir.parent_path(); -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string filename = bfpdestinationdir.filename().string(); -#else - std::string filename = bfpdestinationdir.filename(); -#endif - if( filename != "." ) { - char* pescapedname = curl_easy_escape(_curl, filename.c_str(), filename.size()); - listCreateDirs.push_front(pescapedname); - curl_free(pescapedname); + std::list listCreateDirs; + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < uriDestinationDir.size(); ++i) { + if( uriDestinationDir[i] == '/' ) { + if( startindex != i ) { + char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, i-startindex); + listCreateDirs.push_back(std::string(pescaped)); + curl_free(pescaped); + startindex = i+1; + } } - bfpdestinationdir = bfpparent; + } + if( startindex != uriDestinationDir.size() ) { + char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, uriDestinationDir.size()-startindex); + listCreateDirs.push_back(std::string(pescaped)); + curl_free(pescaped); } // Check that the directory exists @@ -864,7 +1009,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief recursively uploads a directory and creates directories along the way if they don't exist /// - /// overwrites all the files + /// overwrites all the files + /// \param copydir is already file-system encoded + /// \param uri is URI-encoded void _UploadDirectoryToWebDAV(const boost::filesystem::path& copydir, const std::string& uri) { { @@ -882,9 +1029,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::cout << "uploading " << copydir.string() << " -> " << uri << std::endl; for(boost::filesystem::directory_iterator itdir(copydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = itdir->path().filename().string(); + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); #else - std::string dirfilename = itdir->path().filename(); + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); #endif char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); @@ -893,7 +1040,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share _UploadDirectoryToWebDAV(itdir->path(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV(itdir->path().string(), newuri); + _UploadFileToWebDAV(itdir->path(), newuri); } } } @@ -901,11 +1048,11 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief uploads a single file, assumes the directory already exists /// /// overwrites the file if it already exists - void _UploadFileToWebDAV(const std::string& filename, const std::string& uri) + void _UploadFileToWebDAV(const boost::filesystem::path& bfpfilename, const std::string& uri) { - FILE * fd = fopen(filename.c_str(), "rb"); + FILE * fd = fopen(bfpfilename.string().c_str(), "rb"); if(!fd) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", bfpfilename.string(), MEC_InvalidArguments); } #if defined(_WIN32) || defined(_WIN64) @@ -917,7 +1064,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share struct stat file_info; if(fstat(fileno(fd), &file_info) != 0) { fclose(fd); // make sure to close the handle - throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", filename, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", bfpfilename.string(), MEC_InvalidArguments); } curl_off_t filesize = (curl_off_t)file_info.st_size; #endif @@ -933,9 +1080,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); #endif - - //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); - CURLcode res = curl_easy_perform(_curl); fclose(fd); // make sure to close the handle CHECKCURLCODE(res, "curl_easy_perform failed"); From 7cf7847a95354c6301ff8c5342c7a44199061d42 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 4 Apr 2013 09:52:00 -0700 Subject: [PATCH 047/477] removed boost::filesystem from windows builds. japanese names are supported. --- .../mujincontrollerclient.h | 5 - src/mujincontrollerclient.cpp | 192 +++++++++++------- 2 files changed, 122 insertions(+), 75 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a301e62d..21d1544c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -47,11 +47,6 @@ #include #include -#if BOOST_VERSION >= 104400 -// boost filesystem v3 is present after v1.44, so force using it -#define BOOST_FILESYSTEM_VERSION 3 -#endif - #include #include #include diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 33f4157c..3fcf9fed 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -34,8 +34,17 @@ #if defined(_WIN32) || defined(_WIN64) #include #else + +#if BOOST_VERSION >= 104400 +// boost filesystem v3 is present after v1.44, so force using it +#define BOOST_FILESYSTEM_VERSION 3 +#endif + +// only use boost filesystem on linux since it is difficult to get working correctly with windows +#include #include #include + #endif // defined(_WIN32) || defined(_WIN64) #include "utf8.h" @@ -67,24 +76,6 @@ #define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } -#include - -#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION <= 2 -namespace boost { -namespace filesystem { -inline path absolute(const path& p) -{ - return complete(p, initial_path()); -} - -inline path absolute(const path& p, const path& base) -{ - return complete(p, base); -} -} -} -#endif - BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); // need this for utf-16 reading namespace mujinclient { @@ -100,27 +91,28 @@ namespace encoding { std::map InitializeCodePageMap() { std::map mapCodePageToCharset; - mapCodePageToCharset[866] = "IBM866"; - mapCodePageToCharset[852] = "IBM852"; - mapCodePageToCharset[949] = "KS_C_5601-1987"; - mapCodePageToCharset[50220/*CODE_JPN_JIS*/] = "ISO-2022-JP"; - mapCodePageToCharset[874] = "windows-874"; - mapCodePageToCharset[20866] = "koi8-r"; - mapCodePageToCharset[1251] = "x-cp1251"; - mapCodePageToCharset[50225] = "ISO-2022-KR"; - mapCodePageToCharset[1256] = "windows-1256"; - mapCodePageToCharset[1257] = "windows-1257"; - mapCodePageToCharset[1254] = "windows-1254"; - mapCodePageToCharset[1255] = "windows-1255"; - mapCodePageToCharset[1252] = "windows-1252"; - mapCodePageToCharset[1253] = "windows-1253"; - mapCodePageToCharset[1250] = "x-cp1250"; - mapCodePageToCharset[950] = "x-x-big5"; - mapCodePageToCharset[932] = "Shift_JIS"; - mapCodePageToCharset[51932/*CODE_JPN_EUC*/] = "EUC-JP"; - mapCodePageToCharset[28592] = "latin2"; - mapCodePageToCharset[936] = "ISO-IR-58"; + mapCodePageToCharset[866] = "IBM866"; + mapCodePageToCharset[852] = "IBM852"; + mapCodePageToCharset[949] = "KS_C_5601-1987"; + mapCodePageToCharset[50220/*CODE_JPN_JIS*/] = "ISO-2022-JP"; + mapCodePageToCharset[874] = "windows-874"; + mapCodePageToCharset[20866] = "koi8-r"; + mapCodePageToCharset[1251] = "x-cp1251"; + mapCodePageToCharset[50225] = "ISO-2022-KR"; + mapCodePageToCharset[1256] = "windows-1256"; + mapCodePageToCharset[1257] = "windows-1257"; + mapCodePageToCharset[1254] = "windows-1254"; + mapCodePageToCharset[1255] = "windows-1255"; + mapCodePageToCharset[1252] = "windows-1252"; + mapCodePageToCharset[1253] = "windows-1253"; + mapCodePageToCharset[1250] = "x-cp1250"; + mapCodePageToCharset[950] = "x-x-big5"; + mapCodePageToCharset[932] = "Shift_JIS"; + mapCodePageToCharset[51932/*CODE_JPN_EUC*/] = "EUC-JP"; + mapCodePageToCharset[28592] = "latin2"; + mapCodePageToCharset[936] = "ISO-IR-58"; mapCodePageToCharset[1258] = "windows-1258"; + mapCodePageToCharset[65001] = "utf-8"; return mapCodePageToCharset; } static std::map s_mapCodePageToCharset = InitializeCodePageMap(); @@ -224,6 +216,11 @@ std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) } +#ifdef _WIN32 +const char s_filesep = '\\'; +#else +const char s_filesep = '/'; +#endif static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) { @@ -617,7 +614,15 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share baseuploaduri.push_back('/'); } - boost::filesystem::path bfpsourcefilename(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename)); + size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + if( scenetype == "wincaps" ) { // scenefilenames is the WPJ file, so have to open it up to see what directory it points to // note that the encoding is utf-16 @@ -625,7 +630,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // .\threegoaltouch\threegoaltouch.WCN; // // first have to get the raw utf-16 data - std::ifstream wpjfilestream(bfpsourcefilename.string().c_str(), std::ios::binary|std::ios::in); + std::ifstream wpjfilestream(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename), std::ios::binary|std::ios::in); if( !wpjfilestream ) { throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", sourcefilename, MEC_InvalidArguments); } @@ -646,36 +651,45 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share if( strWCNPath.at(strWCNPath.size()-1) == ';') { strWCNPath.resize(strWCNPath.size()-1); } + + std::string strWCNURI = strWCNPath; + size_t lastindex = 0; + for(size_t i = 0; i < strWCNURI.size(); ++i) { + if( strWCNURI[i] == '\\' ) { + strWCNURI[i] = '/'; + lastindex = i; + } + } + + if( strWCNPath.size() >= 2 && (strWCNPath[0] == '.' && strWCNPath[1] == '\\') ) { + // don't need the prefix + strWCNPath = strWCNPath.substr(2); + strWCNURI = strWCNURI.substr(2); + if( lastindex < 2 ) { + lastindex = 0; + } + else { + lastindex -= 2; + } + } + + #if defined(_WIN32) || defined(_WIN64) #else // separator are in windows, so have to convert - for(size_t i = 0; i < strWCNPath.size(); ++i) { - if( strWCNPath[i] == '\\' ) { - strWCNPath[i] = '/'; - } - } + strWCNPath = strWCNURI; #endif - boost::filesystem::path winpath(encoding::ConvertUTF8ToFileSystemEncoding(strWCNPath)); - boost::filesystem::path copydir = bfpsourcefilename.parent_path() / winpath.parent_path().normalize(); - std::string winpathdir = winpath.parent_path().string(); - if( winpathdir.size() >= 2 && (winpathdir.substr(0,2) == "./" || winpathdir.substr(0,2) == ".\\") ) { - // don't need the ./ prefix - winpathdir = winpathdir.substr(2); - } - _UploadDirectoryToWebDAV(copydir, baseuploaduri+_EncodeWithoutSeparator(winpathdir)); + + std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); + _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); } } // sourcefilenamebase is utf-8 -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string sourcefilenamebase = boost::filesystem::path(sourcefilename).filename().string(); -#else - std::string sourcefilenamebase = boost::filesystem::path(sourcefilename).filename(); -#endif - char* pescapeddir = curl_easy_escape(_curl, sourcefilenamebase.c_str(), 0); + char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); - _UploadFileToWebDAV(bfpsourcefilename, uploadfileuri); + _UploadFileToWebDAV_UTF8(sourcefilename, uploadfileuri); /* webdav operations const char *postdata = @@ -1010,9 +1024,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief recursively uploads a directory and creates directories along the way if they don't exist /// /// overwrites all the files - /// \param copydir is already file-system encoded + /// \param copydir is utf-8 encoded /// \param uri is URI-encoded - void _UploadDirectoryToWebDAV(const boost::filesystem::path& copydir, const std::string& uri) + void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) { { // make sure the directory is created @@ -1026,8 +1040,44 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); } } - std::cout << "uploading " << copydir.string() << " -> " << uri << std::endl; - for(boost::filesystem::directory_iterator itdir(copydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { + + std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); + std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; + +#if defined(_WIN32) || defined(_WIN64) + WIN32_FIND_DATA ffd; + std::string searchstr = sCopyDir_FS + std::string("\\*"); + HANDLE hFind = FindFirstFile(searchstr.c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); + } + + do { + std::string filename = std::string(ffd.cFileName); + if( filename != "." && filename != ".." ) { + std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); + std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); + char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + + if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); + } + else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { + _UploadFileToWebDAV_UTF8(newcopydir, newuri); + } + } + } while(FindNextFile(hFind,&ffd) != 0); + + DWORD err = GetLastError(); + FindClose(hFind); + if( err != ERROR_NO_MORE_FILES ) { + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); + } + +#else + for(boost::filesystem::directory_iterator itdir(boost::filesystem::path(copydir)); itdir != boost::filesystem::directory_iterator(); ++itdir) { #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); #else @@ -1037,22 +1087,24 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV(itdir->path(), newuri); + _UploadDirectoryToWebDAV_UTF8(itdir->path(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV(itdir->path(), newuri); + _UploadFileToWebDAV_UTF8(itdir->path(), newuri); } } +#endif // defined(_WIN32) || defined(_WIN64) } /// \brief uploads a single file, assumes the directory already exists /// /// overwrites the file if it already exists - void _UploadFileToWebDAV(const boost::filesystem::path& bfpfilename, const std::string& uri) + void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) { - FILE * fd = fopen(bfpfilename.string().c_str(), "rb"); + std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); + FILE * fd = fopen(sFilename_FS.c_str(), "rb"); if(!fd) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", bfpfilename.string(), MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } #if defined(_WIN32) || defined(_WIN64) @@ -1116,7 +1168,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share int _lastmode; CURL *_curl; - boost::mutex _mutex; + boost::mutex _mutex; std::stringstream _buffer; std::string _baseuri, _baseapiuri, _basewebdavuri, _uri; From 0c3b6512192975b5fa1afecb515a5aead0a99e66 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 5 Apr 2013 02:14:37 +0900 Subject: [PATCH 048/477] fixed linux --- src/mujincontrollerclient.cpp | 87 ++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3fcf9fed..8074d2b1 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -94,7 +94,7 @@ std::map InitializeCodePageMap() mapCodePageToCharset[866] = "IBM866"; mapCodePageToCharset[852] = "IBM852"; mapCodePageToCharset[949] = "KS_C_5601-1987"; - mapCodePageToCharset[50220/*CODE_JPN_JIS*/] = "ISO-2022-JP"; + mapCodePageToCharset[50220 /*CODE_JPN_JIS*/] = "ISO-2022-JP"; mapCodePageToCharset[874] = "windows-874"; mapCodePageToCharset[20866] = "koi8-r"; mapCodePageToCharset[1251] = "x-cp1251"; @@ -108,7 +108,7 @@ std::map InitializeCodePageMap() mapCodePageToCharset[1250] = "x-cp1250"; mapCodePageToCharset[950] = "x-x-big5"; mapCodePageToCharset[932] = "Shift_JIS"; - mapCodePageToCharset[51932/*CODE_JPN_EUC*/] = "EUC-JP"; + mapCodePageToCharset[51932 /*CODE_JPN_EUC*/] = "EUC-JP"; mapCodePageToCharset[28592] = "latin2"; mapCodePageToCharset[936] = "ISO-IR-58"; mapCodePageToCharset[1258] = "windows-1258"; @@ -126,8 +126,8 @@ inline std::wstring ConvertUTF8toUTF16(const std::string& utf8) if ((nLen16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0)) > 0) { utf16.resize(nLen16); ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &utf16[0], nLen16); - // remove the null terminated char that was written - utf16.resize(nLen16-1); + // remove the null terminated char that was written + utf16.resize(nLen16-1); } } return utf16; @@ -142,8 +142,8 @@ inline std::string ConvertUTF16toUTF8(const std::wstring& utf16) if ((nLen8 = ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { utf8.resize(nLen8); ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, &utf8[0], nLen8, NULL, NULL); - // remove the null terminated char that was written - utf8.resize(nLen8-1); + // remove the null terminated char that was written + utf8.resize(nLen8-1); } } return utf8; @@ -158,8 +158,8 @@ inline std::string ConvertUTF16toMBS(const std::wstring& utf16) if ((nLenA = ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { mbs.resize(nLenA); ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, &mbs[0], nLenA, NULL, NULL); - // remove the null terminated char that was written - mbs.resize(nLenA-1); + // remove the null terminated char that was written + mbs.resize(nLenA-1); } } return mbs; @@ -174,8 +174,8 @@ inline std::wstring ConvertMBStoUTF16(const std::string& mbs) if ((nLen16 = ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, NULL, 0)) > 0) { utf16.resize(nLen16); ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, &utf16[0], nLen16); - // remove the null terminated char that was written - utf16.resize(nLen16-1); + // remove the null terminated char that was written + utf16.resize(nLen16-1); } } return utf16; @@ -196,10 +196,10 @@ inline std::string ConvertUTF8toMBS(const std::string& utf8) std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) { #if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertUTF8toMBS(utf8); + return encoding::ConvertUTF8toMBS(utf8); #else - // most linux systems use utf-8, can use getenv("LANG") to double-check - return utf8; + // most linux systems use utf-8, can use getenv("LANG") to double-check + return utf8; #endif } @@ -207,19 +207,19 @@ std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) { #if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertMBStoUTF8(fs); + return encoding::ConvertMBStoUTF8(fs); #else - // most linux systems use utf-8, can use getenv("LANG") to double-check - return fs; + // most linux systems use utf-8, can use getenv("LANG") to double-check + return fs; #endif } } -#ifdef _WIN32 -const char s_filesep = '\\'; -#else -const char s_filesep = '/'; +#ifdef _WIN32 +const char s_filesep = '\\'; +#else +const char s_filesep = '/'; #endif static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) @@ -614,7 +614,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share baseuploaduri.push_back('/'); } - size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); + size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); if( nBaseFilenameStartIndex == std::string::npos ) { // there's no path? nBaseFilenameStartIndex = 0; @@ -630,7 +630,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // .\threegoaltouch\threegoaltouch.WCN; // // first have to get the raw utf-16 data - std::ifstream wpjfilestream(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename), std::ios::binary|std::ios::in); + std::ifstream wpjfilestream(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename).c_str(), std::ios::binary|std::ios::in); if( !wpjfilestream ) { throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", sourcefilename, MEC_InvalidArguments); } @@ -685,7 +685,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } - // sourcefilenamebase is utf-8 + // sourcefilenamebase is utf-8 char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); @@ -957,8 +957,8 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \param destinationdir the directory inside the user webdav folder. has a trailing slash void _EnsureWebDAVDirectories(const std::string& uriDestinationDir) { - std::list listCreateDirs; - std::string output; + std::list listCreateDirs; + std::string output; size_t startindex = 0; for(size_t i = 0; i < uriDestinationDir.size(); ++i) { if( uriDestinationDir[i] == '/' ) { @@ -1023,9 +1023,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief recursively uploads a directory and creates directories along the way if they don't exist /// - /// overwrites all the files - /// \param copydir is utf-8 encoded - /// \param uri is URI-encoded + /// overwrites all the files + /// \param copydir is utf-8 encoded + /// \param uri is URI-encoded void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) { { @@ -1045,12 +1045,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; #if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATA ffd; - std::string searchstr = sCopyDir_FS + std::string("\\*"); + WIN32_FIND_DATA ffd; + std::string searchstr = sCopyDir_FS + std::string("\\*"); HANDLE hFind = FindFirstFile(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); - } + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); + } do { std::string filename = std::string(ffd.cFileName); @@ -1075,11 +1075,12 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share if( err != ERROR_NO_MORE_FILES ) { throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); } - + #else - for(boost::filesystem::directory_iterator itdir(boost::filesystem::path(copydir)); itdir != boost::filesystem::directory_iterator(); ++itdir) { + boost::filesystem::path bfpcopydir(copydir); + for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); #else std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); #endif @@ -1087,10 +1088,10 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF8(itdir->path(), newuri); + _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF8(itdir->path(), newuri); + _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); } } #endif // defined(_WIN32) || defined(_WIN64) @@ -1099,7 +1100,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief uploads a single file, assumes the directory already exists /// /// overwrites the file if it already exists - void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) + void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) { std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); FILE * fd = fopen(sFilename_FS.c_str(), "rb"); @@ -1116,7 +1117,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share struct stat file_info; if(fstat(fileno(fd), &file_info) != 0) { fclose(fd); // make sure to close the handle - throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", bfpfilename.string(), MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", sFilename_FS, MEC_InvalidArguments); } curl_off_t filesize = (curl_off_t)file_info.st_size; #endif @@ -1140,10 +1141,10 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // 204 is when it overwrites the file? if( http_code != 201 && http_code != 204 ) { if( http_code == 400 ) { - throw MUJIN_EXCEPTION_FORMAT("upload failed with HTTP status %s, perhaps file exists already?", http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s, perhaps file exists already?", sFilename_FS%http_code, MEC_HTTPServer); } else { - throw MUJIN_EXCEPTION_FORMAT("upload failed with HTTP status %s", http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s", sFilename_FS%http_code, MEC_HTTPServer); } } // now extract transfer info @@ -1168,7 +1169,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share int _lastmode; CURL *_curl; - boost::mutex _mutex; + boost::mutex _mutex; std::stringstream _buffer; std::string _baseuri, _baseapiuri, _basewebdavuri, _uri; From a5149744ecae2697dc71ef62c55e42d3cb5aabca Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 5 Apr 2013 07:01:47 -0700 Subject: [PATCH 049/477] added utf-16 version of file uploading --- .../mujincontrollerclient.h | 21 +- src/mujincontrollerclient.cpp | 349 ++++++++++++++---- 2 files changed, 292 insertions(+), 78 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 21d1544c..4c94a75f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -302,7 +302,7 @@ class MUJINCLIENT_API ControllerClient /// \brief sets the language code for all output /// - /// Checkout http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; /// \brief If necessary, changes the proxy to communicate to the controller server @@ -372,9 +372,9 @@ class MUJINCLIENT_API ControllerClient /** \brief uploads a particular scene's files into the network filesystem. - \param sourcefilename URI-encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" - \param scenetype The type of scene uploading. + \param scenetype UTF-8 encoded type of scene uploading. \throw mujin_exception if the upload fails, will throw an exception */ virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; @@ -385,6 +385,19 @@ class MUJINCLIENT_API ControllerClient SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); } + /// \see SyncUpload + /// + /// \param sourcefilename UTF-16 encoded + /// \param destinationdir UTF-16 encoded + /// \param scenetype UTF-16 encoded + virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir, const std::string& scenetype) = 0; + + /// \see SyncUpload + virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir) + { + SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); + } + virtual void SetDefaultSceneType(const std::string& scenetype) = 0; virtual const std::string& GetDefaultSceneType() = 0; @@ -606,7 +619,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. \param usernamepassword user:password - \param url the URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. If not specified, will use the default mujin controller URL + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. If not specified, will use the default mujin controller URL \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3fcf9fed..c8c2e469 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -203,6 +203,19 @@ std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) #endif } +/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses +std::string ConvertUTF16ToFileSystemEncoding(const std::wstring& utf16) +{ +#if defined(_WIN32) || defined(_WIN64) + return encoding::ConvertUTF16toMBS(utf16); +#else + // most linux systems use utf-8, can use getenv("LANG") to double-check + std::string utf8; + utf8::utf16to8(utf8.begin(), utf16.end(), std::back_inserter(utf8)); + return utf8; +#endif +} + /// \brief converts utf-8 encoded string into the encoding string that the filesystem uses std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) { @@ -216,10 +229,12 @@ std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) } -#ifdef _WIN32 -const char s_filesep = '\\'; -#else -const char s_filesep = '/'; +#ifdef _WIN32 +const char s_filesep = '\\'; +const char s_wfilesep = L'\\'; +#else +const char s_filesep = '/'; +const char s_wfilesep = L'/'; #endif static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) @@ -258,6 +273,71 @@ static std::string& SearchAndReplace(std::string& out, const std::string& in, co return out; } +template +std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) +{ + // scenefilenames is the WPJ file, so have to open it up to see what directory it points to + // note that the encoding is utf-16 + // + // .\threegoaltouch\threegoaltouch.WCN; + // + // first have to get the raw utf-16 data + std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); + if( !wpjfilestream ) { + throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", ConvertToFileSystemEncoding(sourcefilename), MEC_InvalidArguments); + } + std::wstringstream utf16stream; + bool readbom = false; + while(!wpjfilestream.eof() ) { + unsigned short c; + wpjfilestream.read(reinterpret_cast(&c),sizeof(c)); + if( !wpjfilestream ) { + break; + } + if( readbom || c != 0xfeff ) { + utf16stream << static_cast(c); + } + else { + readbom = true; + } + } + boost::property_tree::wptree wpj; + boost::property_tree::read_xml(utf16stream, wpj); + boost::property_tree::wptree& clsProject = wpj.get_child(L"clsProject"); + boost::property_tree::wptree& WCNPath = clsProject.get_child(L"WCNPath"); + std::wstring strWCNPath = WCNPath.data(); + if( strWCNPath.size() > 0 ) { + // post process the string to get the real filesystem directory + if( strWCNPath.at(strWCNPath.size()-1) == L';') { + strWCNPath.resize(strWCNPath.size()-1); + } + + if( strWCNPath.size() >= 2 && (strWCNPath[0] == L'.' && strWCNPath[1] == L'\\') ) { + // don't need the prefix + strWCNPath = strWCNPath.substr(2); + } + } + + return strWCNPath; +} + +class FileHandler +{ +public: + FileHandler(const char* pfilename) { + _fd = fopen(pfilename, "rb"); + } + FileHandler(const wchar_t* pfilename) { + _fd = _wfopen(pfilename, L"rb"); + } + ~FileHandler() { + if( !!_fd ) { + fclose(_fd); + } + } + FILE* _fd; +}; + #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION @@ -624,62 +704,19 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } if( scenetype == "wincaps" ) { - // scenefilenames is the WPJ file, so have to open it up to see what directory it points to - // note that the encoding is utf-16 - // - // .\threegoaltouch\threegoaltouch.WCN; - // - // first have to get the raw utf-16 data - std::ifstream wpjfilestream(encoding::ConvertUTF8ToFileSystemEncoding(sourcefilename), std::ios::binary|std::ios::in); - if( !wpjfilestream ) { - throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", sourcefilename, MEC_InvalidArguments); - } - std::stringstream wpjfilestream2; - wpjfilestream2 << wpjfilestream.rdbuf() << '\0'; - std::string wpjfilestreamdata = wpjfilestream2.str(); - const unsigned short* pstart = reinterpret_cast(wpjfilestreamdata.c_str()); - const unsigned short* pend = pstart + wpjfilestreamdata.size()/2; - std::stringstream utf8stream; - utf8::utf16to8(pstart, pend, std::ostream_iterator(utf8stream)); - boost::property_tree::ptree wpj; - boost::property_tree::read_xml(utf8stream, wpj); - boost::property_tree::ptree& clsProject = wpj.get_child("clsProject"); - boost::property_tree::ptree& WCNPath = clsProject.get_child("WCNPath"); - std::string strWCNPath = WCNPath.data(); - if( strWCNPath.size() > 0 ) { - // post process the string to get the real filesystem directory - if( strWCNPath.at(strWCNPath.size()-1) == ';') { - strWCNPath.resize(strWCNPath.size()-1); - } - + std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename, encoding::ConvertUTF8ToFileSystemEncoding); + if( strWCNPath_utf16.size() > 0 ) { + std::string strWCNPath; + utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNPath)); std::string strWCNURI = strWCNPath; size_t lastindex = 0; for(size_t i = 0; i < strWCNURI.size(); ++i) { if( strWCNURI[i] == '\\' ) { strWCNURI[i] = '/'; + strWCNPath[i] = s_filesep; lastindex = i; } } - - if( strWCNPath.size() >= 2 && (strWCNPath[0] == '.' && strWCNPath[1] == '\\') ) { - // don't need the prefix - strWCNPath = strWCNPath.substr(2); - strWCNURI = strWCNURI.substr(2); - if( lastindex < 2 ) { - lastindex = 0; - } - else { - lastindex -= 2; - } - } - - -#if defined(_WIN32) || defined(_WIN64) -#else - // separator are in windows, so have to convert - strWCNPath = strWCNURI; -#endif - std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); } @@ -700,6 +737,71 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share */ } + virtual void SyncUpload_UTF16(const std::wstring& sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) + { + // TODO use curl_multi_perform to allow uploading of multiple files simultaneously + // TODO should LOCK with WebDAV repository? + boost::mutex::scoped_lock lock(_mutex); + std::string baseuploaduri; + std::string destinationdir_utf8; + utf8::utf16to8(destinationdir_utf16.begin(), destinationdir_utf16.end(), std::back_inserter(destinationdir_utf8)); + + if( destinationdir_utf8.size() >= 7 && destinationdir_utf8.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + std::string s = destinationdir_utf8.substr(7); + baseuploaduri += _EncodeWithoutSeparator(s); + _EnsureWebDAVDirectories(s); + } + else { + baseuploaduri = destinationdir_utf8; + } + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + + size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + + if( scenetype == "wincaps" ) { + std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename_utf16, encoding::ConvertUTF16ToFileSystemEncoding); + if( strWCNPath_utf16.size() > 0 ) { + std::string strWCNURI; + utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNURI)); + size_t lastindex_utf8 = 0; + for(size_t i = 0; i < strWCNURI.size(); ++i) { + if( strWCNURI[i] == '\\' ) { + strWCNURI[i] = '/'; + lastindex_utf8 = i; + } + } + size_t lastindex_utf16 = 0; + for(size_t i = 0; i < strWCNPath_utf16.size(); ++i) { + if( strWCNPath_utf16[i] == '\\' ) { + strWCNPath_utf16[i] = s_wfilesep; + lastindex_utf16 = i; + } + } + std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); + _UploadDirectoryToWebDAV_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); + } + } + + // sourcefilenamebase is utf-8 + std::string sourcefilenamedir_utf8; + utf8::utf16to8(sourcefilename_utf16.begin(), sourcefilename_utf16.begin()+nBaseFilenameStartIndex, std::back_inserter(sourcefilenamedir_utf8)); + char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); + std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); + curl_free(pescapeddir); + //_UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); + } + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception int CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode=200) { @@ -1026,7 +1128,83 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// overwrites all the files /// \param copydir is utf-8 encoded /// \param uri is URI-encoded - void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) + void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) + { + { + // make sure the directory is created + CurlCustomRequestSetter setter(_curl, "MKCOL"); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); + } + } + + std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); + std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; + +#if defined(_WIN32) || defined(_WIN64) + WIN32_FIND_DATAA ffd; + std::string searchstr = sCopyDir_FS + std::string("\\*"); + HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); + } + + do { + std::string filename = std::string(ffd.cFileName); + if( filename != "." && filename != ".." ) { + std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); + std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); + char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + + if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); + } + else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { + _UploadFileToWebDAV_UTF8(newcopydir, newuri); + } + } + } while(FindNextFileA(hFind,&ffd) != 0); + + DWORD err = GetLastError(); + FindClose(hFind); + if( err != ERROR_NO_MORE_FILES ) { + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); + } + +#else + boost::filesystem::path bfpcopydir(copydir); + for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); +#else + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); +#endif + char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + if( boost::filesystem::is_directory(itdir->status()) ) { + _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); + } + else if( boost::filesystem::is_regular_file(itdir->status()) ) { + _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); + } + } +#endif // defined(_WIN32) || defined(_WIN64) + } + + /// \brief recursively uploads a directory and creates directories along the way if they don't exist + /// + /// overwrites all the files + /// \param copydir is utf-16 encoded + /// \param uri is URI-encoded + void _UploadDirectoryToWebDAV_UTF16(const std::wstring& copydir, const std::string& uri) { { // make sure the directory is created @@ -1041,39 +1219,40 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } - std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); - std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; + std::wstring sCopyDir_FS = copydir; + std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir) << " -> " << uri << std::endl; #if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATA ffd; - std::string searchstr = sCopyDir_FS + std::string("\\*"); - HANDLE hFind = FindFirstFile(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); - } + WIN32_FIND_DATAW ffd; + std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); + HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_Assert); + } do { - std::string filename = std::string(ffd.cFileName); - if( filename != "." && filename != ".." ) { - std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); + std::wstring filename = std::wstring(ffd.cFileName); + if( filename != L"." && filename != L".." ) { + std::string filename_utf8; + utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); + std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir%filename); char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); + _UploadDirectoryToWebDAV_UTF16(newcopydir, newuri); } else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToWebDAV_UTF8(newcopydir, newuri); + _UploadFileToWebDAV_UTF16(newcopydir, newuri); } } - } while(FindNextFile(hFind,&ffd) != 0); + } while(FindNextFileW(hFind,&ffd) != 0); DWORD err = GetLastError(); FindClose(hFind); if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_HTTPServer); } #else @@ -1099,14 +1278,38 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief uploads a single file, assumes the directory already exists /// /// overwrites the file if it already exists + /// \param filename utf-8 encoded void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) { std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - FILE * fd = fopen(sFilename_FS.c_str(), "rb"); - if(!fd) { + FileHandler handler(sFilename_FS.c_str()); + if(!handler._fd) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } + _UploadFileToWebDAV(handler._fd, uri); + } + + void _UploadFileToWebDAV_UTF16(const std::wstring& filename, const std::string& uri) + { + std::string filename_fs = encoding::ConvertUTF16ToFileSystemEncoding(filename); +#if defined(_WIN32) || defined(_WIN64) + FileHandler handler(filename.c_str()); +#else + // linux does not support wide-char fopen + FileHandler handler(filename_fs.c_str()); +#endif + if(!handler._fd) { + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); + } + _UploadFileToWebDAV(handler._fd, uri); + } + /// \brief uploads a single file, assumes the directory already exists + /// + /// overwrites the file if it already exists. + /// \param fd FILE pointer of binary reading file. does not close the handle + void _UploadFileToWebDAV(FILE* fd, const std::string& uri) + { #if defined(_WIN32) || defined(_WIN64) fseek(fd,0,SEEK_END); curl_off_t filesize = ftell(fd); @@ -1115,8 +1318,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share // to get the file size struct stat file_info; if(fstat(fileno(fd), &file_info) != 0) { - fclose(fd); // make sure to close the handle - throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", bfpfilename.string(), MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("failed to stat filename %s for filesize", filename, MEC_InvalidArguments); } curl_off_t filesize = (curl_off_t)file_info.st_size; #endif @@ -1133,7 +1335,6 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share #endif CURLcode res = curl_easy_perform(_curl); - fclose(fd); // make sure to close the handle CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); From 389fbed03e925b0db12f5bbda22ae55f97f3b4f4 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 5 Apr 2013 23:34:49 +0900 Subject: [PATCH 050/477] fixed wchar_t support on linux --- src/mujincontrollerclient.cpp | 54 +++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 78720ef5..fe5f2e29 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -207,12 +207,12 @@ std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) std::string ConvertUTF16ToFileSystemEncoding(const std::wstring& utf16) { #if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertUTF16toMBS(utf16); + return encoding::ConvertUTF16toMBS(utf16); #else - // most linux systems use utf-8, can use getenv("LANG") to double-check + // most linux systems use utf-8, can use getenv("LANG") to double-check std::string utf8; - utf8::utf16to8(utf8.begin(), utf16.end(), std::back_inserter(utf8)); - return utf8; + utf8::utf16to8(utf16.begin(), utf16.end(), std::back_inserter(utf8)); + return utf8; #endif } @@ -282,7 +282,12 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< // .\threegoaltouch\threegoaltouch.WCN; // // first have to get the raw utf-16 data +#if defined(_WIN32) || defined(_WIN64) std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); +#else + // linux doesn't mix ifstream and wstring + std::ifstream wpjfilestream(ConvertToFileSystemEncoding(sourcefilename).c_str(), std::ios::binary|std::ios::in); +#endif if( !wpjfilestream ) { throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", ConvertToFileSystemEncoding(sourcefilename), MEC_InvalidArguments); } @@ -294,6 +299,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< if( !wpjfilestream ) { break; } + // skip the first character (BOM) due to a bug in boost property_tree (should be fixed in 1.49) if( readbom || c != 0xfeff ) { utf16stream << static_cast(c); } @@ -327,9 +333,11 @@ class FileHandler FileHandler(const char* pfilename) { _fd = fopen(pfilename, "rb"); } +#if defined(_WIN32) || defined(_WIN64) FileHandler(const wchar_t* pfilename) { _fd = _wfopen(pfilename, L"rb"); } +#endif ~FileHandler() { if( !!_fd ) { fclose(_fd); @@ -760,7 +768,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share baseuploaduri.push_back('/'); } - size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); + size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); if( nBaseFilenameStartIndex == std::string::npos ) { // there's no path? nBaseFilenameStartIndex = 0; @@ -793,13 +801,13 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } } - // sourcefilenamebase is utf-8 + // sourcefilenamebase is utf-8 std::string sourcefilenamedir_utf8; - utf8::utf16to8(sourcefilename_utf16.begin(), sourcefilename_utf16.begin()+nBaseFilenameStartIndex, std::back_inserter(sourcefilenamedir_utf8)); + utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); - //_UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); + _UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception @@ -1125,9 +1133,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief recursively uploads a directory and creates directories along the way if they don't exist /// - /// overwrites all the files - /// \param copydir is utf-8 encoded - /// \param uri is URI-encoded + /// overwrites all the files + /// \param copydir is utf-8 encoded + /// \param uri is URI-encoded void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) { { @@ -1201,9 +1209,9 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// \brief recursively uploads a directory and creates directories along the way if they don't exist /// - /// overwrites all the files - /// \param copydir is utf-16 encoded - /// \param uri is URI-encoded + /// overwrites all the files + /// \param copydir is utf-16 encoded + /// \param uri is URI-encoded void _UploadDirectoryToWebDAV_UTF16(const std::wstring& copydir, const std::string& uri) { { @@ -1256,21 +1264,23 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share } #else - boost::filesystem::path bfpcopydir(copydir); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { + boost::filesystem::wpath bfpcopydir(copydir); + for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); + std::wstring dirfilename_utf16 = itdir->path().filename().string(); #else - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); + std::wstring dirfilename_utf16 = itdir->path().filename(); #endif + std::string dirfilename; + utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); + _UploadDirectoryToWebDAV_UTF16(itdir->path().string(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); + _UploadFileToWebDAV_UTF16(itdir->path().string(), newuri); } } #endif // defined(_WIN32) || defined(_WIN64) @@ -1280,7 +1290,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share /// /// overwrites the file if it already exists /// \param filename utf-8 encoded - void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) + void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) { std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); FileHandler handler(sFilename_FS.c_str()); @@ -1296,7 +1306,7 @@ class ControllerClientImpl : public ControllerClient, public boost::enable_share #if defined(_WIN32) || defined(_WIN64) FileHandler handler(filename.c_str()); #else - // linux does not support wide-char fopen + // linux does not support wide-char fopen FileHandler handler(filename_fs.c_str()); #endif if(!handler._fd) { From 1bdb11ce74cf040518213350b6025439f25e85f1 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 6 Apr 2013 00:10:39 +0900 Subject: [PATCH 051/477] split library into smaller files, now compiling static files --- src/controllerclientimpl.cpp | 1080 ++++++++++++++++++++++++++++++++++ 1 file changed, 1080 insertions(+) create mode 100644 src/controllerclientimpl.cpp diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp new file mode 100644 index 00000000..aafdd3e7 --- /dev/null +++ b/src/controllerclientimpl.cpp @@ -0,0 +1,1080 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012-2013 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "common.h" +#include "controllerclientimpl.h" + +#define SKIP_PEER_VERIFICATION // temporary +//#define SKIP_HOSTNAME_VERIFICATION + +namespace mujinclient { + +class CurlCustomRequestSetter +{ +public: + CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); + } + ~CurlCustomRequestSetter() { + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); + } +protected: + CURL* _curl; +}; + +class CurlUploadSetter +{ +public: + CurlUploadSetter(CURL *curl) : _curl(curl) { + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); + } + ~CurlUploadSetter() { + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); + } +protected: + CURL* _curl; +}; + +template +std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) +{ + // scenefilenames is the WPJ file, so have to open it up to see what directory it points to + // note that the encoding is utf-16 + // + // .\threegoaltouch\threegoaltouch.WCN; + // + // first have to get the raw utf-16 data +#if defined(_WIN32) || defined(_WIN64) + std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); +#else + // linux doesn't mix ifstream and wstring + std::ifstream wpjfilestream(ConvertToFileSystemEncoding(sourcefilename).c_str(), std::ios::binary|std::ios::in); +#endif + if( !wpjfilestream ) { + throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", ConvertToFileSystemEncoding(sourcefilename), MEC_InvalidArguments); + } + std::wstringstream utf16stream; + bool readbom = false; + while(!wpjfilestream.eof() ) { + unsigned short c; + wpjfilestream.read(reinterpret_cast(&c),sizeof(c)); + if( !wpjfilestream ) { + break; + } + // skip the first character (BOM) due to a bug in boost property_tree (should be fixed in 1.49) + if( readbom || c != 0xfeff ) { + utf16stream << static_cast(c); + } + else { + readbom = true; + } + } + boost::property_tree::wptree wpj; + boost::property_tree::read_xml(utf16stream, wpj); + boost::property_tree::wptree& clsProject = wpj.get_child(L"clsProject"); + boost::property_tree::wptree& WCNPath = clsProject.get_child(L"WCNPath"); + std::wstring strWCNPath = WCNPath.data(); + if( strWCNPath.size() > 0 ) { + // post process the string to get the real filesystem directory + if( strWCNPath.at(strWCNPath.size()-1) == L';') { + strWCNPath.resize(strWCNPath.size()-1); + } + + if( strWCNPath.size() >= 2 && (strWCNPath[0] == L'.' && strWCNPath[1] == L'\\') ) { + // don't need the prefix + strWCNPath = strWCNPath.substr(2); + } + } + + return strWCNPath; +} + +ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) +{ + size_t usernameindex = usernamepassword.find_first_of(':'); + BOOST_ASSERT(usernameindex != std::string::npos ); + std::string username = usernamepassword.substr(0,usernameindex); + std::string password = usernamepassword.substr(usernameindex+1); + + _httpheaders = NULL; + if( baseuri.size() > 0 ) { + _baseuri = baseuri; + // ensure trailing slash + if( _baseuri[_baseuri.size()-1] != '/' ) { + _baseuri.push_back('/'); + } + } + else { + // use the default + _baseuri = "https://controller.mujin.co.jp/"; + } + _baseapiuri = _baseuri + std::string("api/v1/"); + // hack for now since webdav server and api server could be running on different ports + if( boost::algorithm::ends_with(_baseuri, ":8000/") ) { + // testing on localhost, however the webdav server is running on port 80... + _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); + } + else { + _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%username); + } + + //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); + _curl = curl_easy_init(); + BOOST_ASSERT(!!_curl); + +#ifdef _DEBUG + //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); +#endif + _errormessage.resize(CURL_ERROR_SIZE); + curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); + + CURLcode res; +#ifdef SKIP_PEER_VERIFICATION + /* + * if you want to connect to a site who isn't using a certificate that is + * signed by one of the certs in the ca bundle you have, you can skip the + * verification of the server's certificate. this makes the connection + * a lot less secure. + * + * if you have a ca cert for the server stored someplace else than in the + * default bundle, then the curlopt_capath option might come handy for + * you. + */ + curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0l); +#endif + +#ifdef SKIP_HOSTNAME_VERIFICATION + /* + * If the site you're connecting to uses a different host name that what + * they have mentioned in their server certificate's commonName (or + * subjectAltName) fields, libcurl will refuse to connect. You can skip + * this check, but this will make the connection less secure. + */ + curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); +#endif + + if( proxyserverport.size() > 0 ) { + SetProxy(proxyserverport, proxyuserpw); + } + + res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + CHECKCURLCODE(res, "failed to set auth"); + res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); + CHECKCURLCODE(res, "failed to set userpw"); + + // need to set the following? + //CURLOPT_USERAGENT + //CURLOPT_TCP_KEEPIDLE + //CURLOPT_TCP_KEEPALIVE + //CURLOPT_TCP_KEEPINTVL + + curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine + + // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); + CHECKCURLCODE(res, "failed to set writer"); + res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); + CHECKCURLCODE(res, "failed to set write data"); + + std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; + res = curl_easy_setopt(_curl, CURLOPT_USERAGENT, useragent.c_str()); + CHECKCURLCODE(res, "failed to set user-agent"); + + res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 0); // do not bounce through pages since we need to detect when login sessions expired + CHECKCURLCODE(res, "failed to set follow location"); + res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); + CHECKCURLCODE(res, "failed to max redirs"); + + if( !(options & 1) ) { + // make an initial GET call to get the CSRF token + std::string loginuri = _baseuri + "login/"; + curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( http_code == 302 ) { + // most likely apache2-only authentication and login page isn't needed, however need to send another GET for the csrftoken + loginuri = _baseuri + "api/v1/"; // pick some neutral page that is easy to load + curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); + } + _csrfmiddlewaretoken = _GetCSRFFromCookies(); + curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); // necessary for SSL to work + } + else if( http_code == 200 ) { + _csrfmiddlewaretoken = _GetCSRFFromCookies(); + std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%username%password%_csrfmiddlewaretoken); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); + curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); + //std::cout << "---performing post---" << std::endl; + res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 && http_code != 302 ) { + throw MUJIN_EXCEPTION_FORMAT("User login failed. HTTP POST %s returned HTTP status %s", loginuri%http_code, MEC_UserAuthentication); + } + } + else { + throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); + } + } + + _charset = "utf-8"; + _language = "en-us"; +#if defined(_WIN32) || defined(_WIN64) + UINT codepage = GetACP(); + if( encoding::s_mapCodePageToCharset.find(codepage) != encoding::s_mapCodePageToCharset.end() ) { + _charset = encoding::s_mapCodePageToCharset[codepage]; + } +#endif + std::cout << "setting character set to " << _charset << std::endl; + _SetHTTPHeaders(); + + try { + GetProfile(); + } + catch(const MujinException&) { + // most likely username or password are + throw MujinException(str(boost::format("failed to get controller profile, check username/password or if controller is active at %s")%_baseuri), MEC_UserAuthentication); + } +} + +ControllerClientImpl::~ControllerClientImpl() +{ + if( !!_httpheaders ) { + curl_slist_free_all(_httpheaders); + } + curl_easy_cleanup(_curl); +} + +std::string ControllerClientImpl::GetVersion() +{ + return _profile.get("version"); +} + + +void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) +{ + boost::mutex::scoped_lock lock(_mutex); + _charset = newencoding; + _SetHTTPHeaders(); +} + +void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) +{ + curl_easy_setopt(_curl, CURLOPT_PROXY, serverport.c_str()); + curl_easy_setopt(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); +} + +void ControllerClientImpl::SetLanguage(const std::string& language) +{ + boost::mutex::scoped_lock lock(_mutex); + _language = language; + _SetHTTPHeaders(); +} + +void ControllerClientImpl::RestartServer() +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri + std::string("ajax/restartserver/"); + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); + } +} + +void ControllerClientImpl::Upgrade(const std::vector& vdata) +{ + BOOST_ASSERT(vdata.size()>0); + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri + std::string("upgrade/"); + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + + // set new headers and remove the Expect: 100-continue + struct curl_slist *headerlist=NULL; + headerlist = curl_slist_append(headerlist, "Expect:"); + std::string s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + headerlist = curl_slist_append(headerlist, s.c_str()); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + + // Fill in the file upload field + struct curl_httppost *formpost=NULL, *lastptr=NULL; + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "mujinpatch", CURLFORM_BUFFERPTR, &vdata[0], CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + CURLcode res = curl_easy_perform(_curl); + curl_formfree(formpost); + // reset the headers before any exceptions are thrown + _SetHTTPHeaders(); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, please try again or contact MUJIN support", MEC_HTTPServer); + } +} + +void ControllerClientImpl::CancelAllJobs() +{ + CallDelete("job/?format=json"); +} + +void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, int options) +{ + boost::property_tree::ptree pt; + std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; + if( options & 1 ) { + url += std::string(",status_text"); + } + CallGet(url, pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + size_t i = 0; + statuses.resize(objects.size()); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + statuses[i].pk = v.second.get("pk"); + statuses[i].code = static_cast(boost::lexical_cast(v.second.get("status"))); + statuses[i].type = v.second.get("fnname"); + statuses[i].elapsedtime = v.second.get("elapsedtime"); + if( options & 1 ) { + statuses[i].message = v.second.get("status_text"); + } + i++; + } +} + +void ControllerClientImpl::GetScenePrimaryKeys(std::vector& scenekeys) +{ + boost::property_tree::ptree pt; + CallGet("scene/?format=json&limit=0&fields=pk", pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + scenekeys.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + scenekeys[i++] = v.second.get("pk"); + } +} + +SceneResourcePtr ControllerClientImpl::RegisterScene(const std::string& uri, const std::string& scenetype) +{ + BOOST_ASSERT(scenetype.size()>0); + boost::property_tree::ptree pt; + CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; +} + +SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA(const std::string& importuri, const std::string& importformat, const std::string& newuri) +{ + BOOST_ASSERT(importformat.size()>0); + boost::property_tree::ptree pt; + CallPost("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; +} + +void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) +{ + // TODO use curl_multi_perform to allow uploading of multiple files simultaneously + // TODO should LOCK with WebDAV repository? + boost::mutex::scoped_lock lock(_mutex); + std::string baseuploaduri; + if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + baseuploaduri += _EncodeWithoutSeparator(destinationdir.substr(7)); + _EnsureWebDAVDirectories(destinationdir.substr(7)); + } + else { + baseuploaduri = destinationdir; + } + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + + size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + + if( scenetype == "wincaps" ) { + std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename, encoding::ConvertUTF8ToFileSystemEncoding); + if( strWCNPath_utf16.size() > 0 ) { + std::string strWCNPath; + utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNPath)); + std::string strWCNURI = strWCNPath; + size_t lastindex = 0; + for(size_t i = 0; i < strWCNURI.size(); ++i) { + if( strWCNURI[i] == '\\' ) { + strWCNURI[i] = '/'; + strWCNPath[i] = s_filesep; + lastindex = i; + } + } + std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); + _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); + } + } + + // sourcefilenamebase is utf-8 + char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); + std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); + curl_free(pescapeddir); + _UploadFileToWebDAV_UTF8(sourcefilename, uploadfileuri); + + /* webdav operations + const char *postdata = + "" + "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" + " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " + "WHERE \"DAV:isfolder\" = True\r\n"; + */ +} + +void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) +{ + // TODO use curl_multi_perform to allow uploading of multiple files simultaneously + // TODO should LOCK with WebDAV repository? + boost::mutex::scoped_lock lock(_mutex); + std::string baseuploaduri; + std::string destinationdir_utf8; + utf8::utf16to8(destinationdir_utf16.begin(), destinationdir_utf16.end(), std::back_inserter(destinationdir_utf8)); + + if( destinationdir_utf8.size() >= 7 && destinationdir_utf8.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + std::string s = destinationdir_utf8.substr(7); + baseuploaduri += _EncodeWithoutSeparator(s); + _EnsureWebDAVDirectories(s); + } + else { + baseuploaduri = destinationdir_utf8; + } + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + + size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + + if( scenetype == "wincaps" ) { + std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename_utf16, encoding::ConvertUTF16ToFileSystemEncoding); + if( strWCNPath_utf16.size() > 0 ) { + std::string strWCNURI; + utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNURI)); + size_t lastindex_utf8 = 0; + for(size_t i = 0; i < strWCNURI.size(); ++i) { + if( strWCNURI[i] == '\\' ) { + strWCNURI[i] = '/'; + lastindex_utf8 = i; + } + } + size_t lastindex_utf16 = 0; + for(size_t i = 0; i < strWCNPath_utf16.size(); ++i) { + if( strWCNPath_utf16[i] == '\\' ) { + strWCNPath_utf16[i] = s_wfilesep; + lastindex_utf16 = i; + } + } + std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); + _UploadDirectoryToWebDAV_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); + } + } + + // sourcefilenamebase is utf-8 + std::string sourcefilenamedir_utf8; + utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); + char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); + std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); + curl_free(pescapeddir); + _UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); +} + +/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception +int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + return http_code; +} + +/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception +int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + outputdata = _buffer.str(); + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + if( outputdata.size() > 0 ) { + boost::property_tree::ptree pt; + boost::property_tree::read_json(_buffer, pt); + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); + } + return http_code; +} + +/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception +int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_POST, 1); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + return http_code; +} + +int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); + CURLcode res = curl_easy_perform(_curl); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( _buffer.rdbuf()->in_avail() > 0 ) { + boost::property_tree::read_json(_buffer, pt); + } + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = pt.get("error_message", std::string()); + std::string traceback = pt.get("traceback", std::string()); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + } + return http_code; +} + +void ControllerClientImpl::CallDelete(const std::string& relativeuri) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + CURLcode res = curl_easy_perform(_curl); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + if( http_code != 204 ) { // or 200 or 202 or 201? + throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); + } +} + +std::stringstream& ControllerClientImpl::GetBuffer() +{ + return _buffer; +} + +void ControllerClientImpl::SetDefaultSceneType(const std::string& scenetype) +{ + _defaultscenetype = scenetype; +} + +const std::string& ControllerClientImpl::GetDefaultSceneType() +{ + return _defaultscenetype; +} + +void ControllerClientImpl::SetDefaultTaskType(const std::string& tasktype) +{ + _defaultscenetype = tasktype; +} + +const std::string& ControllerClientImpl::GetDefaultTaskType() +{ + return _defaulttasktype; +} + +std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) +{ + size_t index = uri.find(":/"); + MUJIN_ASSERT_OP_FORMAT(index,!=,std::string::npos, "bad URI: %s", uri, MEC_InvalidArguments); + uri.substr(index+2); + char* pcurlresult = curl_easy_escape(_curl, uri.c_str()+index+2,uri.size()-index-2); + std::string sresult(pcurlresult); + curl_free(pcurlresult); // have to release the result + return sresult; +} + +std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) +{ + std::string utf8line; + utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); + return GetScenePrimaryKeyFromURI_UTF8(utf8line); +} + +void ControllerClientImpl::GetProfile() +{ + _profile.clear(); + CallGet("profile/", _profile); +} + +int ControllerClientImpl::_writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) +{ + if (writerData == NULL) { + return 0; + } + writerData->write(data, size*nmemb); + return size * nmemb; +} + +void ControllerClientImpl::_SetHTTPHeaders() +{ + // set the header to only send json + std::string s = std::string("Content-Type: application/json; charset=") + _charset; + if( !!_httpheaders ) { + curl_slist_free_all(_httpheaders); + } + _httpheaders = curl_slist_append(NULL, s.c_str()); + s = str(boost::format("Accept-Language: %s,en-us")%_language); + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") + //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // necessary? + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); + _httpheaders = curl_slist_append(_httpheaders, "Connection: Keep-Alive"); + _httpheaders = curl_slist_append(_httpheaders, "Keep-Alive: 20"); // keep alive for 20s? + // test on windows first + //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); +} + +std::string ControllerClientImpl::_GetCSRFFromCookies() { + struct curl_slist *cookies; + CURLcode res = curl_easy_getinfo(_curl, CURLINFO_COOKIELIST, &cookies); + CHECKCURLCODE(res, "curl_easy_getinfo CURLINFO_COOKIELIST"); + struct curl_slist *nc = cookies; + int i = 1; + std::string csrfmiddlewaretoken; + while (nc) { + //std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; + char* csrftokenstart = strstr(nc->data, "csrftoken"); + if( !!csrftokenstart ) { + std::stringstream ss(csrftokenstart+10); + ss >> csrfmiddlewaretoken; + } + nc = nc->next; + i++; + } + curl_slist_free_all(cookies); + return csrfmiddlewaretoken; +} + +std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw) +{ + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < raw.size(); ++i) { + if( raw[i] == '/' ) { + if( startindex != i ) { + char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, i-startindex); + output += std::string(pescaped); + curl_free(pescaped); + startindex = i+1; + } + output += '/'; + } + } + if( startindex != raw.size() ) { + char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, raw.size()-startindex); + output += std::string(pescaped); + curl_free(pescaped); + } + return output; +} + +void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestinationDir) +{ + std::list listCreateDirs; + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < uriDestinationDir.size(); ++i) { + if( uriDestinationDir[i] == '/' ) { + if( startindex != i ) { + char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, i-startindex); + listCreateDirs.push_back(std::string(pescaped)); + curl_free(pescaped); + startindex = i+1; + } + } + } + if( startindex != uriDestinationDir.size() ) { + char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, uriDestinationDir.size()-startindex); + listCreateDirs.push_back(std::string(pescaped)); + curl_free(pescaped); + } + + // Check that the directory exists + //curl_easy_setopt(_curl, CURLOPT_URL, buff); + //curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + //res = curl_easy_perform(self->send_handle); + //if(res != 0) { + // // does not exist + //} + + CurlCustomRequestSetter setter(_curl, "MKCOL"); + std::string totaluri = ""; + for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { + // first have to create the directory structure up to destinationdir + if( totaluri.size() > 0 ) { + totaluri += '/'; + } + totaluri += *itdir; + _uri = _basewebdavuri + totaluri; + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + /* creating directories + + Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. + + 201 (Created) - The collection or structured resource was created in its entirety. + + 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. + + 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. + + 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. + + 415 (Unsupported Media Type)- The server does not support the request type of the body. + + 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. + + */ + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); + } + } +} + +void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) +{ + { + // make sure the directory is created + CurlCustomRequestSetter setter(_curl, "MKCOL"); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); + } + } + + std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); + std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; + +#if defined(_WIN32) || defined(_WIN64) + WIN32_FIND_DATAA ffd; + std::string searchstr = sCopyDir_FS + std::string("\\*"); + HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); + } + + do { + std::string filename = std::string(ffd.cFileName); + if( filename != "." && filename != ".." ) { + std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); + std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); + char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + + if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); + } + else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { + _UploadFileToWebDAV_UTF8(newcopydir, newuri); + } + } + } while(FindNextFileA(hFind,&ffd) != 0); + + DWORD err = GetLastError(); + FindClose(hFind); + if( err != ERROR_NO_MORE_FILES ) { + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); + } + +#else + boost::filesystem::path bfpcopydir(copydir); + for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); +#else + std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); +#endif + char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + if( boost::filesystem::is_directory(itdir->status()) ) { + _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); + } + else if( boost::filesystem::is_regular_file(itdir->status()) ) { + _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); + } + } +#endif // defined(_WIN32) || defined(_WIN64) +} + +void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& copydir, const std::string& uri) +{ + { + // make sure the directory is created + CurlCustomRequestSetter setter(_curl, "MKCOL"); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 201 && http_code != 301 ) { + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); + } + } + + std::wstring sCopyDir_FS = copydir; + std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir) << " -> " << uri << std::endl; + +#if defined(_WIN32) || defined(_WIN64) + WIN32_FIND_DATAW ffd; + std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); + HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) { + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_Assert); + } + + do { + std::wstring filename = std::wstring(ffd.cFileName); + if( filename != L"." && filename != L".." ) { + std::string filename_utf8; + utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); + std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir%filename); + char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + + if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { + _UploadDirectoryToWebDAV_UTF16(newcopydir, newuri); + } + else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { + _UploadFileToWebDAV_UTF16(newcopydir, newuri); + } + } + } while(FindNextFileW(hFind,&ffd) != 0); + + DWORD err = GetLastError(); + FindClose(hFind); + if( err != ERROR_NO_MORE_FILES ) { + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_HTTPServer); + } + +#else + boost::filesystem::wpath bfpcopydir(copydir); + for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + std::wstring dirfilename_utf16 = itdir->path().filename().string(); +#else + std::wstring dirfilename_utf16 = itdir->path().filename(); +#endif + std::string dirfilename; + utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); + char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + if( boost::filesystem::is_directory(itdir->status()) ) { + _UploadDirectoryToWebDAV_UTF16(itdir->path().string(), newuri); + } + else if( boost::filesystem::is_regular_file(itdir->status()) ) { + _UploadFileToWebDAV_UTF16(itdir->path().string(), newuri); + } + } +#endif // defined(_WIN32) || defined(_WIN64) +} + +void ControllerClientImpl::_UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) +{ + std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); + FileHandler handler(sFilename_FS.c_str()); + if(!handler._fd) { + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); + } + _UploadFileToWebDAV(handler._fd, uri); +} + +void ControllerClientImpl::_UploadFileToWebDAV_UTF16(const std::wstring& filename, const std::string& uri) +{ + std::string filename_fs = encoding::ConvertUTF16ToFileSystemEncoding(filename); +#if defined(_WIN32) || defined(_WIN64) + FileHandler handler(filename.c_str()); +#else + // linux does not support wide-char fopen + FileHandler handler(filename_fs.c_str()); +#endif + if(!handler._fd) { + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); + } + _UploadFileToWebDAV(handler._fd, uri); +} + +void ControllerClientImpl::_UploadFileToWebDAV(FILE* fd, const std::string& uri) +{ +#if defined(_WIN32) || defined(_WIN64) + fseek(fd,0,SEEK_END); + curl_off_t filesize = ftell(fd); + fseek(fd,0,SEEK_SET); +#else + // to get the file size + struct stat file_info; + if(fstat(fileno(fd), &file_info) != 0) { + throw MUJIN_EXCEPTION_FORMAT("failed to stat %s for filesize", uri, MEC_InvalidArguments); + } + curl_off_t filesize = (curl_off_t)file_info.st_size; +#endif + + // tell it to "upload" to the URL + CurlUploadSetter uploadsetter(_curl); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_READDATA, fd); + curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); + //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); +#if defined(_WIN32) || defined(_WIN64) + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); +#endif + + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + // 204 is when it overwrites the file? + if( http_code != 201 && http_code != 204 ) { + if( http_code == 400 ) { + throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s, perhaps file exists already?", uri%http_code, MEC_HTTPServer); + } + else { + throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s", uri%http_code, MEC_HTTPServer); + } + } + // now extract transfer info + //double speed_upload, total_time; + //curl_easy_getinfo(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); + //curl_easy_getinfo(_curl, CURLINFO_TOTAL_TIME, &total_time); + //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); +} + +size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) +{ + curl_off_t nread; + // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally + size_t retcode = fread(ptr, size, nmemb, (FILE*)stream); + + nread = (curl_off_t)retcode; + //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); + return retcode; +} + +} // end namespace mujinclient From 247105481540067068a8d1394e01f3fa8a4906b5 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 6 Apr 2013 00:10:39 +0900 Subject: [PATCH 052/477] split library into smaller files, now compiling static files --- .../mujincontrollerclient.h | 4 +- src/mujincontrollerclient.cpp | 1384 +---------------- 2 files changed, 4 insertions(+), 1384 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 4c94a75f..7cfec8ca 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -14,8 +14,8 @@ /** \file mujincontrollerclient.h \brief Defines the public headers of the MUJIN Controller Client */ -#ifndef MUJINCLIENT_H -#define MUJINCLIENT_H +#ifndef MUJIN_CONTROLLERCLIENT_H +#define MUJIN_CONTROLLERCLIENT_H #ifndef MUJINCLIENT_DISABLE_ASSERT_HANDLER #define BOOST_ENABLE_ASSERT_HANDLER diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index fe5f2e29..82e9230b 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -11,1391 +11,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#define WIN32_LEAN_AND_MEAN -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) -#include -#else - -#if BOOST_VERSION >= 104400 -// boost filesystem v3 is present after v1.44, so force using it -#define BOOST_FILESYSTEM_VERSION 3 -#endif - -// only use boost filesystem on linux since it is difficult to get working correctly with windows -#include -#include -#include - -#endif // defined(_WIN32) || defined(_WIN64) - -#include "utf8.h" - -#ifdef _MSC_VER -#ifndef __PRETTY_FUNCTION__ -#define __PRETTY_FUNCTION__ __FUNCDNAME__ -#endif -#endif - -#define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); -#define CHECKCURLCODE(code, msg) if (code != CURLE_OK) { \ - throw MujinException(str(boost::format("[%s:%d] curl function %s with error='%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%(msg)%curl_easy_strerror(code)%_errormessage), MEC_HTTPClient); \ -} - -#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) - -/// adds the function name and line number to an exception -#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) - -#define MUJIN_ASSERT_FORMAT(testexpr, s, args, errorcode) { if( !(testexpr) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)%args),errorcode); } } - -#define MUJIN_ASSERT_FORMAT0(testexpr, s, errorcode) { if( !(testexpr) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] (%s) failed " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# testexpr)),errorcode); } } - -// note that expr1 and expr2 will be evaluated twice if not equal -#define MUJIN_ASSERT_OP_FORMAT(expr1,op,expr2,s, args, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)%args),errorcode); } } - -#define MUJIN_ASSERT_OP_FORMAT0(expr1,op,expr2,s, errorcode) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) " s)%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),errorcode); } } - -#define MUJIN_ASSERT_OP(expr1,op,expr2) { if( !((expr1) op (expr2)) ) { throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] %s %s %s, (eval %s %s %s) ")%(__PRETTY_FUNCTION__)%(__LINE__)%(# expr1)%(# op)%(# expr2)%(expr1)%(# op)%(expr2)),MEC_Assert); } } - -BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); // need this for utf-16 reading +#include "common.h" +#include "controllerclientimpl.h" namespace mujinclient { - -namespace encoding { - -#if defined(_WIN32) || defined(_WIN64) - -// Build a table of the mapping between code pages and web charsets -// It's hack, but at least it doesn't drag in a bunch of unnecessary dependencies -// http://msdn.microsoft.com/en-us/library/aa288104%28v=vs.71%29.aspx -std::map InitializeCodePageMap() -{ - std::map mapCodePageToCharset; - mapCodePageToCharset[866] = "IBM866"; - mapCodePageToCharset[852] = "IBM852"; - mapCodePageToCharset[949] = "KS_C_5601-1987"; - mapCodePageToCharset[50220 /*CODE_JPN_JIS*/] = "ISO-2022-JP"; - mapCodePageToCharset[874] = "windows-874"; - mapCodePageToCharset[20866] = "koi8-r"; - mapCodePageToCharset[1251] = "x-cp1251"; - mapCodePageToCharset[50225] = "ISO-2022-KR"; - mapCodePageToCharset[1256] = "windows-1256"; - mapCodePageToCharset[1257] = "windows-1257"; - mapCodePageToCharset[1254] = "windows-1254"; - mapCodePageToCharset[1255] = "windows-1255"; - mapCodePageToCharset[1252] = "windows-1252"; - mapCodePageToCharset[1253] = "windows-1253"; - mapCodePageToCharset[1250] = "x-cp1250"; - mapCodePageToCharset[950] = "x-x-big5"; - mapCodePageToCharset[932] = "Shift_JIS"; - mapCodePageToCharset[51932 /*CODE_JPN_EUC*/] = "EUC-JP"; - mapCodePageToCharset[28592] = "latin2"; - mapCodePageToCharset[936] = "ISO-IR-58"; - mapCodePageToCharset[1258] = "windows-1258"; - mapCodePageToCharset[65001] = "utf-8"; - return mapCodePageToCharset; -} -static std::map s_mapCodePageToCharset = InitializeCodePageMap(); - -inline std::wstring ConvertUTF8toUTF16(const std::string& utf8) -{ - std::wstring utf16(L""); - - if (!utf8.empty()) { - size_t nLen16 = 0; - if ((nLen16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0)) > 0) { - utf16.resize(nLen16); - ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &utf16[0], nLen16); - // remove the null terminated char that was written - utf16.resize(nLen16-1); - } - } - return utf16; -} - -inline std::string ConvertUTF16toUTF8(const std::wstring& utf16) -{ - std::string utf8(""); - - if (!utf16.empty()) { - size_t nLen8 = 0; - if ((nLen8 = ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { - utf8.resize(nLen8); - ::WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), -1, &utf8[0], nLen8, NULL, NULL); - // remove the null terminated char that was written - utf8.resize(nLen8-1); - } - } - return utf8; -} - -inline std::string ConvertUTF16toMBS(const std::wstring& utf16) -{ - std::string mbs(""); - - if (!utf16.empty()) { - size_t nLenA = 0; - if ((nLenA = ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, NULL, 0, NULL, NULL)) > 0) { - mbs.resize(nLenA); - ::WideCharToMultiByte(CP_ACP, 0, utf16.c_str(), -1, &mbs[0], nLenA, NULL, NULL); - // remove the null terminated char that was written - mbs.resize(nLenA-1); - } - } - return mbs; -} - -inline std::wstring ConvertMBStoUTF16(const std::string& mbs) -{ - std::wstring utf16(L""); - - if (!mbs.empty()) { - size_t nLen16 = 0; - if ((nLen16 = ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, NULL, 0)) > 0) { - utf16.resize(nLen16); - ::MultiByteToWideChar(CP_ACP, 0, mbs.c_str(), -1, &utf16[0], nLen16); - // remove the null terminated char that was written - utf16.resize(nLen16-1); - } - } - return utf16; -} - -inline std::string ConvertMBStoUTF8(const std::string& mbs) -{ - return ConvertUTF16toUTF8(ConvertMBStoUTF16(mbs)); -} - -inline std::string ConvertUTF8toMBS(const std::string& utf8) -{ - return ConvertUTF16toMBS(ConvertUTF8toUTF16(utf8)); -} -#endif // defined(_WIN32) || defined(_WIN64) - -/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses -std::string ConvertUTF8ToFileSystemEncoding(const std::string& utf8) -{ -#if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertUTF8toMBS(utf8); -#else - // most linux systems use utf-8, can use getenv("LANG") to double-check - return utf8; -#endif -} - -/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses -std::string ConvertUTF16ToFileSystemEncoding(const std::wstring& utf16) -{ -#if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertUTF16toMBS(utf16); -#else - // most linux systems use utf-8, can use getenv("LANG") to double-check - std::string utf8; - utf8::utf16to8(utf16.begin(), utf16.end(), std::back_inserter(utf8)); - return utf8; -#endif -} - -/// \brief converts utf-8 encoded string into the encoding string that the filesystem uses -std::string ConvertFileSystemEncodingToUTF8(const std::string& fs) -{ -#if defined(_WIN32) || defined(_WIN64) - return encoding::ConvertMBStoUTF8(fs); -#else - // most linux systems use utf-8, can use getenv("LANG") to double-check - return fs; -#endif -} - -} - -#ifdef _WIN32 -const char s_filesep = '\\'; -const char s_wfilesep = L'\\'; -#else -const char s_filesep = '/'; -const char s_wfilesep = L'/'; -#endif - -static bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) -{ - return p0.first.size() > p1.first.size(); -} - -static std::string& SearchAndReplace(std::string& out, const std::string& in, const std::vector< std::pair >&_pairs) -{ - BOOST_ASSERT(&out != &in); - std::vector< std::pair >::const_iterator itp, itbestp; - for(itp = _pairs.begin(); itp != _pairs.end(); ++itp) { - BOOST_ASSERT(itp->first.size()>0); - } - std::vector< std::pair > pairs = _pairs; - stable_sort(pairs.begin(),pairs.end(),PairStringLengthCompare); - out.resize(0); - size_t startindex = 0; - while(startindex < in.size()) { - size_t nextindex=std::string::npos; - for(itp = pairs.begin(); itp != pairs.end(); ++itp) { - size_t index = in.find(itp->first,startindex); - if((nextindex == std::string::npos)|| ((index != std::string::npos)&&(index < nextindex)) ) { - nextindex = index; - itbestp = itp; - } - } - if( nextindex == std::string::npos ) { - out += in.substr(startindex); - break; - } - out += in.substr(startindex,nextindex-startindex); - out += itbestp->second; - startindex = nextindex+itbestp->first.size(); - } - return out; -} - -template -std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) -{ - // scenefilenames is the WPJ file, so have to open it up to see what directory it points to - // note that the encoding is utf-16 - // - // .\threegoaltouch\threegoaltouch.WCN; - // - // first have to get the raw utf-16 data -#if defined(_WIN32) || defined(_WIN64) - std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); -#else - // linux doesn't mix ifstream and wstring - std::ifstream wpjfilestream(ConvertToFileSystemEncoding(sourcefilename).c_str(), std::ios::binary|std::ios::in); -#endif - if( !wpjfilestream ) { - throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", ConvertToFileSystemEncoding(sourcefilename), MEC_InvalidArguments); - } - std::wstringstream utf16stream; - bool readbom = false; - while(!wpjfilestream.eof() ) { - unsigned short c; - wpjfilestream.read(reinterpret_cast(&c),sizeof(c)); - if( !wpjfilestream ) { - break; - } - // skip the first character (BOM) due to a bug in boost property_tree (should be fixed in 1.49) - if( readbom || c != 0xfeff ) { - utf16stream << static_cast(c); - } - else { - readbom = true; - } - } - boost::property_tree::wptree wpj; - boost::property_tree::read_xml(utf16stream, wpj); - boost::property_tree::wptree& clsProject = wpj.get_child(L"clsProject"); - boost::property_tree::wptree& WCNPath = clsProject.get_child(L"WCNPath"); - std::wstring strWCNPath = WCNPath.data(); - if( strWCNPath.size() > 0 ) { - // post process the string to get the real filesystem directory - if( strWCNPath.at(strWCNPath.size()-1) == L';') { - strWCNPath.resize(strWCNPath.size()-1); - } - - if( strWCNPath.size() >= 2 && (strWCNPath[0] == L'.' && strWCNPath[1] == L'\\') ) { - // don't need the prefix - strWCNPath = strWCNPath.substr(2); - } - } - - return strWCNPath; -} - -class FileHandler -{ -public: - FileHandler(const char* pfilename) { - _fd = fopen(pfilename, "rb"); - } -#if defined(_WIN32) || defined(_WIN64) - FileHandler(const wchar_t* pfilename) { - _fd = _wfopen(pfilename, L"rb"); - } -#endif - ~FileHandler() { - if( !!_fd ) { - fclose(_fd); - } - } - FILE* _fd; -}; - -#define SKIP_PEER_VERIFICATION // temporary -//#define SKIP_HOSTNAME_VERIFICATION - -class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this -{ -public: - ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) - { - size_t usernameindex = usernamepassword.find_first_of(':'); - BOOST_ASSERT(usernameindex != std::string::npos ); - std::string username = usernamepassword.substr(0,usernameindex); - std::string password = usernamepassword.substr(usernameindex+1); - - _httpheaders = NULL; - if( baseuri.size() > 0 ) { - _baseuri = baseuri; - // ensure trailing slash - if( _baseuri[_baseuri.size()-1] != '/' ) { - _baseuri.push_back('/'); - } - } - else { - // use the default - _baseuri = "https://controller.mujin.co.jp/"; - } - _baseapiuri = _baseuri + std::string("api/v1/"); - // hack for now since webdav server and api server could be running on different ports - if( boost::algorithm::ends_with(_baseuri, ":8000/") ) { - // testing on localhost, however the webdav server is running on port 80... - _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); - } - else { - _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%username); - } - - //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); - _curl = curl_easy_init(); - BOOST_ASSERT(!!_curl); - -#ifdef _DEBUG - //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); -#endif - _errormessage.resize(CURL_ERROR_SIZE); - curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); - - CURLcode res; -#ifdef SKIP_PEER_VERIFICATION - /* - * if you want to connect to a site who isn't using a certificate that is - * signed by one of the certs in the ca bundle you have, you can skip the - * verification of the server's certificate. this makes the connection - * a lot less secure. - * - * if you have a ca cert for the server stored someplace else than in the - * default bundle, then the curlopt_capath option might come handy for - * you. - */ - curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0l); -#endif - -#ifdef SKIP_HOSTNAME_VERIFICATION - /* - * If the site you're connecting to uses a different host name that what - * they have mentioned in their server certificate's commonName (or - * subjectAltName) fields, libcurl will refuse to connect. You can skip - * this check, but this will make the connection less secure. - */ - curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); -#endif - - if( proxyserverport.size() > 0 ) { - SetProxy(proxyserverport, proxyuserpw); - } - - res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - CHECKCURLCODE(res, "failed to set auth"); - res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); - CHECKCURLCODE(res, "failed to set userpw"); - - // need to set the following? - //CURLOPT_USERAGENT - //CURLOPT_TCP_KEEPIDLE - //CURLOPT_TCP_KEEPALIVE - //CURLOPT_TCP_KEEPINTVL - - curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine - - // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout - res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); - CHECKCURLCODE(res, "failed to set writer"); - res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); - CHECKCURLCODE(res, "failed to set write data"); - - std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; - res = curl_easy_setopt(_curl, CURLOPT_USERAGENT, useragent.c_str()); - CHECKCURLCODE(res, "failed to set user-agent"); - - res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 0); // do not bounce through pages since we need to detect when login sessions expired - CHECKCURLCODE(res, "failed to set follow location"); - res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); - CHECKCURLCODE(res, "failed to max redirs"); - - if( !(options & 1) ) { - // make an initial GET call to get the CSRF token - std::string loginuri = _baseuri + "login/"; - curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code == 302 ) { - // most likely apache2-only authentication and login page isn't needed, however need to send another GET for the csrftoken - loginuri = _baseuri + "api/v1/"; // pick some neutral page that is easy to load - curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); - } - _csrfmiddlewaretoken = _GetCSRFFromCookies(); - curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); // necessary for SSL to work - } - else if( http_code == 200 ) { - _csrfmiddlewaretoken = _GetCSRFFromCookies(); - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%username%password%_csrfmiddlewaretoken); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); - curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); - //std::cout << "---performing post---" << std::endl; - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 && http_code != 302 ) { - throw MUJIN_EXCEPTION_FORMAT("User login failed. HTTP POST %s returned HTTP status %s", loginuri%http_code, MEC_UserAuthentication); - } - } - else { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); - } - } - - _charset = "utf-8"; - _language = "en-us"; -#if defined(_WIN32) || defined(_WIN64) - UINT codepage = GetACP(); - if( encoding::s_mapCodePageToCharset.find(codepage) != encoding::s_mapCodePageToCharset.end() ) { - _charset = encoding::s_mapCodePageToCharset[codepage]; - } -#endif - std::cout << "setting character set to " << _charset << std::endl; - _SetHTTPHeaders(); - - try { - GetProfile(); - } - catch(const MujinException&) { - // most likely username or password are - throw MujinException(str(boost::format("failed to get controller profile, check username/password or if controller is active at %s")%_baseuri), MEC_UserAuthentication); - } - } - - std::string GetVersion() - { - return _profile.get("version"); - } - - virtual ~ControllerClientImpl() { - if( !!_httpheaders ) { - curl_slist_free_all(_httpheaders); - } - curl_easy_cleanup(_curl); - } - - virtual void SetCharacterEncoding(const std::string& newencoding) - { - boost::mutex::scoped_lock lock(_mutex); - _charset = newencoding; - _SetHTTPHeaders(); - } - - virtual void SetProxy(const std::string& serverport, const std::string& userpw) - { - curl_easy_setopt(_curl, CURLOPT_PROXY, serverport.c_str()); - curl_easy_setopt(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); - } - - virtual void SetLanguage(const std::string& language) - { - boost::mutex::scoped_lock lock(_mutex); - _language = language; - _SetHTTPHeaders(); - } - - virtual void RestartServer() - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri + std::string("ajax/restartserver/"); - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_POST, 1); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); - } - } - - virtual void Upgrade(const std::vector& vdata) - { - BOOST_ASSERT(vdata.size()>0); - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri + std::string("upgrade/"); - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - - // set new headers and remove the Expect: 100-continue - struct curl_slist *headerlist=NULL; - headerlist = curl_slist_append(headerlist, "Expect:"); - std::string s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - headerlist = curl_slist_append(headerlist, s.c_str()); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); - - // Fill in the file upload field - struct curl_httppost *formpost=NULL, *lastptr=NULL; - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "mujinpatch", CURLFORM_BUFFERPTR, &vdata[0], CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); - curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - CURLcode res = curl_easy_perform(_curl); - curl_formfree(formpost); - // reset the headers before any exceptions are thrown - _SetHTTPHeaders(); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, please try again or contact MUJIN support", MEC_HTTPServer); - } - } - - virtual void CancelAllJobs() - { - CallDelete("job/?format=json"); - } - - virtual void GetRunTimeStatuses(std::vector& statuses, int options) - { - boost::property_tree::ptree pt; - std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; - if( options & 1 ) { - url += std::string(",status_text"); - } - CallGet(url, pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - size_t i = 0; - statuses.resize(objects.size()); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - statuses[i].pk = v.second.get("pk"); - statuses[i].code = static_cast(boost::lexical_cast(v.second.get("status"))); - statuses[i].type = v.second.get("fnname"); - statuses[i].elapsedtime = v.second.get("elapsedtime"); - if( options & 1 ) { - statuses[i].message = v.second.get("status_text"); - } - i++; - } - } - - virtual void GetScenePrimaryKeys(std::vector& scenekeys) - { - boost::property_tree::ptree pt; - CallGet("scene/?format=json&limit=0&fields=pk", pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - scenekeys.resize(objects.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - scenekeys[i++] = v.second.get("pk"); - } - } - - virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& scenetype) - { - BOOST_ASSERT(scenetype.size()>0); - boost::property_tree::ptree pt; - CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); - std::string pk = pt.get("pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; - } - - virtual SceneResourcePtr ImportSceneToCOLLADA(const std::string& importuri, const std::string& importformat, const std::string& newuri) - { - BOOST_ASSERT(importformat.size()>0); - boost::property_tree::ptree pt; - CallPost("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); - std::string pk = pt.get("pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; - } - - class CurlCustomRequestSetter - { -public: - CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); - } - ~CurlCustomRequestSetter() { - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); - } -protected: - CURL* _curl; - }; - - class CurlUploadSetter - { -public: - CurlUploadSetter(CURL *curl) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); - } - ~CurlUploadSetter() { - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); - } -protected: - CURL* _curl; - }; - - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) - { - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? - boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - baseuploaduri += _EncodeWithoutSeparator(destinationdir.substr(7)); - _EnsureWebDAVDirectories(destinationdir.substr(7)); - } - else { - baseuploaduri = destinationdir; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - - size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename, encoding::ConvertUTF8ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNPath; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNPath)); - std::string strWCNURI = strWCNPath; - size_t lastindex = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - strWCNPath[i] = s_filesep; - lastindex = i; - } - } - std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); - _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); - } - } - - // sourcefilenamebase is utf-8 - char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); - std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); - curl_free(pescapeddir); - _UploadFileToWebDAV_UTF8(sourcefilename, uploadfileuri); - - /* webdav operations - const char *postdata = - "" - "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" - " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " - "WHERE \"DAV:isfolder\" = True\r\n"; - */ - } - - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) - { - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? - boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - std::string destinationdir_utf8; - utf8::utf16to8(destinationdir_utf16.begin(), destinationdir_utf16.end(), std::back_inserter(destinationdir_utf8)); - - if( destinationdir_utf8.size() >= 7 && destinationdir_utf8.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - std::string s = destinationdir_utf8.substr(7); - baseuploaduri += _EncodeWithoutSeparator(s); - _EnsureWebDAVDirectories(s); - } - else { - baseuploaduri = destinationdir_utf8; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - - size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename_utf16, encoding::ConvertUTF16ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNURI; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNURI)); - size_t lastindex_utf8 = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - lastindex_utf8 = i; - } - } - size_t lastindex_utf16 = 0; - for(size_t i = 0; i < strWCNPath_utf16.size(); ++i) { - if( strWCNPath_utf16[i] == '\\' ) { - strWCNPath_utf16[i] = s_wfilesep; - lastindex_utf16 = i; - } - } - std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); - _UploadDirectoryToWebDAV_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); - } - } - - // sourcefilenamebase is utf-8 - std::string sourcefilenamedir_utf8; - utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); - char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); - std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); - curl_free(pescapeddir); - _UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); - } - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode=200) - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - if( _buffer.rdbuf()->in_avail() > 0 ) { - boost::property_tree::read_json(_buffer, pt); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } - return http_code; - } - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode=200) - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - outputdata = _buffer.str(); - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - if( outputdata.size() > 0 ) { - boost::property_tree::ptree pt; - boost::property_tree::read_json(_buffer, pt); - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); - } - return http_code; - } - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallPost(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode=201) - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - curl_easy_setopt(_curl, CURLOPT_POST, 1); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( _buffer.rdbuf()->in_avail() > 0 ) { - boost::property_tree::read_json(_buffer, pt); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } - return http_code; - } - - int CallPut(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode=202) - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); - CURLcode res = curl_easy_perform(_curl); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( _buffer.rdbuf()->in_avail() > 0 ) { - boost::property_tree::read_json(_buffer, pt); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } - return http_code; - } - - void CallDelete(const std::string& relativeuri) - { - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - CURLcode res = curl_easy_perform(_curl); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 204 ) { // or 200 or 202 or 201? - throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); - } - } - - std::stringstream& GetBuffer() - { - return _buffer; - } - - virtual void SetDefaultSceneType(const std::string& scenetype) - { - _defaultscenetype = scenetype; - } - - virtual const std::string& GetDefaultSceneType() - { - return _defaultscenetype; - } - - virtual void SetDefaultTaskType(const std::string& tasktype) - { - _defaultscenetype = tasktype; - } - - virtual const std::string& GetDefaultTaskType() - { - return _defaulttasktype; - } - - std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) - { - size_t index = uri.find(":/"); - MUJIN_ASSERT_OP_FORMAT(index,!=,std::string::npos, "bad URI: %s", uri, MEC_InvalidArguments); - uri.substr(index+2); - char* pcurlresult = curl_easy_escape(_curl, uri.c_str()+index+2,uri.size()-index-2); - std::string sresult(pcurlresult); - curl_free(pcurlresult); // have to release the result - return sresult; - } - - std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) - { - std::string utf8line; - utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); - return GetScenePrimaryKeyFromURI_UTF8(utf8line); - } - -protected: - - void GetProfile() - { - _profile.clear(); - CallGet("profile/", _profile); - } - - static int _writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) - { - if (writerData == NULL) { - return 0; - } - writerData->write(data, size*nmemb); - return size * nmemb; - } - - void _SetHTTPHeaders() - { - // set the header to only send json - std::string s = std::string("Content-Type: application/json; charset=") + _charset; - if( !!_httpheaders ) { - curl_slist_free_all(_httpheaders); - } - _httpheaders = curl_slist_append(NULL, s.c_str()); - s = str(boost::format("Accept-Language: %s,en-us")%_language); - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") - //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // necessary? - s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); - _httpheaders = curl_slist_append(_httpheaders, "Connection: Keep-Alive"); - _httpheaders = curl_slist_append(_httpheaders, "Keep-Alive: 20"); // keep alive for 20s? - // test on windows first - //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); - } - - std::string _GetCSRFFromCookies() { - struct curl_slist *cookies; - CURLcode res = curl_easy_getinfo(_curl, CURLINFO_COOKIELIST, &cookies); - CHECKCURLCODE(res, "curl_easy_getinfo CURLINFO_COOKIELIST"); - struct curl_slist *nc = cookies; - int i = 1; - std::string csrfmiddlewaretoken; - while (nc) { - //std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; - char* csrftokenstart = strstr(nc->data, "csrftoken"); - if( !!csrftokenstart ) { - std::stringstream ss(csrftokenstart+10); - ss >> csrfmiddlewaretoken; - } - nc = nc->next; - i++; - } - curl_slist_free_all(cookies); - return csrfmiddlewaretoken; - } - - // encode a URL without the / separator - std::string _EncodeWithoutSeparator(const std::string& raw) - { - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < raw.size(); ++i) { - if( raw[i] == '/' ) { - if( startindex != i ) { - char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, i-startindex); - output += std::string(pescaped); - curl_free(pescaped); - startindex = i+1; - } - output += '/'; - } - } - if( startindex != raw.size() ) { - char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, raw.size()-startindex); - output += std::string(pescaped); - curl_free(pescaped); - } - return output; - } - - /// \param destinationdir the directory inside the user webdav folder. has a trailing slash - void _EnsureWebDAVDirectories(const std::string& uriDestinationDir) - { - std::list listCreateDirs; - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < uriDestinationDir.size(); ++i) { - if( uriDestinationDir[i] == '/' ) { - if( startindex != i ) { - char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, i-startindex); - listCreateDirs.push_back(std::string(pescaped)); - curl_free(pescaped); - startindex = i+1; - } - } - } - if( startindex != uriDestinationDir.size() ) { - char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, uriDestinationDir.size()-startindex); - listCreateDirs.push_back(std::string(pescaped)); - curl_free(pescaped); - } - - // Check that the directory exists - //curl_easy_setopt(_curl, CURLOPT_URL, buff); - //curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); - //res = curl_easy_perform(self->send_handle); - //if(res != 0) { - // // does not exist - //} - - CurlCustomRequestSetter setter(_curl, "MKCOL"); - std::string totaluri = ""; - for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { - // first have to create the directory structure up to destinationdir - if( totaluri.size() > 0 ) { - totaluri += '/'; - } - totaluri += *itdir; - _uri = _basewebdavuri + totaluri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - /* creating directories - - Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. - - 201 (Created) - The collection or structured resource was created in its entirety. - - 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. - - 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. - - 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. - - 415 (Unsupported Media Type)- The server does not support the request type of the body. - - 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. - - */ - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); - } - } - } - - /// \brief recursively uploads a directory and creates directories along the way if they don't exist - /// - /// overwrites all the files - /// \param copydir is utf-8 encoded - /// \param uri is URI-encoded - void _UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) - { - { - // make sure the directory is created - CurlCustomRequestSetter setter(_curl, "MKCOL"); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); - std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; - -#if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATAA ffd; - std::string searchstr = sCopyDir_FS + std::string("\\*"); - HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); - } - - do { - std::string filename = std::string(ffd.cFileName); - if( filename != "." && filename != ".." ) { - std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); - char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToWebDAV_UTF8(newcopydir, newuri); - } - } - } while(FindNextFileA(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); - } - -#else - boost::filesystem::path bfpcopydir(copydir); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); -#else - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); -#endif - char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); - } - } -#endif // defined(_WIN32) || defined(_WIN64) - } - - /// \brief recursively uploads a directory and creates directories along the way if they don't exist - /// - /// overwrites all the files - /// \param copydir is utf-16 encoded - /// \param uri is URI-encoded - void _UploadDirectoryToWebDAV_UTF16(const std::wstring& copydir, const std::string& uri) - { - { - // make sure the directory is created - CurlCustomRequestSetter setter(_curl, "MKCOL"); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::wstring sCopyDir_FS = copydir; - std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir) << " -> " << uri << std::endl; - -#if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATAW ffd; - std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); - HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_Assert); - } - - do { - std::wstring filename = std::wstring(ffd.cFileName); - if( filename != L"." && filename != L".." ) { - std::string filename_utf8; - utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); - std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir%filename); - char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToWebDAV_UTF16(newcopydir, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToWebDAV_UTF16(newcopydir, newuri); - } - } - } while(FindNextFileW(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_HTTPServer); - } - -#else - boost::filesystem::wpath bfpcopydir(copydir); - for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::wstring dirfilename_utf16 = itdir->path().filename().string(); -#else - std::wstring dirfilename_utf16 = itdir->path().filename(); -#endif - std::string dirfilename; - utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF16(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF16(itdir->path().string(), newuri); - } - } -#endif // defined(_WIN32) || defined(_WIN64) - } - - /// \brief uploads a single file, assumes the directory already exists - /// - /// overwrites the file if it already exists - /// \param filename utf-8 encoded - void _UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) - { - std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - FileHandler handler(sFilename_FS.c_str()); - if(!handler._fd) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); - } - _UploadFileToWebDAV(handler._fd, uri); - } - - void _UploadFileToWebDAV_UTF16(const std::wstring& filename, const std::string& uri) - { - std::string filename_fs = encoding::ConvertUTF16ToFileSystemEncoding(filename); -#if defined(_WIN32) || defined(_WIN64) - FileHandler handler(filename.c_str()); -#else - // linux does not support wide-char fopen - FileHandler handler(filename_fs.c_str()); -#endif - if(!handler._fd) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); - } - _UploadFileToWebDAV(handler._fd, uri); - } - - /// \brief uploads a single file, assumes the directory already exists - /// - /// overwrites the file if it already exists. - /// \param fd FILE pointer of binary reading file. does not close the handle - void _UploadFileToWebDAV(FILE* fd, const std::string& uri) - { -#if defined(_WIN32) || defined(_WIN64) - fseek(fd,0,SEEK_END); - curl_off_t filesize = ftell(fd); - fseek(fd,0,SEEK_SET); -#else - // to get the file size - struct stat file_info; - if(fstat(fileno(fd), &file_info) != 0) { - throw MUJIN_EXCEPTION_FORMAT("failed to stat %s for filesize", uri, MEC_InvalidArguments); - } - curl_off_t filesize = (curl_off_t)file_info.st_size; -#endif - - // tell it to "upload" to the URL - CurlUploadSetter uploadsetter(_curl); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_READDATA, fd); - curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); - //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); -#if defined(_WIN32) || defined(_WIN64) - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); -#endif - - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - // 204 is when it overwrites the file? - if( http_code != 201 && http_code != 204 ) { - if( http_code == 400 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s, perhaps file exists already?", uri%http_code, MEC_HTTPServer); - } - else { - throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s", uri%http_code, MEC_HTTPServer); - } - } - // now extract transfer info - //double speed_upload, total_time; - //curl_easy_getinfo(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); - //curl_easy_getinfo(_curl, CURLINFO_TOTAL_TIME, &total_time); - //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); - } - - /// \brief read upload function for win32. - /// MUST also provide this read callback using CURLOPT_READFUNCTION. Failing to do so will give you a crash since a DLL may not use the variable's memory when passed in to it from an app like this. */ - static size_t _ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) - { - curl_off_t nread; - // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally - size_t retcode = fread(ptr, size, nmemb, (FILE*)stream); - - nread = (curl_off_t)retcode; - //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); - return retcode; - } - - int _lastmode; - CURL *_curl; - boost::mutex _mutex; - std::stringstream _buffer; - std::string _baseuri, _baseapiuri, _basewebdavuri, _uri; - - curl_slist *_httpheaders; - std::string _charset, _language; - std::string _csrfmiddlewaretoken; - - boost::property_tree::ptree _profile; ///< user profile and versioning - std::string _errormessage; ///< set when an error occurs in libcurl - - std::string _defaultscenetype, _defaulttasktype; -}; - -typedef boost::shared_ptr ControllerClientImplPtr; - WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) { BOOST_ASSERT(__pk.size()>0); From 2485c49f0421e2a7eaf76f8119176495647256f0 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 5 Apr 2013 08:24:34 -0700 Subject: [PATCH 053/477] windows compilation fixes --- src/controllerclientimpl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index aafdd3e7..b38ee54e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -245,8 +245,9 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _language = "en-us"; #if defined(_WIN32) || defined(_WIN64) UINT codepage = GetACP(); - if( encoding::s_mapCodePageToCharset.find(codepage) != encoding::s_mapCodePageToCharset.end() ) { - _charset = encoding::s_mapCodePageToCharset[codepage]; + std::map::const_iterator itcodepage = encoding::GetCodePageMap().find(codepage); + if( itcodepage != encoding::GetCodePageMap().end() ) { + _charset = itcodepage->second; } #endif std::cout << "setting character set to " << _charset << std::endl; From df1db47975c201aba10485191e05546d190efc4b Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 7 Apr 2013 23:15:20 +0900 Subject: [PATCH 054/477] minor utils --- .../mujincontrollerclient.h | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 7cfec8ca..a04a3547 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -280,7 +280,7 @@ class MUJINCLIENT_API ControllerClient virtual ~ControllerClient() { } -// /** \brief Returns a list of filenames in the user system of a particular type +// \brief Returns a list of filenames in the user system of a particular type // // \param scenetype the type of scene possible values are: // - mujincollada @@ -291,7 +291,7 @@ class MUJINCLIENT_API ControllerClient // - x // - vrml // - stl -// */ +// // virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; /// \brief sets the character encoding for all strings that are being input and output from the resources @@ -419,7 +419,7 @@ class MUJINCLIENT_API ControllerClient Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" \param uri utf-8 encoded URI */ - std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); + virtual std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) = 0; /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) @@ -428,7 +428,27 @@ class MUJINCLIENT_API ControllerClient \param uri utf-16 encoded URI */ - std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); + virtual std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) = 0; + + /// \brief returns the primary key of a name + /// + /// \param name utf-8 encoded + virtual std::string GetPrimaryKeyFromName_UTF8(const std::string& name) = 0; + + /// \brief returns the primary key of a name + /// + /// \param name utf-16 encoded + virtual std::string GetPrimaryKeyFromName_UTF16(const std::wstring& name) = 0; + + /// \brief returns the uncoded name from a primary key + /// + /// \return utf-8 encoded name + virtual std::string GetNameFromPrimaryKey_UTF8(const std::string& pk) = 0; + + /// \brief returns the uncoded name from a primary key + /// + /// \return utf-16 encoded name + virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; }; class MUJINCLIENT_API WebResource @@ -601,9 +621,9 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource /** \brief Gets the raw program information of a specific robot, if supported. - \param[in] programtype The type of program to return. \param[in] robotpk The primary key of the robot instance in the scene. \param[out] outputdata The raw program data + \param[in] programtype The type of program to return. \throw mujin_exception If robot program is not supported, will throw an exception */ virtual void GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype="auto"); @@ -612,6 +632,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource /// /// If the robot doesn't have a recognizable controller, then no programs might be returned. /// \param[out] programs The programs for each robot. The best suited program for each robot is determined from its controller. + /// \param[in] programtype The type of program to return. virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); }; From 2f834fc805e93aca857bae6ec7cc62e4a7130b84 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 7 Apr 2013 23:15:20 +0900 Subject: [PATCH 055/477] minor utils --- src/controllerclientimpl.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b38ee54e..dc0107f9 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -706,6 +706,38 @@ std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wst return GetScenePrimaryKeyFromURI_UTF8(utf8line); } +std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF8(const std::string& name) +{ + char* pcurlresult = curl_easy_escape(_curl, name.c_str(), name.size()); + std::string sresult(pcurlresult); + curl_free(pcurlresult); // have to release the result + return sresult; +} + +std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring& name) +{ + std::string name_utf8; + utf8::utf16to8(name.begin(), name.end(), std::back_inserter(name_utf8)); + return GetPrimaryKeyFromName_UTF8(name_utf8); +} + +std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) +{ + int outlength=0; + char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); + std::string utf8; utf8.reserve(outlength); + std::copy(punescaped,punescaped+outlength,utf8.begin()); + return utf8; +} + +std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) +{ + std::string utf8 = GetNameFromPrimaryKey_UTF8(pk); + std::wstring utf16; + utf8::utf8to16(utf8.begin(), utf8.end(), std::back_inserter(utf16)); + return utf16; +} + void ControllerClientImpl::GetProfile() { _profile.clear(); From a3d815b176f4eca2c1cc57c9f3775fe633bae6d4 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Mon, 8 Apr 2013 11:56:42 +0900 Subject: [PATCH 056/477] fixed GetOrCreate functions passing in encoded names --- .../mujincontrollerclient.h | 38 ++++++++++++++----- src/mujincontrollerclient.cpp | 38 +++++++++++++++---- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a04a3547..055015a1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -234,16 +234,16 @@ struct RobotPlacementOptimizationParameters } inline void SetDefaults() { topstorecandidates = 20; - targetname.clear(); - frame = "0 robot"; + targetpk.clear(); + framepk = "0 robot"; unit = "mm"; minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; ignorebasecollision = 1; } - std::string targetname; ///< what target object to optimize for. If blank, will use robot. - std::string frame; ///< The frame to define the optimization parameters in + std::string targetpk; ///< the primary key of the target object to optimize for. If blank, will use robot. + std::string framepk; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) @@ -512,18 +512,34 @@ class MUJINCLIENT_API SceneResource : public WebResource /** \brief Gets or creates the a task part of the scene If task exists already, validates it with tasktype. - \param taskname the name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown + \param taskname utf-8 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown \param tasktype The type of task to create. Supported types are: - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype); - virtual TaskResourcePtr GetOrCreateTaskFromName(const std::string& taskname) + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname) { - return GetOrCreateTaskFromName(taskname, GetController()->GetDefaultTaskType()); + return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType()); } - virtual TaskResourcePtr GetTaskFromName(const std::string& taskname); + virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname); + + /** \brief Gets or creates the a task part of the scene + + If task exists already, validates it with tasktype. + \param taskname utf-16 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown + \param tasktype The type of task to create. Supported types are: + - itlplanning + */ + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype); + + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname) + { + return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType()); + } + + virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname); /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); @@ -554,7 +570,9 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief Gets or creates the a optimization part of the scene /// /// \param optimizationname the name of the optimization to search for or create - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); + + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 82e9230b..daa90a04 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -54,11 +54,12 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& { } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskname, const std::string& tasktype) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) { GETCONTROLLERIMPL(); + boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%*pescapedtaskname), pt); // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() > 0 ) { @@ -78,11 +79,12 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName(const std::string& taskna return task; } -TaskResourcePtr SceneResource::GetTaskFromName(const std::string& taskname) +TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname) { GETCONTROLLERIMPL(); + boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%taskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() == 0 ) { @@ -94,6 +96,20 @@ TaskResourcePtr SceneResource::GetTaskFromName(const std::string& taskname) return task; } +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype) +{ + std::string taskname_utf8; + utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); + return GetOrCreateTaskFromName_UTF8(taskname_utf8, tasktype); +} + +TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& taskname) +{ + std::string taskname_utf8; + utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); + return GetTaskFromName_UTF8(taskname_utf8); +} + void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) { GETCONTROLLERIMPL(); @@ -180,11 +196,12 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) status.code = JSC_Unknown; } -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std::string& optimizationname, const std::string& optimizationtype) +OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype) { GETCONTROLLERIMPL(); + boost::shared_ptr pescapedoptimizationname = controller->GetURLEscapedString(optimizationname); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%optimizationname), pt); + controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%pescapedoptimizationname), pt); // optimization exists boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() > 0 ) { @@ -204,6 +221,13 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName(const std: return optimization; } +OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype) +{ + std::string optimizationname_utf8; + utf8::utf16to8(optimizationname.begin(), optimizationname.end(), std::back_inserter(optimizationname_utf8)); + return GetOrCreateOptimizationFromName_UTF8(optimizationname_utf8, optimizationtype); +} + void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) { GETCONTROLLERIMPL(); @@ -305,7 +329,7 @@ void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimiz { GETCONTROLLERIMPL(); std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.frame%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); + std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetpk%optparams.framepk%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } From b3c54816ec93f54c3095c22143d5f49bf2926ea6 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 9 Apr 2013 21:28:25 +0900 Subject: [PATCH 057/477] add utf-8/16 versions for RegisterScene and ImportSceneToCOLLADA --- src/controllerclientimpl.cpp | 38 ++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index dc0107f9..a926701e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -387,21 +387,41 @@ void ControllerClientImpl::GetScenePrimaryKeys(std::vector& sceneke } } -SceneResourcePtr ControllerClientImpl::RegisterScene(const std::string& uri, const std::string& scenetype) +SceneResourcePtr ControllerClientImpl::RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) { BOOST_ASSERT(scenetype.size()>0); boost::property_tree::ptree pt; - CallPost("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); + CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA(const std::string& importuri, const std::string& importformat, const std::string& newuri) +SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) +{ + BOOST_ASSERT(scenetype.size()>0); + boost::property_tree::ptree pt; + CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype.c_str()), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; +} + +SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri) +{ + BOOST_ASSERT(importformat.size()>0); + boost::property_tree::ptree pt; + CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); + return scene; +} + +SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri) { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; - CallPost("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; @@ -617,6 +637,16 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st return http_code; } +int ControllerClientImpl::CallPost_UTF8(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + return CallPost(relativeuri, encoding::ConvertUTF8ToFileSystemEncoding(data), pt, expectedhttpcode); +} + +int ControllerClientImpl::CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + return CallPost(relativeuri, encoding::ConvertUTF16ToFileSystemEncoding(data), pt, expectedhttpcode); +} + int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode) { boost::mutex::scoped_lock lock(_mutex); From 1c3a77f0877b76e291795a6a0fffa6d555d294d2 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 9 Apr 2013 21:28:25 +0900 Subject: [PATCH 058/477] add utf-8/16 versions for RegisterScene and ImportSceneToCOLLADA --- .../mujincontrollerclient.h | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 055015a1..b060faea 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -338,6 +338,7 @@ class MUJINCLIENT_API ControllerClient /** \brief Register a scene to be used by the MUJIN Controller + \param uri utf-8 encoded URI of the file on the MUJIN Controller to import. Usually starts with \b mujin:/ \param scenetype The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) @@ -347,17 +348,28 @@ class MUJINCLIENT_API ControllerClient - **stl** - **cecvirfitxml** (CEC Virfit XML environments) */ - virtual SceneResourcePtr RegisterScene(const std::string& uri, const std::string& scenetype) = 0; + virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) = 0; /// \brief registers scene with default scene type - virtual SceneResourcePtr RegisterScene(const std::string& uri) + virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri) { - return RegisterScene(uri,GetDefaultSceneType()); + return RegisterScene_UTF8(uri,GetDefaultSceneType()); + } + + /// \see RegisterScene_UTF8 + /// + /// \param uri utf-16 encoded URI + virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) = 0; + + /// \brief registers scene with default scene type + virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri) + { + return RegisterScene_UTF16(uri,GetDefaultSceneType()); } /** \brief import a scene into COLLADA format using from scene identified by a URI - \param sourceuri URI-encoded original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext + \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext \param sourcescenetype The format of the source file. Can be: - **mujincollada** - **wincaps** (DensoWave WINCAPS III) @@ -366,9 +378,15 @@ class MUJINCLIENT_API ControllerClient - **vrml** - **stl** - **cecvirfitxml** (CEC Virfit XML environments) - \param newuri Then new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae + \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ - virtual SceneResourcePtr ImportSceneToCOLLADA(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; + + /// \see ImportSceneToCOLLADA_UTF8 + /// + /// \param sourceuri utf-16 encoded + /// \param newuri utf-16 encoded + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri) = 0; /** \brief uploads a particular scene's files into the network filesystem. From 6cfa6905ea91387d378aaab4cec9ef9e9181be52 Mon Sep 17 00:00:00 2001 From: yfukaya Date: Wed, 10 Apr 2013 12:26:00 +0900 Subject: [PATCH 059/477] commit changes from mujin orin provider --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index a926701e..d22321a8 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -710,7 +710,7 @@ const std::string& ControllerClientImpl::GetDefaultSceneType() void ControllerClientImpl::SetDefaultTaskType(const std::string& tasktype) { - _defaultscenetype = tasktype; + _defaulttasktype = tasktype; } const std::string& ControllerClientImpl::GetDefaultTaskType() From bfdadc496b377800553bbfb476d5feb2cea8dd3b Mon Sep 17 00:00:00 2001 From: yfukaya Date: Wed, 10 Apr 2013 14:25:01 +0900 Subject: [PATCH 060/477] commit changes from mujin orin provider --- src/controllerclientimpl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index d22321a8..ba56d8aa 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -753,10 +753,10 @@ std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) { - int outlength=0; - char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); - std::string utf8; utf8.reserve(outlength); - std::copy(punescaped,punescaped+outlength,utf8.begin()); + int outlength = 0; + char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); + std::string utf8(punescaped, outlength); + curl_free(punescaped); // have to release the result return utf8; } From 00a6a7217532869508b0207663af5b0832ca08a8 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 11 Apr 2013 16:45:33 +0900 Subject: [PATCH 061/477] minor doc fix --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ba56d8aa..7bcd3b19 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -754,8 +754,8 @@ std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) { int outlength = 0; - char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); - std::string utf8(punescaped, outlength); + char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); + std::string utf8(punescaped, outlength); curl_free(punescaped); // have to release the result return utf8; } From 9e2364fe6b2412350e348a59cb5667310d2f0383 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 9 May 2013 20:08:58 +0900 Subject: [PATCH 062/477] fixed boost filesystem v3 problem --- src/controllerclientimpl.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 7bcd3b19..5e475bd6 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1035,14 +1035,27 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& co throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_HTTPServer); } +#elif defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 + boost::filesystem::path bfpcopydir(copydir); + for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { + std::wstring dirfilename_utf16 = itdir->path().filename().wstring(); + std::string dirfilename; + utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); + char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); + std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); + curl_free(pescapeddir); + if( boost::filesystem::is_directory(itdir->status()) ) { + _UploadDirectoryToWebDAV_UTF16(itdir->path().wstring(), newuri); + } + else if( boost::filesystem::is_regular_file(itdir->status()) ) { + _UploadFileToWebDAV_UTF16(itdir->path().wstring(), newuri); + } + } #else + // boost filesystem v2 boost::filesystem::wpath bfpcopydir(copydir); for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::wstring dirfilename_utf16 = itdir->path().filename().string(); -#else std::wstring dirfilename_utf16 = itdir->path().filename(); -#endif std::string dirfilename; utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); From 6afbb3f88618434330f14fa91fa0239430652279 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 2 Jun 2013 15:19:07 +0900 Subject: [PATCH 063/477] allow robodia files to be uploaded --- src/controllerclientimpl.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 5e475bd6..8eadc558 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -411,7 +411,7 @@ SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::stri { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; - CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; @@ -421,7 +421,7 @@ SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wst { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; - CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_format\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); + CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; @@ -473,6 +473,10 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, co _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); } } + else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { + _UploadDirectoryToWebDAV_UTF8(sourcefilename.substr(0,nBaseFilenameStartIndex), baseuploaduri); + return; + } // sourcefilenamebase is utf-8 char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); @@ -544,6 +548,10 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& sourcefilename_u _UploadDirectoryToWebDAV_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); } } + else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { + _UploadDirectoryToWebDAV_UTF16(sourcefilename_utf16.substr(0,nBaseFilenameStartIndex), baseuploaduri); + return; + } // sourcefilenamebase is utf-8 std::string sourcefilenamedir_utf8; @@ -913,8 +921,18 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestin } } -void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& uri) +void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& rawuri) { + BOOST_ASSERT(rawuri.size()>0); + // if there's a trailing slash, have ot get rid of it + std::string uri; + if( rawuri.at(rawuri.size()-1) == '/' ) { + uri = rawuri.substr(0,rawuri.size()-1); + } + else { + uri = rawuri; + } + { // make sure the directory is created CurlCustomRequestSetter setter(_curl, "MKCOL"); From d0abbbbb7093df4ab78a5f5d301cb2338b1e6ef6 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sun, 2 Jun 2013 15:19:07 +0900 Subject: [PATCH 064/477] allow robodia files to be uploaded --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b060faea..0c0b2179 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -66,6 +66,7 @@ enum MujinErrorCode { MEC_HTTPClient=12, ///< HTTP client error MEC_HTTPServer=13, ///< HTTP server error MEC_UserAuthentication=14, ///< authentication failed + MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -81,6 +82,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_HTTPClient: return "HTTPClient"; case MEC_HTTPServer: return "HTTPServer"; case MEC_UserAuthentication: return "UserAuthentication"; + case MEC_AlreadyExists: return "AlreadyExists"; } // should throw an exception? return ""; From 5113acbe7fa8b4ce2639d55d31023489b80d133b Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 27 Jun 2013 12:06:26 +0900 Subject: [PATCH 065/477] replace / with \ for windows paths --- src/controllerclientimpl.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8eadc558..ca851a7a 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -14,6 +14,8 @@ #include "common.h" #include "controllerclientimpl.h" +#include + #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION @@ -446,6 +448,14 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, co baseuploaduri.push_back('/'); } +#if defined(_WIN32) || defined(_WIN64) + // check if / is used anywhere and send a warning if it is + if( sourcefilename.find_first_of('/') != std::string::npos ) { + std::cout << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\" << std::endl; + boost::replace_all(sourcefilename, '/', '\\'); + } +#endif + size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); if( nBaseFilenameStartIndex == std::string::npos ) { // there's no path? @@ -516,6 +526,14 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& sourcefilename_u baseuploaduri.push_back('/'); } +#if defined(_WIN32) || defined(_WIN64) + // check if / is used anywhere and send a warning if it is + if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { + std::cout << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\" << std::endl; + boost::replace_all(sourcefilename_utf16, L'/', L'\\'); + } +#endif + size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); if( nBaseFilenameStartIndex == std::string::npos ) { // there's no path? From 0ffeffcddbb005c2787c8d03d92a4c8ad0c8e1d1 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 27 Jun 2013 12:06:26 +0900 Subject: [PATCH 066/477] replace / with \ for windows paths --- include/mujincontrollerclient/mujincontrollerclient.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 0c0b2179..53a4193e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -392,8 +392,8 @@ class MUJINCLIENT_API ControllerClient /** \brief uploads a particular scene's files into the network filesystem. - \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. - \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/" + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. + \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/". Use the / separator for different paths. \param scenetype UTF-8 encoded type of scene uploading. \throw mujin_exception if the upload fails, will throw an exception */ @@ -407,7 +407,7 @@ class MUJINCLIENT_API ControllerClient /// \see SyncUpload /// - /// \param sourcefilename UTF-16 encoded + /// \param sourcefilename UTF-16 encoded. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. /// \param destinationdir UTF-16 encoded /// \param scenetype UTF-16 encoded virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir, const std::string& scenetype) = 0; From 95133e2f98a0970a9437a0e7c0706e3f674e64aa Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 27 Jun 2013 20:53:27 -0700 Subject: [PATCH 067/477] fix controller client --- src/controllerclientimpl.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ca851a7a..264f0178 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -429,7 +429,7 @@ SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wst return scene; } -void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) +void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, const std::string& destinationdir, const std::string& scenetype) { // TODO use curl_multi_perform to allow uploading of multiple files simultaneously // TODO should LOCK with WebDAV repository? @@ -448,11 +448,16 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, co baseuploaduri.push_back('/'); } + std::string sourcefilename = _sourcefilename; #if defined(_WIN32) || defined(_WIN64) // check if / is used anywhere and send a warning if it is if( sourcefilename.find_first_of('/') != std::string::npos ) { std::cout << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\" << std::endl; - boost::replace_all(sourcefilename, '/', '\\'); + for(size_t i = 0; i < sourcefilename.size(); ++i) { + if( sourcefilename[i] == '/' ) { + sourcefilename[i] = '\\'; + } + } } #endif @@ -503,7 +508,7 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& sourcefilename, co */ } -void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) +void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) { // TODO use curl_multi_perform to allow uploading of multiple files simultaneously // TODO should LOCK with WebDAV repository? @@ -526,11 +531,18 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& sourcefilename_u baseuploaduri.push_back('/'); } + std::wstring sourcefilename_utf16 = _sourcefilename_utf16; #if defined(_WIN32) || defined(_WIN64) // check if / is used anywhere and send a warning if it is if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { std::cout << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\" << std::endl; - boost::replace_all(sourcefilename_utf16, L'/', L'\\'); + for(size_t i = 0; i < sourcefilename_utf16.size(); ++i) { + if( sourcefilename_utf16[i] == L'/' ) { + sourcefilename_utf16[i] = L'\\'; + } + } + + boost::replace_all(sourcefilename_utf16, L"/", L"\\"); } #endif From 4f4c938c2fb6faa730089690cf13734122c33c92 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 19 Jul 2013 00:47:01 +0900 Subject: [PATCH 068/477] add ideal usage scenario for densowave wincaps simulations, fixed several bugs --- .../mujincontrollerclient.h | 19 ++++++++++--------- src/mujincontrollerclient.cpp | 9 +++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 53a4193e..50b43c30 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -236,21 +236,21 @@ struct RobotPlacementOptimizationParameters } inline void SetDefaults() { topstorecandidates = 20; - targetpk.clear(); - framepk = "0 robot"; + targetname.clear(); + framename = "0 robot"; unit = "mm"; minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; - ignorebasecollision = 1; + ignorebasecollision = 0; } - std::string targetpk; ///< the primary key of the target object to optimize for. If blank, will use robot. - std::string framepk; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. + std::string targetname; ///< the primary key of the target object to optimize for. If blank, will use robot. + std::string framename; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) - int ignorebasecollision; ///< When moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. + int ignorebasecollision; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; @@ -626,10 +626,11 @@ class MUJINCLIENT_API OptimizationResource : public WebResource /// \brief get the run-time status of the executed optimization. virtual void GetRunTimeStatus(JobStatus& status); - /// \brief gets the fastest results of the optimization execution. + /// \brief Gets the results of the optimization execution ordered by task_time. /// - /// \param fastestnum The number of results to get starting with the fastest task_time. If 0, will return ALL results. - virtual void GetResults(int fastestnum, std::vector& results); + /// \param startoffset The offset to retrieve the results from. Ordered + /// \param num The number of results to get starting at startoffset. If 0, will return ALL results. + virtual void GetResults(std::vector& results, int startoffset=0, int num=0); }; class MUJINCLIENT_API PlanningResultResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index daa90a04..fde6f19e 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -59,7 +59,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%*pescapedtaskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); if( objects.size() > 0 ) { @@ -329,16 +329,17 @@ void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimiz { GETCONTROLLERIMPL(); std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetpk%optparams.framepk%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); + std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } -void OptimizationResource::GetResults(int fastestnum, std::vector& results) +void OptimizationResource::GetResults(std::vector& results, int startoffset, int num) { GETCONTROLLERIMPL(); + std::string querystring = str(boost::format("optimization/%s/result/?format=json&fields=pk&order_by=task_time&offset=%d&limit=%d")%GetPrimaryKey()%startoffset%num); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("optimization/%s/result/?format=json&limit=%d&fields=pk&order_by=task_time")%GetPrimaryKey()%fastestnum), pt); + controller->CallGet(querystring, pt); boost::property_tree::ptree& objects = pt.get_child("objects"); results.resize(objects.size()); size_t i = 0; From 4445cd0f738b5862a8e71f07b78fba8f3cfb9259 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 19 Jul 2013 11:05:29 +0900 Subject: [PATCH 069/477] add ideal densowave sample, fix bugs with creating optimizations, etc --- .../mujincontrollerclient.h | 16 ++++++++-- src/mujincontrollerclient.cpp | 30 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 50b43c30..a170d3a1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -585,6 +585,7 @@ class MUJINCLIENT_API TaskResource : public WebResource /// /// This will only work if the task has been previously Executed with execute /// If the task is not currently running, will set status.code to JSC_Unknown + /// \param options if options is 1, also get the message virtual void GetRunTimeStatus(JobStatus& status, int options = 1); /// \brief Gets or creates the a optimization part of the scene @@ -607,7 +608,7 @@ class MUJINCLIENT_API TaskResource : public WebResource virtual PlanningResultResourcePtr GetResult(); protected: - std::string _jobpk; + std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called }; class MUJINCLIENT_API OptimizationResource : public WebResource @@ -618,19 +619,28 @@ class MUJINCLIENT_API OptimizationResource : public WebResource } /// \brief execute the optimization - virtual void Execute(); + /// + /// \param bClearOldResults if true, will clear the old optimiation results. If false, will keep the old optimization results and only compute those that need to be computed. + virtual void Execute(bool bClearOldResults=true); /// \brief Set new task info for tasks of type robotplanning void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); /// \brief get the run-time status of the executed optimization. - virtual void GetRunTimeStatus(JobStatus& status); + /// + /// This will only work if the optimization has been previously Executed with execute + /// If the task is not currently running, will set status.code to JSC_Unknown + /// \param options if options is 1, also get the message + virtual void GetRunTimeStatus(JobStatus& status, int options = 1); /// \brief Gets the results of the optimization execution ordered by task_time. /// /// \param startoffset The offset to retrieve the results from. Ordered /// \param num The number of results to get starting at startoffset. If 0, will return ALL results. virtual void GetResults(std::vector& results, int startoffset=0, int num=0); + +protected: + std::string _jobpk; ///< the job primary key used to track the status of the running optimization after \ref Execute is called }; class MUJINCLIENT_API PlanningResultResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index fde6f19e..237e4ac1 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -175,6 +175,7 @@ bool TaskResource::Execute() void TaskResource::GetRunTimeStatus(JobStatus& status, int options) { + status.code = JSC_Unknown; if( _jobpk.size() > 0 ) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; @@ -192,8 +193,6 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) status.message = pt.get("status_text"); } } - - status.code = JSC_Unknown; } OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype) @@ -314,15 +313,34 @@ OptimizationResource::OptimizationResource(ControllerClientPtr controller, const { } -void OptimizationResource::Execute() +void OptimizationResource::Execute(bool bClearOldResults) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), std::string(), pt, 200); + controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), str(boost::format("{\"clear\":%d}")%bClearOldResults), pt, 200); + _jobpk = pt.get("jobpk"); } -void OptimizationResource::GetRunTimeStatus(JobStatus& status) { - throw MujinException("not implemented yet"); +void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) +{ + status.code = JSC_Unknown; + if( _jobpk.size() > 0 ) { + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); + if( options & 1 ) { + url += std::string(",status_text"); + } + controller->CallGet(url, pt); + //pt.get("error_message") + status.pk = pt.get("pk"); + status.code = static_cast(boost::lexical_cast(pt.get("status"))); + status.type = pt.get("fnname"); + status.elapsedtime = pt.get("elapsedtime"); + if( options & 1 ) { + status.message = pt.get("status_text"); + } + } } void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams) From a4b57708c968ece2b366da4c5275c2af27ecb38f Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 18 Jul 2013 22:19:29 -0700 Subject: [PATCH 070/477] fixed character encoding http header --- src/controllerclientimpl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 264f0178..855e7918 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -122,7 +122,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } _baseapiuri = _baseuri + std::string("api/v1/"); // hack for now since webdav server and api server could be running on different ports - if( boost::algorithm::ends_with(_baseuri, ":8000/") ) { + if( boost::algorithm::ends_with(_baseuri, ":7999/") ) { // testing on localhost, however the webdav server is running on port 80... _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); } @@ -831,6 +831,8 @@ void ControllerClientImpl::_SetHTTPHeaders() _httpheaders = curl_slist_append(NULL, s.c_str()); s = str(boost::format("Accept-Language: %s,en-us")%_language); _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") + s = str(boost::format("Accept-Charset: %s")%_charset); + _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // necessary? s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; _httpheaders = curl_slist_append(_httpheaders, s.c_str()); From 53d014e6430ce4c9ee9f4ea7d804e977a34c1440 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 30 Jul 2013 11:40:56 +0900 Subject: [PATCH 071/477] added upload/delete/download functions to the controller API, upgrade version to 0.2.8 --- src/controllerclientimpl.cpp | 534 ++++++++++++++++++++++++++++++----- 1 file changed, 469 insertions(+), 65 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 855e7918..bc12598f 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -25,7 +25,7 @@ class CurlCustomRequestSetter { public: CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); } ~CurlCustomRequestSetter() { curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); @@ -34,11 +34,24 @@ class CurlCustomRequestSetter CURL* _curl; }; +class CurlWriteDataSetter +{ +public: + CurlWriteDataSetter(CURL *curl, const void* pdata) : _curl(curl) { + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, pdata); + } + ~CurlWriteDataSetter() { + curl_easy_setopt(_curl, CURLOPT_WRITEDATA, NULL); + } +protected: + CURL* _curl; +}; + class CurlUploadSetter { public: CurlUploadSetter(CURL *curl) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); } ~CurlUploadSetter() { curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); @@ -122,7 +135,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } _baseapiuri = _baseuri + std::string("api/v1/"); // hack for now since webdav server and api server could be running on different ports - if( boost::algorithm::ends_with(_baseuri, ":7999/") ) { + if( boost::algorithm::ends_with(_baseuri, ":8000/") || (options&0x80000000) ) { // testing on localhost, however the webdav server is running on port 80... _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); } @@ -183,7 +196,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout - res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _writer); + res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); CHECKCURLCODE(res, "failed to set writer"); res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); CHECKCURLCODE(res, "failed to set write data"); @@ -306,7 +319,10 @@ void ControllerClientImpl::RestartServer() curl_easy_setopt(_curl, CURLOPT_POST, 1); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - CURLcode res = curl_easy_perform(_curl); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -332,11 +348,15 @@ void ControllerClientImpl::Upgrade(const std::vector& vdata) headerlist = curl_slist_append(headerlist, s.c_str()); curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + // Fill in the file upload field struct curl_httppost *formpost=NULL, *lastptr=NULL; curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "mujinpatch", CURLFORM_BUFFERPTR, &vdata[0], CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); curl_formfree(formpost); // reset the headers before any exceptions are thrown _SetHTTPHeaders(); @@ -485,11 +505,14 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c } } std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); - _UploadDirectoryToWebDAV_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); + _UploadDirectoryToController_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); } } else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - _UploadDirectoryToWebDAV_UTF8(sourcefilename.substr(0,nBaseFilenameStartIndex), baseuploaduri); + if( nBaseFilenameStartIndex > 0 ) { + // sourcefilename[nBaseFilenameStartIndex] should be == s_filesep + _UploadDirectoryToController_UTF8(sourcefilename.substr(0,nBaseFilenameStartIndex), baseuploaduri); + } return; } @@ -497,7 +520,7 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); - _UploadFileToWebDAV_UTF8(sourcefilename, uploadfileuri); + _UploadFileToController_UTF8(sourcefilename, uploadfileuri); /* webdav operations const char *postdata = @@ -575,11 +598,14 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ } } std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); - _UploadDirectoryToWebDAV_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); + _UploadDirectoryToController_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); } } else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - _UploadDirectoryToWebDAV_UTF16(sourcefilename_utf16.substr(0,nBaseFilenameStartIndex), baseuploaduri); + if( nBaseFilenameStartIndex > 0 ) { + // sourcefilename_utf16[nBaseFilenameStartIndex] should be == s_filesep + _UploadDirectoryToController_UTF16(sourcefilename_utf16.substr(0,nBaseFilenameStartIndex), baseuploaduri); + } return; } @@ -589,7 +615,7 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); curl_free(pescapeddir); - _UploadFileToWebDAV_UTF16(sourcefilename_utf16, uploadfileuri); + _UploadFileToController_UTF16(sourcefilename_utf16, uploadfileuri); } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception @@ -598,11 +624,19 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::propert boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + return _CallGet(_uri, pt, expectedhttpcode); +} + +int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_tree::ptree& pt, int expectedhttpcode) +{ + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); _buffer.str(""); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -613,22 +647,29 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::propert if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; } -/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + return _CallGet(_uri, outputdata, expectedhttpcode); +} + +int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode) +{ + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); _buffer.str(""); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -640,9 +681,54 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& o boost::property_tree::read_json(_buffer, pt); std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); + } + return http_code; +} + +int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + return _CallGet(_uri, outputdata, expectedhttpcode); +} + +int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode) +{ + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteVectorCallback); + CHECKCURLCODE(res, "failed to set writer"); + outputdata.resize(0); + CurlWriteDataSetter writedata(_curl, &outputdata); + + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); + res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + if( outputdata.size() > 0 ) { + std::stringstream ss; + ss.write((const char*)&outputdata[0], outputdata.size()); + std::string error_message, traceback; + try { + boost::property_tree::ptree pt; + boost::property_tree::read_json(ss, pt); + error_message = pt.get("error_message", std::string()); + traceback = pt.get("traceback", std::string()); + } + catch(const std::exception& ex) { + // probably failed parsing JSON + error_message = ss.str(); + } + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); + } + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); } return http_code; } @@ -656,10 +742,13 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); _buffer.clear(); _buffer.str(""); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_POST, 1); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -693,10 +782,13 @@ int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::str curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); _buffer.clear(); _buffer.str(""); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; @@ -812,7 +904,7 @@ void ControllerClientImpl::GetProfile() CallGet("profile/", _profile); } -int ControllerClientImpl::_writer(char *data, size_t size, size_t nmemb, std::stringstream *writerData) +int ControllerClientImpl::_WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData) { if (writerData == NULL) { return 0; @@ -821,6 +913,15 @@ int ControllerClientImpl::_writer(char *data, size_t size, size_t nmemb, std::st return size * nmemb; } +int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData) +{ + if (writerData == NULL) { + return 0; + } + writerData->insert(writerData->end(), data, data+size*nmemb); + return size * nmemb; +} + void ControllerClientImpl::_SetHTTPHeaders() { // set the header to only send json @@ -887,23 +988,23 @@ std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw return output; } -void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestinationDir) +void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeuri) { std::list listCreateDirs; std::string output; size_t startindex = 0; - for(size_t i = 0; i < uriDestinationDir.size(); ++i) { - if( uriDestinationDir[i] == '/' ) { + for(size_t i = 0; i < relativeuri.size(); ++i) { + if( relativeuri[i] == '/' ) { if( startindex != i ) { - char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, i-startindex); + char* pescaped = curl_easy_escape(_curl, relativeuri.c_str()+startindex, i-startindex); listCreateDirs.push_back(std::string(pescaped)); curl_free(pescaped); startindex = i+1; } } } - if( startindex != uriDestinationDir.size() ) { - char* pescaped = curl_easy_escape(_curl, uriDestinationDir.c_str()+startindex, uriDestinationDir.size()-startindex); + if( startindex != relativeuri.size() ) { + char* pescaped = curl_easy_escape(_curl, relativeuri.c_str()+startindex, relativeuri.size()-startindex); listCreateDirs.push_back(std::string(pescaped)); curl_free(pescaped); } @@ -916,7 +1017,11 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestin // // does not exist //} + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); CurlCustomRequestSetter setter(_curl, "MKCOL"); + std::string totaluri = ""; for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { // first have to create the directory structure up to destinationdir @@ -926,6 +1031,8 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestin totaluri += *itdir; _uri = _basewebdavuri + totaluri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; @@ -953,23 +1060,186 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& uriDestin } } -void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copydir, const std::string& rawuri) +std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) +{ + std::string baseuploaduri; + if( rawuri.size() >= 7 && rawuri.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + std::string s = rawuri.substr(7); + baseuploaduri += _EncodeWithoutSeparator(s); + if( bEnsurePath ) { + if( !bIsDirectory ) { + size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); + if( nBaseFilenameStartIndex != std::string::npos ) { + s = s.substr(0, nBaseFilenameStartIndex); + } + } + _EnsureWebDAVDirectories(s); + } + } + else { + if( !bEnsureSlash ) { + return rawuri; + } + baseuploaduri = rawuri; + } + if( bEnsureSlash ) { + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + } + return baseuploaduri; +} + +std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstring& rawuri_utf16, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) +{ + boost::mutex::scoped_lock lock(_mutex); + std::string baseuploaduri; + std::string desturi_utf8; + utf8::utf16to8(rawuri_utf16.begin(), rawuri_utf16.end(), std::back_inserter(desturi_utf8)); + + if( desturi_utf8.size() >= 7 && desturi_utf8.substr(0,7) == "mujin:/" ) { + baseuploaduri = _basewebdavuri; + std::string s = desturi_utf8.substr(7); + baseuploaduri += _EncodeWithoutSeparator(s); + if( bEnsurePath ) { + if( !bIsDirectory ) { + size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); + if( nBaseFilenameStartIndex != std::string::npos ) { + s = s.substr(0, nBaseFilenameStartIndex); + } + } + _EnsureWebDAVDirectories(s); + } + } + else { + if( !bEnsureSlash ) { + return desturi_utf8; + } + baseuploaduri = desturi_utf8; + } + if( bEnsureSlash ) { + // ensure trailing slash + if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { + baseuploaduri.push_back('/'); + } + } + return baseuploaduri; +} + +void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadFileToController_UTF8(filename, _PrepareDestinationURI_UTF8(desturi)); +} + +void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& filename_utf16, const std::wstring& desturi_utf16) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16)); +} + +void ControllerClientImpl::UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDataToController(vdata, _PrepareDestinationURI_UTF8(desturi)); +} + +void ControllerClientImpl::UploadDataToController_UTF16(const std::vector& vdata, const std::wstring& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDataToController(vdata, _PrepareDestinationURI_UTF16(desturi)); +} + +void ControllerClientImpl::UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDirectoryToController_UTF8(copydir, _PrepareDestinationURI_UTF8(desturi, true, false, true)); +} + +void ControllerClientImpl::UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDirectoryToController_UTF16(copydir, _PrepareDestinationURI_UTF16(desturi, true, false, true)); +} + +void ControllerClientImpl::DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) +{ + boost::mutex::scoped_lock lock(_mutex); + _CallGet(_PrepareDestinationURI_UTF8(desturi, false), vdata); +} + +void ControllerClientImpl::DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) +{ + boost::mutex::scoped_lock lock(_mutex); + _CallGet(_PrepareDestinationURI_UTF16(desturi, false), vdata); +} + +void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _DeleteFileOnController(_PrepareDestinationURI_UTF8(desturi, false)); +} + +void ControllerClientImpl::DeleteFileOnController_UTF16(const std::wstring& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _DeleteFileOnController(_PrepareDestinationURI_UTF16(desturi, false)); +} + +void ControllerClientImpl::DeleteDirectoryOnController_UTF8(const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _DeleteDirectoryOnController(_PrepareDestinationURI_UTF8(desturi, false, false, true)); +} + +void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); +} + +void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) { - BOOST_ASSERT(rawuri.size()>0); - // if there's a trailing slash, have ot get rid of it + BOOST_ASSERT(rawuri.size()>0 && copydir_utf8.size()>0); + + // if there's a trailing slash, have to get rid of it std::string uri; if( rawuri.at(rawuri.size()-1) == '/' ) { - uri = rawuri.substr(0,rawuri.size()-1); + if( copydir_utf8.at(copydir_utf8.size()-1) != s_filesep ) { + // append the copydir_utf8 name to rawuri + size_t nBaseFilenameStartIndex = copydir_utf8.find_last_of(s_filesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + char* pescapeddir = curl_easy_escape(_curl, copydir_utf8.substr(nBaseFilenameStartIndex).c_str(), 0); + uri = rawuri + std::string(pescapeddir); + curl_free(pescapeddir); + } + else { + // copydir also ends in a fileseparator, so remove the file separator from rawuri + uri = rawuri.substr(0, rawuri.size()-1); + } } else { + MUJIN_ASSERT_OP_FORMAT(copydir_utf8.at(copydir_utf8.size()-1),!=,s_filesep,"copydir '%s' cannot end in slash '%s'", copydir_utf8%s_filesep, MEC_InvalidArguments); uri = rawuri; } + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + { // make sure the directory is created CurlCustomRequestSetter setter(_curl, "MKCOL"); curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -978,7 +1248,11 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copy } } - std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir); + std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir_utf8); + // remove the fileseparator if it exists + if( sCopyDir_FS.size() > 0 && sCopyDir_FS.at(sCopyDir_FS.size()-1) == s_filesep ) { + sCopyDir_FS.resize(sCopyDir_FS.size()-1); + } std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; #if defined(_WIN32) || defined(_WIN64) @@ -993,16 +1267,16 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copy std::string filename = std::string(ffd.cFileName); if( filename != "." && filename != ".." ) { std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir = str(boost::format("%s\\%s")%copydir%filename_utf8); + std::string newcopydir_utf8 = str(boost::format("%s\\%s")%copydir_utf8%filename_utf8); char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToWebDAV_UTF8(newcopydir, newuri); + _UploadDirectoryToController_UTF8(newcopydir_utf8, newuri); } else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToWebDAV_UTF8(newcopydir, newuri); + _UploadFileToController_UTF8(newcopydir_utf8, newuri); } } } while(FindNextFileA(hFind,&ffd) != 0); @@ -1014,7 +1288,7 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copy } #else - boost::filesystem::path bfpcopydir(copydir); + boost::filesystem::path bfpcopydir(copydir_utf8); for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); @@ -1025,22 +1299,57 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF8(const std::string& copy std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF8(itdir->path().string(), newuri); + _UploadDirectoryToController_UTF8(itdir->path().string(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF8(itdir->path().string(), newuri); + _UploadFileToController_UTF8(itdir->path().string(), newuri); } } #endif // defined(_WIN32) || defined(_WIN64) } -void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& copydir, const std::string& uri) +void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring& copydir_utf16, const std::string& rawuri) { + BOOST_ASSERT(rawuri.size()>0 && copydir_utf16.size()>0); + MUJIN_ASSERT_OP_FORMAT(copydir_utf16.at(copydir_utf16.size()-1),!=,s_wfilesep,"copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); + + // if there's a trailing slash, have to get rid of it + std::string uri; + if( rawuri.at(rawuri.size()-1) == '/' ) { + if( copydir_utf16.at(copydir_utf16.size()-1) != s_filesep ) { + // append the copydir_utf16 name to rawuri + size_t nBaseFilenameStartIndex = copydir_utf16.find_last_of(s_filesep); + if( nBaseFilenameStartIndex == std::string::npos ) { + // there's no path? + nBaseFilenameStartIndex = 0; + } + else { + nBaseFilenameStartIndex++; + } + std::string name_utf8; + utf8::utf16to8(copydir_utf16.begin()+nBaseFilenameStartIndex, copydir_utf16.end(), std::back_inserter(name_utf8)); + char* pescapeddir = curl_easy_escape(_curl, name_utf8.c_str(), 0); + uri = rawuri + std::string(pescapeddir); + curl_free(pescapeddir); + } + else { + // copydir also ends in a fileseparator, so remove the file separator from rawuri + uri = rawuri.substr(0, rawuri.size()-1); + } + } + else { + uri = rawuri; + } + + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + { // make sure the directory is created CurlCustomRequestSetter setter(_curl, "MKCOL"); curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - CURLcode res = curl_easy_perform(_curl); + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -1049,8 +1358,15 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& co } } - std::wstring sCopyDir_FS = copydir; - std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir) << " -> " << uri << std::endl; + std::wstring sCopyDir_FS; + // remove the fileseparator if it exists + if( copydir_utf16.size() > 0 && copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep ) { + sCopyDir_FS = copydir_utf16.substr(0,copydir_utf16.size()-1); + } + else { + sCopyDir_FS = copydir_utf16; + } + std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri << std::endl; #if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAW ffd; @@ -1071,10 +1387,10 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& co curl_free(pescapeddir); if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToWebDAV_UTF16(newcopydir, newuri); + _UploadDirectoryToController_UTF16(newcopydir, newuri); } else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToWebDAV_UTF16(newcopydir, newuri); + _UploadFileToController_UTF16(newcopydir, newuri); } } } while(FindNextFileW(hFind,&ffd) != 0); @@ -1095,15 +1411,15 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& co std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF16(itdir->path().wstring(), newuri); + _UploadDirectoryToController_UTF16(itdir->path().wstring(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF16(itdir->path().wstring(), newuri); + _UploadFileToController_UTF16(itdir->path().wstring(), newuri); } } #else // boost filesystem v2 - boost::filesystem::wpath bfpcopydir(copydir); + boost::filesystem::wpath bfpcopydir(copydir_utf16); for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { std::wstring dirfilename_utf16 = itdir->path().filename(); std::string dirfilename; @@ -1112,26 +1428,26 @@ void ControllerClientImpl::_UploadDirectoryToWebDAV_UTF16(const std::wstring& co std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToWebDAV_UTF16(itdir->path().string(), newuri); + _UploadDirectoryToController_UTF16(itdir->path().string(), newuri); } else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToWebDAV_UTF16(itdir->path().string(), newuri); + _UploadFileToController_UTF16(itdir->path().string(), newuri); } } #endif // defined(_WIN32) || defined(_WIN64) } -void ControllerClientImpl::_UploadFileToWebDAV_UTF8(const std::string& filename, const std::string& uri) +void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filename, const std::string& uri) { std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); FileHandler handler(sFilename_FS.c_str()); if(!handler._fd) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - _UploadFileToWebDAV(handler._fd, uri); + _UploadFileToController(handler._fd, uri); } -void ControllerClientImpl::_UploadFileToWebDAV_UTF16(const std::wstring& filename, const std::string& uri) +void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) { std::string filename_fs = encoding::ConvertUTF16ToFileSystemEncoding(filename); #if defined(_WIN32) || defined(_WIN64) @@ -1143,10 +1459,10 @@ void ControllerClientImpl::_UploadFileToWebDAV_UTF16(const std::wstring& filenam if(!handler._fd) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); } - _UploadFileToWebDAV(handler._fd, uri); + _UploadFileToController(handler._fd, uri); } -void ControllerClientImpl::_UploadFileToWebDAV(FILE* fd, const std::string& uri) +void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) { #if defined(_WIN32) || defined(_WIN64) fseek(fd,0,SEEK_END); @@ -1170,19 +1486,25 @@ void ControllerClientImpl::_UploadFileToWebDAV(FILE* fd, const std::string& uri) //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); #if defined(_WIN32) || defined(_WIN64) curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); +#else + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, NULL); #endif - CURLcode res = curl_easy_perform(_curl); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + + res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); // 204 is when it overwrites the file? if( http_code != 201 && http_code != 204 ) { if( http_code == 400 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s, perhaps file exists already?", uri%http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("upload to %s failed with HTTP status %s, perhaps file exists already?", uri%http_code, MEC_HTTPServer); } else { - throw MUJIN_EXCEPTION_FORMAT("upload of %s failed with HTTP status %s", uri%http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("upload to %s failed with HTTP status %s", uri%http_code, MEC_HTTPServer); } } // now extract transfer info @@ -1192,15 +1514,97 @@ void ControllerClientImpl::_UploadFileToWebDAV(FILE* fd, const std::string& uri) //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); } +void ControllerClientImpl::_UploadDataToController(const std::vector& vdata, const std::string& desturi) +{ + curl_off_t filesize = vdata.size(); + + // tell it to "upload" to the URL + CurlUploadSetter uploadsetter(_curl); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + std::pair::const_iterator, size_t> streamdata; + streamdata.first = vdata.begin(); + streamdata.second = vdata.size(); + curl_easy_setopt(_curl, CURLOPT_READDATA, &streamdata); + curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); + //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadInMemoryUploadCallback); + + res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + + // reset the read state + curl_easy_setopt(_curl, CURLOPT_READDATA, NULL); + curl_easy_setopt(_curl, CURLOPT_READFUNCTION, NULL); + + // 204 is when it overwrites the file? + if( http_code != 201 && http_code != 204 ) { + if( http_code == 400 ) { + throw MUJIN_EXCEPTION_FORMAT("upload of to failed with HTTP status %s, perhaps file exists already?", desturi%http_code, MEC_HTTPServer); + } + else { + throw MUJIN_EXCEPTION_FORMAT("upload of to failed with HTTP status %s", desturi%http_code, MEC_HTTPServer); + } + } +} + +void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) +{ + CurlCustomRequestSetter setter(_curl, "DELETE"); + + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + // 204 is when it overwrites the file? + if( http_code != 204 ) { + if( http_code == 400 ) { + throw MUJIN_EXCEPTION_FORMAT("delete failed with HTTP status %s, perhaps file exists already?", desturi%http_code, MEC_HTTPServer); + } + else { + throw MUJIN_EXCEPTION_FORMAT("delete failed with HTTP status %s", desturi%http_code, MEC_HTTPServer); + } + } +} + +void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) +{ + CurlCustomRequestSetter setter(_curl, "DELETE"); + curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + std::cout << http_code << std::endl; +} + size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) { - curl_off_t nread; // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally - size_t retcode = fread(ptr, size, nmemb, (FILE*)stream); - - nread = (curl_off_t)retcode; + size_t nread = fread(ptr, size, nmemb, (FILE*)stream); //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); - return retcode; + return nread; +} + +size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) +{ + std::pair::const_iterator, size_t>* pstreamdata = static_cast::const_iterator, size_t>*>(stream); + size_t nBytesToRead = size*nmemb; + if( nBytesToRead > pstreamdata->second ) { + nBytesToRead = pstreamdata->second; + } + if( nBytesToRead > 0 ) { + std::copy(pstreamdata->first, pstreamdata->first+nBytesToRead, static_cast(ptr)); + pstreamdata->first += nBytesToRead; + pstreamdata->second -= nBytesToRead; + } + return nBytesToRead; } } // end namespace mujinclient From 80043734c8eb49b9ae00b1199e0da0e14909304d Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 30 Jul 2013 11:40:56 +0900 Subject: [PATCH 072/477] added upload/delete/download functions to the controller API, upgrade version to 0.2.8 --- .../mujincontrollerclient.h | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a170d3a1..e87d481b 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -298,7 +298,7 @@ class MUJINCLIENT_API ControllerClient /// \brief sets the character encoding for all strings that are being input and output from the resources /// - /// The default character encoding is utf-8, can also set it to Shift_JIS for windows japanese unicode, iso-2022-jp + /// The default character encoding is \b utf-8, can also set it to \b Shift_JIS for windows japanese unicode, \b iso-2022-jp /// List of possible sets: http://www.iana.org/assignments/character-sets/character-sets.xml virtual void SetCharacterEncoding(const std::string& newencoding) = 0; @@ -390,22 +390,23 @@ class MUJINCLIENT_API ControllerClient /// \param newuri utf-16 encoded virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri) = 0; - /** \brief uploads a particular scene's files into the network filesystem. + /** \brief Recommended way of uploading a scene's files into the network filesystem. + Depending on the scenetype, can upload entire directory trees. \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. - \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default use: "mujin:/". Use the / separator for different paths. + \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default prefix with "mujin:/". Use the / separator for different paths. \param scenetype UTF-8 encoded type of scene uploading. \throw mujin_exception if the upload fails, will throw an exception */ virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; - /// \see SyncUpload + /// \see SyncUpload_UTF8 virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir) { SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); } - /// \see SyncUpload + /// \see SyncUpload_UTF8 /// /// \param sourcefilename UTF-16 encoded. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. /// \param destinationdir UTF-16 encoded @@ -418,6 +419,66 @@ class MUJINCLIENT_API ControllerClient SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); } + /// \brief Uploads a single file to the controller network filesystem. + /// + /// Overwrites the file if it already exists + /// \param filename utf-8 encoded path of the file on the system + /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. + virtual void UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) = 0; + + /// \brief \see UploadFileToController_UTF8 + /// + /// \param filename utf-16 encoded + /// \param desturi UTF-16 encoded + virtual void UploadFileToController_UTF16(const std::wstring& filename, const std::wstring& desturi) = 0; + + /// \brief Uploads binary data to a single file on the controller network filesystem. + /// + /// Overwrites the destination uri if it already exists + /// \param data binary data to upload to the uri + /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. + virtual void UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) = 0; + + /** \brief Recursively uploads a directory to the controller network filesystem. + + Creates directories along the way if they don't exist. + By default, overwrites all the files + \param copydir is utf-8 encoded. Cannot have trailing slashes '/', '\' + \param desturi UTF-8 encoded destination file in the network filesystem. If it has a trailing slash, then copydir is inside that URL. If there is no trailing slash, the copydir directory is renamed to the URI. By default prefix with "mujin:/". Use the / separator for different paths. + */ + virtual void UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) = 0; + + /// \brief \see UploadDirectoryToController_UTF8 + /// + /// \param copydir is utf-16 encoded + /// \param desturi UTF-16 encoded + virtual void UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) = 0; + + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) = 0; + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) = 0; + + /// \brief Deletes a file on the controller network filesystem. + /// + /// \param uri UTF-8 encoded file in the network filesystem to delete. + virtual void DeleteFileOnController_UTF8(const std::string& uri) = 0; + + /// \brief \see DeleteFileOnController_UTF8 + /// + /// \param uri UTF-16 encoded file in the network filesystem to delete. + virtual void DeleteFileOnController_UTF16(const std::wstring& uri) = 0; + + /// \brief Recursively deletes a directory on the controller network filesystem. + /// + /// \param uri UTF-8 encoded file in the network filesystem to delete. + virtual void DeleteDirectoryOnController_UTF8(const std::string& uri) = 0; + + /// \brief \see DeleteDirectoryOnController_UTF8 + /// + /// \param uri UTF-16 encoded + virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; + virtual void SetDefaultSceneType(const std::string& scenetype) = 0; virtual const std::string& GetDefaultSceneType() = 0; @@ -692,7 +753,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. If not specified, will use the default mujin controller URL \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options extra options for connecting to the controller. If 1, the client will optimize usage to only allow GET calls + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 From dc8dabe7d073b2b7da1d08f6d520ee47cc77e578 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Mon, 29 Jul 2013 19:53:17 -0700 Subject: [PATCH 073/477] fix copydir windows compilation --- src/controllerclientimpl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index bc12598f..aa3112f0 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1373,7 +1373,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_Assert); + throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_Assert); } do { @@ -1381,7 +1381,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring if( filename != L"." && filename != L".." ) { std::string filename_utf8; utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); - std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir%filename); + std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir_utf16%filename); char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); @@ -1398,7 +1398,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring DWORD err = GetLastError(); FindClose(hFind); if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_HTTPServer); } #elif defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 From 6727b6da53b0cc3d3d6a2c2d1f9858a36b4cc615 Mon Sep 17 00:00:00 2001 From: controller Date: Tue, 6 Aug 2013 15:48:27 +0900 Subject: [PATCH 074/477] fix boost 1.49 compilation --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index aa3112f0..e4bc8931 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1402,7 +1402,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring } #elif defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - boost::filesystem::path bfpcopydir(copydir); + boost::filesystem::path bfpcopydir(copydir_utf16); for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { std::wstring dirfilename_utf16 = itdir->path().filename().wstring(); std::string dirfilename; From 2651380a7f796ee61c7cd69527cade0e8232cb11 Mon Sep 17 00:00:00 2001 From: ompugao Date: Mon, 12 Aug 2013 13:51:02 +0900 Subject: [PATCH 075/477] add InstObject::SetTransform --- .../mujincontrollerclient.h | 14 ++++--- src/mujincontrollerclient.cpp | 39 ++++++++++++++----- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e87d481b..ef3620c3 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -167,11 +167,11 @@ struct JobStatus struct Transform { Transform() { - quat[0] = 1; quat[1] = 0; quat[2] = 0; quat[3] = 0; - translation[0] = 0; translation[1] = 0; translation[2] = 0; + quaternion[0] = 1; quaternion[1] = 0; quaternion[2] = 0; quaternion[3] = 0; + translate[0] = 0; translate[1] = 0; translate[2] = 0; } - Real quat[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] - Real translation[3]; ///< translation x,y,z + Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] + Real translate[3]; ///< translation x,y,z }; struct InstanceObjectState @@ -577,11 +577,13 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~InstObject() { } + void SetTransform(const Transform& t); + std::vector dofvalues; std::string name; std::string object_pk; std::string reference_uri; - Real rotate[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; }; typedef boost::shared_ptr InstObjectPtr; @@ -627,6 +629,8 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the instance objects of the scene virtual void GetInstObjects(std::vector& instobjects); + + virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 237e4ac1..28f710ab 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -50,6 +50,14 @@ SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std: { } +void SceneResource::InstObject::SetTransform(const Transform& t) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f]}, \"translate\":[%.15f, %.15f, %.15f]")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); + controller->CallPut(str(boost::format("%s/%s/?format=json&fields=")%GetResourceName()%GetPrimaryKey()), data, pt); +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { } @@ -145,10 +153,10 @@ void SceneResource::GetInstObjects(std::vector& in instobject->dofvalues[idof++] = boost::lexical_cast(vdof.second.data()); } - size_t irotate = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vrotate, v.second.get_child("rotate")) { - BOOST_ASSERT( irotate < 4 ); - instobject->rotate[irotate++] = boost::lexical_cast(vrotate.second.data()); + size_t iquaternion = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + instobject->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); } size_t itranslate = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { @@ -160,6 +168,17 @@ void SceneResource::GetInstObjects(std::vector& in } } +SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) +//void SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real rotate[4], Real translation[3]) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPost(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"reference_uri\":\"%s\",\"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f] }")%name%reference_uri%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translation[0]%translation[1]%translation[2]), pt); + std::string inst_pk = pt.get("pk"); + SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); + return instobject; +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } @@ -387,21 +406,21 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) BOOST_ASSERT(iquat<4); Real f = boost::lexical_cast(v.second.data()); dist2 += f * f; - objstate.transform.quat[iquat++] = f; + objstate.transform.quaternion[iquat++] = f; } // normalize the quaternion if( dist2 > 0 ) { Real fnorm =1/std::sqrt(dist2); - objstate.transform.quat[0] *= fnorm; - objstate.transform.quat[1] *= fnorm; - objstate.transform.quat[2] *= fnorm; - objstate.transform.quat[3] *= fnorm; + objstate.transform.quaternion[0] *= fnorm; + objstate.transform.quaternion[1] *= fnorm; + objstate.transform.quaternion[2] *= fnorm; + objstate.transform.quaternion[3] *= fnorm; } boost::property_tree::ptree& translationjson = objstatejson.second.get_child("translation_"); int itranslation=0; BOOST_FOREACH(boost::property_tree::ptree::value_type &v, translationjson) { BOOST_ASSERT(iquat<3); - objstate.transform.translation[itranslation++] = boost::lexical_cast(v.second.data()); + objstate.transform.translate[itranslation++] = boost::lexical_cast(v.second.data()); } envstate[name] = objstate; } From a32dd7cd4531c8c48b07456aa81a2527a517580b Mon Sep 17 00:00:00 2001 From: ompugao Date: Mon, 26 Aug 2013 11:39:20 +0900 Subject: [PATCH 076/477] fix a bug at InstObject::SetTransform --- src/mujincontrollerclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 28f710ab..8a14d1aa 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -54,8 +54,8 @@ void SceneResource::InstObject::SetTransform(const Transform& t) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f]}, \"translate\":[%.15f, %.15f, %.15f]")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPut(str(boost::format("%s/%s/?format=json&fields=")%GetResourceName()%GetPrimaryKey()), data, pt); + std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) From f5cd954d02903bb9203794a5ce830db48917e164 Mon Sep 17 00:00:00 2001 From: ompugao Date: Tue, 27 Aug 2013 18:06:12 +0900 Subject: [PATCH 077/477] add a function to set transform to multiple instobjects with one http request" --- .../mujincontrollerclient.h | 3 +++ src/mujincontrollerclient.cpp | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ef3620c3..6a6ac9ce 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -581,6 +581,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector dofvalues; std::string name; + std::string pk; std::string object_pk; std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] @@ -591,6 +592,8 @@ class MUJINCLIENT_API SceneResource : public WebResource SceneResource(ControllerClientPtr controller, const std::string& pk); virtual ~SceneResource() { } + + virtual void SetMultipleInstObjectsTransform(const std::vector& instobjects, const std::vector& transforms); /** \brief Gets or creates the a task part of the scene diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 8a14d1aa..86191df9 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -52,10 +52,10 @@ SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std: void SceneResource::InstObject::SetTransform(const Transform& t) { - GETCONTROLLERIMPL(); + GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); + std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) @@ -87,6 +87,26 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t return task; } +void SceneResource::SetMultipleInstObjectsTransform(const std::vector& instobjects, const std::vector& transforms) +{ + GETCONTROLLERIMPL(); + if (instobjects.size() != transforms.size()) { + throw MUJIN_EXCEPTION_FORMAT("the size of instobjects (%d) and the one of transforms (%d) must be the same",instobjects.size()%transforms.size(),MEC_InvalidArguments); + } + boost::property_tree::ptree pt; + boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}"); + std::string datastring = ""; + + for(size_t i = 0 ; i < instobjects.size(); ++i) { + datastring += str(transformtemplate%instobjects[i]->pk%transforms[i].quaternion[0]%transforms[i].quaternion[1]%transforms[i].quaternion[2]%transforms[i].quaternion[3]%transforms[i].translate[0]%transforms[i].translate[1]%transforms[i].translate[2]); + if ( i != instobjects.size()-1) { + datastring += ","; + } + } + std::string data = str(boost::format("{\"objects\": [%s]}")%datastring); + controller->CallPut(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); +} + TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname) { GETCONTROLLERIMPL(); @@ -143,6 +163,7 @@ void SceneResource::GetInstObjects(std::vector& in InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); //instobject->dofvalues instobject->name = v.second.get("name"); + instobject->pk = v.second.get("pk"); instobject->object_pk = v.second.get("object_pk"); instobject->reference_uri = v.second.get("reference_uri"); From be0ea864c4c4232963ff724ded0217c2df382775 Mon Sep 17 00:00:00 2001 From: controller8 Date: Wed, 28 Aug 2013 10:18:27 +0900 Subject: [PATCH 078/477] fix api for inst object setting state --- .../mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6a6ac9ce..657c5a94 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -177,7 +177,7 @@ struct Transform struct InstanceObjectState { Transform transform; ///< the transform of this instance object - std::vector jointvalues; ///< the joint values + std::vector dofvalues; ///< the joint values }; typedef std::map EnvironmentState; @@ -593,7 +593,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~SceneResource() { } - virtual void SetMultipleInstObjectsTransform(const std::vector& instobjects, const std::vector& transforms); + virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); /** \brief Gets or creates the a task part of the scene diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 86191df9..62f80634 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -87,18 +87,26 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t return task; } -void SceneResource::SetMultipleInstObjectsTransform(const std::vector& instobjects, const std::vector& transforms) +void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) { GETCONTROLLERIMPL(); - if (instobjects.size() != transforms.size()) { - throw MUJIN_EXCEPTION_FORMAT("the size of instobjects (%d) and the one of transforms (%d) must be the same",instobjects.size()%transforms.size(),MEC_InvalidArguments); - } + MUJIN_ASSERT_OP_FORMAT(instobjects.size(), !=, states.size(), "the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); boost::property_tree::ptree pt; - boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}"); - std::string datastring = ""; - + boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); + std::string datastring, sdofvalues; for(size_t i = 0 ; i < instobjects.size(); ++i) { - datastring += str(transformtemplate%instobjects[i]->pk%transforms[i].quaternion[0]%transforms[i].quaternion[1]%transforms[i].quaternion[2]%transforms[i].quaternion[3]%transforms[i].translate[0]%transforms[i].translate[1]%transforms[i].translate[2]); + const Transform& transform = states[i].transform; + if( states[i].dofvalues.size() > 0 ) { + sdofvalues = str(boost::format(", \"dofvalues\":[%.15f")%states[i].dofvalues.at(0)); + for(size_t j = 1; j < states[i].dofvalues.size(); ++j) { + sdofvalues += str(boost::format(", %.15f")%states[i].dofvalues.at(j)); + } + sdofvalues += "]"; + } + else { + sdofvalues = ""; + } + datastring += str(transformtemplate%instobjects[i]->pk%transform.quaternion[0]%transform.quaternion[1]%transform.quaternion[2]%transform.quaternion[3]%transform.translate[0]%transform.translate[1]%transform.translate[2]%sdofvalues); if ( i != instobjects.size()-1) { datastring += ","; } From 1deb85ef9e2cc2dde398eed8a74136e63a0bc42c Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 6 Sep 2013 11:43:13 +0900 Subject: [PATCH 079/477] minor doc fixes --- include/mujincontrollerclient/mujincontrollerclient.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ef3620c3..7d5cfbb3 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -288,7 +288,7 @@ class MUJINCLIENT_API ControllerClient // - mujincollada // - wincaps // - rttoolbox -// - cecvirfitxml +// - cecrobodiaxml // - stl // - x // - vrml @@ -348,7 +348,7 @@ class MUJINCLIENT_API ControllerClient - **x** (DirectX) - **vrml** - **stl** - - **cecvirfitxml** (CEC Virfit XML environments) + - **cecrobodiaxml** (CEC RoboDiA XML environments) */ virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) = 0; @@ -379,7 +379,7 @@ class MUJINCLIENT_API ControllerClient - **x** (DirectX) - **vrml** - **stl** - - **cecvirfitxml** (CEC Virfit XML environments) + - **cecrobodiaxml** (CEC RoboDiA XML environments) \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae */ virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; @@ -577,7 +577,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~InstObject() { } - void SetTransform(const Transform& t); + void SetTransform(const Transform& t); std::vector dofvalues; std::string name; @@ -725,7 +725,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource - mujinxml - \b xml - melfabasicv - \b json with Mitsubishi-specific programs - densowaverc8pac - \b json with DensoWave-specific programs - - cecvirfitsim - zip file + - cecrobodiasim - zip file If \b auto is set, then the robot-maker specific program is returned if possible. If not possible, then mujin xml is returned. All the programs for all robots planned are returned. From 17d7ebc2f343ec99697d4edadab8b229bba72a13 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Mon, 16 Sep 2013 19:27:21 +0900 Subject: [PATCH 080/477] fix target processor for windows cross compilation --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 62f80634..cb8f1c1a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -90,7 +90,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) { GETCONTROLLERIMPL(); - MUJIN_ASSERT_OP_FORMAT(instobjects.size(), !=, states.size(), "the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); + MUJIN_ASSERT_OP_FORMAT(instobjects.size(), ==, states.size(), "the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); boost::property_tree::ptree pt; boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); std::string datastring, sdofvalues; From 55fa399e04dc50d0add14c4e966f3265e6722c3e Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 19 Sep 2013 16:47:25 +0900 Subject: [PATCH 081/477] fix GetAllRawProgramData --- src/mujincontrollerclient.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index cb8f1c1a..f44bbe55 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -52,10 +52,10 @@ SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std: void SceneResource::InstObject::SetTransform(const Transform& t) { - GETCONTROLLERIMPL(); + GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); + std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) @@ -89,12 +89,12 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) { - GETCONTROLLERIMPL(); + GETCONTROLLERIMPL(); MUJIN_ASSERT_OP_FORMAT(instobjects.size(), ==, states.size(), "the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); boost::property_tree::ptree pt; boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); std::string datastring, sdofvalues; - for(size_t i = 0 ; i < instobjects.size(); ++i) { + for(size_t i = 0; i < instobjects.size(); ++i) { const Transform& transform = states[i].transform; if( states[i].dofvalues.size() > 0 ) { sdofvalues = str(boost::format(", \"dofvalues\":[%.15f")%states[i].dofvalues.at(0)); @@ -107,12 +107,12 @@ void SceneResource::SetInstObjectsState(const std::vectorpk%transform.quaternion[0]%transform.quaternion[1]%transform.quaternion[2]%transform.quaternion[3]%transform.translate[0]%transform.translate[1]%transform.translate[2]%sdofvalues); - if ( i != instobjects.size()-1) { - datastring += ","; - } - } - std::string data = str(boost::format("{\"objects\": [%s]}")%datastring); - controller->CallPut(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); + if ( i != instobjects.size()-1) { + datastring += ","; + } + } + std::string data = str(boost::format("{\"objects\": [%s]}")%datastring); + controller->CallPut(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname) @@ -171,7 +171,7 @@ void SceneResource::GetInstObjects(std::vector& in InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); //instobject->dofvalues instobject->name = v.second.get("name"); - instobject->pk = v.second.get("pk"); + instobject->pk = v.second.get("pk"); instobject->object_pk = v.second.get("object_pk"); instobject->reference_uri = v.second.get("reference_uri"); @@ -458,13 +458,13 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) { GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), outputdata); + controller->CallGet(str(boost::format("%s/%s/program/?type=%s")%GetResourceName()%GetPrimaryKey()%programtype), outputdata); } void PlanningResultResource::GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype) { GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/%s/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%robotpk%programtype), outputdata); + controller->CallGet(str(boost::format("%s/%s/program/%s/?type=%s")%GetResourceName()%GetPrimaryKey()%robotpk%programtype), outputdata); } void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, const std::string& programtype) From 43aef01e5befa7403cd0f1bd7cf9427a86f2121e Mon Sep 17 00:00:00 2001 From: ompugao Date: Tue, 1 Oct 2013 21:39:25 +0900 Subject: [PATCH 082/477] fix memory access violation bug. it occurs when built with Release configuration --- src/controllerclientimpl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e4bc8931..7554f8fe 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -116,7 +116,8 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) { - size_t usernameindex = usernamepassword.find_first_of(':'); + size_t usernameindex = 0; + usernameindex = usernamepassword.find_first_of(':'); BOOST_ASSERT(usernameindex != std::string::npos ); std::string username = usernamepassword.substr(0,usernameindex); std::string password = usernamepassword.substr(usernameindex+1); From 28d139ba0c12c0353e2aa9feb98ae8ccd28a0caf Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 2 Oct 2013 12:28:42 +0900 Subject: [PATCH 083/477] minor fix for displaying filenames --- .../mujincontrollerclient/mujincontrollerclient.h | 12 +++++++++--- src/mujincontrollerclient.cpp | 11 +++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 357e5a5b..1351ee6f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -581,7 +581,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector dofvalues; std::string name; - std::string pk; + std::string pk; std::string object_pk; std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] @@ -592,8 +592,8 @@ class MUJINCLIENT_API SceneResource : public WebResource SceneResource(ControllerClientPtr controller, const std::string& pk); virtual ~SceneResource() { } - - virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); + + virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); /** \brief Gets or creates the a task part of the scene @@ -649,6 +649,9 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \return true if task was executed fine virtual bool Execute(); + /// \brief if the task is currently executing, send a cancel request + virtual void Cancel(); + /// \brief get the run-time status of the executed task. /// /// This will only work if the task has been previously Executed with execute @@ -691,6 +694,9 @@ class MUJINCLIENT_API OptimizationResource : public WebResource /// \param bClearOldResults if true, will clear the old optimiation results. If false, will keep the old optimization results and only compute those that need to be computed. virtual void Execute(bool bClearOldResults=true); + /// \brief if the optimization is currently executing, send a cancel request + virtual void Cancel(); + /// \brief Set new task info for tasks of type robotplanning void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f44bbe55..0183cc15 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -221,6 +221,12 @@ bool TaskResource::Execute() return true; } +void TaskResource::Cancel() +{ + // have to look through all jobs for the task + BOOST_ASSERT(0); +} + void TaskResource::GetRunTimeStatus(JobStatus& status, int options) { status.code = JSC_Unknown; @@ -369,6 +375,11 @@ void OptimizationResource::Execute(bool bClearOldResults) _jobpk = pt.get("jobpk"); } +void OptimizationResource::Cancel() +{ + BOOST_ASSERT(0); +} + void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) { status.code = JSC_Unknown; From 709d09698e05d60b5cfa251cbc7fb55708436588 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 2 Oct 2013 12:28:42 +0900 Subject: [PATCH 084/477] minor fix for displaying filenames --- src/controllerclientimpl.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e4bc8931..1fe18cf1 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1250,8 +1250,10 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir_utf8); // remove the fileseparator if it exists + bool bhasseparator = false; if( sCopyDir_FS.size() > 0 && sCopyDir_FS.at(sCopyDir_FS.size()-1) == s_filesep ) { sCopyDir_FS.resize(sCopyDir_FS.size()-1); + bhasseparator = true; } std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; @@ -1267,7 +1269,13 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& std::string filename = std::string(ffd.cFileName); if( filename != "." && filename != ".." ) { std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir_utf8 = str(boost::format("%s\\%s")%copydir_utf8%filename_utf8); + std::string newcopydir_utf8; + if( bhasseparator ) { + newcopydir_utf8 = copydir_utf8 + filename_utf8; + } + else { + newcopydir_utf8 = str(boost::format("%s%c%s")%copydir_utf8%s_filesep%filename_utf8); + } char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); curl_free(pescapeddir); From e8c2bde541958a37ff0961de6a05c965df55656f Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 3 Oct 2013 14:02:02 +0900 Subject: [PATCH 085/477] add placements optimization type --- .../mujincontrollerclient.h | 52 +++++++++++++++++-- src/mujincontrollerclient.cpp | 20 ++++++- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1351ee6f..465a95fb 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -50,6 +50,7 @@ #include #include #include +#include namespace mujinclient { @@ -229,28 +230,64 @@ class DensoWaveWincapsTaskParameters : public ITLPlanningTaskParameters int preservespeedparameters; ///< if 1, preserves all SPEED/ACCEL commands as best as possible. }; +/// \brief placement optimization for a robot or another target. struct RobotPlacementOptimizationParameters { RobotPlacementOptimizationParameters() { SetDefaults(); } inline void SetDefaults() { + unit = "mm"; topstorecandidates = 20; targetname.clear(); - framename = "0 robot"; - unit = "mm"; + framename.clear(); minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; ignorebasecollision = 0; } - std::string targetname; ///< the primary key of the target object to optimize for. If blank, will use robot. - std::string framename; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + std::string targetname; ///< the name of the target object to optimize for. If blank, will use robot. + std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. Has to be prefixed with "0 "! Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) int ignorebasecollision; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. + + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. +}; + +struct PlacementsOptimizationParameters +{ + PlacementsOptimizationParameters() { + SetDefaults(); + } + inline void SetDefaults() { + unit = "mm"; + topstorecandidates = 20; + for(size_t itarget = 0; itarget < targetnames.size(); ++itarget) { + targetnames[itarget].clear(); + framenames[itarget].clear(); + ignorebasecollisions[itarget] = 0; + } + minranges[0][0] = -400; minranges[0][1] = -400; minranges[0][2] = 0; minranges[0][3] = -180; + maxranges[0][0] = 400; maxranges[0][1] = 400; maxranges[0][2] = 400; maxranges[0][3] = 90; + stepsizes[0][0] = 100; stepsizes[0][1] = 100; stepsizes[0][2] = 100; stepsizes[0][3] = 90; + minranges[1][0] = -100; minranges[1][1] = -100; minranges[1][2] = 0; minranges[1][3] = 0; + maxranges[1][0] = 100; maxranges[1][1] = 100; maxranges[1][2] = 100; maxranges[1][3] = 0; + stepsizes[1][0] = 100; stepsizes[1][1] = 100; stepsizes[1][2] = 100; stepsizes[1][3] = 90; + } + + // for every target, there's one setting: + boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. + boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. + boost::array maxranges; ///< X, Y, Z, Angle (deg) + boost::array minranges; ///< X, Y, Z, Angle (deg) + boost::array stepsizes; ///< X, Y, Z, Angle (deg) + boost::array ignorebasecollisions; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. + + // shared settings + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; @@ -662,8 +699,10 @@ class MUJINCLIENT_API TaskResource : public WebResource /// \brief Gets or creates the a optimization part of the scene /// /// \param optimizationname the name of the optimization to search for or create + /// \param optimizaitontype The type of optimization, can be "robotplacement" or "placements" virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); + /// \brief \see GetOrCreateOptimizationFromName_UTF8 virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); /// \brief gets a list of all the scene primary keys currently available to the user @@ -700,6 +739,9 @@ class MUJINCLIENT_API OptimizationResource : public WebResource /// \brief Set new task info for tasks of type robotplanning void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); + /// \brief Set new task info for tasks of type placements + void SetOptimizationParameters(const PlacementsOptimizationParameters& optparams); + /// \brief get the run-time status of the executed optimization. /// /// This will only work if the optimization has been previously Executed with execute diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 0183cc15..03f83e91 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -406,11 +406,29 @@ void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimiz { GETCONTROLLERIMPL(); std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationtype\": \"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); + std::string optimizationgoalput = str(boost::format("{\"optimizationtype\":\"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } +void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizationParameters& optparams) +{ + GETCONTROLLERIMPL(); + std::stringstream optimizationgoalput; + optimizationgoalput << str(boost::format("{\"optimizationtype\":\"placements\", \"optimizationparameters\":{ \"unit\":\"%s\", \"topstorecandidates\":%d")%optparams.unit%optparams.topstorecandidates); + for(size_t itarget = 0; itarget < optparams.targetnames.size(); ++itarget) { + std::string ignorebasecollision = optparams.ignorebasecollisions[itarget] ? "True" : "False"; + std::string suffix; + if( itarget > 0 ) { + suffix = boost::lexical_cast(itarget+1); + } + optimizationgoalput << str(boost::format(", \"targetname%s\":\"%s\", \"frame%s\":\"%s\", \"ignorebasecollision%s\":\"%s\", , \"maxrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize%s_\":[ %.15f, %.15f, %.15f, %.15f]")%suffix%optparams.targetnames[itarget]%suffix%optparams.framenames[itarget]%suffix%ignorebasecollision%suffix%optparams.maxranges[itarget][0]%optparams.maxranges[itarget][1]%optparams.maxranges[itarget][2]%optparams.maxranges[itarget][3]%suffix%optparams.minranges[itarget][0]%optparams.minranges[itarget][1]%optparams.minranges[itarget][2]%optparams.minranges[itarget][3]%suffix%optparams.stepsizes[itarget][0]%optparams.stepsizes[itarget][1]%optparams.stepsizes[itarget][2]%optparams.stepsizes[itarget][3]); + } + optimizationgoalput << "} }"; + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); +} + void OptimizationResource::GetResults(std::vector& results, int startoffset, int num) { GETCONTROLLERIMPL(); From a8e78276c67008c9c5c68fa83442536051bcf9ae Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 3 Oct 2013 15:50:01 +0900 Subject: [PATCH 086/477] fix minranges --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 465a95fb..1a7baa08 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -282,7 +282,7 @@ struct PlacementsOptimizationParameters boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. boost::array maxranges; ///< X, Y, Z, Angle (deg) - boost::array minranges; ///< X, Y, Z, Angle (deg) + boost::array minranges; ///< X, Y, Z, Angle (deg) boost::array stepsizes; ///< X, Y, Z, Angle (deg) boost::array ignorebasecollisions; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. From 5f98267d329e1789661fe5e001725cef20455ac1 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 3 Oct 2013 16:49:53 +0900 Subject: [PATCH 087/477] update comments on optimization params --- include/mujincontrollerclient/mujincontrollerclient.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1a7baa08..1c512ae9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -246,8 +246,8 @@ struct RobotPlacementOptimizationParameters stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; ignorebasecollision = 0; } - std::string targetname; ///< the name of the target object to optimize for. If blank, will use robot. - std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. Has to be prefixed with "0 "! + std::string targetname; ///< the name of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. + std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) @@ -279,8 +279,8 @@ struct PlacementsOptimizationParameters } // for every target, there's one setting: - boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. - boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. + boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. + boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. boost::array maxranges; ///< X, Y, Z, Angle (deg) boost::array minranges; ///< X, Y, Z, Angle (deg) boost::array stepsizes; ///< X, Y, Z, Angle (deg) From e7b37e9a87403b805fd066532e436a4cbbd3d436 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 8 Oct 2013 19:53:50 +0900 Subject: [PATCH 088/477] check if the scene exists or not --- src/mujincontrollerclient.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 03f83e91..5251d003 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -58,8 +58,12 @@ void SceneResource::InstObject::SetTransform(const Transform& t) controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } -SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) +SceneResource::SceneResource(ControllerClientPtr controllerptr, const std::string& pk) : WebResource(controllerptr, "scene", pk) { + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + // check the existance of the scene + controller->CallGet(str(boost::format("scene/%s/?format=json&limit=0&fields=uri")%pk), pt); } TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) From 9611c6c206d93b8e09c9d86bbb7e5b6f61887d8b Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 8 Oct 2013 22:31:07 +0900 Subject: [PATCH 089/477] simplify --- src/mujincontrollerclient.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5251d003..903efddb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -60,10 +60,7 @@ void SceneResource::InstObject::SetTransform(const Transform& t) SceneResource::SceneResource(ControllerClientPtr controllerptr, const std::string& pk) : WebResource(controllerptr, "scene", pk) { - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - // check the existance of the scene - controller->CallGet(str(boost::format("scene/%s/?format=json&limit=0&fields=uri")%pk), pt); + this->Get(""); } TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) From 6f3185de5665673dec419a8833fbfc9858bf8a56 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 12 Oct 2013 01:47:47 +0900 Subject: [PATCH 090/477] implement binpickingtask. NOT TESTED --- .../mujincontrollerclient.h | 114 +++++++++++++ src/mujincontrollerclient.cpp | 156 +++++++++++++++++- 2 files changed, 267 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1c512ae9..37164914 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -121,6 +121,7 @@ class MUJINCLIENT_API MujinException : public std::exception class ControllerClient; class SceneResource; class TaskResource; +class BinPickingTaskResource; class OptimizationResource; class PlanningResultResource; @@ -130,6 +131,8 @@ typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; +typedef boost::shared_ptr BinPickingTaskResourcePtr; +typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; typedef boost::shared_ptr OptimizationResourcePtr; typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; @@ -291,6 +294,63 @@ struct PlacementsOptimizationParameters int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; +/// \brief holds information about the binpicking task parameters +class BinPickingTaskParameters +{ +public: + BinPickingTaskParameters() { + SetDefaults(); + } + virtual void SetDefaults() { + command = "GetJointValues"; + robottype = "densowave"; + controllerip = "controller.mujin.co.jp"; + controllerport = 5007; + envclearance = 0; + speed = 1; + } + + std::string _GenerateJsonString (const std::vector& vec) const + { + std::stringstream ss; + ss << std::setprecision(std::numeric_limits::digits10+1); + if( vec.size() > 0 ) { + ss << "["; + for (unsigned int i = 0; i < vec.size(); i++) { + ss << vec[i]; + if( i != vec.size()-1) { + ss << ", "; + } + } + ss << "]"; + } + return ss.str(); + } + std::string _GenerateJsonString (const std::vector& vec) const + { + std::stringstream ss; + if( vec.size() > 0 ) { + ss << "["; + for (unsigned int i = 0; i < vec.size(); i++) { + ss << vec[i]; + if( i != vec.size()-1) { + ss << ", "; + } + } + ss << "]"; + } + return ss.str(); + } + std::string command; ///< command to call + std::string robottype; ///< the type of robot + std::string controllerip; ///< the ip of the computer on which the robot controller runs + int controllerport; ///< the port of the computer on which the robot controller runs + std::vector goaljoints; ///< the joint values of goal point + std::vector jointindices; + double envclearance; + double speed; +}; + /// \brief program data for an individual robot class RobotProgramData { @@ -721,6 +781,60 @@ class MUJINCLIENT_API TaskResource : public WebResource std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called }; +class MUJINCLIENT_API BinPickingTaskResource : public TaskResource +{ +public: + BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, + ControllerClientPtr controller, const std::string& pk); + virtual ~BinPickingTaskResource() { + } + + class MUJINCLIENT_API BinPickingResultResource : public WebResource + { + public: + BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task", pk+"/result/") + { + } + virtual ~BinPickingResultResource() { + } + class ResultGetJointValues + { + public: + std::string robottype; + std::vector jointnames; + std::vector currentjointvalues; + std::map > tools; + }; + + class ResultMoveJoints + { + public: + std::string robot; + std::vector goaljoints; + std::vector jointindices; + int envclearance; + }; + + void GetResultGetJointValues(ResultGetJointValues& result); + void GetResultMoveJoints(ResultMoveJoints& result); + }; + typedef boost::shared_ptr BinPickingResultResourcePtr; + + virtual int GetResult(BinPickingResultResourcePtr& result); + virtual void GetJointValues(int timeout /* [sec] */, BinPickingResultResource::ResultGetJointValues& result); + virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); + + /// \brief Get the task info for tasks of type binpicking + virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); + + /// \brief Set the task info for tasks of type binpicking + virtual void SetTaskParameters(const BinPickingTaskParameters& taskparameters); +private: + std::string _controllerip; + int _controllerport; + std::string _taskname; +}; + class MUJINCLIENT_API OptimizationResource : public WebResource { public: diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 903efddb..967a0ab1 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "common.h" #include "controllerclientimpl.h" +#include // for sleep namespace mujinclient { @@ -58,9 +59,8 @@ void SceneResource::InstObject::SetTransform(const Transform& t) controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } -SceneResource::SceneResource(ControllerClientPtr controllerptr, const std::string& pk) : WebResource(controllerptr, "scene", pk) +SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { - this->Get(""); } TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) @@ -193,7 +193,6 @@ void SceneResource::GetInstObjects(std::vector& in BOOST_ASSERT( itranslate < 3 ); instobject->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); } - instobjects[i++] = instobject; } } @@ -364,6 +363,157 @@ PlanningResultResourcePtr TaskResource::GetResult() return result; } +void BinPickingTaskResource::BinPickingResultResource::GetResultGetJointValues(ResultGetJointValues& result) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(boost::str(boost::format("%s/%s/?format=json&limit=1")%GetResourceName()%GetPrimaryKey()), pt); + + result.robottype = pt.get("robottype"); + + boost::property_tree::ptree& jointnames = pt.get_child("jointnames"); + result.currentjointvalues.resize(jointnames.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, jointnames) { + result.jointnames[i++] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& currentjointvalues = pt.get_child("currentjointvalues"); + result.currentjointvalues.resize(currentjointvalues.size()); + i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, currentjointvalues) { + result.currentjointvalues[i++] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& tools = pt.get_child("tools"); + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, tools) { + std::string first = v.first; + BOOST_FOREACH(boost::property_tree::ptree::value_type &x, v.second) { + result.tools[first].push_back(boost::lexical_cast(x.second.data())); + } + } +} + +void BinPickingTaskResource::BinPickingResultResource::GetResultMoveJoints(ResultMoveJoints& result) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(boost::str(boost::format("%s/%s/?format=json&limit=1")%GetResourceName()%GetPrimaryKey()), pt); + + result.robot = pt.get("robot"); + + boost::property_tree::ptree& goaljoints = pt.get_child("goaljoints"); + result.goaljoints.resize(goaljoints.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, goaljoints) { + result.goaljoints[i++] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& jointindices = pt.get_child("jointindices"); + result.jointindices.resize(jointindices.size()); + i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, jointindices) { + result.jointindices[i++] = boost::lexical_cast(v.second.data()); + } + + result.envclearance = boost::lexical_cast(pt.get("envclearance")); +} + +BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, const std::string& pk) : TaskResource(controller,pk) +{ + _taskname = taskname; + _controllerip = controllerip; + _controllerport = controllerport; +} + +void BinPickingTaskResource::GetJointValues(int timeout, BinPickingResultResource::ResultGetJointValues& result) +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + + param.command = "GetJointValues"; + param.controllerip = _controllerip; + param.controllerport = _controllerport; + param.robottype = "densowave"; + this->SetTaskParameters(param); + this->Execute(); + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultGetJointValues(result); + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > timeout ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} + +void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout, BinPickingResultResource::ResultMoveJoints& result) +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + + param.command = "MoveJoints"; + param.controllerip = _controllerip; + param.controllerport = _controllerport; + param.robottype = "densowave"; + param.goaljoints = jointvalues; + param.jointindices = jointindices; + param.envclearance = 30; + param.speed = 10; + this->SetTaskParameters(param); + this->Execute(); + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultMoveJoints(result); + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > timeout ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} + +void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) +{ + throw MujinException("not implemented yet"); +} + +void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& taskparameters) +{ + GETCONTROLLERIMPL(); + + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":%s, \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); +} + +int BinPickingTaskResource::GetResult(BinPickingResultResourcePtr& result) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); + if( objects.size() == 0 ) { + return 0; + } + std::string pk = objects.begin()->second.get("pk"); + result.reset(new BinPickingResultResource(GetController(), pk)); + return objects.size(); +} + OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) { } From 0b4512db11f2de8a761cc6f41467b1ec82d67fb6 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 12 Oct 2013 19:39:32 +0900 Subject: [PATCH 091/477] getjointvalues/movejoints now works --- .../mujincontrollerclient.h | 23 ++-- src/mujincontrollerclient.cpp | 113 +++++++++++------- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 37164914..01fc2fa9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -314,31 +314,31 @@ class BinPickingTaskParameters { std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - if( vec.size() > 0 ) { - ss << "["; + ss << "["; + if( vec.size() > 0 ) { for (unsigned int i = 0; i < vec.size(); i++) { ss << vec[i]; if( i != vec.size()-1) { ss << ", "; } } - ss << "]"; } + ss << "]"; return ss.str(); } std::string _GenerateJsonString (const std::vector& vec) const { std::stringstream ss; + ss << "["; if( vec.size() > 0 ) { - ss << "["; for (unsigned int i = 0; i < vec.size(); i++) { ss << vec[i]; if( i != vec.size()-1) { ss << ", "; } } - ss << "]"; } + ss << "]"; return ss.str(); } std::string command; ///< command to call @@ -785,14 +785,14 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource { public: BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, - ControllerClientPtr controller, const std::string& pk); + ControllerClientPtr controller, SceneResourcePtr scene); virtual ~BinPickingTaskResource() { } class MUJINCLIENT_API BinPickingResultResource : public WebResource { public: - BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task", pk+"/result/") + BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task", pk) { } virtual ~BinPickingResultResource() { @@ -809,10 +809,10 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource class ResultMoveJoints { public: - std::string robot; - std::vector goaljoints; - std::vector jointindices; - int envclearance; + std::string robottype; + int numpoints; + std::vector timedjointvalues; + //double elapsedtime; }; void GetResultGetJointValues(ResultGetJointValues& result); @@ -830,6 +830,7 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource /// \brief Set the task info for tasks of type binpicking virtual void SetTaskParameters(const BinPickingTaskParameters& taskparameters); private: + std::string _GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname); std::string _controllerip; int _controllerport; std::string _taskname; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 967a0ab1..e4923a61 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -367,29 +367,35 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultGetJointValues(R { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("%s/%s/?format=json&limit=1")%GetResourceName()%GetPrimaryKey()), pt); - - result.robottype = pt.get("robottype"); - - boost::property_tree::ptree& jointnames = pt.get_child("jointnames"); - result.currentjointvalues.resize(jointnames.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, jointnames) { - result.jointnames[i++] = boost::lexical_cast(v.second.data()); - } - - boost::property_tree::ptree& currentjointvalues = pt.get_child("currentjointvalues"); - result.currentjointvalues.resize(currentjointvalues.size()); - i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, currentjointvalues) { - result.currentjointvalues[i++] = boost::lexical_cast(v.second.data()); - } - - boost::property_tree::ptree& tools = pt.get_child("tools"); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, tools) { - std::string first = v.first; - BOOST_FOREACH(boost::property_tree::ptree::value_type &x, v.second) { - result.tools[first].push_back(boost::lexical_cast(x.second.data())); + controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); + BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { + boost::property_tree::ptree& output = obj.second.get_child("output"); + BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { + if( value.first == "robottype") { + result.robottype = value.second.data(); + } + else if (value.first == "jointnames") { + result.jointnames.resize(value.second.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + result.jointnames[i++] = boost::lexical_cast(v.second.data()); + } + } + else if (value.first == "currentjointvalues" ) { + result.currentjointvalues.resize(value.second.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + result.currentjointvalues[i++] = boost::lexical_cast(v.second.data()); + } + } + else if (value.first == "tools") { + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + std::string first = v.first; + BOOST_FOREACH(boost::property_tree::ptree::value_type &x, v.second) { + result.tools[first].push_back(boost::lexical_cast(x.second.data())); + } + } + } } } } @@ -398,34 +404,49 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultMoveJoints(Resul { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("%s/%s/?format=json&limit=1")%GetResourceName()%GetPrimaryKey()), pt); - - result.robot = pt.get("robot"); - - boost::property_tree::ptree& goaljoints = pt.get_child("goaljoints"); - result.goaljoints.resize(goaljoints.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, goaljoints) { - result.goaljoints[i++] = boost::lexical_cast(v.second.data()); - } - - boost::property_tree::ptree& jointindices = pt.get_child("jointindices"); - result.jointindices.resize(jointindices.size()); - i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, jointindices) { - result.jointindices[i++] = boost::lexical_cast(v.second.data()); - } + controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); + BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { + boost::property_tree::ptree& output = obj.second.get_child("output"); + BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { + if (value.first == "robottype" ) { + result.robottype = value.second.data(); + } + else if (value.first == "timedjointvalues") { + result.timedjointvalues.resize(value.second.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + result.timedjointvalues[i++] = boost::lexical_cast(v.second.data()); + } + } + else if (value.first == "numpoints" ) { + result.numpoints = boost::lexical_cast(value.second.data()); + } + /* + else if (value.first == "elapsedtime" ) { + //TODO lexical_cast doesn't work with such kind of string: "4.99999999999998e-06" + result.elapsedtime = boost::lexical_cast(value.second.data()); + } + */ + } + } - result.envclearance = boost::lexical_cast(pt.get("envclearance")); + } -BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, const std::string& pk) : TaskResource(controller,pk) +BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene) : TaskResource(controller,_GetOrCreateTaskAndGetPk(scene, taskname)) { _taskname = taskname; _controllerip = controllerip; _controllerport = controllerport; } +std::string BinPickingTaskResource::_GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname) +{ + TaskResourcePtr task = scene->GetOrCreateTaskFromName_UTF8(taskname,"binpicking"); + std::string pk = task->Get("pk"); + return pk; +} + void BinPickingTaskResource::GetJointValues(int timeout, BinPickingResultResource::ResultGetJointValues& result) { GETCONTROLLERIMPL(); @@ -495,9 +516,9 @@ void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& t { GETCONTROLLERIMPL(); - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":%s, \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed); + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed); boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); + controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); } int BinPickingTaskResource::GetResult(BinPickingResultResourcePtr& result) @@ -509,8 +530,8 @@ int BinPickingTaskResource::GetResult(BinPickingResultResourcePtr& result) if( objects.size() == 0 ) { return 0; } - std::string pk = objects.begin()->second.get("pk"); - result.reset(new BinPickingResultResource(GetController(), pk)); + //std::string pk = objects.begin()->second.get("pk"); + result.reset(new BinPickingResultResource(GetController(), GetPrimaryKey())); return objects.size(); } From 16ff8b14ca8ea5588b17f94942af4be230d4cfac Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 16 Oct 2013 21:44:33 +0900 Subject: [PATCH 092/477] add SetTrasnform/GetTransform api --- .../mujincontrollerclient.h | 6 ++ src/mujincontrollerclient.cpp | 85 ++++++++++++++++++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 01fc2fa9..202fe86f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -308,6 +308,7 @@ class BinPickingTaskParameters controllerport = 5007; envclearance = 0; speed = 1; + targetname = ""; } std::string _GenerateJsonString (const std::vector& vec) const @@ -349,6 +350,8 @@ class BinPickingTaskParameters std::vector jointindices; double envclearance; double speed; + std::string targetname; + Transform transform; }; /// \brief program data for an individual robot @@ -817,12 +820,15 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource void GetResultGetJointValues(ResultGetJointValues& result); void GetResultMoveJoints(ResultMoveJoints& result); + void GetResultTransform(Transform& transform); }; typedef boost::shared_ptr BinPickingResultResourcePtr; virtual int GetResult(BinPickingResultResourcePtr& result); virtual void GetJointValues(int timeout /* [sec] */, BinPickingResultResource::ResultGetJointValues& result); virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); + virtual Transform GetTransform(const std::string& targetname); + virtual void SetTransform(const std::string& targetname, const Transform& transform); /// \brief Get the task info for tasks of type binpicking virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index e4923a61..adf0109a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -428,11 +428,37 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultMoveJoints(Resul } */ } + } +} +void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transform& transform) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); + BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { + boost::property_tree::ptree& output = obj.second.get_child("output"); + BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { + if( value.first == "translation") { + size_t i = 0; + if ( value.second.size() != 3 ) { + throw MujinException("the length of translation is invalid", MEC_Timeout); + } + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + transform.translate[i++] = boost::lexical_cast(v.second.data()); + } + } + else if (value.first == "quaternion") { + size_t i = 0; + if ( value.second.size() != 4 ) { + throw MujinException("the length of quaternion is invalid", MEC_Timeout); + } + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { + transform.quaternion[i++] = boost::lexical_cast(v.second.data()); + } + } + } } - - } - BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene) : TaskResource(controller,_GetOrCreateTaskAndGetPk(scene, taskname)) { _taskname = taskname; @@ -506,6 +532,57 @@ void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, } } } +Transform BinPickingTaskResource::GetTransform(const std::string& targetname) +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + + Transform transform; + param.command = "GetTransform"; + param.targetname = targetname; + this->SetTaskParameters(param); + this->Execute(); + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultTransform(transform); + return transform; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} +void BinPickingTaskResource::SetTransform(const std::string& targetname, const Transform& transform) +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + + param.command = "SetTransform"; + param.targetname = targetname; + param.transform = transform; + this->SetTaskParameters(param); + this->Execute(); + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) + { + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) { @@ -516,7 +593,7 @@ void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& t { GETCONTROLLERIMPL(); - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed); + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f]} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); } From a69067bce4085341c045f87cc0d0a07428fa0c28 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 17 Oct 2013 23:55:16 +0900 Subject: [PATCH 093/477] bugfix and add new api --- .../mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 202fe86f..a7b9ad91 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -829,7 +829,7 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); virtual Transform GetTransform(const std::string& targetname); virtual void SetTransform(const std::string& targetname, const Transform& transform); - + virtual Transform GetManipTransformToRobot(); /// \brief Get the task info for tasks of type binpicking virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index adf0109a..c37fabab 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -540,6 +540,8 @@ Transform BinPickingTaskResource::GetTransform(const std::string& targetname) Transform transform; param.command = "GetTransform"; + param.controllerip = _controllerip; + param.controllerport = _controllerport; param.targetname = targetname; this->SetTaskParameters(param); this->Execute(); @@ -566,6 +568,8 @@ void BinPickingTaskResource::SetTransform(const std::string& targetname, const T param.command = "SetTransform"; param.targetname = targetname; + param.controllerip = _controllerip; + param.controllerport = _controllerport; param.transform = transform; this->SetTaskParameters(param); this->Execute(); @@ -584,6 +588,34 @@ void BinPickingTaskResource::SetTransform(const std::string& targetname, const T } } +Transform BinPickingTaskResource::GetManipTransformToRobot() +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + Transform transform; + + param.command = "GetManipTransformToRobot"; + param.controllerip = _controllerip; + param.controllerport = _controllerport; + this->SetTaskParameters(param); + this->Execute(); + + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultTransform(transform); + return transform; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) { throw MujinException("not implemented yet"); From d83c63b6b4df667f8ec3e256fbe6adb60acdb404 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Thu, 24 Oct 2013 00:02:16 +0900 Subject: [PATCH 094/477] add AddPointCloudObstacle function for binpicking task --- .../mujincontrollerclient.h | 101 +++----- src/mujincontrollerclient.cpp | 219 ++++++++++++------ 2 files changed, 185 insertions(+), 135 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a7b9ad91..81d3eb47 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -294,62 +294,27 @@ struct PlacementsOptimizationParameters int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; -/// \brief holds information about the binpicking task parameters -class BinPickingTaskParameters -{ -public: - BinPickingTaskParameters() { - SetDefaults(); - } - virtual void SetDefaults() { - command = "GetJointValues"; - robottype = "densowave"; - controllerip = "controller.mujin.co.jp"; - controllerport = 5007; - envclearance = 0; - speed = 1; - targetname = ""; - } +/// \brief holds information about the binpicking task parameters +class BinPickingTaskParameters +{ +public: + BinPickingTaskParameters() { + SetDefaults(); + } + + virtual void SetDefaults(); - std::string _GenerateJsonString (const std::vector& vec) const - { - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); - } - std::string _GenerateJsonString (const std::vector& vec) const - { - std::stringstream ss; - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); - } - std::string command; ///< command to call - std::string robottype; ///< the type of robot - std::string controllerip; ///< the ip of the computer on which the robot controller runs - int controllerport; ///< the port of the computer on which the robot controller runs - std::vector goaljoints; ///< the joint values of goal point - std::vector jointindices; - double envclearance; - double speed; + std::string GenerateJsonString (const std::vector& vec) const; + std::string GenerateJsonString (const std::vector& vec) const; + + std::string command; ///< command to call + std::string robottype; ///< the type of robot + std::string controllerip; ///< the ip of the computer on which the robot controller runs + int controllerport; ///< the port of the computer on which the robot controller runs + std::vector goaljoints; ///< the joint values of goal point + std::vector jointindices; + Real envclearance; + Real speed; std::string targetname; Transform transform; }; @@ -787,8 +752,8 @@ class MUJINCLIENT_API TaskResource : public WebResource class MUJINCLIENT_API BinPickingTaskResource : public TaskResource { public: - BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, - ControllerClientPtr controller, SceneResourcePtr scene); + BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene); + virtual ~BinPickingTaskResource() { } @@ -803,19 +768,19 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource class ResultGetJointValues { public: - std::string robottype; - std::vector jointnames; - std::vector currentjointvalues; - std::map > tools; + std::string robottype; + std::vector jointnames; + std::vector currentjointvalues; + std::map > tools; }; class ResultMoveJoints { public: - std::string robottype; - int numpoints; - std::vector timedjointvalues; - //double elapsedtime; + std::string robottype; + int numpoints; + std::vector timedjointvalues; + //Real elapsedtime; }; void GetResultGetJointValues(ResultGetJointValues& result); @@ -826,10 +791,14 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource virtual int GetResult(BinPickingResultResourcePtr& result); virtual void GetJointValues(int timeout /* [sec] */, BinPickingResultResource::ResultGetJointValues& result); - virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); + virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); virtual Transform GetTransform(const std::string& targetname); virtual void SetTransform(const std::string& targetname, const Transform& transform); virtual Transform GetManipTransformToRobot(); + + /// \brief Dynamically add a point cloud collision obstacle with name to the environment. + virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); + /// \brief Get the task info for tasks of type binpicking virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c37fabab..a3b0f2a8 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -242,7 +242,7 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) status.pk = pt.get("pk"); status.code = static_cast(boost::lexical_cast(pt.get("status"))); status.type = pt.get("fnname"); - status.elapsedtime = pt.get("elapsedtime"); + status.elapsedtime = pt.get("elapsedtime"); if( options & 1 ) { status.message = pt.get("status_text"); } @@ -363,6 +363,49 @@ PlanningResultResourcePtr TaskResource::GetResult() return result; } +void BinPickingTaskParameters::SetDefaults() +{ + command = "GetJointValues"; + robottype = "densowave"; + controllerip = ""; + controllerport = 0; + envclearance = 20; + speed = 0.5; + targetname = ""; +} + +std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const +{ + std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); + ss << "["; + if( vec.size() > 0 ) { + for (unsigned int i = 0; i < vec.size(); i++) { + ss << vec[i]; + if( i != vec.size()-1) { + ss << ", "; + } + } + } + ss << "]"; + return ss.str(); +} + +std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const +{ + std::stringstream ss; + ss << "["; + if( vec.size() > 0 ) { + for (unsigned int i = 0; i < vec.size(); i++) { + ss << vec[i]; + if( i != vec.size()-1) { + ss << ", "; + } + } + } + ss << "]"; + return ss.str(); +} + void BinPickingTaskResource::BinPickingResultResource::GetResultGetJointValues(ResultGetJointValues& result) { GETCONTROLLERIMPL(); @@ -440,7 +483,7 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transf BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { if( value.first == "translation") { size_t i = 0; - if ( value.second.size() != 3 ) { + if ( value.second.size() != 3 ) { throw MujinException("the length of translation is invalid", MEC_Timeout); } BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { @@ -448,8 +491,8 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transf } } else if (value.first == "quaternion") { - size_t i = 0; - if ( value.second.size() != 4 ) { + size_t i = 0; + if ( value.second.size() != 4 ) { throw MujinException("the length of quaternion is invalid", MEC_Timeout); } BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { @@ -459,6 +502,7 @@ void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transf } } } + BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene) : TaskResource(controller,_GetOrCreateTaskAndGetPk(scene, taskname)) { _taskname = taskname; @@ -486,22 +530,22 @@ void BinPickingTaskResource::GetJointValues(int timeout, BinPickingResultResourc this->SetTaskParameters(param); this->Execute(); int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultGetJointValues(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultGetJointValues(result); + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > timeout ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } } } -void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout, BinPickingResultResource::ResultMoveJoints& result) +void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout, BinPickingResultResource::ResultMoveJoints& result) { GETCONTROLLERIMPL(); BinPickingResultResourcePtr resultresource; @@ -513,25 +557,26 @@ void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, param.robottype = "densowave"; param.goaljoints = jointvalues; param.jointindices = jointindices; - param.envclearance = 30; - param.speed = 10; + param.envclearance = 20; + param.speed = 0.5; this->SetTaskParameters(param); this->Execute(); int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultMoveJoints(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultMoveJoints(result); + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > timeout ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } } } + Transform BinPickingTaskResource::GetTransform(const std::string& targetname) { GETCONTROLLERIMPL(); @@ -546,20 +591,21 @@ Transform BinPickingTaskResource::GetTransform(const std::string& targetname) this->SetTaskParameters(param); this->Execute(); int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultTransform(transform); + return transform; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } } } + void BinPickingTaskResource::SetTransform(const std::string& targetname, const Transform& transform) { GETCONTROLLERIMPL(); @@ -574,17 +620,17 @@ void BinPickingTaskResource::SetTransform(const std::string& targetname, const T this->SetTaskParameters(param); this->Execute(); int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } + while (1) { + if (this->GetResult(resultresource) != 0) + { + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } } } @@ -602,20 +648,55 @@ Transform BinPickingTaskResource::GetManipTransformToRobot() this->Execute(); int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } + while (1) { + if (this->GetResult(resultresource) != 0) + { + resultresource->GetResultTransform(transform); + return transform; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } } } + +void BinPickingTaskResource::AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name) +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + + std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); + + ss << boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"AddPointCloudObstacle\", \"pointsize\":%f, \"name\": \"%s\"")%pointsize%name); + if( vpoints.size() > 0 ) { + ss << ", \"points\":[" << vpoints.at(0); + for(size_t i = 1; i < vpoints.size(); ++i) { + ss << "," << vpoints[i]; + } + ss << "]"; + } + ss << "}}"; + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), ss.str(), pt); + + this->Execute(); + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) { + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); + ++iterations; + if( iterations > 10 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} + void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) { throw MujinException("not implemented yet"); @@ -623,9 +704,9 @@ void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskpar void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& taskparameters) { - GETCONTROLLERIMPL(); + GETCONTROLLERIMPL(); - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f]} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters._GenerateJsonString(taskparameters.goaljoints)%taskparameters._GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]); + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f]} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); } @@ -676,7 +757,7 @@ void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) status.pk = pt.get("pk"); status.code = static_cast(boost::lexical_cast(pt.get("status"))); status.type = pt.get("fnname"); - status.elapsedtime = pt.get("elapsedtime"); + status.elapsedtime = pt.get("elapsedtime"); if( options & 1 ) { status.message = pt.get("status_text"); } From fbf1e9835c583d7a5370388eaa943bf356d43372 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Fri, 25 Oct 2013 10:25:53 +0900 Subject: [PATCH 095/477] removed bad assert --- src/mujincontrollerclient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 903efddb..3be5251f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -60,7 +60,7 @@ void SceneResource::InstObject::SetTransform(const Transform& t) SceneResource::SceneResource(ControllerClientPtr controllerptr, const std::string& pk) : WebResource(controllerptr, "scene", pk) { - this->Get(""); + this->Get(""); } TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) @@ -478,7 +478,6 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) boost::property_tree::ptree& translationjson = objstatejson.second.get_child("translation_"); int itranslation=0; BOOST_FOREACH(boost::property_tree::ptree::value_type &v, translationjson) { - BOOST_ASSERT(iquat<3); objstate.transform.translate[itranslation++] = boost::lexical_cast(v.second.data()); } envstate[name] = objstate; From 2d5e68dd7881d4c495039e1788c12836ec79b1d2 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Sat, 26 Oct 2013 20:18:20 +0900 Subject: [PATCH 096/477] add an api to initialize zmq connection --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 81d3eb47..f861971d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -795,6 +795,7 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource virtual Transform GetTransform(const std::string& targetname); virtual void SetTransform(const std::string& targetname, const Transform& transform); virtual Transform GetManipTransformToRobot(); + virtual void InitializeZMQ(); /// \brief Dynamically add a point cloud collision obstacle with name to the environment. virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index a3b0f2a8..c617a3f0 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -663,6 +663,29 @@ Transform BinPickingTaskResource::GetManipTransformToRobot() } } +void BinPickingTaskResource::InitializeZMQ() +{ + GETCONTROLLERIMPL(); + BinPickingResultResourcePtr resultresource; + BinPickingTaskParameters param; + + param.command = "InitZMQ"; + this->SetTaskParameters(param); + this->Execute(); + + int iterations = 0; + while (1) { + if (this->GetResult(resultresource) != 0) { + return; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + ++iterations; + if( iterations > 20 ) { + controller->CancelAllJobs(); + throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); + } + } +} void BinPickingTaskResource::AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name) { GETCONTROLLERIMPL(); From e69d97f2bb1afd02787d4a3f9f126a31cfdcc64f Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Sat, 26 Oct 2013 21:08:23 +0900 Subject: [PATCH 097/477] fix a bug: give a parameter(port) to InitializeZMQ --- include/mujincontrollerclient/mujincontrollerclient.h | 3 ++- src/mujincontrollerclient.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f861971d..c5d6dcf1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -313,6 +313,7 @@ class BinPickingTaskParameters int controllerport; ///< the port of the computer on which the robot controller runs std::vector goaljoints; ///< the joint values of goal point std::vector jointindices; + int port; Real envclearance; Real speed; std::string targetname; @@ -795,7 +796,7 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource virtual Transform GetTransform(const std::string& targetname); virtual void SetTransform(const std::string& targetname, const Transform& transform); virtual Transform GetManipTransformToRobot(); - virtual void InitializeZMQ(); + virtual void InitializeZMQ(int zmqport); /// \brief Dynamically add a point cloud collision obstacle with name to the environment. virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c617a3f0..6ec21a23 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -663,13 +663,14 @@ Transform BinPickingTaskResource::GetManipTransformToRobot() } } -void BinPickingTaskResource::InitializeZMQ() +void BinPickingTaskResource::InitializeZMQ(int zmqport) { GETCONTROLLERIMPL(); BinPickingResultResourcePtr resultresource; BinPickingTaskParameters param; param.command = "InitZMQ"; + param.port = zmqport; this->SetTaskParameters(param); this->Execute(); @@ -729,7 +730,7 @@ void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& t { GETCONTROLLERIMPL(); - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f]} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]); + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f],\"port\": %d} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]%taskparameters.port); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); } From 2dfa4ed3abdcf0775724010446f24adf77006862 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Sat, 26 Oct 2013 21:08:23 +0900 Subject: [PATCH 098/477] fix a bug: give a parameter(port) to InitializeZMQ --- include/mujincontrollerclient/mujincontrollerclient.h | 3 ++- src/mujincontrollerclient.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f861971d..c5d6dcf1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -313,6 +313,7 @@ class BinPickingTaskParameters int controllerport; ///< the port of the computer on which the robot controller runs std::vector goaljoints; ///< the joint values of goal point std::vector jointindices; + int port; Real envclearance; Real speed; std::string targetname; @@ -795,7 +796,7 @@ class MUJINCLIENT_API BinPickingTaskResource : public TaskResource virtual Transform GetTransform(const std::string& targetname); virtual void SetTransform(const std::string& targetname, const Transform& transform); virtual Transform GetManipTransformToRobot(); - virtual void InitializeZMQ(); + virtual void InitializeZMQ(int zmqport); /// \brief Dynamically add a point cloud collision obstacle with name to the environment. virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c617a3f0..6ec21a23 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -663,13 +663,14 @@ Transform BinPickingTaskResource::GetManipTransformToRobot() } } -void BinPickingTaskResource::InitializeZMQ() +void BinPickingTaskResource::InitializeZMQ(int zmqport) { GETCONTROLLERIMPL(); BinPickingResultResourcePtr resultresource; BinPickingTaskParameters param; param.command = "InitZMQ"; + param.port = zmqport; this->SetTaskParameters(param); this->Execute(); @@ -729,7 +730,7 @@ void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& t { GETCONTROLLERIMPL(); - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f]} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]); + std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f],\"port\": %d} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]%taskparameters.port); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); } From e1452f2096790de839c77a47c0d197b224b1b430 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Nov 2013 11:47:42 +0900 Subject: [PATCH 099/477] added binpicking task stuff, added overwrite method --- src/controllerclientimpl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 32d630c1..3ca9332a 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -430,21 +430,21 @@ SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& u return scene; } -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri) +SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; - CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); + CallPost_UTF8(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri) +SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); boost::property_tree::ptree pt; - CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); + CallPost_UTF16(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); std::string pk = pt.get("pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; From 93fd8c053f0e3bbdb15e4fb8a64989800675cd6c Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Nov 2013 11:47:42 +0900 Subject: [PATCH 100/477] added binpicking task stuff, added overwrite method --- .../mujincontrollerclient.h | 97 +---- src/mujincontrollerclient.cpp | 386 ------------------ 2 files changed, 3 insertions(+), 480 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c5d6dcf1..6c070f52 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -121,7 +121,6 @@ class MUJINCLIENT_API MujinException : public std::exception class ControllerClient; class SceneResource; class TaskResource; -class BinPickingTaskResource; class OptimizationResource; class PlanningResultResource; @@ -131,8 +130,6 @@ typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; -typedef boost::shared_ptr BinPickingTaskResourcePtr; -typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; typedef boost::shared_ptr OptimizationResourcePtr; typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; @@ -294,32 +291,6 @@ struct PlacementsOptimizationParameters int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; -/// \brief holds information about the binpicking task parameters -class BinPickingTaskParameters -{ -public: - BinPickingTaskParameters() { - SetDefaults(); - } - - virtual void SetDefaults(); - - std::string GenerateJsonString (const std::vector& vec) const; - std::string GenerateJsonString (const std::vector& vec) const; - - std::string command; ///< command to call - std::string robottype; ///< the type of robot - std::string controllerip; ///< the ip of the computer on which the robot controller runs - int controllerport; ///< the port of the computer on which the robot controller runs - std::vector goaljoints; ///< the joint values of goal point - std::vector jointindices; - int port; - Real envclearance; - Real speed; - std::string targetname; - Transform transform; -}; - /// \brief program data for an individual robot class RobotProgramData { @@ -447,14 +418,15 @@ class MUJINCLIENT_API ControllerClient - **stl** - **cecrobodiaxml** (CEC RoboDiA XML environments) \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae + \param overwrite if true, will overwrite any existing scenes at newuri with the new scene. */ - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri, bool overwrite=false) = 0; /// \see ImportSceneToCOLLADA_UTF8 /// /// \param sourceuri utf-16 encoded /// \param newuri utf-16 encoded - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; /** \brief Recommended way of uploading a scene's files into the network filesystem. @@ -750,69 +722,6 @@ class MUJINCLIENT_API TaskResource : public WebResource std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called }; -class MUJINCLIENT_API BinPickingTaskResource : public TaskResource -{ -public: - BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene); - - virtual ~BinPickingTaskResource() { - } - - class MUJINCLIENT_API BinPickingResultResource : public WebResource - { - public: - BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task", pk) - { - } - virtual ~BinPickingResultResource() { - } - class ResultGetJointValues - { - public: - std::string robottype; - std::vector jointnames; - std::vector currentjointvalues; - std::map > tools; - }; - - class ResultMoveJoints - { - public: - std::string robottype; - int numpoints; - std::vector timedjointvalues; - //Real elapsedtime; - }; - - void GetResultGetJointValues(ResultGetJointValues& result); - void GetResultMoveJoints(ResultMoveJoints& result); - void GetResultTransform(Transform& transform); - }; - typedef boost::shared_ptr BinPickingResultResourcePtr; - - virtual int GetResult(BinPickingResultResourcePtr& result); - virtual void GetJointValues(int timeout /* [sec] */, BinPickingResultResource::ResultGetJointValues& result); - virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); - virtual Transform GetTransform(const std::string& targetname); - virtual void SetTransform(const std::string& targetname, const Transform& transform); - virtual Transform GetManipTransformToRobot(); - virtual void InitializeZMQ(int zmqport); - - /// \brief Dynamically add a point cloud collision obstacle with name to the environment. - virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); - - /// \brief Get the task info for tasks of type binpicking - virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); - - /// \brief Set the task info for tasks of type binpicking - virtual void SetTaskParameters(const BinPickingTaskParameters& taskparameters); -private: - std::string _GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname); - std::string _controllerip; - int _controllerport; - std::string _taskname; -}; - class MUJINCLIENT_API OptimizationResource : public WebResource { public: diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3a56404e..914169a2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -365,392 +365,6 @@ PlanningResultResourcePtr TaskResource::GetResult() return result; } -void BinPickingTaskParameters::SetDefaults() -{ - command = "GetJointValues"; - robottype = "densowave"; - controllerip = ""; - controllerport = 0; - envclearance = 20; - speed = 0.5; - targetname = ""; -} - -std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const -{ - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); -} - -std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const -{ - std::stringstream ss; - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); -} - -void BinPickingTaskResource::BinPickingResultResource::GetResultGetJointValues(ResultGetJointValues& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if( value.first == "robottype") { - result.robottype = value.second.data(); - } - else if (value.first == "jointnames") { - result.jointnames.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.jointnames[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "currentjointvalues" ) { - result.currentjointvalues.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.currentjointvalues[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "tools") { - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - std::string first = v.first; - BOOST_FOREACH(boost::property_tree::ptree::value_type &x, v.second) { - result.tools[first].push_back(boost::lexical_cast(x.second.data())); - } - } - } - } - } -} - -void BinPickingTaskResource::BinPickingResultResource::GetResultMoveJoints(ResultMoveJoints& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if (value.first == "robottype" ) { - result.robottype = value.second.data(); - } - else if (value.first == "timedjointvalues") { - result.timedjointvalues.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.timedjointvalues[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "numpoints" ) { - result.numpoints = boost::lexical_cast(value.second.data()); - } - /* - else if (value.first == "elapsedtime" ) { - //TODO lexical_cast doesn't work with such kind of string: "4.99999999999998e-06" - result.elapsedtime = boost::lexical_cast(value.second.data()); - } - */ - } - } -} -void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transform& transform) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if( value.first == "translation") { - size_t i = 0; - if ( value.second.size() != 3 ) { - throw MujinException("the length of translation is invalid", MEC_Timeout); - } - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - transform.translate[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "quaternion") { - size_t i = 0; - if ( value.second.size() != 4 ) { - throw MujinException("the length of quaternion is invalid", MEC_Timeout); - } - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - transform.quaternion[i++] = boost::lexical_cast(v.second.data()); - } - } - } - } -} - -BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene) : TaskResource(controller,_GetOrCreateTaskAndGetPk(scene, taskname)) -{ - _taskname = taskname; - _controllerip = controllerip; - _controllerport = controllerport; -} - -std::string BinPickingTaskResource::_GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname) -{ - TaskResourcePtr task = scene->GetOrCreateTaskFromName_UTF8(taskname,"binpicking"); - std::string pk = task->Get("pk"); - return pk; -} - -void BinPickingTaskResource::GetJointValues(int timeout, BinPickingResultResource::ResultGetJointValues& result) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "GetJointValues"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.robottype = "densowave"; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultGetJointValues(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout, BinPickingResultResource::ResultMoveJoints& result) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "MoveJoints"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.robottype = "densowave"; - param.goaljoints = jointvalues; - param.jointindices = jointindices; - param.envclearance = 20; - param.speed = 0.5; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultMoveJoints(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -Transform BinPickingTaskResource::GetTransform(const std::string& targetname) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - Transform transform; - param.command = "GetTransform"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.targetname = targetname; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::SetTransform(const std::string& targetname, const Transform& transform) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "SetTransform"; - param.targetname = targetname; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.transform = transform; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -Transform BinPickingTaskResource::GetManipTransformToRobot() -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - Transform transform; - - param.command = "GetManipTransformToRobot"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - this->SetTaskParameters(param); - this->Execute(); - - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::InitializeZMQ(int zmqport) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "InitZMQ"; - param.port = zmqport; - this->SetTaskParameters(param); - this->Execute(); - - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - ++iterations; - if( iterations > 20 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} -void BinPickingTaskResource::AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - - ss << boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"AddPointCloudObstacle\", \"pointsize\":%f, \"name\": \"%s\"")%pointsize%name); - if( vpoints.size() > 0 ) { - ss << ", \"points\":[" << vpoints.at(0); - for(size_t i = 1; i < vpoints.size(); ++i) { - ss << "," << vpoints[i]; - } - ss << "]"; - } - ss << "}}"; - boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), ss.str(), pt); - - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) -{ - throw MujinException("not implemented yet"); -} - -void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f],\"port\": %d} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]%taskparameters.port); - boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); -} - -int BinPickingTaskResource::GetResult(BinPickingResultResourcePtr& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { - return 0; - } - //std::string pk = objects.begin()->second.get("pk"); - result.reset(new BinPickingResultResource(GetController(), GetPrimaryKey())); - return objects.size(); -} - OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) { } From 37c347f3a1abc8c5be0888bb41665517ba52ef1f Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Nov 2013 11:47:42 +0900 Subject: [PATCH 101/477] added binpicking task stuff, added overwrite method --- .../mujincontrollerclient.h | 97 +---- src/mujincontrollerclient.cpp | 386 ------------------ 2 files changed, 3 insertions(+), 480 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c5d6dcf1..6c070f52 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -121,7 +121,6 @@ class MUJINCLIENT_API MujinException : public std::exception class ControllerClient; class SceneResource; class TaskResource; -class BinPickingTaskResource; class OptimizationResource; class PlanningResultResource; @@ -131,8 +130,6 @@ typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; -typedef boost::shared_ptr BinPickingTaskResourcePtr; -typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; typedef boost::shared_ptr OptimizationResourcePtr; typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; @@ -294,32 +291,6 @@ struct PlacementsOptimizationParameters int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. }; -/// \brief holds information about the binpicking task parameters -class BinPickingTaskParameters -{ -public: - BinPickingTaskParameters() { - SetDefaults(); - } - - virtual void SetDefaults(); - - std::string GenerateJsonString (const std::vector& vec) const; - std::string GenerateJsonString (const std::vector& vec) const; - - std::string command; ///< command to call - std::string robottype; ///< the type of robot - std::string controllerip; ///< the ip of the computer on which the robot controller runs - int controllerport; ///< the port of the computer on which the robot controller runs - std::vector goaljoints; ///< the joint values of goal point - std::vector jointindices; - int port; - Real envclearance; - Real speed; - std::string targetname; - Transform transform; -}; - /// \brief program data for an individual robot class RobotProgramData { @@ -447,14 +418,15 @@ class MUJINCLIENT_API ControllerClient - **stl** - **cecrobodiaxml** (CEC RoboDiA XML environments) \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae + \param overwrite if true, will overwrite any existing scenes at newuri with the new scene. */ - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri, bool overwrite=false) = 0; /// \see ImportSceneToCOLLADA_UTF8 /// /// \param sourceuri utf-16 encoded /// \param newuri utf-16 encoded - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri) = 0; + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; /** \brief Recommended way of uploading a scene's files into the network filesystem. @@ -750,69 +722,6 @@ class MUJINCLIENT_API TaskResource : public WebResource std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called }; -class MUJINCLIENT_API BinPickingTaskResource : public TaskResource -{ -public: - BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene); - - virtual ~BinPickingTaskResource() { - } - - class MUJINCLIENT_API BinPickingResultResource : public WebResource - { - public: - BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task", pk) - { - } - virtual ~BinPickingResultResource() { - } - class ResultGetJointValues - { - public: - std::string robottype; - std::vector jointnames; - std::vector currentjointvalues; - std::map > tools; - }; - - class ResultMoveJoints - { - public: - std::string robottype; - int numpoints; - std::vector timedjointvalues; - //Real elapsedtime; - }; - - void GetResultGetJointValues(ResultGetJointValues& result); - void GetResultMoveJoints(ResultMoveJoints& result); - void GetResultTransform(Transform& transform); - }; - typedef boost::shared_ptr BinPickingResultResourcePtr; - - virtual int GetResult(BinPickingResultResourcePtr& result); - virtual void GetJointValues(int timeout /* [sec] */, BinPickingResultResource::ResultGetJointValues& result); - virtual void MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout /* [sec] */, BinPickingResultResource::ResultMoveJoints& result); - virtual Transform GetTransform(const std::string& targetname); - virtual void SetTransform(const std::string& targetname, const Transform& transform); - virtual Transform GetManipTransformToRobot(); - virtual void InitializeZMQ(int zmqport); - - /// \brief Dynamically add a point cloud collision obstacle with name to the environment. - virtual void AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name); - - /// \brief Get the task info for tasks of type binpicking - virtual void GetTaskParameters(BinPickingTaskParameters& taskparameters); - - /// \brief Set the task info for tasks of type binpicking - virtual void SetTaskParameters(const BinPickingTaskParameters& taskparameters); -private: - std::string _GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname); - std::string _controllerip; - int _controllerport; - std::string _taskname; -}; - class MUJINCLIENT_API OptimizationResource : public WebResource { public: diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3a56404e..914169a2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -365,392 +365,6 @@ PlanningResultResourcePtr TaskResource::GetResult() return result; } -void BinPickingTaskParameters::SetDefaults() -{ - command = "GetJointValues"; - robottype = "densowave"; - controllerip = ""; - controllerport = 0; - envclearance = 20; - speed = 0.5; - targetname = ""; -} - -std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const -{ - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); -} - -std::string BinPickingTaskParameters::GenerateJsonString (const std::vector& vec) const -{ - std::stringstream ss; - ss << "["; - if( vec.size() > 0 ) { - for (unsigned int i = 0; i < vec.size(); i++) { - ss << vec[i]; - if( i != vec.size()-1) { - ss << ", "; - } - } - } - ss << "]"; - return ss.str(); -} - -void BinPickingTaskResource::BinPickingResultResource::GetResultGetJointValues(ResultGetJointValues& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if( value.first == "robottype") { - result.robottype = value.second.data(); - } - else if (value.first == "jointnames") { - result.jointnames.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.jointnames[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "currentjointvalues" ) { - result.currentjointvalues.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.currentjointvalues[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "tools") { - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - std::string first = v.first; - BOOST_FOREACH(boost::property_tree::ptree::value_type &x, v.second) { - result.tools[first].push_back(boost::lexical_cast(x.second.data())); - } - } - } - } - } -} - -void BinPickingTaskResource::BinPickingResultResource::GetResultMoveJoints(ResultMoveJoints& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if (value.first == "robottype" ) { - result.robottype = value.second.data(); - } - else if (value.first == "timedjointvalues") { - result.timedjointvalues.resize(value.second.size()); - size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - result.timedjointvalues[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "numpoints" ) { - result.numpoints = boost::lexical_cast(value.second.data()); - } - /* - else if (value.first == "elapsedtime" ) { - //TODO lexical_cast doesn't work with such kind of string: "4.99999999999998e-06" - result.elapsedtime = boost::lexical_cast(value.second.data()); - } - */ - } - } -} -void BinPickingTaskResource::BinPickingResultResource::GetResultTransform(Transform& transform) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(boost::str(boost::format("task/%s/result/?format=json&limit=1")%GetPrimaryKey()), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type& obj, pt.get_child("objects")) { - boost::property_tree::ptree& output = obj.second.get_child("output"); - BOOST_FOREACH(boost::property_tree::ptree::value_type& value, output) { - if( value.first == "translation") { - size_t i = 0; - if ( value.second.size() != 3 ) { - throw MujinException("the length of translation is invalid", MEC_Timeout); - } - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - transform.translate[i++] = boost::lexical_cast(v.second.data()); - } - } - else if (value.first == "quaternion") { - size_t i = 0; - if ( value.second.size() != 4 ) { - throw MujinException("the length of quaternion is invalid", MEC_Timeout); - } - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, value.second) { - transform.quaternion[i++] = boost::lexical_cast(v.second.data()); - } - } - } - } -} - -BinPickingTaskResource::BinPickingTaskResource(const std::string& taskname, const std::string& controllerip, const int controllerport, ControllerClientPtr controller, SceneResourcePtr scene) : TaskResource(controller,_GetOrCreateTaskAndGetPk(scene, taskname)) -{ - _taskname = taskname; - _controllerip = controllerip; - _controllerport = controllerport; -} - -std::string BinPickingTaskResource::_GetOrCreateTaskAndGetPk(SceneResourcePtr scene, const std::string& taskname) -{ - TaskResourcePtr task = scene->GetOrCreateTaskFromName_UTF8(taskname,"binpicking"); - std::string pk = task->Get("pk"); - return pk; -} - -void BinPickingTaskResource::GetJointValues(int timeout, BinPickingResultResource::ResultGetJointValues& result) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "GetJointValues"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.robottype = "densowave"; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultGetJointValues(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::MoveJoints(const std::vector& jointvalues, const std::vector& jointindices, int timeout, BinPickingResultResource::ResultMoveJoints& result) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "MoveJoints"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.robottype = "densowave"; - param.goaljoints = jointvalues; - param.jointindices = jointindices; - param.envclearance = 20; - param.speed = 0.5; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultMoveJoints(result); - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > timeout ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -Transform BinPickingTaskResource::GetTransform(const std::string& targetname) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - Transform transform; - param.command = "GetTransform"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.targetname = targetname; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::SetTransform(const std::string& targetname, const Transform& transform) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "SetTransform"; - param.targetname = targetname; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - param.transform = transform; - this->SetTaskParameters(param); - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -Transform BinPickingTaskResource::GetManipTransformToRobot() -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - Transform transform; - - param.command = "GetManipTransformToRobot"; - param.controllerip = _controllerip; - param.controllerport = _controllerport; - this->SetTaskParameters(param); - this->Execute(); - - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) - { - resultresource->GetResultTransform(transform); - return transform; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::InitializeZMQ(int zmqport) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - BinPickingTaskParameters param; - - param.command = "InitZMQ"; - param.port = zmqport; - this->SetTaskParameters(param); - this->Execute(); - - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - ++iterations; - if( iterations > 20 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} -void BinPickingTaskResource::AddPointCloudObstacle(const std::vector& vpoints, Real pointsize, const std::string& name) -{ - GETCONTROLLERIMPL(); - BinPickingResultResourcePtr resultresource; - - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - - ss << boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"AddPointCloudObstacle\", \"pointsize\":%f, \"name\": \"%s\"")%pointsize%name); - if( vpoints.size() > 0 ) { - ss << ", \"points\":[" << vpoints.at(0); - for(size_t i = 1; i < vpoints.size(); ++i) { - ss << "," << vpoints[i]; - } - ss << "]"; - } - ss << "}}"; - boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), ss.str(), pt); - - this->Execute(); - int iterations = 0; - while (1) { - if (this->GetResult(resultresource) != 0) { - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - ++iterations; - if( iterations > 10 ) { - controller->CancelAllJobs(); - throw MujinException("operation timed out, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::GetTaskParameters(BinPickingTaskParameters& taskparameters) -{ - throw MujinException("not implemented yet"); -} - -void BinPickingTaskResource::SetTaskParameters(const BinPickingTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - - std::string taskgoalput = boost::str(boost::format("{\"tasktype\": \"binpicking\", \"taskparameters\":{\"command\":\"%s\", \"robottype\":\"%s\", \"controllerip\":\"%s\", \"controllerport\":%d, \"goaljoints\":%s, \"jointindices\":%s, \"envclearance\":%f, \"speed\": %f, \"targetname\": \"%s\", \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f],\"port\": %d} }")%taskparameters.command%taskparameters.robottype%taskparameters.controllerip%taskparameters.controllerport%taskparameters.GenerateJsonString(taskparameters.goaljoints)%taskparameters.GenerateJsonString(taskparameters.jointindices)%taskparameters.envclearance%taskparameters.speed%taskparameters.targetname%taskparameters.transform.translate[0]%taskparameters.transform.translate[1]%taskparameters.transform.translate[2]%taskparameters.transform.quaternion[0]%taskparameters.transform.quaternion[1]%taskparameters.transform.quaternion[2]%taskparameters.transform.quaternion[3]%taskparameters.port); - boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), taskgoalput, pt); -} - -int BinPickingTaskResource::GetResult(BinPickingResultResourcePtr& result) -{ - GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { - return 0; - } - //std::string pk = objects.begin()->second.get("pk"); - result.reset(new BinPickingResultResource(GetController(), GetPrimaryKey())); - return objects.size(); -} - OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) { } From d3902bfee8ed1314a7fee0983dde8ba709895023 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Wed, 13 Nov 2013 14:46:14 +0900 Subject: [PATCH 102/477] fix deletedirectory --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3ca9332a..448aeeb0 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1585,7 +1585,7 @@ void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) { CurlCustomRequestSetter setter(_curl, "DELETE"); - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); CURLcode res = curl_easy_perform(_curl); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; From 939cacc0e6870efdd2f7bf25786afa0dc4ef62e6 Mon Sep 17 00:00:00 2001 From: controller Date: Sun, 1 Dec 2013 21:30:05 +0900 Subject: [PATCH 103/477] change some structure --- include/mujincontrollerclient/mujincontrollerclient.h | 5 +++++ src/mujincontrollerclient.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6c070f52..e25d5107 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -68,6 +68,8 @@ enum MujinErrorCode { MEC_HTTPServer=13, ///< HTTP server error MEC_UserAuthentication=14, ///< authentication failed MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated + MEC_BinPickingError=16, ///< BinPicking failed + MEC_HandEyeCalibrationError=17 ///< HandEye Calibration failed }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -84,6 +86,8 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_HTTPServer: return "HTTPServer"; case MEC_UserAuthentication: return "UserAuthentication"; case MEC_AlreadyExists: return "AlreadyExists"; + case MEC_BinPickingError: return "BinPickingError"; + case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; } // should throw an exception? return ""; @@ -763,6 +767,7 @@ class MUJINCLIENT_API OptimizationResource : public WebResource class MUJINCLIENT_API PlanningResultResource : public WebResource { public: + PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk); PlanningResultResource(ControllerClientPtr controller, const std::string& pk); virtual ~PlanningResultResource() { } diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 914169a2..78c2845c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -445,6 +445,10 @@ void OptimizationResource::GetResults(std::vector& re } } +PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk) : WebResource(controller,resulttype,pk) +{ +} + PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) { } From ed40806c8a5463762aeae8221bb537477a5ad76c Mon Sep 17 00:00:00 2001 From: controller Date: Sun, 1 Dec 2013 21:30:05 +0900 Subject: [PATCH 104/477] change some structure --- include/mujincontrollerclient/mujincontrollerclient.h | 5 +++++ src/mujincontrollerclient.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6c070f52..e25d5107 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -68,6 +68,8 @@ enum MujinErrorCode { MEC_HTTPServer=13, ///< HTTP server error MEC_UserAuthentication=14, ///< authentication failed MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated + MEC_BinPickingError=16, ///< BinPicking failed + MEC_HandEyeCalibrationError=17 ///< HandEye Calibration failed }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -84,6 +86,8 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_HTTPServer: return "HTTPServer"; case MEC_UserAuthentication: return "UserAuthentication"; case MEC_AlreadyExists: return "AlreadyExists"; + case MEC_BinPickingError: return "BinPickingError"; + case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; } // should throw an exception? return ""; @@ -763,6 +767,7 @@ class MUJINCLIENT_API OptimizationResource : public WebResource class MUJINCLIENT_API PlanningResultResource : public WebResource { public: + PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk); PlanningResultResource(ControllerClientPtr controller, const std::string& pk); virtual ~PlanningResultResource() { } diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 914169a2..78c2845c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -445,6 +445,10 @@ void OptimizationResource::GetResults(std::vector& re } } +PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk) : WebResource(controller,resulttype,pk) +{ +} + PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) { } From 24af4d940db396a37d2ee1290f9d542bc5d5f5cb Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Wed, 11 Dec 2013 09:06:03 +0900 Subject: [PATCH 105/477] add SceneResource::Copy function and calibtask::GetManipTransform --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e25d5107..84ae928c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -676,6 +676,8 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetInstObjects(std::vector& instobjects); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); + + virtual SceneResourcePtr Copy(const std::string& name); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 78c2845c..9afdea24 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -200,7 +200,6 @@ void SceneResource::GetInstObjects(std::vector& in } SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) -//void SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real rotate[4], Real translation[3]) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; @@ -210,6 +209,16 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& return instobject; } +SceneResourcePtr SceneResource::Copy(const std::string& name) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPost("scene/?format=json", str(boost::format("{\"name\":\"%s\", \"reference_pk\":\"%s\", \"overwrite\": \"1\"}")%name%GetPrimaryKey()), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(GetController(), pk)); + return scene; +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From afb521000b8812cb159cf58d36c0609de64a5a09 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Wed, 11 Dec 2013 09:06:03 +0900 Subject: [PATCH 106/477] add SceneResource::Copy function and calibtask::GetManipTransform --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e25d5107..84ae928c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -676,6 +676,8 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetInstObjects(std::vector& instobjects); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); + + virtual SceneResourcePtr Copy(const std::string& name); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 78c2845c..9afdea24 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -200,7 +200,6 @@ void SceneResource::GetInstObjects(std::vector& in } SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) -//void SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real rotate[4], Real translation[3]) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; @@ -210,6 +209,16 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& return instobject; } +SceneResourcePtr SceneResource::Copy(const std::string& name) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPost("scene/?format=json", str(boost::format("{\"name\":\"%s\", \"reference_pk\":\"%s\", \"overwrite\": \"1\"}")%name%GetPrimaryKey()), pt); + std::string pk = pt.get("pk"); + SceneResourcePtr scene(new SceneResource(GetController(), pk)); + return scene; +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From 5daa5776cd8accba731a165af57539e0a2a4f1c9 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Fri, 13 Dec 2013 08:41:41 +0900 Subject: [PATCH 107/477] implement setdofvalues --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 84ae928c..2e0a5603 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -620,6 +620,7 @@ class MUJINCLIENT_API SceneResource : public WebResource } void SetTransform(const Transform& t); + void SetDOFValues(); std::vector dofvalues; std::string name; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9afdea24..3f4bab40 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -59,6 +59,25 @@ void SceneResource::InstObject::SetTransform(const Transform& t) controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } +void SceneResource::InstObject::SetDOFValues() +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + std::stringstream ss; + ss << "{\"dofvalues\":"; + ss << "["; + if( this->dofvalues.size() > 0 ) { + for (unsigned int i = 0; i < this->dofvalues.size(); i++) { + ss << this->dofvalues[i]; + if( i != this->dofvalues.size()-1) { + ss << ", "; + } + } + } + ss << "]}"; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? From 3b16332cb5b1c8244d476192bffb8ad1b4d9e2ae Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Fri, 13 Dec 2013 08:41:41 +0900 Subject: [PATCH 108/477] implement setdofvalues --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 84ae928c..2e0a5603 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -620,6 +620,7 @@ class MUJINCLIENT_API SceneResource : public WebResource } void SetTransform(const Transform& t); + void SetDOFValues(); std::vector dofvalues; std::string name; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9afdea24..3f4bab40 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -59,6 +59,25 @@ void SceneResource::InstObject::SetTransform(const Transform& t) controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } +void SceneResource::InstObject::SetDOFValues() +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + std::stringstream ss; + ss << "{\"dofvalues\":"; + ss << "["; + if( this->dofvalues.size() > 0 ) { + for (unsigned int i = 0; i < this->dofvalues.size(); i++) { + ss << this->dofvalues[i]; + if( i != this->dofvalues.size()-1) { + ss << ", "; + } + } + } + ss << "]}"; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? From e422822533be790c2851fb9044a6f1a18e411235 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Sat, 14 Dec 2013 04:11:27 +0900 Subject: [PATCH 109/477] add member 'link' and 'tool' to instobject --- .../mujincontrollerclient.h | 24 ++++ src/mujincontrollerclient.cpp | 122 +++++++++++++++++- 2 files changed, 145 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2e0a5603..ce5f2ac5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -619,6 +619,26 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~InstObject() { } + class MUJINCLIENT_API Link { +public: + std::string name; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Tool { +public: + std::string name; + Real direction[3]; + std::string frame_origin, frame_tip; + std::string pk; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Grab { + }; + void SetTransform(const Transform& t); void SetDOFValues(); @@ -629,6 +649,10 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; + //std::vector grabs; + std::vector links; + std::vector tools; + void Print(); }; typedef boost::shared_ptr InstObjectPtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3f4bab40..aa3db38a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -78,6 +78,71 @@ void SceneResource::InstObject::SetDOFValues() controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } +void SceneResource::InstObject::Print() +{ + std::cout << "dofvalues: "; + for (int i = 0; i < dofvalues.size(); i++) { + std::cout << dofvalues[i] << ", "; + } + std::cout << std::endl; + std::cout << "name: " << name << std::endl; + std::cout << "pk: " << pk << std::endl; + std::cout << "object_pk: " << object_pk << std::endl; + std::cout << "reference_uri: " << reference_uri << std::endl; + + std::cout << "quaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << quaternion[i] << ", "; + } + std::cout << std::endl; + std::cout << "translate: "; + for (int i = 0; i < 3; i++) { + std::cout << translate[i] << ", "; + } + std::cout << std::endl; + + std::cout << "links: " << std::endl; + for (int i = 0; i < links.size(); i++) { + std::cout << "\tname: " << links[i].name << std::endl; + std::cout << "\tquaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << links[i].quaternion[i] << ", "; + } + std::cout << std::endl; + std::cout << "\ttranslate: "; + for (int i = 0; i < 3; i++) { + std::cout << links[i].translate[i] << ", "; + } + std::cout << std::endl; + } + + std::cout << "tools: " << std::endl; + for (int i = 0; i < tools.size(); i++) { + std::cout << "\tname: " << tools[i].name << std::endl; + std::cout << "\tframe_origin: " << tools[i].frame_origin << std::endl; + std::cout << "\tframe_tip: " << tools[i].frame_tip << std::endl; + std::cout << "\tpk: " << tools[i].pk << std::endl; + + std::cout << "\tquaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << tools[i].quaternion[i] << ", "; + } + std::cout << std::endl; + + std::cout << "\ttranslate: "; + for (int i = 0; i < 3; i++) { + std::cout << tools[i].translate[i] << ", "; + } + std::cout << std::endl; + + std::cout << "\tdirection: "; + for (int i = 0; i < 3; i++) { + std::cout << tools[i].direction[i] << ", "; + } + std::cout << std::endl; + } +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? @@ -191,7 +256,7 @@ void SceneResource::GetInstObjects(std::vector& in size_t i = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); - //instobject->dofvalues + instobject->name = v.second.get("name"); instobject->pk = v.second.get("pk"); instobject->object_pk = v.second.get("object_pk"); @@ -214,6 +279,61 @@ void SceneResource::GetInstObjects(std::vector& in BOOST_ASSERT( itranslate < 3 ); instobject->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); } + + boost::property_tree::ptree& jsonlinks = v.second.get_child("links"); + instobject->links.resize(jsonlinks.size()); + size_t ilink = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vlink, jsonlinks) { + instobject->links[ilink].name = vlink.second.get("name"); + + boost::property_tree::ptree& quatjson = vlink.second.get_child("quaternion"); + int iquat=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->links[ilink].quaternion[iquat] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& transjson = vlink.second.get_child("translate"); + int itrans=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_ASSERT(itrans<3); + instobject->links[ilink].translate[itrans] = boost::lexical_cast(v.second.data()); + } + ilink++; + } + + boost::property_tree::ptree& jsontools = v.second.get_child("tools"); + instobject->tools.resize(jsontools.size()); + size_t itool = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtool, jsontools) { + instobject->tools[itool].name = vtool.second.get("name"); + instobject->tools[itool].frame_origin = vtool.second.get("frame_origin"); + instobject->tools[itool].frame_tip = vtool.second.get("frame_tip"); + instobject->tools[itool].pk = vtool.second.get("pk"); + + boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); + int iquat=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->tools[itool].quaternion[iquat] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& transjson = vtool.second.get_child("translate"); + int itrans=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_ASSERT(itrans<3); + instobject->tools[itool].translate[itrans] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& directionjson = vtool.second.get_child("direction"); + int idir=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, directionjson) { + BOOST_ASSERT(idir<3); + instobject->tools[itool].direction[idir] = boost::lexical_cast(v.second.data()); + } + itool++; + } + instobjects[i++] = instobject; } } From cd71fdca84bc1a5246888c26e4f9162e75d6dafb Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Sat, 14 Dec 2013 04:11:27 +0900 Subject: [PATCH 110/477] add member 'link' and 'tool' to instobject --- .../mujincontrollerclient.h | 24 ++++ src/mujincontrollerclient.cpp | 122 +++++++++++++++++- 2 files changed, 145 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2e0a5603..ce5f2ac5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -619,6 +619,26 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual ~InstObject() { } + class MUJINCLIENT_API Link { +public: + std::string name; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Tool { +public: + std::string name; + Real direction[3]; + std::string frame_origin, frame_tip; + std::string pk; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Grab { + }; + void SetTransform(const Transform& t); void SetDOFValues(); @@ -629,6 +649,10 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; + //std::vector grabs; + std::vector links; + std::vector tools; + void Print(); }; typedef boost::shared_ptr InstObjectPtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3f4bab40..aa3db38a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -78,6 +78,71 @@ void SceneResource::InstObject::SetDOFValues() controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } +void SceneResource::InstObject::Print() +{ + std::cout << "dofvalues: "; + for (int i = 0; i < dofvalues.size(); i++) { + std::cout << dofvalues[i] << ", "; + } + std::cout << std::endl; + std::cout << "name: " << name << std::endl; + std::cout << "pk: " << pk << std::endl; + std::cout << "object_pk: " << object_pk << std::endl; + std::cout << "reference_uri: " << reference_uri << std::endl; + + std::cout << "quaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << quaternion[i] << ", "; + } + std::cout << std::endl; + std::cout << "translate: "; + for (int i = 0; i < 3; i++) { + std::cout << translate[i] << ", "; + } + std::cout << std::endl; + + std::cout << "links: " << std::endl; + for (int i = 0; i < links.size(); i++) { + std::cout << "\tname: " << links[i].name << std::endl; + std::cout << "\tquaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << links[i].quaternion[i] << ", "; + } + std::cout << std::endl; + std::cout << "\ttranslate: "; + for (int i = 0; i < 3; i++) { + std::cout << links[i].translate[i] << ", "; + } + std::cout << std::endl; + } + + std::cout << "tools: " << std::endl; + for (int i = 0; i < tools.size(); i++) { + std::cout << "\tname: " << tools[i].name << std::endl; + std::cout << "\tframe_origin: " << tools[i].frame_origin << std::endl; + std::cout << "\tframe_tip: " << tools[i].frame_tip << std::endl; + std::cout << "\tpk: " << tools[i].pk << std::endl; + + std::cout << "\tquaternion: "; + for (int i = 0; i < 4; i++) { + std::cout << tools[i].quaternion[i] << ", "; + } + std::cout << std::endl; + + std::cout << "\ttranslate: "; + for (int i = 0; i < 3; i++) { + std::cout << tools[i].translate[i] << ", "; + } + std::cout << std::endl; + + std::cout << "\tdirection: "; + for (int i = 0; i < 3; i++) { + std::cout << tools[i].direction[i] << ", "; + } + std::cout << std::endl; + } +} + SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? @@ -191,7 +256,7 @@ void SceneResource::GetInstObjects(std::vector& in size_t i = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); - //instobject->dofvalues + instobject->name = v.second.get("name"); instobject->pk = v.second.get("pk"); instobject->object_pk = v.second.get("object_pk"); @@ -214,6 +279,61 @@ void SceneResource::GetInstObjects(std::vector& in BOOST_ASSERT( itranslate < 3 ); instobject->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); } + + boost::property_tree::ptree& jsonlinks = v.second.get_child("links"); + instobject->links.resize(jsonlinks.size()); + size_t ilink = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vlink, jsonlinks) { + instobject->links[ilink].name = vlink.second.get("name"); + + boost::property_tree::ptree& quatjson = vlink.second.get_child("quaternion"); + int iquat=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->links[ilink].quaternion[iquat] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& transjson = vlink.second.get_child("translate"); + int itrans=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_ASSERT(itrans<3); + instobject->links[ilink].translate[itrans] = boost::lexical_cast(v.second.data()); + } + ilink++; + } + + boost::property_tree::ptree& jsontools = v.second.get_child("tools"); + instobject->tools.resize(jsontools.size()); + size_t itool = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtool, jsontools) { + instobject->tools[itool].name = vtool.second.get("name"); + instobject->tools[itool].frame_origin = vtool.second.get("frame_origin"); + instobject->tools[itool].frame_tip = vtool.second.get("frame_tip"); + instobject->tools[itool].pk = vtool.second.get("pk"); + + boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); + int iquat=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->tools[itool].quaternion[iquat] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& transjson = vtool.second.get_child("translate"); + int itrans=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_ASSERT(itrans<3); + instobject->tools[itool].translate[itrans] = boost::lexical_cast(v.second.data()); + } + + boost::property_tree::ptree& directionjson = vtool.second.get_child("direction"); + int idir=0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, directionjson) { + BOOST_ASSERT(idir<3); + instobject->tools[itool].direction[idir] = boost::lexical_cast(v.second.data()); + } + itool++; + } + instobjects[i++] = instobject; } } From 3589f53069d02c894b5b337f1af4f9d3b8095fa9 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Sun, 15 Dec 2013 00:12:16 +0900 Subject: [PATCH 111/477] remove frame_origin, frame_tip, pk from tools --- include/mujincontrollerclient/mujincontrollerclient.h | 2 -- src/mujincontrollerclient.cpp | 6 ------ 2 files changed, 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ce5f2ac5..58b9fced 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -630,8 +630,6 @@ class MUJINCLIENT_API SceneResource : public WebResource public: std::string name; Real direction[3]; - std::string frame_origin, frame_tip; - std::string pk; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index aa3db38a..e37605f6 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -119,9 +119,6 @@ void SceneResource::InstObject::Print() std::cout << "tools: " << std::endl; for (int i = 0; i < tools.size(); i++) { std::cout << "\tname: " << tools[i].name << std::endl; - std::cout << "\tframe_origin: " << tools[i].frame_origin << std::endl; - std::cout << "\tframe_tip: " << tools[i].frame_tip << std::endl; - std::cout << "\tpk: " << tools[i].pk << std::endl; std::cout << "\tquaternion: "; for (int i = 0; i < 4; i++) { @@ -307,9 +304,6 @@ void SceneResource::GetInstObjects(std::vector& in size_t itool = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &vtool, jsontools) { instobject->tools[itool].name = vtool.second.get("name"); - instobject->tools[itool].frame_origin = vtool.second.get("frame_origin"); - instobject->tools[itool].frame_tip = vtool.second.get("frame_tip"); - instobject->tools[itool].pk = vtool.second.get("pk"); boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); int iquat=0; From c0bf5c1e9dc7b6391ca5e94f33cbc03adfa6c603 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Sun, 15 Dec 2013 00:12:16 +0900 Subject: [PATCH 112/477] remove frame_origin, frame_tip, pk from tools --- include/mujincontrollerclient/mujincontrollerclient.h | 2 -- src/mujincontrollerclient.cpp | 6 ------ 2 files changed, 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ce5f2ac5..58b9fced 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -630,8 +630,6 @@ class MUJINCLIENT_API SceneResource : public WebResource public: std::string name; Real direction[3]; - std::string frame_origin, frame_tip; - std::string pk; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index aa3db38a..e37605f6 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -119,9 +119,6 @@ void SceneResource::InstObject::Print() std::cout << "tools: " << std::endl; for (int i = 0; i < tools.size(); i++) { std::cout << "\tname: " << tools[i].name << std::endl; - std::cout << "\tframe_origin: " << tools[i].frame_origin << std::endl; - std::cout << "\tframe_tip: " << tools[i].frame_tip << std::endl; - std::cout << "\tpk: " << tools[i].pk << std::endl; std::cout << "\tquaternion: "; for (int i = 0; i < 4; i++) { @@ -307,9 +304,6 @@ void SceneResource::GetInstObjects(std::vector& in size_t itool = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &vtool, jsontools) { instobject->tools[itool].name = vtool.second.get("name"); - instobject->tools[itool].frame_origin = vtool.second.get("frame_origin"); - instobject->tools[itool].frame_tip = vtool.second.get("frame_tip"); - instobject->tools[itool].pk = vtool.second.get("pk"); boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); int iquat=0; From 6c6414d8928d78311a0065d927008b9bd2924a76 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 16 Dec 2013 05:37:11 +0900 Subject: [PATCH 113/477] add robotresource/objectresource and getlinks/gettools functions --- .../mujincontrollerclient.h | 80 ++++++++++++++++- src/mujincontrollerclient.cpp | 89 +++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 58b9fced..85c96207 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -123,6 +123,7 @@ class MUJINCLIENT_API MujinException : public std::exception }; class ControllerClient; +class RobotResource; class SceneResource; class TaskResource; class OptimizationResource; @@ -130,6 +131,8 @@ class PlanningResultResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr RobotResourcePtr; +typedef boost::weak_ptr RobotResourceWeakPtr; typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; @@ -608,6 +611,76 @@ class MUJINCLIENT_API WebResource std::string __resourcename, __pk; }; +class MUJINCLIENT_API ObjectResource : public WebResource +{ +public: + class MUJINCLIENT_API LinkResource : public WebResource { +public: + LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~LinkResource() { + } + + std::vector attachmentpks; + std::string name; + std::string pk; + //TODO transforms + }; + typedef boost::shared_ptr LinkResourcePtr; + + ObjectResource(ControllerClientPtr controller, const std::string& pk); + virtual ~ObjectResource() { + } + + virtual void GetLinks(std::vector& links); + + std::string name; + int nundof; + std::string datemodified; + std::string geometry; + bool isrobot; + std::string pk; + std::string resource_uri; + std::string scenepk; + std::string unit; + std::string uri; + +protected: + ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); + +}; + +class MUJINCLIENT_API RobotResource : public ObjectResource +{ +public: + class MUJINCLIENT_API ToolResource : public WebResource { +public: + ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~ToolResource() { + } + + std::string name; + std::string frame_origin; + std::string frame_tip; + std::string pk; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + typedef boost::shared_ptr ToolResourcePtr; + + RobotResource(ControllerClientPtr controller, const std::string& pk); + virtual ~RobotResource() { + } + + virtual void GetTools(std::vector& tools); + + // attachments + // ikparams + // images + int numdof; + std::string simulation_file; +}; + class MUJINCLIENT_API SceneResource : public WebResource { public: @@ -635,6 +708,10 @@ class MUJINCLIENT_API SceneResource : public WebResource }; class MUJINCLIENT_API Grab { +public: + std::string instobjectpk; ///< grabed_instobject_pk + std::string grabbed_link_pk; + std::string grabbing_link_pk; }; void SetTransform(const Transform& t); @@ -647,7 +724,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; - //std::vector grabs; + std::vector grabs; std::vector links; std::vector tools; void Print(); @@ -701,6 +778,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); virtual SceneResourcePtr Copy(const std::string& name); + virtual void Grab(const std::string grabbingname, const std::string& grabbedname); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index e37605f6..1f25a50c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -47,6 +47,91 @@ void WebResource::Copy(const std::string& newname, int options) throw MujinException("not implemented yet"); } +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "object", pk) +{ +} + +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk) +{ +} + +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk) +{ +} + +void ObjectResource::GetLinks(std::vector& links) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("object/%s/link/?format=json&limit=0&fields=links")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("links"); + links.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + link->name = v.second.get("name"); + link->pk = v.second.get("pk"); + + boost::property_tree::ptree& jsonattachments = v.second.get_child("attachmentpks"); + link->attachmentpks.resize(jsonattachments.size()); + size_t iattch = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &att, jsonattachments) { + link->attachmentpks[iattch++] = att.second.data(); + } + + //TODO transforms + links[i++] = link; + } +} + +RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk) : ObjectResource(controller, "robot", pk) +{ +} + +RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk) +{ +} + +void RobotResource::GetTools(std::vector& tools) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("robot/%s/tool/?format=json&limit=0&fields=tools")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("tools"); + tools.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + tool->name = v.second.get("name"); + tool->pk = v.second.get("pk"); + tool->frame_origin = v.second.get("frame_origin"); + tool->frame_tip = v.second.get("frame_tip"); + + boost::property_tree::ptree& jsondirection = v.second.get_child("direction"); + size_t idir = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vdir, jsondirection) { + tool->direction[idir++] = boost::lexical_cast(vdir.second.data()); + } + + size_t iquaternion = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + tool->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + } + size_t itranslate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + tool->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + } + + tools[i++] = tool; + } +} + SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) { } @@ -352,6 +437,10 @@ SceneResourcePtr SceneResource::Copy(const std::string& name) return scene; } +void SceneResource::Grab(const std::string grabbingname, const std::string& grabbedname) +{ +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From 4b0d75e0785e3a638328d59366b074679e1b6382 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 16 Dec 2013 05:37:11 +0900 Subject: [PATCH 114/477] add robotresource/objectresource and getlinks/gettools functions --- .../mujincontrollerclient.h | 80 ++++++++++++++++- src/mujincontrollerclient.cpp | 89 +++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 58b9fced..85c96207 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -123,6 +123,7 @@ class MUJINCLIENT_API MujinException : public std::exception }; class ControllerClient; +class RobotResource; class SceneResource; class TaskResource; class OptimizationResource; @@ -130,6 +131,8 @@ class PlanningResultResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr RobotResourcePtr; +typedef boost::weak_ptr RobotResourceWeakPtr; typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; @@ -608,6 +611,76 @@ class MUJINCLIENT_API WebResource std::string __resourcename, __pk; }; +class MUJINCLIENT_API ObjectResource : public WebResource +{ +public: + class MUJINCLIENT_API LinkResource : public WebResource { +public: + LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~LinkResource() { + } + + std::vector attachmentpks; + std::string name; + std::string pk; + //TODO transforms + }; + typedef boost::shared_ptr LinkResourcePtr; + + ObjectResource(ControllerClientPtr controller, const std::string& pk); + virtual ~ObjectResource() { + } + + virtual void GetLinks(std::vector& links); + + std::string name; + int nundof; + std::string datemodified; + std::string geometry; + bool isrobot; + std::string pk; + std::string resource_uri; + std::string scenepk; + std::string unit; + std::string uri; + +protected: + ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); + +}; + +class MUJINCLIENT_API RobotResource : public ObjectResource +{ +public: + class MUJINCLIENT_API ToolResource : public WebResource { +public: + ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~ToolResource() { + } + + std::string name; + std::string frame_origin; + std::string frame_tip; + std::string pk; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + typedef boost::shared_ptr ToolResourcePtr; + + RobotResource(ControllerClientPtr controller, const std::string& pk); + virtual ~RobotResource() { + } + + virtual void GetTools(std::vector& tools); + + // attachments + // ikparams + // images + int numdof; + std::string simulation_file; +}; + class MUJINCLIENT_API SceneResource : public WebResource { public: @@ -635,6 +708,10 @@ class MUJINCLIENT_API SceneResource : public WebResource }; class MUJINCLIENT_API Grab { +public: + std::string instobjectpk; ///< grabed_instobject_pk + std::string grabbed_link_pk; + std::string grabbing_link_pk; }; void SetTransform(const Transform& t); @@ -647,7 +724,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; - //std::vector grabs; + std::vector grabs; std::vector links; std::vector tools; void Print(); @@ -701,6 +778,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); virtual SceneResourcePtr Copy(const std::string& name); + virtual void Grab(const std::string grabbingname, const std::string& grabbedname); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index e37605f6..1f25a50c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -47,6 +47,91 @@ void WebResource::Copy(const std::string& newname, int options) throw MujinException("not implemented yet"); } +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "object", pk) +{ +} + +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk) +{ +} + +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk) +{ +} + +void ObjectResource::GetLinks(std::vector& links) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("object/%s/link/?format=json&limit=0&fields=links")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("links"); + links.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + link->name = v.second.get("name"); + link->pk = v.second.get("pk"); + + boost::property_tree::ptree& jsonattachments = v.second.get_child("attachmentpks"); + link->attachmentpks.resize(jsonattachments.size()); + size_t iattch = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &att, jsonattachments) { + link->attachmentpks[iattch++] = att.second.data(); + } + + //TODO transforms + links[i++] = link; + } +} + +RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk) : ObjectResource(controller, "robot", pk) +{ +} + +RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk) +{ +} + +void RobotResource::GetTools(std::vector& tools) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("robot/%s/tool/?format=json&limit=0&fields=tools")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("tools"); + tools.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + tool->name = v.second.get("name"); + tool->pk = v.second.get("pk"); + tool->frame_origin = v.second.get("frame_origin"); + tool->frame_tip = v.second.get("frame_tip"); + + boost::property_tree::ptree& jsondirection = v.second.get_child("direction"); + size_t idir = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vdir, jsondirection) { + tool->direction[idir++] = boost::lexical_cast(vdir.second.data()); + } + + size_t iquaternion = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + tool->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + } + size_t itranslate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + tool->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + } + + tools[i++] = tool; + } +} + SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) { } @@ -352,6 +437,10 @@ SceneResourcePtr SceneResource::Copy(const std::string& name) return scene; } +void SceneResource::Grab(const std::string grabbingname, const std::string& grabbedname) +{ +} + TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From d7d855dfcf90c09c48130ae73627bc0db66b768e Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 16 Dec 2013 07:05:03 +0900 Subject: [PATCH 115/477] impl grab/release object --- .../mujincontrollerclient.h | 28 ++++++-- src/mujincontrollerclient.cpp | 72 +++++++++++++++++-- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 85c96207..d82f3237 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -123,6 +123,7 @@ class MUJINCLIENT_API MujinException : public std::exception }; class ControllerClient; +class ObjectResource; class RobotResource; class SceneResource; class TaskResource; @@ -131,6 +132,8 @@ class PlanningResultResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr ObjectResourcePtr; +typedef boost::weak_ptr ObjectResourceWeakPtr; typedef boost::shared_ptr RobotResourcePtr; typedef boost::weak_ptr RobotResourceWeakPtr; typedef boost::shared_ptr SceneResourcePtr; @@ -684,6 +687,8 @@ class MUJINCLIENT_API RobotResource : public ObjectResource class MUJINCLIENT_API SceneResource : public WebResource { public: + class InstObject; + typedef boost::shared_ptr InstObjectPtr; /// \brief nested resource in the scene describe an object in the scene class MUJINCLIENT_API InstObject : public WebResource { @@ -710,12 +715,28 @@ class MUJINCLIENT_API SceneResource : public WebResource class MUJINCLIENT_API Grab { public: std::string instobjectpk; ///< grabed_instobject_pk - std::string grabbed_link_pk; - std::string grabbing_link_pk; + std::string grabbed_linkpk; + std::string grabbing_linkpk; + + std::string Serialize() { + return boost::str(boost::format("{\"instobjectpk\": \"%s\", \"grabbed_linkpk\": \"%s\", \"grabbing_linkpk\": \"%s\"}")%instobjectpk%grabbed_linkpk%grabbing_linkpk); + } + + bool operator==(const Grab grab) { + if (this->instobjectpk == grab.instobjectpk + && this->grabbed_linkpk == grab.grabbed_linkpk + && this->grabbing_linkpk == grab.grabbing_linkpk) { + return true; + } + return false; + } }; void SetTransform(const Transform& t); void SetDOFValues(); + virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + virtual void ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + std::vector dofvalues; std::string name; @@ -729,7 +750,6 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector tools; void Print(); }; - typedef boost::shared_ptr InstObjectPtr; SceneResource(ControllerClientPtr controller, const std::string& pk); virtual ~SceneResource() { @@ -744,6 +764,7 @@ class MUJINCLIENT_API SceneResource : public WebResource \param tasktype The type of task to create. Supported types are: - itlplanning */ + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype); virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname) @@ -778,7 +799,6 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); virtual SceneResourcePtr Copy(const std::string& name); - virtual void Grab(const std::string grabbingname, const std::string& grabbedname); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1f25a50c..f9dff60f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -163,6 +163,64 @@ void SceneResource::InstObject::SetDOFValues() controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } + +void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) +{ + SceneResource::InstObject::Grab grab; + grab.instobjectpk = grabbedobject->pk; + grab.grabbed_linkpk = grabbedobjectlinkpk; + grab.grabbing_linkpk = grabbinglinkpk; + for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { + if (this->grabs[igrab] == grab) { + std::cerr << grabbedobject->name << "is already grabbed" << std::endl; + return; + } + } + std::stringstream ss; + ss << "{\"grabs\":"; + ss << "["; + if( this->grabs.size() > 0 ) { + for (unsigned int i = 0; i < this->grabs.size(); i++) { + ss << this->grabs[i].Serialize() << ", "; + } + } + ss << grab.Serialize(); + ss << "]}"; + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); +} + +void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) +{ + SceneResource::InstObject::Grab grab; + grab.instobjectpk = grabbedobject->pk; + grab.grabbed_linkpk = grabbedobjectlinkpk; + grab.grabbing_linkpk = grabbinglinkpk; + for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { + if (this->grabs[igrab] == grab) { + this->grabs.erase(std::remove(this->grabs.begin(), this->grabs.end(), this->grabs[igrab]), this->grabs.end()); + std::stringstream ss; + ss << "{\"grabs\":"; + ss << "["; + if( this->grabs.size() > 0 ) { + for (unsigned int i = 0; i < this->grabs.size(); i++) { + ss << this->grabs[i].Serialize() << ", "; + } + if( igrab != this->grabs.size()-1) { + ss << ", "; + } + } + ss << "]}"; + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); + } + } + std::cerr << grabbedobject->name << "is not grabbed" << std::endl; + +} + void SceneResource::InstObject::Print() { std::cout << "dofvalues: "; @@ -413,6 +471,16 @@ void SceneResource::GetInstObjects(std::vector& in itool++; } + boost::property_tree::ptree& jsongrabs = v.second.get_child("grabs"); + instobject->grabs.resize(jsongrabs.size()); + size_t igrab = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vgrab, jsongrabs) { + instobject->grabs[igrab].instobjectpk = vgrab.second.get("instobjectpk"); + instobject->grabs[igrab].grabbed_linkpk = vgrab.second.get("grabbed_linkpk"); + instobject->grabs[igrab].grabbing_linkpk = vgrab.second.get("grabbing_linkpk"); + igrab++; + } + instobjects[i++] = instobject; } } @@ -437,10 +505,6 @@ SceneResourcePtr SceneResource::Copy(const std::string& name) return scene; } -void SceneResource::Grab(const std::string grabbingname, const std::string& grabbedname) -{ -} - TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From 3bcc33c738a31467bcbb92bf0d31261778ae99f3 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 16 Dec 2013 07:05:03 +0900 Subject: [PATCH 116/477] impl grab/release object --- .../mujincontrollerclient.h | 28 ++++++-- src/mujincontrollerclient.cpp | 72 +++++++++++++++++-- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 85c96207..d82f3237 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -123,6 +123,7 @@ class MUJINCLIENT_API MujinException : public std::exception }; class ControllerClient; +class ObjectResource; class RobotResource; class SceneResource; class TaskResource; @@ -131,6 +132,8 @@ class PlanningResultResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr ObjectResourcePtr; +typedef boost::weak_ptr ObjectResourceWeakPtr; typedef boost::shared_ptr RobotResourcePtr; typedef boost::weak_ptr RobotResourceWeakPtr; typedef boost::shared_ptr SceneResourcePtr; @@ -684,6 +687,8 @@ class MUJINCLIENT_API RobotResource : public ObjectResource class MUJINCLIENT_API SceneResource : public WebResource { public: + class InstObject; + typedef boost::shared_ptr InstObjectPtr; /// \brief nested resource in the scene describe an object in the scene class MUJINCLIENT_API InstObject : public WebResource { @@ -710,12 +715,28 @@ class MUJINCLIENT_API SceneResource : public WebResource class MUJINCLIENT_API Grab { public: std::string instobjectpk; ///< grabed_instobject_pk - std::string grabbed_link_pk; - std::string grabbing_link_pk; + std::string grabbed_linkpk; + std::string grabbing_linkpk; + + std::string Serialize() { + return boost::str(boost::format("{\"instobjectpk\": \"%s\", \"grabbed_linkpk\": \"%s\", \"grabbing_linkpk\": \"%s\"}")%instobjectpk%grabbed_linkpk%grabbing_linkpk); + } + + bool operator==(const Grab grab) { + if (this->instobjectpk == grab.instobjectpk + && this->grabbed_linkpk == grab.grabbed_linkpk + && this->grabbing_linkpk == grab.grabbing_linkpk) { + return true; + } + return false; + } }; void SetTransform(const Transform& t); void SetDOFValues(); + virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + virtual void ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + std::vector dofvalues; std::string name; @@ -729,7 +750,6 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector tools; void Print(); }; - typedef boost::shared_ptr InstObjectPtr; SceneResource(ControllerClientPtr controller, const std::string& pk); virtual ~SceneResource() { @@ -744,6 +764,7 @@ class MUJINCLIENT_API SceneResource : public WebResource \param tasktype The type of task to create. Supported types are: - itlplanning */ + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype); virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname) @@ -778,7 +799,6 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); virtual SceneResourcePtr Copy(const std::string& name); - virtual void Grab(const std::string grabbingname, const std::string& grabbedname); }; class MUJINCLIENT_API TaskResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1f25a50c..f9dff60f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -163,6 +163,64 @@ void SceneResource::InstObject::SetDOFValues() controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } + +void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) +{ + SceneResource::InstObject::Grab grab; + grab.instobjectpk = grabbedobject->pk; + grab.grabbed_linkpk = grabbedobjectlinkpk; + grab.grabbing_linkpk = grabbinglinkpk; + for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { + if (this->grabs[igrab] == grab) { + std::cerr << grabbedobject->name << "is already grabbed" << std::endl; + return; + } + } + std::stringstream ss; + ss << "{\"grabs\":"; + ss << "["; + if( this->grabs.size() > 0 ) { + for (unsigned int i = 0; i < this->grabs.size(); i++) { + ss << this->grabs[i].Serialize() << ", "; + } + } + ss << grab.Serialize(); + ss << "]}"; + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); +} + +void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) +{ + SceneResource::InstObject::Grab grab; + grab.instobjectpk = grabbedobject->pk; + grab.grabbed_linkpk = grabbedobjectlinkpk; + grab.grabbing_linkpk = grabbinglinkpk; + for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { + if (this->grabs[igrab] == grab) { + this->grabs.erase(std::remove(this->grabs.begin(), this->grabs.end(), this->grabs[igrab]), this->grabs.end()); + std::stringstream ss; + ss << "{\"grabs\":"; + ss << "["; + if( this->grabs.size() > 0 ) { + for (unsigned int i = 0; i < this->grabs.size(); i++) { + ss << this->grabs[i].Serialize() << ", "; + } + if( igrab != this->grabs.size()-1) { + ss << ", "; + } + } + ss << "]}"; + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); + } + } + std::cerr << grabbedobject->name << "is not grabbed" << std::endl; + +} + void SceneResource::InstObject::Print() { std::cout << "dofvalues: "; @@ -413,6 +471,16 @@ void SceneResource::GetInstObjects(std::vector& in itool++; } + boost::property_tree::ptree& jsongrabs = v.second.get_child("grabs"); + instobject->grabs.resize(jsongrabs.size()); + size_t igrab = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vgrab, jsongrabs) { + instobject->grabs[igrab].instobjectpk = vgrab.second.get("instobjectpk"); + instobject->grabs[igrab].grabbed_linkpk = vgrab.second.get("grabbed_linkpk"); + instobject->grabs[igrab].grabbing_linkpk = vgrab.second.get("grabbing_linkpk"); + igrab++; + } + instobjects[i++] = instobject; } } @@ -437,10 +505,6 @@ SceneResourcePtr SceneResource::Copy(const std::string& name) return scene; } -void SceneResource::Grab(const std::string grabbingname, const std::string& grabbedname) -{ -} - TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) { } From 1686f9ff632f8b6b6658ecc01b8d7a26b06e3dbe Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Wed, 18 Dec 2013 04:34:40 +0900 Subject: [PATCH 117/477] bugfix/fix some interface functions --- .../mujincontrollerclient.h | 6 +- src/mujincontrollerclient.cpp | 98 +++++-------------- 2 files changed, 29 insertions(+), 75 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index d82f3237..c3f584d8 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -724,8 +724,8 @@ class MUJINCLIENT_API SceneResource : public WebResource bool operator==(const Grab grab) { if (this->instobjectpk == grab.instobjectpk - && this->grabbed_linkpk == grab.grabbed_linkpk - && this->grabbing_linkpk == grab.grabbing_linkpk) { + && this->grabbed_linkpk == grab.grabbed_linkpk + && this->grabbing_linkpk == grab.grabbing_linkpk) { return true; } return false; @@ -748,7 +748,6 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector grabs; std::vector links; std::vector tools; - void Print(); }; SceneResource(ControllerClientPtr controller, const std::string& pk); @@ -795,6 +794,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the instance objects of the scene virtual void GetInstObjects(std::vector& instobjects); + virtual bool FindInstObject(std::string& name, InstObjectPtr& instobject); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f9dff60f..9d559678 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -170,6 +170,7 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str grab.instobjectpk = grabbedobject->pk; grab.grabbed_linkpk = grabbedobjectlinkpk; grab.grabbing_linkpk = grabbinglinkpk; + //TODO do not use this->grabs. this is the cached information for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { if (this->grabs[igrab] == grab) { std::cerr << grabbedobject->name << "is already grabbed" << std::endl; @@ -221,68 +222,6 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: } -void SceneResource::InstObject::Print() -{ - std::cout << "dofvalues: "; - for (int i = 0; i < dofvalues.size(); i++) { - std::cout << dofvalues[i] << ", "; - } - std::cout << std::endl; - std::cout << "name: " << name << std::endl; - std::cout << "pk: " << pk << std::endl; - std::cout << "object_pk: " << object_pk << std::endl; - std::cout << "reference_uri: " << reference_uri << std::endl; - - std::cout << "quaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << quaternion[i] << ", "; - } - std::cout << std::endl; - std::cout << "translate: "; - for (int i = 0; i < 3; i++) { - std::cout << translate[i] << ", "; - } - std::cout << std::endl; - - std::cout << "links: " << std::endl; - for (int i = 0; i < links.size(); i++) { - std::cout << "\tname: " << links[i].name << std::endl; - std::cout << "\tquaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << links[i].quaternion[i] << ", "; - } - std::cout << std::endl; - std::cout << "\ttranslate: "; - for (int i = 0; i < 3; i++) { - std::cout << links[i].translate[i] << ", "; - } - std::cout << std::endl; - } - - std::cout << "tools: " << std::endl; - for (int i = 0; i < tools.size(); i++) { - std::cout << "\tname: " << tools[i].name << std::endl; - - std::cout << "\tquaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << tools[i].quaternion[i] << ", "; - } - std::cout << std::endl; - - std::cout << "\ttranslate: "; - for (int i = 0; i < 3; i++) { - std::cout << tools[i].translate[i] << ", "; - } - std::cout << std::endl; - - std::cout << "\tdirection: "; - for (int i = 0; i < 3; i++) { - std::cout << tools[i].direction[i] << ", "; - } - std::cout << std::endl; - } -} - SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? @@ -428,16 +367,16 @@ void SceneResource::GetInstObjects(std::vector& in boost::property_tree::ptree& quatjson = vlink.second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->links[ilink].quaternion[iquat] = boost::lexical_cast(v.second.data()); + instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q.second.data()); } boost::property_tree::ptree& transjson = vlink.second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { BOOST_ASSERT(itrans<3); - instobject->links[ilink].translate[itrans] = boost::lexical_cast(v.second.data()); + instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t.second.data()); } ilink++; } @@ -450,23 +389,23 @@ void SceneResource::GetInstObjects(std::vector& in boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->tools[itool].quaternion[iquat] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q.second.data()); } boost::property_tree::ptree& transjson = vtool.second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { BOOST_ASSERT(itrans<3); - instobject->tools[itool].translate[itrans] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t.second.data()); } boost::property_tree::ptree& directionjson = vtool.second.get_child("direction"); int idir=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, directionjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &d, directionjson) { BOOST_ASSERT(idir<3); - instobject->tools[itool].direction[idir] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].direction[idir++] = boost::lexical_cast(d.second.data()); } itool++; } @@ -485,6 +424,21 @@ void SceneResource::GetInstObjects(std::vector& in } } +bool SceneResource::FindInstObject(std::string& name, SceneResource::InstObjectPtr& instobject) +{ + + std::vector instobjects; + this->GetInstObjects(instobjects); + for(size_t i = 0; i < instobjects.size(); ++i) { + std::size_t found_at = instobjects[i]->name.find(name); + if (found_at != std::string::npos) { + instobject = instobjects[i]; + return true; + } + } + return false; +} + SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) { GETCONTROLLERIMPL(); From f08498d6db2d5cc18629841d5892bc03c27389e1 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Wed, 18 Dec 2013 04:34:40 +0900 Subject: [PATCH 118/477] bugfix/fix some interface functions --- .../mujincontrollerclient.h | 6 +- src/mujincontrollerclient.cpp | 98 +++++-------------- 2 files changed, 29 insertions(+), 75 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index d82f3237..c3f584d8 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -724,8 +724,8 @@ class MUJINCLIENT_API SceneResource : public WebResource bool operator==(const Grab grab) { if (this->instobjectpk == grab.instobjectpk - && this->grabbed_linkpk == grab.grabbed_linkpk - && this->grabbing_linkpk == grab.grabbing_linkpk) { + && this->grabbed_linkpk == grab.grabbed_linkpk + && this->grabbing_linkpk == grab.grabbing_linkpk) { return true; } return false; @@ -748,7 +748,6 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector grabs; std::vector links; std::vector tools; - void Print(); }; SceneResource(ControllerClientPtr controller, const std::string& pk); @@ -795,6 +794,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the instance objects of the scene virtual void GetInstObjects(std::vector& instobjects); + virtual bool FindInstObject(std::string& name, InstObjectPtr& instobject); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f9dff60f..9d559678 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -170,6 +170,7 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str grab.instobjectpk = grabbedobject->pk; grab.grabbed_linkpk = grabbedobjectlinkpk; grab.grabbing_linkpk = grabbinglinkpk; + //TODO do not use this->grabs. this is the cached information for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { if (this->grabs[igrab] == grab) { std::cerr << grabbedobject->name << "is already grabbed" << std::endl; @@ -221,68 +222,6 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: } -void SceneResource::InstObject::Print() -{ - std::cout << "dofvalues: "; - for (int i = 0; i < dofvalues.size(); i++) { - std::cout << dofvalues[i] << ", "; - } - std::cout << std::endl; - std::cout << "name: " << name << std::endl; - std::cout << "pk: " << pk << std::endl; - std::cout << "object_pk: " << object_pk << std::endl; - std::cout << "reference_uri: " << reference_uri << std::endl; - - std::cout << "quaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << quaternion[i] << ", "; - } - std::cout << std::endl; - std::cout << "translate: "; - for (int i = 0; i < 3; i++) { - std::cout << translate[i] << ", "; - } - std::cout << std::endl; - - std::cout << "links: " << std::endl; - for (int i = 0; i < links.size(); i++) { - std::cout << "\tname: " << links[i].name << std::endl; - std::cout << "\tquaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << links[i].quaternion[i] << ", "; - } - std::cout << std::endl; - std::cout << "\ttranslate: "; - for (int i = 0; i < 3; i++) { - std::cout << links[i].translate[i] << ", "; - } - std::cout << std::endl; - } - - std::cout << "tools: " << std::endl; - for (int i = 0; i < tools.size(); i++) { - std::cout << "\tname: " << tools[i].name << std::endl; - - std::cout << "\tquaternion: "; - for (int i = 0; i < 4; i++) { - std::cout << tools[i].quaternion[i] << ", "; - } - std::cout << std::endl; - - std::cout << "\ttranslate: "; - for (int i = 0; i < 3; i++) { - std::cout << tools[i].translate[i] << ", "; - } - std::cout << std::endl; - - std::cout << "\tdirection: "; - for (int i = 0; i < 3; i++) { - std::cout << tools[i].direction[i] << ", "; - } - std::cout << std::endl; - } -} - SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) { // get something from the scene? @@ -428,16 +367,16 @@ void SceneResource::GetInstObjects(std::vector& in boost::property_tree::ptree& quatjson = vlink.second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->links[ilink].quaternion[iquat] = boost::lexical_cast(v.second.data()); + instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q.second.data()); } boost::property_tree::ptree& transjson = vlink.second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { BOOST_ASSERT(itrans<3); - instobject->links[ilink].translate[itrans] = boost::lexical_cast(v.second.data()); + instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t.second.data()); } ilink++; } @@ -450,23 +389,23 @@ void SceneResource::GetInstObjects(std::vector& in boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->tools[itool].quaternion[iquat] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q.second.data()); } boost::property_tree::ptree& transjson = vtool.second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, transjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { BOOST_ASSERT(itrans<3); - instobject->tools[itool].translate[itrans] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t.second.data()); } boost::property_tree::ptree& directionjson = vtool.second.get_child("direction"); int idir=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, directionjson) { + BOOST_FOREACH(boost::property_tree::ptree::value_type &d, directionjson) { BOOST_ASSERT(idir<3); - instobject->tools[itool].direction[idir] = boost::lexical_cast(v.second.data()); + instobject->tools[itool].direction[idir++] = boost::lexical_cast(d.second.data()); } itool++; } @@ -485,6 +424,21 @@ void SceneResource::GetInstObjects(std::vector& in } } +bool SceneResource::FindInstObject(std::string& name, SceneResource::InstObjectPtr& instobject) +{ + + std::vector instobjects; + this->GetInstObjects(instobjects); + for(size_t i = 0; i < instobjects.size(); ++i) { + std::size_t found_at = instobjects[i]->name.find(name); + if (found_at != std::string::npos) { + instobject = instobjects[i]; + return true; + } + } + return false; +} + SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) { GETCONTROLLERIMPL(); From 7dceb566ca5c3b7bd99789007193f125707dab43 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 17 Feb 2014 18:42:59 +0900 Subject: [PATCH 119/477] add api for fetching camera sensor data --- .../mujincontrollerclient.h | 29 +++++++++ src/mujincontrollerclient.cpp | 59 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c3f584d8..47cfffa4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -671,11 +671,40 @@ class MUJINCLIENT_API RobotResource : public ObjectResource }; typedef boost::shared_ptr ToolResourcePtr; + class MUJINCLIENT_API AttachedSensorResource : public WebResource { +public: + AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~AttachedSensorResource() { + } + + std::string name; + std::string frame_origin; + std::string pk; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + std::string sensortype; + + class SensorData { +public: + Real distortion_coeffs[5]; + std::string distortion_model; + Real focal_length; + int image_dimensions[3]; + Real intrinsic[6]; + Real measurement_time; + }; + SensorData sensordata; + }; + + typedef boost::shared_ptr AttachedSensorResourcePtr; + RobotResource(ControllerClientPtr controller, const std::string& pk); virtual ~RobotResource() { } virtual void GetTools(std::vector& tools); + virtual void GetAttachedSensors(std::vector& attachedsensors); // attachments // ikparams diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9d559678..62c4dbeb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -132,6 +132,65 @@ void RobotResource::GetTools(std::vector& tools) } } +RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk) +{ +} + +void RobotResource::GetAttachedSensors(std::vector& attachedsensors) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); + attachedsensors.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + attachedsensor->name = v.second.get("name"); + attachedsensor->pk = v.second.get("pk"); + attachedsensor->frame_origin = v.second.get("frame_origin"); + attachedsensor->sensortype = v.second.get("sensortype"); + + size_t iquaternion = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + attachedsensor->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + } + size_t itranslate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + attachedsensor->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + } + + size_t icoeff = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &coeff, v.second.get_child("sensordata.distortion_coeffs")) { + BOOST_ASSERT( icoeff < 5 ); + attachedsensor->sensordata.distortion_coeffs[icoeff++] = boost::lexical_cast(coeff.second.data()); + } + + attachedsensor->sensordata.distortion_model = v.second.get("sensordata.distortion_model"); + attachedsensor->sensordata.focal_length = (Real)v.second.get("sensordata.focal_length"); + attachedsensor->sensordata.measurement_time = (Real)v.second.get("sensordata.measurement_time"); + + size_t iintrinsic = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &intrinsic, v.second.get_child("sensordata.intrinsic")) { + BOOST_ASSERT( iintrinsic < 6 ); + attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic.second.data()); + } + + + size_t idim = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &imgdim, v.second.get_child("sensordata.image_dimensions")) { + BOOST_ASSERT( idim < 3 ); + attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); + } + + attachedsensors[i++] = attachedsensor; + } +} + SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) { } From aa04efe3a18fc2b12ca8cf66949156297784c8f9 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Mon, 17 Feb 2014 18:42:59 +0900 Subject: [PATCH 120/477] add api for fetching camera sensor data --- .../mujincontrollerclient.h | 29 +++++++++ src/mujincontrollerclient.cpp | 59 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c3f584d8..47cfffa4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -671,11 +671,40 @@ class MUJINCLIENT_API RobotResource : public ObjectResource }; typedef boost::shared_ptr ToolResourcePtr; + class MUJINCLIENT_API AttachedSensorResource : public WebResource { +public: + AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~AttachedSensorResource() { + } + + std::string name; + std::string frame_origin; + std::string pk; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + std::string sensortype; + + class SensorData { +public: + Real distortion_coeffs[5]; + std::string distortion_model; + Real focal_length; + int image_dimensions[3]; + Real intrinsic[6]; + Real measurement_time; + }; + SensorData sensordata; + }; + + typedef boost::shared_ptr AttachedSensorResourcePtr; + RobotResource(ControllerClientPtr controller, const std::string& pk); virtual ~RobotResource() { } virtual void GetTools(std::vector& tools); + virtual void GetAttachedSensors(std::vector& attachedsensors); // attachments // ikparams diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9d559678..62c4dbeb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -132,6 +132,65 @@ void RobotResource::GetTools(std::vector& tools) } } +RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk) +{ +} + +void RobotResource::GetAttachedSensors(std::vector& attachedsensors) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); + attachedsensors.resize(objects.size()); + size_t i = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), v.second.get("pk"))); + + + attachedsensor->name = v.second.get("name"); + attachedsensor->pk = v.second.get("pk"); + attachedsensor->frame_origin = v.second.get("frame_origin"); + attachedsensor->sensortype = v.second.get("sensortype"); + + size_t iquaternion = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + attachedsensor->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + } + size_t itranslate = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + attachedsensor->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + } + + size_t icoeff = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &coeff, v.second.get_child("sensordata.distortion_coeffs")) { + BOOST_ASSERT( icoeff < 5 ); + attachedsensor->sensordata.distortion_coeffs[icoeff++] = boost::lexical_cast(coeff.second.data()); + } + + attachedsensor->sensordata.distortion_model = v.second.get("sensordata.distortion_model"); + attachedsensor->sensordata.focal_length = (Real)v.second.get("sensordata.focal_length"); + attachedsensor->sensordata.measurement_time = (Real)v.second.get("sensordata.measurement_time"); + + size_t iintrinsic = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &intrinsic, v.second.get_child("sensordata.intrinsic")) { + BOOST_ASSERT( iintrinsic < 6 ); + attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic.second.data()); + } + + + size_t idim = 0; + BOOST_FOREACH(boost::property_tree::ptree::value_type &imgdim, v.second.get_child("sensordata.image_dimensions")) { + BOOST_ASSERT( idim < 3 ); + attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); + } + + attachedsensors[i++] = attachedsensor; + } +} + SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) { } From ada7c8b900e632f626140a3ab73495d72deb3f33 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 20 Feb 2014 23:41:10 +0900 Subject: [PATCH 121/477] add parameter named 'asus_depth_parameters --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 47cfffa4..1127af60 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -693,6 +693,7 @@ class MUJINCLIENT_API RobotResource : public ObjectResource int image_dimensions[3]; Real intrinsic[6]; Real measurement_time; + std::vector asus_depth_parameters; }; SensorData sensordata; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 62c4dbeb..2e81725f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -14,6 +14,7 @@ #include "common.h" #include "controllerclientimpl.h" #include // for sleep +#include namespace mujinclient { @@ -180,13 +181,32 @@ void RobotResource::GetAttachedSensors(std::vector& a attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic.second.data()); } - size_t idim = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &imgdim, v.second.get_child("sensordata.image_dimensions")) { BOOST_ASSERT( idim < 3 ); attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); } + if (boost::optional asus_depth_parameters_ptree = v.second.get_child_optional("sensordata.asus_depth_parameters")) { + std::string parameters_string = asus_depth_parameters_ptree.get().data(); + //std::cout << "asus param " << parameters_string << std::endl; + std::list results; + boost::split(results, parameters_string, boost::is_any_of(" ")); + results.remove(""); + attachedsensor->sensordata.asus_depth_parameters.resize(results.size()); + size_t iparam = 0; + BOOST_FOREACH(std::string p, results) { + //std::cout << "'"<< p << "'"<< std::endl; + try { + attachedsensor->sensordata.asus_depth_parameters[iparam++] = boost::lexical_cast(p); + } catch (...){ + //lexical_cast fails... + } + } + } else { + //std::cout << "no asus param" << std::endl; + } + attachedsensors[i++] = attachedsensor; } } From 1592071f25da0e24ecb91498eacb6e083457cca3 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 20 Feb 2014 23:41:10 +0900 Subject: [PATCH 122/477] add parameter named 'asus_depth_parameters --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 47cfffa4..1127af60 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -693,6 +693,7 @@ class MUJINCLIENT_API RobotResource : public ObjectResource int image_dimensions[3]; Real intrinsic[6]; Real measurement_time; + std::vector asus_depth_parameters; }; SensorData sensordata; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 62c4dbeb..2e81725f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -14,6 +14,7 @@ #include "common.h" #include "controllerclientimpl.h" #include // for sleep +#include namespace mujinclient { @@ -180,13 +181,32 @@ void RobotResource::GetAttachedSensors(std::vector& a attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic.second.data()); } - size_t idim = 0; BOOST_FOREACH(boost::property_tree::ptree::value_type &imgdim, v.second.get_child("sensordata.image_dimensions")) { BOOST_ASSERT( idim < 3 ); attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); } + if (boost::optional asus_depth_parameters_ptree = v.second.get_child_optional("sensordata.asus_depth_parameters")) { + std::string parameters_string = asus_depth_parameters_ptree.get().data(); + //std::cout << "asus param " << parameters_string << std::endl; + std::list results; + boost::split(results, parameters_string, boost::is_any_of(" ")); + results.remove(""); + attachedsensor->sensordata.asus_depth_parameters.resize(results.size()); + size_t iparam = 0; + BOOST_FOREACH(std::string p, results) { + //std::cout << "'"<< p << "'"<< std::endl; + try { + attachedsensor->sensordata.asus_depth_parameters[iparam++] = boost::lexical_cast(p); + } catch (...){ + //lexical_cast fails... + } + } + } else { + //std::cout << "no asus param" << std::endl; + } + attachedsensors[i++] = attachedsensor; } } From 7cc69e9a25f0eae6f61cee1bc194832a0c4b3028 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 28 Feb 2014 12:55:39 +0900 Subject: [PATCH 123/477] added more examples; minor changes to client --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1127af60..46e523f5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -824,7 +824,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the instance objects of the scene virtual void GetInstObjects(std::vector& instobjects); - virtual bool FindInstObject(std::string& name, InstObjectPtr& instobject); + virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 2e81725f..5120f971 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -503,7 +503,7 @@ void SceneResource::GetInstObjects(std::vector& in } } -bool SceneResource::FindInstObject(std::string& name, SceneResource::InstObjectPtr& instobject) +bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstObjectPtr& instobject) { std::vector instobjects; From 7431fc9bf8741e4d50334d285ec88ae328a00b25 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 28 Feb 2014 12:55:39 +0900 Subject: [PATCH 124/477] added more examples; minor changes to client --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1127af60..46e523f5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -824,7 +824,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the instance objects of the scene virtual void GetInstObjects(std::vector& instobjects); - virtual bool FindInstObject(std::string& name, InstObjectPtr& instobject); + virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 2e81725f..5120f971 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -503,7 +503,7 @@ void SceneResource::GetInstObjects(std::vector& in } } -bool SceneResource::FindInstObject(std::string& name, SceneResource::InstObjectPtr& instobject) +bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstObjectPtr& instobject) { std::vector instobjects; From 2f2e47c8d158b57c0103b2f88351d0c54b81e605 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 28 Feb 2014 17:09:32 +0900 Subject: [PATCH 125/477] renamed destructor; updated examples --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 46e523f5..fab4eb34 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -981,7 +981,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources -MUJINCLIENT_API void ControllerClientDestroy(); +MUJINCLIENT_API void DestroyControllerClient(); /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5120f971..eb6b38a2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -848,7 +848,7 @@ ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); } -void ControllerClientDestroy() +void DestroyControllerClient() { } From c694f89ebea4c68df8ed6714476e80980f915efe Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 28 Feb 2014 17:09:32 +0900 Subject: [PATCH 126/477] renamed destructor; updated examples --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 46e523f5..fab4eb34 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -981,7 +981,7 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); /// \brief called at the very end of an application to safely destroy all controller client resources -MUJINCLIENT_API void ControllerClientDestroy(); +MUJINCLIENT_API void DestroyControllerClient(); /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5120f971..eb6b38a2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -848,7 +848,7 @@ ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); } -void ControllerClientDestroy() +void DestroyControllerClient() { } From 45c06b0106699da310d1d6308bfa006d6a55267c Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Tue, 18 Mar 2014 15:42:28 +0900 Subject: [PATCH 127/477] deprecated old destructor --- .../mujincontrollerclient/mujincontrollerclient.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index fab4eb34..82358602 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -34,6 +34,12 @@ #else #endif +#if defined(__GNUC__) +#define MUJINCLIENT_DEPRECATED __attribute__((deprecated)) +#else +#define MUJINCLIENT_DEPRECATED +#endif + #include #include #include @@ -983,6 +989,12 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); +/// \deprecated 14/03/14 +inline void ControllerClientDestroy() MUJINCLIENT_DEPRECATED +{ + DestroyControllerClient(); +} + /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); From 43fdd4886bb076d97e54634c4bebbfd55b8c8d8f Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Tue, 18 Mar 2014 15:42:28 +0900 Subject: [PATCH 128/477] deprecated old destructor --- .../mujincontrollerclient/mujincontrollerclient.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index fab4eb34..82358602 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -34,6 +34,12 @@ #else #endif +#if defined(__GNUC__) +#define MUJINCLIENT_DEPRECATED __attribute__((deprecated)) +#else +#define MUJINCLIENT_DEPRECATED +#endif + #include #include #include @@ -983,6 +989,12 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); +/// \deprecated 14/03/14 +inline void ControllerClientDestroy() MUJINCLIENT_DEPRECATED +{ + DestroyControllerClient(); +} + /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); From 856388c3a4d558364723ad34ba2c27481bbc143a Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Tue, 25 Mar 2014 23:34:54 +0900 Subject: [PATCH 129/477] refactored binpickingtask to support both http and zmq based operations; to be tested --- include/mujincontrollerclient/mujincontrollerclient.h | 11 +++++++---- src/mujincontrollerclient.cpp | 5 +++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 82358602..732f9999 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -58,6 +58,12 @@ #include #include +#define FOREACH(it, v) for(BOOST_TYPEOF(v) ::iterator it = (v).begin(); it != (v).end(); (it)++) +#define FOREACH_NOINC(it, v) for(BOOST_TYPEOF(v) ::iterator it = (v).begin(); it != (v).end(); ) + +#define FOREACHC(it, v) for(BOOST_TYPEOF(v) ::const_iterator it = (v).begin(); it != (v).end(); (it)++) +#define FOREACHC_NOINC(it, v) for(BOOST_TYPEOF(v) ::const_iterator it = (v).begin(); it != (v).end(); ) + namespace mujinclient { #include @@ -990,10 +996,7 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us MUJINCLIENT_API void DestroyControllerClient(); /// \deprecated 14/03/14 -inline void ControllerClientDestroy() MUJINCLIENT_DEPRECATED -{ - DestroyControllerClient(); -} +MUJINCLIENT_API void ControllerClientDestroy() MUJINCLIENT_DEPRECATED; /// \brief Compute a 3x4 matrix from a Transform MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index eb6b38a2..4dea557c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -848,6 +848,11 @@ ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); } +void ControllerClientDestroy() +{ + DestroyControllerClient(); +} + void DestroyControllerClient() { } From 27e9d00356e579368da86e9df0e4ca47ad0c207e Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 3 Apr 2014 20:03:11 +0900 Subject: [PATCH 130/477] add an sample to compute image_roi --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 732f9999..811b8bf1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -692,7 +692,7 @@ class MUJINCLIENT_API RobotResource : public ObjectResource std::string name; std::string frame_origin; std::string pk; - Real direction[3]; + //Real direction[3]; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; std::string sensortype; From 32bef28ae99b9af318944b6c5b0099e3ff9a8739 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Tue, 8 Apr 2014 19:14:18 +0900 Subject: [PATCH 131/477] post to job instead of task resource --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 82358602..030aaf3f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -990,7 +990,7 @@ MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& us MUJINCLIENT_API void DestroyControllerClient(); /// \deprecated 14/03/14 -inline void ControllerClientDestroy() MUJINCLIENT_DEPRECATED +MUJINCLIENT_DEPRECATED inline void ControllerClientDestroy() { DestroyControllerClient(); } From 715091e91f827b0edbb118e7f838212320fea569 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Tue, 8 Apr 2014 19:16:19 +0900 Subject: [PATCH 132/477] post to job instead of task resource --- src/mujincontrollerclient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index eb6b38a2..55e2c442 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -546,7 +546,8 @@ bool TaskResource::Execute() { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt, 200); + controller->CallPost("job/", str(boost::format("{\"resource_type\":\"task\", \"target_pk\":%s}")%GetPrimaryKey()), pt, 200); + _jobpk = pt.get("jobpk"); return true; } From 31e11e448279eaa6d238c52d57a47d171156699c Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 9 Apr 2014 01:43:48 +0900 Subject: [PATCH 133/477] post to job instead of task resource; merged binpickingtaskhttp.h into binpickingtask.h; added timeout to ExecuteCommand; added mujinclient::utils global methods (GetSensorData, DeleteObject, UpdateObjects) --- .../mujincontrollerclient.h | 35 ++++++++--- src/mujincontrollerclient.cpp | 58 ++++++++++++++----- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 811b8bf1..66278a29 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -84,6 +84,11 @@ enum MujinErrorCode { MEC_HandEyeCalibrationError=17 ///< HandEye Calibration failed }; +enum TaskResourceOptions +{ + TRO_EnableZMQ=1, ///< create a task resource with zeromq client +}; + inline const char* GetErrorCodeString(MujinErrorCode error) { switch(error) { @@ -139,8 +144,11 @@ class ObjectResource; class RobotResource; class SceneResource; class TaskResource; +class BinPickingTaskResource; +class BinPickingTaskZmqResource; class OptimizationResource; class PlanningResultResource; +class BinPickingResultResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; @@ -152,10 +160,16 @@ typedef boost::shared_ptr SceneResourcePtr; typedef boost::weak_ptr SceneResourceWeakPtr; typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; +typedef boost::shared_ptr BinPickingTaskResourcePtr; +typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; +typedef boost::shared_ptr BinPickingTaskZmqResourcePtr; +typedef boost::weak_ptr BinPickingTaskZmqResourceWeakPtr; typedef boost::shared_ptr OptimizationResourcePtr; typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; typedef boost::weak_ptr PlanningResultResourceWeakPtr; +typedef boost::shared_ptr BinPickingResultResourcePtr; +typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef double Real; /// \brief status code for a job @@ -806,14 +820,14 @@ class MUJINCLIENT_API SceneResource : public WebResource - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname) + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) { - return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType()); + return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType(), options); } - virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname); + virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname, int options=0); /** \brief Gets or creates the a task part of the scene @@ -822,14 +836,19 @@ class MUJINCLIENT_API SceneResource : public WebResource \param tasktype The type of task to create. Supported types are: - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options=0); - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname) + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, int options=0) { - return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType()); + return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType(), options); } - virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname); + virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); + + + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options=0); + /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 4dea557c..89014967 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -15,6 +15,7 @@ #include "controllerclientimpl.h" #include // for sleep #include +#include "binpickingtaskzmq.h" namespace mujinclient { @@ -199,7 +200,7 @@ void RobotResource::GetAttachedSensors(std::vector& a //std::cout << "'"<< p << "'"<< std::endl; try { attachedsensor->sensordata.asus_depth_parameters[iparam++] = boost::lexical_cast(p); - } catch (...){ + } catch (...) { //lexical_cast fails... } } @@ -307,7 +308,7 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& //this->Get(""); } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); @@ -315,21 +316,38 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); // task exists boost::property_tree::ptree& objects = pt.get_child("objects"); + std::string pk; if( objects.size() > 0 ) { - std::string pk = objects.begin()->second.get("pk"); + pk = objects.begin()->second.get("pk"); std::string currenttasktype = objects.begin()->second.get("tasktype"); if( currenttasktype != tasktype ) { throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype, MEC_InvalidState); } + } + else { + pt.clear(); + controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype%GetPrimaryKey()), pt); + pk = pt.get("pk"); + } + + if( pk.size() == 0 ) { + return TaskResourcePtr(); + } + + if( tasktype == "binpicking" ) { + BinPickingTaskResourcePtr task; + if( options & 1 ) { + task.reset(new BinPickingTaskZmqResource(GetController(), pk)); + } + else { + task.reset(new BinPickingTaskResource(GetController(), pk)); + } + return task; + } + else { TaskResourcePtr task(new TaskResource(GetController(), pk)); return task; } - - pt.clear(); - controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype%GetPrimaryKey()), pt); - std::string pk = pt.get("pk"); - TaskResourcePtr task(new TaskResource(GetController(), pk)); - return task; } void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) @@ -360,7 +378,7 @@ void SceneResource::SetInstObjectsState(const std::vectorCallPut(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } -TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname) +TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname, int options) { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); @@ -377,18 +395,28 @@ TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname) return task; } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) { std::string taskname_utf8; utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetOrCreateTaskFromName_UTF8(taskname_utf8, tasktype); + return GetOrCreateTaskFromName_UTF8(taskname_utf8, tasktype, options); } -TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& taskname) +TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& taskname, int options) { std::string taskname_utf8; utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetTaskFromName_UTF8(taskname_utf8); + return GetTaskFromName_UTF8(taskname_utf8, options); +} + +BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options) +{ + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, "binpicking", options)); +} + +BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options) +{ + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, "binpicking", options)); } void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) @@ -546,7 +574,7 @@ bool TaskResource::Execute() { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPost(str(boost::format("task/%s/")%GetPrimaryKey()), std::string(), pt, 200); + controller->CallPost("job/", str(boost::format("{\"resource_type\":\"task\", \"target_pk\":%s}")%GetPrimaryKey()), pt, 200); _jobpk = pt.get("jobpk"); return true; } From c69b43fed22d7a7ad1a31bbe5cd192a867e98a08 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 17 Apr 2014 15:32:57 +0900 Subject: [PATCH 134/477] add a sensordata.extra_parameters attribute --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 66278a29..aa7e2f64 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -719,7 +719,7 @@ class MUJINCLIENT_API RobotResource : public ObjectResource int image_dimensions[3]; Real intrinsic[6]; Real measurement_time; - std::vector asus_depth_parameters; + std::vector extra_parameters; }; SensorData sensordata; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 89014967..3ae403fd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -188,18 +188,18 @@ void RobotResource::GetAttachedSensors(std::vector& a attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); } - if (boost::optional asus_depth_parameters_ptree = v.second.get_child_optional("sensordata.asus_depth_parameters")) { - std::string parameters_string = asus_depth_parameters_ptree.get().data(); - //std::cout << "asus param " << parameters_string << std::endl; + if (boost::optional extra_parameters_ptree = v.second.get_child_optional("sensordata.extra_parameters")) { + std::string parameters_string = extra_parameters_ptree.get().data(); + //std::cout << "extra param " << parameters_string << std::endl; std::list results; boost::split(results, parameters_string, boost::is_any_of(" ")); results.remove(""); - attachedsensor->sensordata.asus_depth_parameters.resize(results.size()); + attachedsensor->sensordata.extra_parameters.resize(results.size()); size_t iparam = 0; BOOST_FOREACH(std::string p, results) { //std::cout << "'"<< p << "'"<< std::endl; try { - attachedsensor->sensordata.asus_depth_parameters[iparam++] = boost::lexical_cast(p); + attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); } catch (...) { //lexical_cast fails... } From 81b4003a15708c6f2bc1a07d45d7aa39d0ac45ae Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 7 May 2014 23:23:40 +0900 Subject: [PATCH 135/477] converted BOOST_FOREACH to FOREACH --- .../mujincontrollerclient.h | 7 +- src/mujincontrollerclient.cpp | 224 +++++++++--------- 2 files changed, 115 insertions(+), 116 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index aa7e2f64..3580cb58 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -58,11 +58,10 @@ #include #include -#define FOREACH(it, v) for(BOOST_TYPEOF(v) ::iterator it = (v).begin(); it != (v).end(); (it)++) -#define FOREACH_NOINC(it, v) for(BOOST_TYPEOF(v) ::iterator it = (v).begin(); it != (v).end(); ) +#define FOREACH(it, v) for(typeof((v).begin())it = (v).begin(); it != (v).end(); (it)++) +#define FOREACH_NOINC(it, v) for(typeof((v).begin())it = (v).begin(); it != (v).end(); ) -#define FOREACHC(it, v) for(BOOST_TYPEOF(v) ::const_iterator it = (v).begin(); it != (v).end(); (it)++) -#define FOREACHC_NOINC(it, v) for(BOOST_TYPEOF(v) ::const_iterator it = (v).begin(); it != (v).end(); ) +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) namespace mujinclient { diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 3ae403fd..df45fb47 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -69,18 +69,18 @@ void ObjectResource::GetLinks(std::vector& link boost::property_tree::ptree& objects = pt.get_child("links"); links.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v.second.get("pk"))); + FOREACH(v, objects) { + LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v->second.get("pk"))); - link->name = v.second.get("name"); - link->pk = v.second.get("pk"); + link->name = v->second.get("name"); + link->pk = v->second.get("pk"); - boost::property_tree::ptree& jsonattachments = v.second.get_child("attachmentpks"); + boost::property_tree::ptree& jsonattachments = v->second.get_child("attachmentpks"); link->attachmentpks.resize(jsonattachments.size()); size_t iattch = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &att, jsonattachments) { - link->attachmentpks[iattch++] = att.second.data(); + FOREACH(att, jsonattachments) { + link->attachmentpks[iattch++] = att->second.data(); } //TODO transforms @@ -104,30 +104,30 @@ void RobotResource::GetTools(std::vector& tools) boost::property_tree::ptree& objects = pt.get_child("tools"); tools.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), v.second.get("pk"))); + FOREACH(v, objects) { + ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), v->second.get("pk"))); - tool->name = v.second.get("name"); - tool->pk = v.second.get("pk"); - tool->frame_origin = v.second.get("frame_origin"); - tool->frame_tip = v.second.get("frame_tip"); + tool->name = v->second.get("name"); + tool->pk = v->second.get("pk"); + tool->frame_origin = v->second.get("frame_origin"); + tool->frame_tip = v->second.get("frame_tip"); - boost::property_tree::ptree& jsondirection = v.second.get_child("direction"); + boost::property_tree::ptree& jsondirection = v->second.get_child("direction"); size_t idir = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vdir, jsondirection) { - tool->direction[idir++] = boost::lexical_cast(vdir.second.data()); + FOREACH(vdir, jsondirection) { + tool->direction[idir++] = boost::lexical_cast(vdir->second.data()); } size_t iquaternion = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + FOREACH(vquaternion, v->second.get_child("quaternion")) { BOOST_ASSERT( iquaternion < 4 ); - tool->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + tool->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); } size_t itranslate = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + FOREACH(vtranslate, v->second.get_child("translate")) { BOOST_ASSERT( itranslate < 3 ); - tool->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + tool->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); } tools[i++] = tool; @@ -146,49 +146,49 @@ void RobotResource::GetAttachedSensors(std::vector& a boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); attachedsensors.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), v.second.get("pk"))); + FOREACH(v, objects) { + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), v->second.get("pk"))); - attachedsensor->name = v.second.get("name"); - attachedsensor->pk = v.second.get("pk"); - attachedsensor->frame_origin = v.second.get("frame_origin"); - attachedsensor->sensortype = v.second.get("sensortype"); + attachedsensor->name = v->second.get("name"); + attachedsensor->pk = v->second.get("pk"); + attachedsensor->frame_origin = v->second.get("frame_origin"); + attachedsensor->sensortype = v->second.get("sensortype"); size_t iquaternion = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + FOREACH(vquaternion, v->second.get_child("quaternion")) { BOOST_ASSERT( iquaternion < 4 ); - attachedsensor->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + attachedsensor->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); } size_t itranslate = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + FOREACH(vtranslate, v->second.get_child("translate")) { BOOST_ASSERT( itranslate < 3 ); - attachedsensor->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + attachedsensor->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); } size_t icoeff = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &coeff, v.second.get_child("sensordata.distortion_coeffs")) { + FOREACH(coeff, v->second.get_child("sensordata.distortion_coeffs")) { BOOST_ASSERT( icoeff < 5 ); - attachedsensor->sensordata.distortion_coeffs[icoeff++] = boost::lexical_cast(coeff.second.data()); + attachedsensor->sensordata.distortion_coeffs[icoeff++] = boost::lexical_cast(coeff->second.data()); } - attachedsensor->sensordata.distortion_model = v.second.get("sensordata.distortion_model"); - attachedsensor->sensordata.focal_length = (Real)v.second.get("sensordata.focal_length"); - attachedsensor->sensordata.measurement_time = (Real)v.second.get("sensordata.measurement_time"); + attachedsensor->sensordata.distortion_model = v->second.get("sensordata.distortion_model"); + attachedsensor->sensordata.focal_length = (Real)v->second.get("sensordata.focal_length"); + attachedsensor->sensordata.measurement_time = (Real)v->second.get("sensordata.measurement_time"); size_t iintrinsic = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &intrinsic, v.second.get_child("sensordata.intrinsic")) { + FOREACH(intrinsic, v->second.get_child("sensordata.intrinsic")) { BOOST_ASSERT( iintrinsic < 6 ); - attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic.second.data()); + attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic->second.data()); } size_t idim = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &imgdim, v.second.get_child("sensordata.image_dimensions")) { + FOREACH(imgdim, v->second.get_child("sensordata.image_dimensions")) { BOOST_ASSERT( idim < 3 ); - attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim.second.data()); + attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim->second.data()); } - if (boost::optional extra_parameters_ptree = v.second.get_child_optional("sensordata.extra_parameters")) { + if (boost::optional extra_parameters_ptree = v->second.get_child_optional("sensordata.extra_parameters")) { std::string parameters_string = extra_parameters_ptree.get().data(); //std::cout << "extra param " << parameters_string << std::endl; std::list results; @@ -427,8 +427,8 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) boost::property_tree::ptree& objects = pt.get_child("objects"); taskkeys.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - taskkeys[i++] = v.second.get("pk"); + FOREACH(v, objects) { + taskkeys[i++] = v->second.get("pk"); } } @@ -440,90 +440,90 @@ void SceneResource::GetInstObjects(std::vector& in boost::property_tree::ptree& objects = pt.get_child("instobjects"); instobjects.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v.second.get("pk"))); + FOREACH(v, objects) { + InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v->second.get("pk"))); - instobject->name = v.second.get("name"); - instobject->pk = v.second.get("pk"); - instobject->object_pk = v.second.get("object_pk"); - instobject->reference_uri = v.second.get("reference_uri"); + instobject->name = v->second.get("name"); + instobject->pk = v->second.get("pk"); + instobject->object_pk = v->second.get("object_pk"); + instobject->reference_uri = v->second.get("reference_uri"); - boost::property_tree::ptree& jsondofvalues = v.second.get_child("dofvalues"); + boost::property_tree::ptree& jsondofvalues = v->second.get_child("dofvalues"); instobject->dofvalues.resize(jsondofvalues.size()); size_t idof = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vdof, jsondofvalues) { - instobject->dofvalues[idof++] = boost::lexical_cast(vdof.second.data()); + FOREACH(vdof, jsondofvalues) { + instobject->dofvalues[idof++] = boost::lexical_cast(vdof->second.data()); } size_t iquaternion = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vquaternion, v.second.get_child("quaternion")) { + FOREACH(vquaternion, v->second.get_child("quaternion")) { BOOST_ASSERT( iquaternion < 4 ); - instobject->quaternion[iquaternion++] = boost::lexical_cast(vquaternion.second.data()); + instobject->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); } size_t itranslate = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vtranslate, v.second.get_child("translate")) { + FOREACH(vtranslate, v->second.get_child("translate")) { BOOST_ASSERT( itranslate < 3 ); - instobject->translate[itranslate++] = boost::lexical_cast(vtranslate.second.data()); + instobject->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); } - boost::property_tree::ptree& jsonlinks = v.second.get_child("links"); + boost::property_tree::ptree& jsonlinks = v->second.get_child("links"); instobject->links.resize(jsonlinks.size()); size_t ilink = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vlink, jsonlinks) { - instobject->links[ilink].name = vlink.second.get("name"); + FOREACH(vlink, jsonlinks) { + instobject->links[ilink].name = vlink->second.get("name"); - boost::property_tree::ptree& quatjson = vlink.second.get_child("quaternion"); + boost::property_tree::ptree& quatjson = vlink->second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { + FOREACH(q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q.second.data()); + instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q->second.data()); } - boost::property_tree::ptree& transjson = vlink.second.get_child("translate"); + boost::property_tree::ptree& transjson = vlink->second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { + FOREACH(t, transjson) { BOOST_ASSERT(itrans<3); - instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t.second.data()); + instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t->second.data()); } ilink++; } - boost::property_tree::ptree& jsontools = v.second.get_child("tools"); + boost::property_tree::ptree& jsontools = v->second.get_child("tools"); instobject->tools.resize(jsontools.size()); size_t itool = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vtool, jsontools) { - instobject->tools[itool].name = vtool.second.get("name"); + FOREACH(vtool, jsontools) { + instobject->tools[itool].name = vtool->second.get("name"); - boost::property_tree::ptree& quatjson = vtool.second.get_child("quaternion"); + boost::property_tree::ptree& quatjson = vtool->second.get_child("quaternion"); int iquat=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &q, quatjson) { + FOREACH(q, quatjson) { BOOST_ASSERT(iquat<4); - instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q.second.data()); + instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q->second.data()); } - boost::property_tree::ptree& transjson = vtool.second.get_child("translate"); + boost::property_tree::ptree& transjson = vtool->second.get_child("translate"); int itrans=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &t, transjson) { + FOREACH(t, transjson) { BOOST_ASSERT(itrans<3); - instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t.second.data()); + instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t->second.data()); } - boost::property_tree::ptree& directionjson = vtool.second.get_child("direction"); + boost::property_tree::ptree& directionjson = vtool->second.get_child("direction"); int idir=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &d, directionjson) { + FOREACH(d, directionjson) { BOOST_ASSERT(idir<3); - instobject->tools[itool].direction[idir++] = boost::lexical_cast(d.second.data()); + instobject->tools[itool].direction[idir++] = boost::lexical_cast(d->second.data()); } itool++; } - boost::property_tree::ptree& jsongrabs = v.second.get_child("grabs"); + boost::property_tree::ptree& jsongrabs = v->second.get_child("grabs"); instobject->grabs.resize(jsongrabs.size()); size_t igrab = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &vgrab, jsongrabs) { - instobject->grabs[igrab].instobjectpk = vgrab.second.get("instobjectpk"); - instobject->grabs[igrab].grabbed_linkpk = vgrab.second.get("grabbed_linkpk"); - instobject->grabs[igrab].grabbing_linkpk = vgrab.second.get("grabbing_linkpk"); + FOREACH(vgrab, jsongrabs) { + instobject->grabs[igrab].instobjectpk = vgrab->second.get("instobjectpk"); + instobject->grabs[igrab].grabbed_linkpk = vgrab->second.get("grabbed_linkpk"); + instobject->grabs[igrab].grabbing_linkpk = vgrab->second.get("grabbing_linkpk"); igrab++; } @@ -647,8 +647,8 @@ void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimiza boost::property_tree::ptree& objects = pt.get_child("objects"); optimizationkeys.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - optimizationkeys[i++] = v.second.get("pk"); + FOREACH(v, objects) { + optimizationkeys[i++] = v->second.get("pk"); } } @@ -663,27 +663,27 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) } boost::property_tree::ptree& taskparametersjson = pt.get_child("taskparameters"); taskparameters.SetDefaults(); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, taskparametersjson) { - if( v.first == "startfromcurrent" ) { - taskparameters.startfromcurrent = v.second.data() == std::string("True"); + FOREACH(v, taskparametersjson) { + if( v->first == "startfromcurrent" ) { + taskparameters.startfromcurrent = v->second.data() == std::string("True"); } - else if( v.first == "returntostart" ) { - taskparameters.returntostart = v.second.data() == std::string("True"); + else if( v->first == "returntostart" ) { + taskparameters.returntostart = v->second.data() == std::string("True"); } - else if( v.first == "ignorefigure" ) { - taskparameters.ignorefigure = v.second.data() == std::string("True"); + else if( v->first == "ignorefigure" ) { + taskparameters.ignorefigure = v->second.data() == std::string("True"); } - else if( v.first == "vrcruns" ) { - taskparameters.vrcruns = boost::lexical_cast(v.second.data()); + else if( v->first == "vrcruns" ) { + taskparameters.vrcruns = boost::lexical_cast(v->second.data()); } - else if( v.first == "unit" ) { - taskparameters.unit = v.second.data(); + else if( v->first == "unit" ) { + taskparameters.unit = v->second.data(); } - else if( v.first == "optimizationvalue" ) { - taskparameters.optimizationvalue = boost::lexical_cast(v.second.data()); + else if( v->first == "optimizationvalue" ) { + taskparameters.optimizationvalue = boost::lexical_cast(v->second.data()); } - else if( v.first == "program" ) { - taskparameters.program = v.second.data(); + else if( v->first == "program" ) { + taskparameters.program = v->second.data(); } } } @@ -796,8 +796,8 @@ void OptimizationResource::GetResults(std::vector& re boost::property_tree::ptree& objects = pt.get_child("objects"); results.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - results[i++].reset(new PlanningResultResource(controller, v.second.get("pk"))); + FOREACH(v, objects) { + results[i++].reset(new PlanningResultResource(controller, v->second.get("pk"))); } } @@ -816,15 +816,15 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); boost::property_tree::ptree& envstatejson = pt.get_child("envstate"); envstate.clear(); - BOOST_FOREACH(boost::property_tree::ptree::value_type &objstatejson, envstatejson) { + FOREACH(objstatejson, envstatejson) { InstanceObjectState objstate; - std::string name = objstatejson.second.get("name"); - boost::property_tree::ptree& quatjson = objstatejson.second.get_child("quat_"); + std::string name = objstatejson->second.get("name"); + boost::property_tree::ptree& quatjson = objstatejson->second.get_child("quat_"); int iquat=0; Real dist2 = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, quatjson) { + FOREACH(v, quatjson) { BOOST_ASSERT(iquat<4); - Real f = boost::lexical_cast(v.second.data()); + Real f = boost::lexical_cast(v->second.data()); dist2 += f * f; objstate.transform.quaternion[iquat++] = f; } @@ -836,10 +836,10 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) objstate.transform.quaternion[2] *= fnorm; objstate.transform.quaternion[3] *= fnorm; } - boost::property_tree::ptree& translationjson = objstatejson.second.get_child("translation_"); + boost::property_tree::ptree& translationjson = objstatejson->second.get_child("translation_"); int itranslation=0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, translationjson) { - objstate.transform.translate[itranslation++] = boost::lexical_cast(v.second.data()); + FOREACH(v, translationjson) { + objstate.transform.translate[itranslation++] = boost::lexical_cast(v->second.data()); } envstate[name] = objstate; } @@ -863,10 +863,10 @@ void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, cons boost::property_tree::ptree pt; programs.programs.clear(); controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), pt); - BOOST_FOREACH(boost::property_tree::ptree::value_type &robotdatajson, pt) { - std::string robotpk = robotdatajson.first; - std::string program = robotdatajson.second.get("program"); - std::string currenttype = robotdatajson.second.get("type"); + FOREACH(robotdatajson, pt) { + std::string robotpk = robotdatajson->first; + std::string program = robotdatajson->second.get("program"); + std::string currenttype = robotdatajson->second.get("type"); programs.programs[robotpk] = RobotProgramData(program, currenttype); } } From 5567699f87832d33be26f76f2a7fda5d1ae103b0 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 7 May 2014 23:23:40 +0900 Subject: [PATCH 136/477] converted BOOST_FOREACH to FOREACH --- src/controllerclientimpl.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 448aeeb0..3bcdecc7 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -386,13 +386,13 @@ void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, boost::property_tree::ptree& objects = pt.get_child("objects"); size_t i = 0; statuses.resize(objects.size()); - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - statuses[i].pk = v.second.get("pk"); - statuses[i].code = static_cast(boost::lexical_cast(v.second.get("status"))); - statuses[i].type = v.second.get("fnname"); - statuses[i].elapsedtime = v.second.get("elapsedtime"); + FOREACH(v, objects) { + statuses[i].pk = v->second.get("pk"); + statuses[i].code = static_cast(boost::lexical_cast(v->second.get("status"))); + statuses[i].type = v->second.get("fnname"); + statuses[i].elapsedtime = v->second.get("elapsedtime"); if( options & 1 ) { - statuses[i].message = v.second.get("status_text"); + statuses[i].message = v->second.get("status_text"); } i++; } @@ -405,8 +405,8 @@ void ControllerClientImpl::GetScenePrimaryKeys(std::vector& sceneke boost::property_tree::ptree& objects = pt.get_child("objects"); scenekeys.resize(objects.size()); size_t i = 0; - BOOST_FOREACH(boost::property_tree::ptree::value_type &v, objects) { - scenekeys[i++] = v.second.get("pk"); + FOREACH(v, objects) { + scenekeys[i++] = v->second.get("pk"); } } From 986af873619817f219da70c645ac34466aa23a7c Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 31 Jul 2014 21:10:03 +0900 Subject: [PATCH 137/477] add a new meaning to reinitializetime param, add tasktype function param --- include/mujincontrollerclient/mujincontrollerclient.h | 6 +++--- src/mujincontrollerclient.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3580cb58..30aa4c58 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -819,7 +819,7 @@ class MUJINCLIENT_API SceneResource : public WebResource - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options=0); virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) { @@ -845,8 +845,8 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype="binpicking", int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype="binpicking", int options=0); /// \brief gets a list of all the scene primary keys currently available to the user diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index df45fb47..8e6649f8 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -308,7 +308,7 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& //this->Get(""); } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options) { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); @@ -409,14 +409,14 @@ TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& tasknam return GetTaskFromName_UTF8(taskname_utf8, options); } -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options) + BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, "binpicking", options)); + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, tasktype, options)); } -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options) +BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) { - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, "binpicking", options)); + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, tasktype, options)); } void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) From b010d2a76c58fa587726e520a6705342dbf48bb9 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 1 Aug 2014 10:12:06 +0900 Subject: [PATCH 138/477] add support for the new backend zmq architecture --- src/mujincontrollerclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index df45fb47..960dfbc5 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -337,10 +337,10 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t if( tasktype == "binpicking" ) { BinPickingTaskResourcePtr task; if( options & 1 ) { - task.reset(new BinPickingTaskZmqResource(GetController(), pk)); + task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); } else { - task.reset(new BinPickingTaskResource(GetController(), pk)); + task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); } return task; } From 29e3938ab87eaaa03a3a8e2a78422565178c284d Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Tue, 5 Aug 2014 14:25:37 +0900 Subject: [PATCH 139/477] temporary change for cablepicking: should create CablePickingTaskResource, or generic RealTimeTaskResource --- src/mujincontrollerclient.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 8e6649f8..28e67169 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -344,6 +344,16 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t } return task; } + else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource OR generic RealTimeTaskResource + BinPickingTaskResourcePtr task; + if( options & 1 ) { + task.reset(new BinPickingTaskZmqResource(GetController(), pk)); + } + else { + task.reset(new BinPickingTaskResource(GetController(), pk)); + } + return task; + } else { TaskResourcePtr task(new TaskResource(GetController(), pk)); return task; From 56836d036c714beb4800f86742512a9fb45d1ce5 Mon Sep 17 00:00:00 2001 From: Kanunikov Denys Date: Tue, 5 Aug 2014 16:37:50 +0900 Subject: [PATCH 140/477] fix freezing by adding timeout for recv messages via zmq. --- include/mujincontrollerclient/mujincontrollerclient.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3580cb58..34e22a35 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -80,7 +80,8 @@ enum MujinErrorCode { MEC_UserAuthentication=14, ///< authentication failed MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated MEC_BinPickingError=16, ///< BinPicking failed - MEC_HandEyeCalibrationError=17 ///< HandEye Calibration failed + MEC_HandEyeCalibrationError=17, ///< HandEye Calibration failed + MEC_ZMQNoResponse=20 ///< No response from the zmq server, using REQ-REP }; enum TaskResourceOptions @@ -104,6 +105,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_AlreadyExists: return "AlreadyExists"; case MEC_BinPickingError: return "BinPickingError"; case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; + case MEC_ZMQNoResponse: return "NoResponse"; } // should throw an exception? return ""; From 4211d752dbe8023540909df6a80e967d512e5da7 Mon Sep 17 00:00:00 2001 From: Shohei Fujii Date: Thu, 31 Jul 2014 21:10:03 +0900 Subject: [PATCH 141/477] add a new meaning to reinitializetime param, add tasktype function param --- include/mujincontrollerclient/mujincontrollerclient.h | 6 +++--- src/mujincontrollerclient.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 34e22a35..dd4f2447 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -821,7 +821,7 @@ class MUJINCLIENT_API SceneResource : public WebResource - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options=0); virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) { @@ -847,8 +847,8 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype="binpicking", int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype="binpicking", int options=0); /// \brief gets a list of all the scene primary keys currently available to the user diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 960dfbc5..44a0fb17 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -308,7 +308,7 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& //this->Get(""); } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options) { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); @@ -409,14 +409,14 @@ TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& tasknam return GetTaskFromName_UTF8(taskname_utf8, options); } -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, int options) + BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, "binpicking", options)); + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, tasktype, options)); } -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, int options) +BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) { - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, "binpicking", options)); + return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, tasktype, options)); } void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) From 02be4c8c5646fd24f9b80f23fa7a45a9c43af3c8 Mon Sep 17 00:00:00 2001 From: Kanunikov Denys Date: Wed, 6 Aug 2014 11:52:19 +0900 Subject: [PATCH 142/477] minor fixes --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index dd4f2447..5eba5559 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -821,7 +821,7 @@ class MUJINCLIENT_API SceneResource : public WebResource - itlplanning */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options=0); + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) { diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index b037a3fd..436408b0 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -308,7 +308,7 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& //this->Get(""); } -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string tasktype, int options) +TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); @@ -347,10 +347,10 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource OR generic RealTimeTaskResource BinPickingTaskResourcePtr task; if( options & 1 ) { - task.reset(new BinPickingTaskZmqResource(GetController(), pk)); + task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); } else { - task.reset(new BinPickingTaskResource(GetController(), pk)); + task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); } return task; } @@ -419,7 +419,7 @@ TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& tasknam return GetTaskFromName_UTF8(taskname_utf8, options); } - BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) +BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, tasktype, options)); } From 4643d1c1ae5c3d19d321ee91f1f7ef0fec3b5a1b Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 26 Sep 2014 00:49:13 +0900 Subject: [PATCH 143/477] added GetUsername() --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5eba5559..8967cfd4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -381,6 +381,9 @@ class MUJINCLIENT_API ControllerClient /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; + /// \brief returns the username logged into this controller + virtual const std::string& GetUserName() const = 0; + /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. From b9e6324e0985e49e12d6071cbd5a94e73c7a4d48 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 26 Sep 2014 00:49:13 +0900 Subject: [PATCH 144/477] added GetUsername() --- src/controllerclientimpl.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3bcdecc7..92bca294 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -119,7 +119,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, size_t usernameindex = 0; usernameindex = usernamepassword.find_first_of(':'); BOOST_ASSERT(usernameindex != std::string::npos ); - std::string username = usernamepassword.substr(0,usernameindex); + _username = usernamepassword.substr(0,usernameindex); std::string password = usernamepassword.substr(usernameindex+1); _httpheaders = NULL; @@ -138,10 +138,10 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, // hack for now since webdav server and api server could be running on different ports if( boost::algorithm::ends_with(_baseuri, ":8000/") || (options&0x80000000) ) { // testing on localhost, however the webdav server is running on port 80... - _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%username); + _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%_username); } else { - _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%username); + _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_username); } //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); @@ -238,7 +238,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } else if( http_code == 200 ) { _csrfmiddlewaretoken = _GetCSRFFromCookies(); - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%username%password%_csrfmiddlewaretoken); + std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%_username%password%_csrfmiddlewaretoken); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); @@ -291,6 +291,10 @@ std::string ControllerClientImpl::GetVersion() return _profile.get("version"); } +const std::string& ControllerClientImpl::GetUserName() const +{ + return _username; +} void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { From 4b13ac629d1c121875920105f1a66b7486967f67 Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 13 Oct 2014 14:30:03 +0900 Subject: [PATCH 145/477] minor comments --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6c070f52..45ce9954 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -246,8 +246,8 @@ struct RobotPlacementOptimizationParameters stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; ignorebasecollision = 0; } - std::string targetname; ///< the name of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. - std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. + std::string targetname; ///< the name of the target object to optimize for. Cannot be blank. Has to start with "0 instobject " is targetting an environment instance object. For Example "0 instobject myrobot". + std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) From 456ab84ff11e1d5c71b51ad8b7a2120f75344860 Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 13 Oct 2014 15:18:40 +0900 Subject: [PATCH 146/477] fix cmake scripts and make zmq optional --- include/mujincontrollerclient/mujincontrollerclient.h | 8 -------- src/mujincontrollerclient.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 8967cfd4..b6fabb7b 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -58,11 +58,6 @@ #include #include -#define FOREACH(it, v) for(typeof((v).begin())it = (v).begin(); it != (v).end(); (it)++) -#define FOREACH_NOINC(it, v) for(typeof((v).begin())it = (v).begin(); it != (v).end(); ) - -#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) - namespace mujinclient { #include @@ -146,7 +141,6 @@ class RobotResource; class SceneResource; class TaskResource; class BinPickingTaskResource; -class BinPickingTaskZmqResource; class OptimizationResource; class PlanningResultResource; class BinPickingResultResource; @@ -163,8 +157,6 @@ typedef boost::shared_ptr TaskResourcePtr; typedef boost::weak_ptr TaskResourceWeakPtr; typedef boost::shared_ptr BinPickingTaskResourcePtr; typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; -typedef boost::shared_ptr BinPickingTaskZmqResourcePtr; -typedef boost::weak_ptr BinPickingTaskZmqResourceWeakPtr; typedef boost::shared_ptr OptimizationResourcePtr; typedef boost::weak_ptr OptimizationResourceWeakPtr; typedef boost::shared_ptr PlanningResultResourcePtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 436408b0..75341f02 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -15,7 +15,10 @@ #include "controllerclientimpl.h" #include // for sleep #include + +#ifdef MUJIN_USEZMQ #include "binpickingtaskzmq.h" +#endif namespace mujinclient { @@ -337,7 +340,11 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t if( tasktype == "binpicking" ) { BinPickingTaskResourcePtr task; if( options & 1 ) { +#ifdef MUJIN_USEZMQ task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); +#else + throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); +#endif } else { task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); From f67c5f15a0b43c15524972575e72928dfdfec673 Mon Sep 17 00:00:00 2001 From: 3dp_nakamura Date: Mon, 13 Oct 2014 00:24:59 -0700 Subject: [PATCH 147/477] fixes for windows compilation --- src/mujincontrollerclient.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 75341f02..bae8db02 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -16,6 +16,8 @@ #include // for sleep #include +#include + #ifdef MUJIN_USEZMQ #include "binpickingtaskzmq.h" #endif @@ -354,7 +356,11 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource OR generic RealTimeTaskResource BinPickingTaskResourcePtr task; if( options & 1 ) { +#ifdef MUJIN_USEZMQ task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); +#else + throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); +#endif } else { task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); From 6c8cc5c46045f5931ce0248e0f10a9b3517d27e8 Mon Sep 17 00:00:00 2001 From: 3dp_nakamura Date: Mon, 13 Oct 2014 00:24:59 -0700 Subject: [PATCH 148/477] fixes for windows compilation --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 92bca294..4d2adbfa 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -729,7 +729,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector Date: Mon, 13 Oct 2014 17:52:20 +0900 Subject: [PATCH 149/477] add initial_envstate, final_envstate, and returnmode parameters to ITLPlanningTaskParameters --- .../mujincontrollerclient.h | 17 +- src/mujincontrollerclient.cpp | 252 ++++++++++++------ 2 files changed, 181 insertions(+), 88 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e201eac3..320da549 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -229,20 +229,27 @@ class ITLPlanningTaskParameters } virtual void SetDefaults() { startfromcurrent = 0; - returntostart = 1; + returnmode = "start"; vrcruns = 1; ignorefigure = 1; unit = "mm"; optimizationvalue = 1; program.clear(); } + int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. - int returntostart; ///< Plan the return path of the robot to where the entire trajectory started. Makes it possible to loop the robot motion. + std::string returnmode; ///< specifies the final movement of the robot. There's 3 different modes: + ///< "" - (empty string) meaning robot doesn't return to anything + ///< "start" - robot returns to wherever it started + ///< "final" - robot returns to the final_envstate int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) std::string program; ///< itl program + + EnvironmentState initial_envstate; ///< initial environment state to set the ITL task to. + EnvironmentState final_envstate; ///< final environment state that describes where the robot should end at. If returnmode is set to final, then use this state. }; /// program is wincaps rc8 pac script @@ -276,7 +283,7 @@ struct RobotPlacementOptimizationParameters ignorebasecollision = 0; } std::string targetname; ///< the name of the target object to optimize for. Cannot be blank. Has to start with "0 instobject " is targetting an environment instance object. For Example "0 instobject myrobot". - std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" + std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" Real maxrange[4]; ///< X, Y, Z, Angle (deg) Real minrange[4]; ///< X, Y, Z, Angle (deg) Real stepsize[4]; ///< X, Y, Z, Angle (deg) @@ -375,7 +382,7 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the username logged into this controller virtual const std::string& GetUserName() const = 0; - + /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. @@ -1032,6 +1039,8 @@ MUJINCLIENT_API void ComputeZXYFromMatrix(Real ZXY[3], const Real matrix[12]); MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &transform); +MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); + } #if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index bae8db02..bc20a226 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -24,6 +24,81 @@ namespace mujinclient { +void ExtractEnvironmentStateFromPTree(const boost::property_tree::ptree& envstatejson, EnvironmentState& envstate) +{ + envstate.clear(); + FOREACH(objstatejson, envstatejson) { + InstanceObjectState objstate; + std::string name = objstatejson->second.get("name"); + const boost::property_tree::ptree& quatjson = objstatejson->second.get_child("quat_"); + int iquat=0; + Real dist2 = 0; + FOREACHC(v, quatjson) { + BOOST_ASSERT(iquat<4); + Real f = boost::lexical_cast(v->second.data()); + dist2 += f * f; + objstate.transform.quaternion[iquat++] = f; + } + // normalize the quaternion + if( dist2 > 0 ) { + Real fnorm =1/std::sqrt(dist2); + objstate.transform.quaternion[0] *= fnorm; + objstate.transform.quaternion[1] *= fnorm; + objstate.transform.quaternion[2] *= fnorm; + objstate.transform.quaternion[3] *= fnorm; + } + const boost::property_tree::ptree& translationjson = objstatejson->second.get_child("translation_"); + int itranslation=0; + FOREACHC(v, translationjson) { + objstate.transform.translate[itranslation++] = boost::lexical_cast(v->second.data()); + } + const boost::property_tree::ptree& dofvaluesjson = objstatejson->second.get_child("dofvalues"); + objstate.dofvalues.resize(dofvaluesjson.size()); + unsigned int idof = 0; + FOREACHC(v, dofvaluesjson) { + objstate.dofvalues.at(idof++) = boost::lexical_cast(v->second.data()); + } + envstate[name] = objstate; + } +} + +void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os) +{ + os << "["; + bool bhaswritten = false; + FOREACHC(itstate, envstate) { + if( itstate->first.size() > 0 ) { + if( bhaswritten ) { + os << ","; + } + os << "{ \"name\":\"" << itstate->first << "\", \"translation_\":["; + for(int i = 0; i < 3; ++i) { + if( i > 0 ) { + os << ","; + } + os << itstate->second.transform.translate[i]; + } + os << "], \"quat_\":["; + for(int i = 0; i < 4; ++i) { + if( i > 0 ) { + os << ","; + } + os << itstate->second.transform.quaternion[i]; + } + os << "], \"dofvalues\":["; + for(size_t i = 0; i < itstate->second.dofvalues.size(); ++i) { + if( i > 0 ) { + os << ","; + } + os << itstate->second.dofvalues.at(i); + } + os << "] }"; + bhaswritten = true; + } + } + os << "]"; +} + WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) { BOOST_ASSERT(__pk.size()>0); @@ -462,7 +537,7 @@ void SceneResource::GetInstObjects(std::vector& in controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); boost::property_tree::ptree& objects = pt.get_child("instobjects"); instobjects.resize(objects.size()); - size_t i = 0; + size_t iobj = 0; FOREACH(v, objects) { InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v->second.get("pk"))); @@ -489,68 +564,74 @@ void SceneResource::GetInstObjects(std::vector& in instobject->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); } - boost::property_tree::ptree& jsonlinks = v->second.get_child("links"); - instobject->links.resize(jsonlinks.size()); - size_t ilink = 0; - FOREACH(vlink, jsonlinks) { - instobject->links[ilink].name = vlink->second.get("name"); - - boost::property_tree::ptree& quatjson = vlink->second.get_child("quaternion"); - int iquat=0; - FOREACH(q, quatjson) { - BOOST_ASSERT(iquat<4); - instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q->second.data()); - } + if( v->second.find("links") != v->second.not_found() ) { + boost::property_tree::ptree& jsonlinks = v->second.get_child("links"); + instobject->links.resize(jsonlinks.size()); + size_t ilink = 0; + FOREACH(vlink, jsonlinks) { + instobject->links[ilink].name = vlink->second.get("name"); + + boost::property_tree::ptree& quatjson = vlink->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } - boost::property_tree::ptree& transjson = vlink->second.get_child("translate"); - int itrans=0; - FOREACH(t, transjson) { - BOOST_ASSERT(itrans<3); - instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t->second.data()); + boost::property_tree::ptree& transjson = vlink->second.get_child("translate"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t->second.data()); + } + ilink++; } - ilink++; } - boost::property_tree::ptree& jsontools = v->second.get_child("tools"); - instobject->tools.resize(jsontools.size()); - size_t itool = 0; - FOREACH(vtool, jsontools) { - instobject->tools[itool].name = vtool->second.get("name"); - - boost::property_tree::ptree& quatjson = vtool->second.get_child("quaternion"); - int iquat=0; - FOREACH(q, quatjson) { - BOOST_ASSERT(iquat<4); - instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q->second.data()); - } + if( v->second.find("tools") != v->second.not_found() ) { + boost::property_tree::ptree& jsontools = v->second.get_child("tools"); + instobject->tools.resize(jsontools.size()); + size_t itool = 0; + FOREACH(vtool, jsontools) { + instobject->tools[itool].name = vtool->second.get("name"); + + boost::property_tree::ptree& quatjson = vtool->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } - boost::property_tree::ptree& transjson = vtool->second.get_child("translate"); - int itrans=0; - FOREACH(t, transjson) { - BOOST_ASSERT(itrans<3); - instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t->second.data()); - } + boost::property_tree::ptree& transjson = vtool->second.get_child("translate"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t->second.data()); + } - boost::property_tree::ptree& directionjson = vtool->second.get_child("direction"); - int idir=0; - FOREACH(d, directionjson) { - BOOST_ASSERT(idir<3); - instobject->tools[itool].direction[idir++] = boost::lexical_cast(d->second.data()); + boost::property_tree::ptree& directionjson = vtool->second.get_child("direction"); + int idir=0; + FOREACH(d, directionjson) { + BOOST_ASSERT(idir<3); + instobject->tools[itool].direction[idir++] = boost::lexical_cast(d->second.data()); + } + itool++; } - itool++; } - boost::property_tree::ptree& jsongrabs = v->second.get_child("grabs"); - instobject->grabs.resize(jsongrabs.size()); - size_t igrab = 0; - FOREACH(vgrab, jsongrabs) { - instobject->grabs[igrab].instobjectpk = vgrab->second.get("instobjectpk"); - instobject->grabs[igrab].grabbed_linkpk = vgrab->second.get("grabbed_linkpk"); - instobject->grabs[igrab].grabbing_linkpk = vgrab->second.get("grabbing_linkpk"); - igrab++; + if( v->second.find("grabs") != v->second.not_found() ) { + boost::property_tree::ptree& jsongrabs = v->second.get_child("grabs"); + instobject->grabs.resize(jsongrabs.size()); + size_t igrab = 0; + FOREACH(vgrab, jsongrabs) { + instobject->grabs[igrab].instobjectpk = vgrab->second.get("instobjectpk"); + instobject->grabs[igrab].grabbed_linkpk = vgrab->second.get("grabbed_linkpk"); + instobject->grabs[igrab].grabbing_linkpk = vgrab->second.get("grabbing_linkpk"); + igrab++; + } } - instobjects[i++] = instobject; + instobjects.at(iobj++) = instobject; } } @@ -686,12 +767,18 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) } boost::property_tree::ptree& taskparametersjson = pt.get_child("taskparameters"); taskparameters.SetDefaults(); + bool bhasreturnmode = false, bhasreturntostart = false, breturntostart = false; FOREACH(v, taskparametersjson) { if( v->first == "startfromcurrent" ) { taskparameters.startfromcurrent = v->second.data() == std::string("True"); } else if( v->first == "returntostart" ) { - taskparameters.returntostart = v->second.data() == std::string("True"); + bhasreturntostart = true; + breturntostart = v->second.data() == std::string("True"); + } + else if( v->first == "returnmode" ) { + taskparameters.returnmode = v->second.data(); + bhasreturnmode = true; } else if( v->first == "ignorefigure" ) { taskparameters.ignorefigure = v->second.data() == std::string("True"); @@ -708,6 +795,19 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) else if( v->first == "program" ) { taskparameters.program = v->second.data(); } + else if( v->first == "initial_envstate" ) { + ExtractEnvironmentStateFromPTree(v->second, taskparameters.initial_envstate); + } + else if( v->first == "final_envstate" ) { + ExtractEnvironmentStateFromPTree(v->second, taskparameters.final_envstate); + } + else { + std::cout << "unsupported ITL task parameter " << v->first << std::endl; + } + } + // for back compat + if( !bhasreturnmode && bhasreturntostart ) { + taskparameters.returnmode = breturntostart ? "start" : ""; } } @@ -715,17 +815,29 @@ void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparame { GETCONTROLLERIMPL(); std::string startfromcurrent = taskparameters.startfromcurrent ? "True" : "False"; - std::string returntostart = taskparameters.returntostart ? "True" : "False"; std::string ignorefigure = taskparameters.ignorefigure ? "True" : "False"; std::string vrcruns = boost::lexical_cast(taskparameters.vrcruns); + std::stringstream ssinitial_envstate; + if( taskparameters.initial_envstate.size() > 0 ) { + ssinitial_envstate << std::setprecision(std::numeric_limits::digits10+1); + ssinitial_envstate << ", \"initial_envstate\":"; + SerializeEnvironmentStateToJSON(taskparameters.initial_envstate, ssinitial_envstate); + } + std::stringstream ssfinal_envstate; + if( taskparameters.final_envstate.size() > 0 ) { + ssfinal_envstate << std::setprecision(std::numeric_limits::digits10+1); + ssfinal_envstate << ", \"final_envstate\":"; + SerializeEnvironmentStateToJSON(taskparameters.final_envstate, ssfinal_envstate); + } + // because program will inside string, encode newlines std::string program; std::vector< std::pair > serachpairs(2); serachpairs[0].first = "\n"; serachpairs[0].second = "\\n"; serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; SearchAndReplace(program, taskparameters.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returntostart\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d} }")%taskparameters.optimizationvalue%program%taskparameters.unit%returntostart%startfromcurrent%ignorefigure%vrcruns); + std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); boost::property_tree::ptree pt; controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } @@ -837,35 +949,7 @@ void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) GETCONTROLLERIMPL(); boost::property_tree::ptree pt; controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); - boost::property_tree::ptree& envstatejson = pt.get_child("envstate"); - envstate.clear(); - FOREACH(objstatejson, envstatejson) { - InstanceObjectState objstate; - std::string name = objstatejson->second.get("name"); - boost::property_tree::ptree& quatjson = objstatejson->second.get_child("quat_"); - int iquat=0; - Real dist2 = 0; - FOREACH(v, quatjson) { - BOOST_ASSERT(iquat<4); - Real f = boost::lexical_cast(v->second.data()); - dist2 += f * f; - objstate.transform.quaternion[iquat++] = f; - } - // normalize the quaternion - if( dist2 > 0 ) { - Real fnorm =1/std::sqrt(dist2); - objstate.transform.quaternion[0] *= fnorm; - objstate.transform.quaternion[1] *= fnorm; - objstate.transform.quaternion[2] *= fnorm; - objstate.transform.quaternion[3] *= fnorm; - } - boost::property_tree::ptree& translationjson = objstatejson->second.get_child("translation_"); - int itranslation=0; - FOREACH(v, translationjson) { - objstate.transform.translate[itranslation++] = boost::lexical_cast(v->second.data()); - } - envstate[name] = objstate; - } + ExtractEnvironmentStateFromPTree(pt.get_child("envstate"), envstate); } void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) From 1d0ffa08576737b4a29502edb73f9393f30ba55c Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 13 Oct 2014 18:01:34 +0900 Subject: [PATCH 150/477] minor doc change --- include/mujincontrollerclient/mujincontrollerclient.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 320da549..87604030 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -238,10 +238,13 @@ class ITLPlanningTaskParameters } int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. - std::string returnmode; ///< specifies the final movement of the robot. There's 3 different modes: - ///< "" - (empty string) meaning robot doesn't return to anything - ///< "start" - robot returns to wherever it started - ///< "final" - robot returns to the final_envstate + + /// specifies the final movement of the robot. There's 3 different modes: + /// - \b "" - (empty string) meaning robot doesn't return to anything + /// - \b "start" - robot returns to wherever it started + /// - \b "final" - robot returns to the final_envstate + std::string returnmode; + int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc From af438c47b5afe1382d021c5bad08ad75a4b9f5a7 Mon Sep 17 00:00:00 2001 From: 3dp_nakamura Date: Mon, 13 Oct 2014 02:24:15 -0700 Subject: [PATCH 151/477] fix msvc compilation --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index bc20a226..90ffd5c2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -27,7 +27,7 @@ namespace mujinclient { void ExtractEnvironmentStateFromPTree(const boost::property_tree::ptree& envstatejson, EnvironmentState& envstate) { envstate.clear(); - FOREACH(objstatejson, envstatejson) { + FOREACHC(objstatejson, envstatejson) { InstanceObjectState objstate; std::string name = objstatejson->second.get("name"); const boost::property_tree::ptree& quatjson = objstatejson->second.get_child("quat_"); From 18bea885b7239149f199fa4c7271190cd82793d8 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 19 Nov 2014 12:27:21 +0900 Subject: [PATCH 152/477] updated GetSensorTransform --- include/mujincontrollerclient/mujincontrollerclient.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 87604030..ce1055fb 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -794,6 +794,13 @@ class MUJINCLIENT_API SceneResource : public WebResource } }; + class MUJINCLIENT_API AttachedSensor { +public: + std::string name; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + void SetTransform(const Transform& t); void SetDOFValues(); virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); @@ -810,6 +817,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::vector grabs; std::vector links; std::vector tools; + std::vector attachedsensors; }; SceneResource(ControllerClientPtr controller, const std::string& pk); From c6ed7f040172abd2520f072e2da69503936ffb22 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 19 Nov 2014 14:49:35 +0900 Subject: [PATCH 153/477] added attachedsensors to GetInstObjects --- src/mujincontrollerclient.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 90ffd5c2..0a416c23 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -631,6 +631,25 @@ void SceneResource::GetInstObjects(std::vector& in } } + if ( v->second.find("attachedsensors") != v->second.not_found() ) { + boost::property_tree::ptree& jsonattachedsensors = v->second.get_child("attachedsensors"); + instobject->attachedsensors.resize(jsonattachedsensors.size()); + size_t iattchedsensor = 0; + FOREACH(vattachedsensor, jsonattachedsensors) { + instobject->attachedsensors[iattchedsensor].name = vattachedsensor->second.get("name"); + size_t iquaternion = 0; + FOREACH(vquaternion, vattachedsensor->second.get_child("quaternion")) { + BOOST_ASSERT( iquaternion < 4 ); + instobject->attachedsensors[iattchedsensor].quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); + } + size_t itranslate = 0; + FOREACH(vtranslate, vattachedsensor->second.get_child("translate")) { + BOOST_ASSERT( itranslate < 3 ); + instobject->attachedsensors[iattchedsensor].translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); + } + iattchedsensor++; + } + } instobjects.at(iobj++) = instobject; } } From d7f5476e5c80da6383507b6c21c5db87c294dcee Mon Sep 17 00:00:00 2001 From: 3dp_nakamura Date: Mon, 1 Dec 2014 17:42:53 -0800 Subject: [PATCH 154/477] fix uploading cecrobodiaxml files with utf-16 --- src/controllerclientimpl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 4d2adbfa..c040169b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1324,14 +1324,13 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring& copydir_utf16, const std::string& rawuri) { BOOST_ASSERT(rawuri.size()>0 && copydir_utf16.size()>0); - MUJIN_ASSERT_OP_FORMAT(copydir_utf16.at(copydir_utf16.size()-1),!=,s_wfilesep,"copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); // if there's a trailing slash, have to get rid of it std::string uri; if( rawuri.at(rawuri.size()-1) == '/' ) { - if( copydir_utf16.at(copydir_utf16.size()-1) != s_filesep ) { + if( copydir_utf16.at(copydir_utf16.size()-1) != s_wfilesep ) { // append the copydir_utf16 name to rawuri - size_t nBaseFilenameStartIndex = copydir_utf16.find_last_of(s_filesep); + size_t nBaseFilenameStartIndex = copydir_utf16.find_last_of(s_wfilesep); if( nBaseFilenameStartIndex == std::string::npos ) { // there's no path? nBaseFilenameStartIndex = 0; @@ -1351,6 +1350,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring } } else { + MUJIN_ASSERT_OP_FORMAT(copydir_utf16.at(copydir_utf16.size()-1),!=,s_wfilesep,"copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); uri = rawuri; } From a463765370427981f703e0212342211d2e98365a Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 2 Jan 2015 17:35:53 +0900 Subject: [PATCH 155/477] updated FindInstObj to use exact string matching --- src/mujincontrollerclient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 0a416c23..9e536e9f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -660,8 +660,7 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO std::vector instobjects; this->GetInstObjects(instobjects); for(size_t i = 0; i < instobjects.size(); ++i) { - std::size_t found_at = instobjects[i]->name.find(name); - if (found_at != std::string::npos) { + if (instobjects[i]->name == name) { instobject = instobjects[i]; return true; } From 8511c98cb4fe90f699ed794c0a024f90daa8b77e Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 10 Apr 2015 16:22:26 +0900 Subject: [PATCH 156/477] converted logging to log4cpp compatible --- src/controllerclientimpl.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c040169b..95e51400 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -266,7 +266,9 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _charset = itcodepage->second; } #endif - std::cout << "setting character set to " << _charset << std::endl; + std::stringstream ss; + ss << "setting character set to " << _charset; + CLIENT_LOG_INFO(ss.str()); _SetHTTPHeaders(); try { @@ -477,7 +479,9 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c #if defined(_WIN32) || defined(_WIN64) // check if / is used anywhere and send a warning if it is if( sourcefilename.find_first_of('/') != std::string::npos ) { - std::cout << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\" << std::endl; + std::stringstream ss; + ss << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\"; + CLIENT_LOG_INFO(ss.str()); for(size_t i = 0; i < sourcefilename.size(); ++i) { if( sourcefilename[i] == '/' ) { sourcefilename[i] = '\\'; @@ -563,7 +567,9 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ #if defined(_WIN32) || defined(_WIN64) // check if / is used anywhere and send a warning if it is if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { - std::cout << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\" << std::endl; + std::stringstream ss; + ss << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\"; + CLIENT_LOG_INFO(ss.str()); for(size_t i = 0; i < sourcefilename_utf16.size(); ++i) { if( sourcefilename_utf16[i] == L'/' ) { sourcefilename_utf16[i] = L'\\'; @@ -1260,7 +1266,9 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& sCopyDir_FS.resize(sCopyDir_FS.size()-1); bhasseparator = true; } - std::cout << "uploading " << sCopyDir_FS << " -> " << uri << std::endl; + std::stringstream ss; + ss << "uploading " << sCopyDir_FS << " -> " << uri; + CLIENT_LOG_INFO(ss.str()); #if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAA ffd; @@ -1379,7 +1387,9 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring else { sCopyDir_FS = copydir_utf16; } - std::cout << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri << std::endl; + std::stringstream ss; + ss << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri; + CLIENT_LOG_INFO(ss.str()); #if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAW ffd; @@ -1594,7 +1604,7 @@ void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& destu CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - std::cout << http_code << std::endl; + CLIENT_LOG_INFO(http_code); } size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) From 183f155c66ddd2048a27309ed477df7dfcc2a868 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 10 Apr 2015 16:22:26 +0900 Subject: [PATCH 157/477] converted logging to log4cpp compatible --- .../mujincontrollerclient.h | 17 +++++++++++++++++ src/mujincontrollerclient.cpp | 12 +++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ce1055fb..0b536cc5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -58,6 +58,23 @@ #include #include +#ifndef USE_LOG4CPP // logging + +#define CLIENT_LOG_INFO(msg) std::cout << msg << std::endl; +#define CLIENT_LOG_ERROR(msg) std::cerr << msg << std::endl; + +#else + +#include +#include + +LOG4CPP_LOGGER_N(mujincontrollerclientlogger, "mujincontrollerclient"); + +#define CLIENT_LOG_INFO(msg) LOG4CPP_INFO_S(mujincontrollerclientlogger) << msg; +#define CLIENT_LOG_ERROR(msg) LOG4CPP_ERROR_S(mujincontrollerclientlogger) << msg; + +#endif // logging + namespace mujinclient { #include diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9e536e9f..202cc1ae 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -333,7 +333,9 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str //TODO do not use this->grabs. this is the cached information for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { if (this->grabs[igrab] == grab) { - std::cerr << grabbedobject->name << "is already grabbed" << std::endl; + std::stringstream ss; + ss << grabbedobject->name << "is already grabbed"; + CLIENT_LOG_ERROR(ss.str()); return; } } @@ -378,7 +380,9 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } } - std::cerr << grabbedobject->name << "is not grabbed" << std::endl; + std::stringstream ss; + ss << grabbedobject->name << "is not grabbed"; + CLIENT_LOG_ERROR(ss.str()); } @@ -820,7 +824,9 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) ExtractEnvironmentStateFromPTree(v->second, taskparameters.final_envstate); } else { - std::cout << "unsupported ITL task parameter " << v->first << std::endl; + std::stringstream ss; + ss << "unsupported ITL task parameter " << v->first; + CLIENT_LOG_ERROR(ss.str()); } } // for back compat From 996829d4a4fa2a12b8d4e80657a06b2a3bb8eaf8 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 23 Jul 2015 11:56:44 +0900 Subject: [PATCH 158/477] added userinfo to binpicking task commands --- src/controllerclientimpl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 95e51400..2d42c84c 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -298,6 +298,11 @@ const std::string& ControllerClientImpl::GetUserName() const return _username; } +const std::string& ControllerClientImpl::GetUserInfo() const +{ + return _userinfo_json; +} + void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); @@ -316,6 +321,9 @@ void ControllerClientImpl::SetLanguage(const std::string& language) boost::mutex::scoped_lock lock(_mutex); _language = language; _SetHTTPHeaders(); + std::stringstream ss; + ss << "\"userinfo\": {" << "\"username\": " << _username << ", \"locale\": " << _language << "}"; + _userinfo_json = ss.str(); } void ControllerClientImpl::RestartServer() From ba8256b9cedfff4ef7b57f76a1039fcdcd051c43 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 23 Jul 2015 11:56:44 +0900 Subject: [PATCH 159/477] added userinfo to binpicking task commands --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 0b536cc5..c2263873 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -403,6 +403,9 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the username logged into this controller virtual const std::string& GetUserName() const = 0; + /// \brief returns the uesrinfo json string for the current logged in user + virtual const std::string& GetUserInfo() const = 0; + /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. From b6ce8253e37f2e1a0c44ea7d49207ff909438dc7 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 23 Jul 2015 14:30:39 +0900 Subject: [PATCH 160/477] better GetUserInfo() --- src/controllerclientimpl.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2d42c84c..2f49490e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -300,7 +300,7 @@ const std::string& ControllerClientImpl::GetUserName() const const std::string& ControllerClientImpl::GetUserInfo() const { - return _userinfo_json; + return "\"userinfo\": {\"username\": " + _username + ", \"locale\": " + _language + "}"; } void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) @@ -321,9 +321,6 @@ void ControllerClientImpl::SetLanguage(const std::string& language) boost::mutex::scoped_lock lock(_mutex); _language = language; _SetHTTPHeaders(); - std::stringstream ss; - ss << "\"userinfo\": {" << "\"username\": " << _username << ", \"locale\": " << _language << "}"; - _userinfo_json = ss.str(); } void ControllerClientImpl::RestartServer() From a98404e7646660e4411b2dd0148e86d5680268ad Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 23 Jul 2015 15:00:21 +0900 Subject: [PATCH 161/477] better GetUserInfo() --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2f49490e..0dd64a0f 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -300,7 +300,7 @@ const std::string& ControllerClientImpl::GetUserName() const const std::string& ControllerClientImpl::GetUserInfo() const { - return "\"userinfo\": {\"username\": " + _username + ", \"locale\": " + _language + "}"; + return "{\"username\": " + _username + ", \"locale\": " + _language + "}"; } void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) From 15a70e0d518ab78243f168d0389f0d77944e4447 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 23 Jul 2015 15:28:06 +0900 Subject: [PATCH 162/477] updated locale --- src/controllerclientimpl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 0dd64a0f..cc5d87e1 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -300,7 +300,10 @@ const std::string& ControllerClientImpl::GetUserName() const const std::string& ControllerClientImpl::GetUserInfo() const { - return "{\"username\": " + _username + ", \"locale\": " + _language + "}"; + std::string locale0 = _language.substr(0,_language.find("-")); + std::string locale1 = boost::to_upper_copy(_language.substr(_language.find("-")+1)); + + return "{\"username\": " + _username + ", \"locale\": " + locale0 + "_" + locale1 + "}"; } void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) From 059a50cca6ef20772bd7c27e9d81a2d33b1c19fc Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 29 Jul 2015 17:58:14 +0900 Subject: [PATCH 163/477] fixed userinfo --- include/mujincontrollerclient/mujincontrollerclient.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c2263873..0b536cc5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -403,9 +403,6 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the username logged into this controller virtual const std::string& GetUserName() const = 0; - /// \brief returns the uesrinfo json string for the current logged in user - virtual const std::string& GetUserInfo() const = 0; - /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. From a5518c5fadd653f50882d851ed90222b42241c30 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 29 Jul 2015 17:58:14 +0900 Subject: [PATCH 164/477] fixed userinfo --- src/controllerclientimpl.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index cc5d87e1..9832347e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -298,14 +298,6 @@ const std::string& ControllerClientImpl::GetUserName() const return _username; } -const std::string& ControllerClientImpl::GetUserInfo() const -{ - std::string locale0 = _language.substr(0,_language.find("-")); - std::string locale1 = boost::to_upper_copy(_language.substr(_language.find("-")+1)); - - return "{\"username\": " + _username + ", \"locale\": " + locale0 + "_" + locale1 + "}"; -} - void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); @@ -322,7 +314,9 @@ void ControllerClientImpl::SetProxy(const std::string& serverport, const std::st void ControllerClientImpl::SetLanguage(const std::string& language) { boost::mutex::scoped_lock lock(_mutex); - _language = language; + if (language!= "") { + _language = language; + } _SetHTTPHeaders(); } From fde827eeab4ac6d2d7f9d82425d7cc1de297d9cf Mon Sep 17 00:00:00 2001 From: Robert Ye Date: Thu, 24 Sep 2015 12:32:48 +0900 Subject: [PATCH 165/477] add get scene sensor mapping to client cpp --- .../mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 0b536cc5..a7db0d26 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -57,6 +57,7 @@ #include #include #include +#include #ifndef USE_LOG4CPP // logging @@ -885,6 +886,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetTaskPrimaryKeys(std::vector& taskkeys); /// \brief gets a list of all the instance objects of the scene + virtual void GetSensorMapping(boost::property_tree::ptree& sensormapping); virtual void GetInstObjects(std::vector& instobjects); virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 202cc1ae..0778f75f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -534,6 +534,34 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) } } +void SceneResource::GetSensorMapping(boost::property_tree::ptree& sensormapping) +{ + GETCONTROLLERIMPL(); + sensormapping.clear(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("instobjects"); + FOREACH(v, objects) { + if ( v->second.find("attachedsensors") != v->second.not_found() ) { + boost::property_tree::ptree& jsonattachedsensors = v->second.get_child("attachedsensors"); + if (jsonattachedsensors.size() > 0) { + std::string object_pk = v->second.get("object_pk"); + std::string cameracontainername = v->second.get("name"); + boost::property_tree::ptree pt_robot; + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%object_pk), pt_robot); + boost::property_tree::ptree pt_attachedsensors = pt_robot.get_child("attachedsensors"); + FOREACH(sensor, pt_attachedsensors) { + std::string sensorname = sensor->second.get("name"); + //boost::property_tree::ptree& pt_sensordata = sensor->second.get_child("sensordata"); + std::string cameraid = sensor->second.get("sensordata.hardware_id"); + std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); + std::cout << camerafullname << ": " << cameraid << std::endl; + } + } + } + } +} + void SceneResource::GetInstObjects(std::vector& instobjects) { GETCONTROLLERIMPL(); From 376bb015b8097ba6ce24de22dcbff9a7b3c76515 Mon Sep 17 00:00:00 2001 From: Robert Ye Date: Fri, 2 Oct 2015 15:32:55 +0900 Subject: [PATCH 166/477] make get sensormapping result a std map --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a7db0d26..cb1760c6 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -886,7 +886,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetTaskPrimaryKeys(std::vector& taskkeys); /// \brief gets a list of all the instance objects of the scene - virtual void GetSensorMapping(boost::property_tree::ptree& sensormapping); + virtual void GetSensorMapping(std::map& sensormapping); virtual void GetInstObjects(std::vector& instobjects); virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 0778f75f..f1bfc49b 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -534,7 +534,7 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) } } -void SceneResource::GetSensorMapping(boost::property_tree::ptree& sensormapping) +void SceneResource::GetSensorMapping(std::map& sensormapping) { GETCONTROLLERIMPL(); sensormapping.clear(); @@ -549,13 +549,12 @@ void SceneResource::GetSensorMapping(boost::property_tree::ptree& sensormapping) std::string cameracontainername = v->second.get("name"); boost::property_tree::ptree pt_robot; controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%object_pk), pt_robot); - boost::property_tree::ptree pt_attachedsensors = pt_robot.get_child("attachedsensors"); + boost::property_tree::ptree& pt_attachedsensors = pt_robot.get_child("attachedsensors"); FOREACH(sensor, pt_attachedsensors) { std::string sensorname = sensor->second.get("name"); - //boost::property_tree::ptree& pt_sensordata = sensor->second.get_child("sensordata"); - std::string cameraid = sensor->second.get("sensordata.hardware_id"); std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); - std::cout << camerafullname << ": " << cameraid << std::endl; + std::string cameraid = sensor->second.get("sensordata.hardware_id"); + sensormapping[camerafullname] = cameraid; } } } From 0b933bf67b099b96d4e03e2ec5511c268cfa69e7 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 27 Jan 2016 14:48:20 +0900 Subject: [PATCH 167/477] Convert to log4cxx. --- src/controllerclientimpl.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 9832347e..ab976441 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -19,6 +19,10 @@ #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION +#include "logging.h" + +MUJIN_LOGGER("mujin.controllerclientcpp"); + namespace mujinclient { class CurlCustomRequestSetter @@ -268,7 +272,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, #endif std::stringstream ss; ss << "setting character set to " << _charset; - CLIENT_LOG_INFO(ss.str()); + MUJIN_LOG_INFO(ss.str()); _SetHTTPHeaders(); try { @@ -483,7 +487,7 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c if( sourcefilename.find_first_of('/') != std::string::npos ) { std::stringstream ss; ss << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\"; - CLIENT_LOG_INFO(ss.str()); + MUJIN_LOG_INFO(ss.str()); for(size_t i = 0; i < sourcefilename.size(); ++i) { if( sourcefilename[i] == '/' ) { sourcefilename[i] = '\\'; @@ -571,7 +575,7 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { std::stringstream ss; ss << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\"; - CLIENT_LOG_INFO(ss.str()); + MUJIN_LOG_INFO(ss.str()); for(size_t i = 0; i < sourcefilename_utf16.size(); ++i) { if( sourcefilename_utf16[i] == L'/' ) { sourcefilename_utf16[i] = L'\\'; @@ -1270,7 +1274,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& } std::stringstream ss; ss << "uploading " << sCopyDir_FS << " -> " << uri; - CLIENT_LOG_INFO(ss.str()); + MUJIN_LOG_INFO(ss.str()); #if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAA ffd; @@ -1391,7 +1395,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring } std::stringstream ss; ss << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri; - CLIENT_LOG_INFO(ss.str()); + MUJIN_LOG_INFO(ss.str()); #if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAW ffd; @@ -1606,7 +1610,7 @@ void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& destu CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CLIENT_LOG_INFO(http_code); + MUJIN_LOG_INFO(http_code); } size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) From 1334c1d7f0bee8d50bdc4b51a0c372072aa02342 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 27 Jan 2016 14:48:20 +0900 Subject: [PATCH 168/477] Convert to log4cxx. --- .../mujincontrollerclient.h | 17 ----------------- src/mujincontrollerclient.cpp | 10 +++++++--- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index cb1760c6..602afedb 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -59,23 +59,6 @@ #include #include -#ifndef USE_LOG4CPP // logging - -#define CLIENT_LOG_INFO(msg) std::cout << msg << std::endl; -#define CLIENT_LOG_ERROR(msg) std::cerr << msg << std::endl; - -#else - -#include -#include - -LOG4CPP_LOGGER_N(mujincontrollerclientlogger, "mujincontrollerclient"); - -#define CLIENT_LOG_INFO(msg) LOG4CPP_INFO_S(mujincontrollerclientlogger) << msg; -#define CLIENT_LOG_ERROR(msg) LOG4CPP_ERROR_S(mujincontrollerclientlogger) << msg; - -#endif // logging - namespace mujinclient { #include diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f1bfc49b..d822ddb7 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -22,6 +22,10 @@ #include "binpickingtaskzmq.h" #endif +#include "logging.h" + +MUJIN_LOGGER("mujin.controllerclientcpp"); + namespace mujinclient { void ExtractEnvironmentStateFromPTree(const boost::property_tree::ptree& envstatejson, EnvironmentState& envstate) @@ -335,7 +339,7 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str if (this->grabs[igrab] == grab) { std::stringstream ss; ss << grabbedobject->name << "is already grabbed"; - CLIENT_LOG_ERROR(ss.str()); + MUJIN_LOG_ERROR(ss.str()); return; } } @@ -382,7 +386,7 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: } std::stringstream ss; ss << grabbedobject->name << "is not grabbed"; - CLIENT_LOG_ERROR(ss.str()); + MUJIN_LOG_ERROR(ss.str()); } @@ -853,7 +857,7 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) else { std::stringstream ss; ss << "unsupported ITL task parameter " << v->first; - CLIENT_LOG_ERROR(ss.str()); + MUJIN_LOG_ERROR(ss.str()); } } // for back compat From d92fcd1fbbcd4e9e38b4d6537c9df2da06d4b41a Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Fri, 26 Feb 2016 14:37:25 +0900 Subject: [PATCH 169/477] Add If-Modified-Since support for downloading. --- src/controllerclientimpl.cpp | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ab976441..a142f231 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1193,6 +1193,54 @@ void ControllerClientImpl::DownloadFileFromController_UTF16(const std::wstring& _CallGet(_PrepareDestinationURI_UTF16(desturi, false), vdata); } +void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata) +{ + boost::mutex::scoped_lock lock(_mutex); + _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata); +} + +void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata) +{ + boost::mutex::scoped_lock lock(_mutex); + _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata); +} + +void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata) +{ + // on exit, reset the curl options we are going to set + boost::shared_ptr onexitresetfiletime((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_FILETIME, 0)); + boost::shared_ptr onexitresettimecondition((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE)); + boost::shared_ptr onexitresettimevalue((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_TIMEVALUE, 0)); + + remotetimeval = 0; + + // ask for remote file time + curl_easy_setopt(_curl, CURLOPT_FILETIME, 1); + + // use if modified since if local file time is provided + if (localtimeval > 0) { + curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, localtimeval); + } + + // do the get call + long http_code = _CallGet(desturi, outputdata, 0); + if ((http_code != 200 && http_code != 304)) { + if (outputdata.size() > 0) { + std::stringstream ss; + ss.write((const char*)&outputdata[0], outputdata.size()); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%ss.str(), MEC_HTTPServer); + } + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); + } + + // retrieve remote file time + if (http_code != 304) { + CURLcode res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &remotetimeval); + CHECKCURLCODE(res, "curl_easy_getinfo"); + } +} + void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); From 695d585694eeca54ffedb7f2451dd193bc511658 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Fri, 26 Feb 2016 14:37:25 +0900 Subject: [PATCH 170/477] Add If-Modified-Since support for downloading. --- include/mujincontrollerclient/mujincontrollerclient.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 602afedb..8d507826 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -540,6 +540,16 @@ class MUJINCLIENT_API ControllerClient /// \param vdata filled with the contents of the file on the controller filesystem virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) = 0; + /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header + /// \param remotetimeval will output the modified date in response + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata) = 0; + + /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header + /// \param remotetimeval will output the modified date in response + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata) = 0; + /// \brief Deletes a file on the controller network filesystem. /// /// \param uri UTF-8 encoded file in the network filesystem to delete. From a72cc983d48a286b9e7577058dc60a38c8d51307 Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 17 Mar 2016 17:03:52 +0900 Subject: [PATCH 171/477] add macros --- src/controllerclientimpl.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index a142f231..3c4c1743 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -23,6 +23,8 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); +#define CURL_OPTION_SAVER(curlopt, curvalue, curltype) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, curlopt, curvalue)); + namespace mujinclient { class CurlCustomRequestSetter @@ -1208,9 +1210,9 @@ void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata) { // on exit, reset the curl options we are going to set - boost::shared_ptr onexitresetfiletime((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_FILETIME, 0)); - boost::shared_ptr onexitresettimecondition((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE)); - boost::shared_ptr onexitresettimevalue((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, CURLOPT_TIMEVALUE, 0)); + CURL_OPTION_SAVER(CURLOPT_FILETIME, 0, long); + CURL_OPTION_SAVER(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, curl_TimeCond); + CURL_OPTION_SAVER(CURLOPT_TIMEVALUE, 0, long); remotetimeval = 0; @@ -1236,6 +1238,7 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur // retrieve remote file time if (http_code != 304) { + // got the entire file so fill in the timestamp of that file CURLcode res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &remotetimeval); CHECKCURLCODE(res, "curl_easy_getinfo"); } From 774a3fdcb6c6fdc329cf0f72bc496105103b87df Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Tue, 19 Jul 2016 15:02:52 +0900 Subject: [PATCH 172/477] implemented MoveToolLinear, MoveToHandPosition and SetJogModeVelocities and samples showing how to use them --- src/controllerclientimpl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3c4c1743..381c40c4 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -31,7 +31,7 @@ class CurlCustomRequestSetter { public: CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { - CURLcode res = curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); + curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); } ~CurlCustomRequestSetter() { curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); @@ -44,7 +44,7 @@ class CurlWriteDataSetter { public: CurlWriteDataSetter(CURL *curl, const void* pdata) : _curl(curl) { - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, pdata); + curl_easy_setopt(_curl, CURLOPT_WRITEDATA, pdata); } ~CurlWriteDataSetter() { curl_easy_setopt(_curl, CURLOPT_WRITEDATA, NULL); @@ -57,7 +57,7 @@ class CurlUploadSetter { public: CurlUploadSetter(CURL *curl) : _curl(curl) { - CURLcode res = curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); } ~CurlUploadSetter() { curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); @@ -1318,16 +1318,17 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir_utf8); // remove the fileseparator if it exists + std::stringstream ss; + ss << "uploading " << sCopyDir_FS << " -> " << uri; + MUJIN_LOG_INFO(ss.str()); + +#if defined(_WIN32) || defined(_WIN64) bool bhasseparator = false; if( sCopyDir_FS.size() > 0 && sCopyDir_FS.at(sCopyDir_FS.size()-1) == s_filesep ) { sCopyDir_FS.resize(sCopyDir_FS.size()-1); bhasseparator = true; } - std::stringstream ss; - ss << "uploading " << sCopyDir_FS << " -> " << uri; - MUJIN_LOG_INFO(ss.str()); -#if defined(_WIN32) || defined(_WIN64) WIN32_FIND_DATAA ffd; std::string searchstr = sCopyDir_FS + std::string("\\*"); HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); From 487685f0840bd610bc8c594d39ce3eb4645af2a4 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Tue, 19 Jul 2016 20:41:21 +0900 Subject: [PATCH 173/477] use realtimeitlplanning tasktype when appropriate --- src/mujincontrollerclient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d822ddb7..558d8160 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -422,11 +422,11 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t return TaskResourcePtr(); } - if( tasktype == "binpicking" ) { + if( tasktype == "binpicking" || tasktype == "realtimeitlplanning") { BinPickingTaskResourcePtr task; if( options & 1 ) { #ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); + task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey(), tasktype)); #else throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); #endif @@ -436,7 +436,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t } return task; } - else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource OR generic RealTimeTaskResource + else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource BinPickingTaskResourcePtr task; if( options & 1 ) { #ifdef MUJIN_USEZMQ From f9e98e23a74f5dfbd9e78a097a6e0cec2d0c51b3 Mon Sep 17 00:00:00 2001 From: rdiankov Date: Tue, 19 Jul 2016 06:54:59 -0700 Subject: [PATCH 174/477] tested jogging example in windows with vc100 --- src/controllerclientimpl.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 381c40c4..77449bc4 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -661,7 +661,18 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_t res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( _buffer.rdbuf()->in_avail() > 0 ) { +#ifdef _WIN32 + // sometimes buffer can container \n or \\, which windows boost property_tree does not like + std::string newbuffer; + std::vector< std::pair > serachpairs(2); + serachpairs[0].first = "\n"; serachpairs[0].second = ""; + serachpairs[1].first = "\\"; serachpairs[1].second = ""; + SearchAndReplace(newbuffer, _buffer.str(), serachpairs); + std::stringstream newss(newbuffer); + boost::property_tree::read_json(newss, pt); +#else boost::property_tree::read_json(_buffer, pt); +#endif } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); From 1e9d5d22b283ed35f5a2969fded8c71fa5bff8a8 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 31 Aug 2016 15:53:35 +0900 Subject: [PATCH 175/477] Add timeout parameters. --- src/controllerclientimpl.cpp | 42 ++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 77449bc4..854c86ec 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -23,10 +23,23 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); -#define CURL_OPTION_SAVER(curlopt, curvalue, curltype) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), _curl, curlopt, curvalue)); +#define CURL_OPTION_SAVER(curl, curlopt, curvalue, curltype) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)); namespace mujinclient { +class CurlTimeoutSetter +{ +public: + CurlTimeoutSetter(CURL *curl, double timeout) : _curl(curl) { + curl_easy_setopt(_curl, CURLOPT_TIMEOUT_MS, (long)(timeout * 1000)); + } + ~CurlTimeoutSetter() { + curl_easy_setopt(_curl, CURLOPT_TIMEOUT_MS, 0); + } +protected: + CURL* _curl; +}; + class CurlCustomRequestSetter { public: @@ -120,7 +133,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } -ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options) +ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { size_t usernameindex = 0; usernameindex = usernamepassword.find_first_of(':'); @@ -215,9 +228,14 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 0); // do not bounce through pages since we need to detect when login sessions expired CHECKCURLCODE(res, "failed to set follow location"); res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); - CHECKCURLCODE(res, "failed to max redirs"); + CHECKCURLCODE(res, "failed to set max redirs"); + res = curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1); + CHECKCURLCODE(res, "failed to set no signal"); if( !(options & 1) ) { + // specify a reasonable timeout for the login calls + CurlTimeoutSetter timeoutsetter(_curl, timeout); + // make an initial GET call to get the CSRF token std::string loginuri = _baseuri + "login/"; curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); @@ -1206,24 +1224,26 @@ void ControllerClientImpl::DownloadFileFromController_UTF16(const std::wstring& _CallGet(_PrepareDestinationURI_UTF16(desturi, false), vdata); } -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata) +void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) { boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata); + _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata, timeout); } -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata) +void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) { boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata); + _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata, timeout); } -void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata) +void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) { + CurlTimeoutSetter timeoutsetter(_curl, timeout); + // on exit, reset the curl options we are going to set - CURL_OPTION_SAVER(CURLOPT_FILETIME, 0, long); - CURL_OPTION_SAVER(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, curl_TimeCond); - CURL_OPTION_SAVER(CURLOPT_TIMEVALUE, 0, long); + CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 0, long); + CURL_OPTION_SAVER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, curl_TimeCond); + CURL_OPTION_SAVER(_curl, CURLOPT_TIMEVALUE, 0, long); remotetimeval = 0; From 4623dd0f2e1f4ed6fec675d3bab98b0a9c16b49e Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 31 Aug 2016 15:53:35 +0900 Subject: [PATCH 176/477] Add timeout parameters. --- include/mujincontrollerclient/mujincontrollerclient.h | 7 ++++--- src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 8d507826..f4080c87 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -543,12 +543,12 @@ class MUJINCLIENT_API ControllerClient /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header /// \param remotetimeval will output the modified date in response /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata) = 0; + virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header /// \param remotetimeval will output the modified date in response /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata) = 0; + virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; /// \brief Deletes a file on the controller network filesystem. /// @@ -1034,8 +1034,9 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 558d8160..5faf1585 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1033,9 +1033,9 @@ void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, cons } } -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); } void ControllerClientDestroy() From 167f747815570e6c94fe1a08d4f027cc1aa19be8 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 31 Aug 2016 16:41:52 +0900 Subject: [PATCH 177/477] Add timeout to most api calls, albeit some of them are not configurable. --- src/controllerclientimpl.cpp | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 854c86ec..74c66e47 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -344,9 +344,10 @@ void ControllerClientImpl::SetLanguage(const std::string& language) _SetHTTPHeaders(); } -void ControllerClientImpl::RestartServer() +void ControllerClientImpl::RestartServer(double timeout) { boost::mutex::scoped_lock lock(_mutex); + CurlTimeoutSetter timeoutsetter(_curl, timeout); _uri = _baseuri + std::string("ajax/restartserver/"); curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); curl_easy_setopt(_curl, CURLOPT_POST, 1); @@ -656,16 +657,17 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode) +int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallGet(_uri, pt, expectedhttpcode); + return _CallGet(_uri, pt, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_tree::ptree& pt, int expectedhttpcode) +int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { + CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); _buffer.str(""); @@ -700,16 +702,17 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_t return http_code; } -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode) +int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallGet(_uri, outputdata, expectedhttpcode); + return _CallGet(_uri, outputdata, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode) +int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) { + CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); _buffer.str(""); @@ -736,16 +739,17 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp return http_code; } -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode) +int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallGet(_uri, outputdata, expectedhttpcode); + return _CallGet(_uri, outputdata, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode) +int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode, double timeout) { + CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteVectorCallback); @@ -782,8 +786,9 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector listCreateDirs; std::string output; size_t startindex = 0; From afb53197c76cde7d468222d4131f9cc4de803662 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Wed, 31 Aug 2016 16:41:52 +0900 Subject: [PATCH 178/477] Add timeout to most api calls, albeit some of them are not configurable. --- .../mujincontrollerclient/mujincontrollerclient.h | 10 +++++----- src/mujincontrollerclient.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f4080c87..9d9fe045 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -397,7 +397,7 @@ class MUJINCLIENT_API ControllerClient /// /// If the server is not responding, call this method to clear the server state and initialize everything. /// The method is blocking, when it returns the MUJIN Controller would have been restarted. - virtual void RestartServer() = 0; + virtual void RestartServer(double timeout = 5.0) = 0; /// \brief Upgrade the controller with this data virtual void Upgrade(const std::vector& vdata) = 0; @@ -641,16 +641,16 @@ class MUJINCLIENT_API WebResource } /// \brief gets an attribute of this web resource - virtual std::string Get(const std::string& field); + virtual std::string Get(const std::string& field, double timeout = 5.0); /// \brief sets an attribute of this web resource - virtual void Set(const std::string& field, const std::string& newvalue); + virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); /// \brief delete the resource and all its child resources - virtual void Delete(); + virtual void Delete(double timeout = 5.0); /// \brief copy the resource and all its child resources to a new name - virtual void Copy(const std::string& newname, int options); + virtual void Copy(const std::string& newname, int options, double timeout = 5.0); private: ControllerClientPtr __controller; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 5faf1585..d188360f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -108,27 +108,27 @@ WebResource::WebResource(ControllerClientPtr controller, const std::string& reso BOOST_ASSERT(__pk.size()>0); } -std::string WebResource::Get(const std::string& field) +std::string WebResource::Get(const std::string& field, double timeout) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt); + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, timeout); std::string fieldvalue = pt.get(field); return fieldvalue; } -void WebResource::Set(const std::string& field, const std::string& newvalue) +void WebResource::Set(const std::string& field, const std::string& newvalue, double timeout) { throw MujinException("not implemented"); } -void WebResource::Delete() +void WebResource::Delete(double timeout) { GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey())); + controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey()), timeout); } -void WebResource::Copy(const std::string& newname, int options) +void WebResource::Copy(const std::string& newname, int options, double timeout) { throw MujinException("not implemented yet"); } From afec2c5e579ba054a7d0cda75ffeb387fb88b346 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 16 Nov 2016 20:20:10 +0900 Subject: [PATCH 179/477] organize windows boost hacks --- src/controllerclientimpl.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 74c66e47..a0421a24 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -25,6 +25,7 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); #define CURL_OPTION_SAVER(curl, curlopt, curvalue, curltype) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)); + namespace mujinclient { class CurlTimeoutSetter @@ -681,15 +682,8 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_t res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( _buffer.rdbuf()->in_avail() > 0 ) { -#ifdef _WIN32 - // sometimes buffer can container \n or \\, which windows boost property_tree does not like - std::string newbuffer; - std::vector< std::pair > serachpairs(2); - serachpairs[0].first = "\n"; serachpairs[0].second = ""; - serachpairs[1].first = "\\"; serachpairs[1].second = ""; - SearchAndReplace(newbuffer, _buffer.str(), serachpairs); - std::stringstream newss(newbuffer); - boost::property_tree::read_json(newss, pt); +#if defined(_WIN32) || defined(_WIN64) + ParsePropertyTreeWin(_buffer.str(), pt); #else boost::property_tree::read_json(_buffer, pt); #endif @@ -729,7 +723,11 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { if( outputdata.size() > 0 ) { boost::property_tree::ptree pt; - boost::property_tree::read_json(_buffer, pt); +#if defined(_WIN32) || defined(_WIN64) + ParsePropertyTreeWin(_buffer.str(), pt); +#else + boost::property_tree::read_json(_buffer, pt); +#endif std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); @@ -770,7 +768,11 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector("error_message", std::string()); traceback = pt.get("traceback", std::string()); } @@ -807,7 +809,11 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( _buffer.rdbuf()->in_avail() > 0 ) { +#if defined(_WIN32) || defined(_WIN64) + ParsePropertyTreeWin(_buffer.str(), pt); +#else boost::property_tree::read_json(_buffer, pt); +#endif } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); @@ -849,7 +855,11 @@ int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::str res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( _buffer.rdbuf()->in_avail() > 0 ) { +#if defined(_WIN32) || defined(_WIN64) + ParsePropertyTreeWin(_buffer.str(), pt); +#else boost::property_tree::read_json(_buffer, pt); +#endif } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); From efa6dd95cd0948e05c9f729610ab7b6e05e39f9c Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Thu, 17 Nov 2016 12:33:49 +0900 Subject: [PATCH 180/477] windows fix about replacing slash. tidyng --- src/controllerclientimpl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index a0421a24..92e3234e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -683,7 +683,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_t CHECKCURLCODE(res, "curl_easy_getinfo"); if( _buffer.rdbuf()->in_avail() > 0 ) { #if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); + ParsePropertyTreeWin(_buffer.str(), pt); #else boost::property_tree::read_json(_buffer, pt); #endif @@ -724,9 +724,9 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp if( outputdata.size() > 0 ) { boost::property_tree::ptree pt; #if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); + ParsePropertyTreeWin(_buffer.str(), pt); #else - boost::property_tree::read_json(_buffer, pt); + boost::property_tree::read_json(_buffer, pt); #endif std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); @@ -769,7 +769,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vectorin_avail() > 0 ) { #if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); + ParsePropertyTreeWin(_buffer.str(), pt); #else boost::property_tree::read_json(_buffer, pt); #endif @@ -856,7 +856,7 @@ int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::str CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( _buffer.rdbuf()->in_avail() > 0 ) { #if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); + ParsePropertyTreeWin(_buffer.str(), pt); #else boost::property_tree::read_json(_buffer, pt); #endif From ed547220eaee909cade2a3b9bb60427cefcd03ac Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 23 Nov 2016 19:42:16 +0900 Subject: [PATCH 181/477] grab and release api and sample code. fix lexical_cast not working. this is related to #3247 --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 92e3234e..74c0e3d4 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -422,7 +422,7 @@ void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, statuses.resize(objects.size()); FOREACH(v, objects) { statuses[i].pk = v->second.get("pk"); - statuses[i].code = static_cast(boost::lexical_cast(v->second.get("status"))); + statuses[i].code = GetStatusCode(v->second.get("status")); statuses[i].type = v->second.get("fnname"); statuses[i].elapsedtime = v->second.get("elapsedtime"); if( options & 1 ) { From a7e2e218bf69fd5009dcb192f9fa6e52fccd6417 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 23 Nov 2016 19:42:16 +0900 Subject: [PATCH 182/477] grab and release api and sample code. fix lexical_cast not working. this is related to #3247 --- .../mujincontrollerclient.h | 7 +++++++ src/mujincontrollerclient.cpp | 21 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9d9fe045..4d000787 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -183,6 +183,13 @@ enum JobStatusCode { JSC_Unknown = 0xffffffff, ///< the job is unknown }; + +/// \brief get status code from string representation +/// +/// \param str string representation of status +/// \return JobStatusCode equivalent +JobStatusCode GetStatusCode(const std::string& str); + struct JobStatus { JobStatus() : code(JSC_Unknown) { diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d188360f..1c5a3f7c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -742,6 +742,23 @@ void TaskResource::Cancel() BOOST_ASSERT(0); } +JobStatusCode GetStatusCode(const std::string& str) +{ + MUJIN_LOG_INFO(str); + if (str == "pending") return JSC_Pending; + if (str == "active") return JSC_Active; + if (str == "preempted") return JSC_Preempted; + if (str == "succeeded") return JSC_Succeeded; + if (str == "aborted") return JSC_Aborted; + if (str == "rejected") return JSC_Rejected; + if (str == "preempting") return JSC_Preempting; + if (str == "recalling") return JSC_Recalling; + if (str == "recalled") return JSC_Recalled; + if (str == "lost") return JSC_Lost; + if (str == "unknown") return JSC_Unknown; + throw MUJIN_EXCEPTION_FORMAT("unknown staus %s", str, MEC_InvalidArguments); +} + void TaskResource::GetRunTimeStatus(JobStatus& status, int options) { status.code = JSC_Unknown; @@ -755,7 +772,7 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) controller->CallGet(url, pt); //pt.get("error_message") status.pk = pt.get("pk"); - status.code = static_cast(boost::lexical_cast(pt.get("status"))); + status.code = GetStatusCode(pt.get("status")); status.type = pt.get("fnname"); status.elapsedtime = pt.get("elapsedtime"); if( options & 1 ) { @@ -941,7 +958,7 @@ void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) controller->CallGet(url, pt); //pt.get("error_message") status.pk = pt.get("pk"); - status.code = static_cast(boost::lexical_cast(pt.get("status"))); + status.code = GetStatusCode(pt.get("status")); status.type = pt.get("fnname"); status.elapsedtime = pt.get("elapsedtime"); if( options & 1 ) { From 4203e016bc458e646776b59178979f6e3679b2c3 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 23 Nov 2016 22:38:15 +0900 Subject: [PATCH 183/477] add and delete geometry --- src/controllerclientimpl.cpp | 100 ++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 74c0e3d4..6c9d5648 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -142,7 +142,8 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _username = usernamepassword.substr(0,usernameindex); std::string password = usernamepassword.substr(usernameindex+1); - _httpheaders = NULL; + _httpheadersjson = NULL; + _httpheadersstl = NULL; if( baseuri.size() > 0 ) { _baseuri = baseuri; // ensure trailing slash @@ -294,8 +295,8 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, std::stringstream ss; ss << "setting character set to " << _charset; MUJIN_LOG_INFO(ss.str()); - _SetHTTPHeaders(); - + _SetHTTPHeadersJSON(); + _SetHTTPHeadersSTL(); try { GetProfile(); } @@ -307,8 +308,11 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, ControllerClientImpl::~ControllerClientImpl() { - if( !!_httpheaders ) { - curl_slist_free_all(_httpheaders); + if( !!_httpheadersjson ) { + curl_slist_free_all(_httpheadersjson); + } + if( !!_httpheadersstl ) { + curl_slist_free_all(_httpheadersstl); } curl_easy_cleanup(_curl); } @@ -327,7 +331,7 @@ void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); _charset = newencoding; - _SetHTTPHeaders(); + _SetHTTPHeadersJSON(); } void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) @@ -342,7 +346,7 @@ void ControllerClientImpl::SetLanguage(const std::string& language) if (language!= "") { _language = language; } - _SetHTTPHeaders(); + _SetHTTPHeadersJSON(); } void ControllerClientImpl::RestartServer(double timeout) @@ -394,7 +398,7 @@ void ControllerClientImpl::Upgrade(const std::vector& vdata) res = curl_easy_perform(_curl); curl_formfree(formpost); // reset the headers before any exceptions are thrown - _SetHTTPHeaders(); + _SetHTTPHeadersJSON(); CHECKCURLCODE(res, "curl_easy_perform failed"); long http_code = 0; res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); @@ -792,6 +796,7 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st { CurlTimeoutSetter timeoutsetter(_curl, timeout); boost::mutex::scoped_lock lock(_mutex); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersjson); _uri = _baseapiuri; _uri += relativeuri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); @@ -833,9 +838,10 @@ int ControllerClientImpl::CallPost_UTF16(const std::string& relativeuri, const s return CallPost(relativeuri, encoding::ConvertUTF16ToFileSystemEncoding(data), pt, expectedhttpcode, timeout); } -int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, boost::property_tree::ptree& pt, curl_slist* headers, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headers);//isJson ? _httpheadersjson : _httpheadersstl); CurlTimeoutSetter timeoutsetter(_curl, timeout); _uri = _baseapiuri; _uri += relativeuri; @@ -846,8 +852,8 @@ int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::str CHECKCURLCODE(res, "failed to set writer"); CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, nDataSize);//data.size()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, pdata);//data.size() > 0 ? data.c_str() : NULL); res = curl_easy_perform(_curl); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -864,11 +870,21 @@ int ControllerClientImpl::CallPut(const std::string& relativeuri, const std::str if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = pt.get("error_message", std::string()); std::string traceback = pt.get("traceback", std::string()); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP PUT to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } return http_code; } +int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +{ + return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, 30); +} + +int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +{ + return _CallPut(relativeuri, static_cast(&data), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); +} + void ControllerClientImpl::CallDelete(const std::string& relativeuri, double timeout) { boost::mutex::scoped_lock lock(_mutex); @@ -963,6 +979,25 @@ std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string return utf16; } +std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, double timeout) +{ + boost::property_tree::ptree pt; + const std::string geometryData("{\"name\":\"" + name + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"mesh\"}"); + const std::string uri(str(boost::format("object\/%s\/geometry\/") % objectPk)); + + CallPost(uri, geometryData, pt, 201, timeout); + return pt.get("pk"); +} + +std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit, double timeout) +{ + boost::property_tree::ptree pt; + const std::string uri(str(boost::format("object\/%s\/geometry\/%s\/")%objectPk%geometryPk)); + const int status = CallPutSTL(uri, data, pt, 202, timeout); + assert(status == 202); + return pt.get("pk"); +} + void ControllerClientImpl::GetProfile() { _profile.clear(); @@ -987,26 +1022,43 @@ int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t n return size * nmemb; } -void ControllerClientImpl::_SetHTTPHeaders() +void ControllerClientImpl::_SetHTTPHeadersJSON() { // set the header to only send json std::string s = std::string("Content-Type: application/json; charset=") + _charset; - if( !!_httpheaders ) { - curl_slist_free_all(_httpheaders); + if( !!_httpheadersjson ) { + curl_slist_free_all(_httpheadersjson); } - _httpheaders = curl_slist_append(NULL, s.c_str()); + _httpheadersjson = curl_slist_append(NULL, s.c_str()); s = str(boost::format("Accept-Language: %s,en-us")%_language); - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); //,en;q=0.7,ja;q=0.3',") + _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); //,en;q=0.7,ja;q=0.3',") s = str(boost::format("Accept-Charset: %s")%_charset); - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); - //_httpheaders = curl_slist_append(_httpheaders, "Accept:"); // necessary? + _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); + //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept:"); // necessary? + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); + _httpheadersjson = curl_slist_append(_httpheadersjson, "Connection: Keep-Alive"); + _httpheadersjson = curl_slist_append(_httpheadersjson, "Keep-Alive: 20"); // keep alive for 20s? + // test on windows first + //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept-Encoding: gzip, deflate"); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersjson); +} + +void ControllerClientImpl::_SetHTTPHeadersSTL() +{ + // set the header to only send stl + std::string s = std::string("Content-Type: application/sla"); + if( !!_httpheadersstl ) { + curl_slist_free_all(_httpheadersstl); + } + _httpheadersstl = curl_slist_append(NULL, s.c_str()); + //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept:"); // necessary? s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - _httpheaders = curl_slist_append(_httpheaders, s.c_str()); - _httpheaders = curl_slist_append(_httpheaders, "Connection: Keep-Alive"); - _httpheaders = curl_slist_append(_httpheaders, "Keep-Alive: 20"); // keep alive for 20s? + _httpheadersstl = curl_slist_append(_httpheadersstl, s.c_str()); + _httpheadersstl = curl_slist_append(_httpheadersstl, "Connection: Keep-Alive"); + _httpheadersstl = curl_slist_append(_httpheadersstl, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first - //_httpheaders = curl_slist_append(_httpheaders, "Accept-Encoding: gzip, deflate"); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheaders); + //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); } std::string ControllerClientImpl::_GetCSRFFromCookies() { From 9b5251a341e46f5ad86edd17c827e17f9f998592 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 23 Nov 2016 22:38:15 +0900 Subject: [PATCH 184/477] add and delete geometry --- .../mujincontrollerclient.h | 31 +++++++++++- src/mujincontrollerclient.cpp | 48 +++++++++++++++---- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 4d000787..928687b5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -628,6 +628,18 @@ class MUJINCLIENT_API ControllerClient /// /// \return utf-16 encoded name virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; + + virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, double timeout) = 0; + + /// \brief set geometry mesh to an object + /// \param objectPk primary key for the object to set mesh data to + /// \param geometryPk primary key for the geometry + /// \param data stl format binary mesh data + /// \param unit length unit of mesh + /// \param timeout timeout of uploading mesh + /// + virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; + }; class MUJINCLIENT_API WebResource @@ -667,25 +679,40 @@ class MUJINCLIENT_API WebResource class MUJINCLIENT_API ObjectResource : public WebResource { public: + class MUJINCLIENT_API GeometryResource : public WebResource { +public: + GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~GeometryResource() { + } + std::string name; + std::string pk; + }; + typedef boost::shared_ptr GeometryResourcePtr; + class MUJINCLIENT_API LinkResource : public WebResource { public: LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); virtual ~LinkResource() { } + virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout); + + virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); + std::vector attachmentpks; std::string name; std::string pk; + std::string objectpk; // is this necessary? //TODO transforms }; typedef boost::shared_ptr LinkResourcePtr; + ObjectResource(ControllerClientPtr controller, const std::string& pk); virtual ~ObjectResource() { } - virtual void GetLinks(std::vector& links); - + std::string name; int nundof; std::string datemodified; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1c5a3f7c..7e8476fd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -141,10 +141,40 @@ ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string { } -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk) +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), objectpk(objectpk) { } +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk) +{ +} + +ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + const std::string& linkpk = GetPrimaryKey(); + const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, timeout); + + controller->SetObjectGeometryMesh(this->objectpk, geometryPk, rawstldata, unit, timeout); + return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, geometryPk)); +} + +ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); + controller->CallGet(relativeuri, pt); + boost::property_tree::ptree& objects = pt.get_child("geometries"); + FOREACH(v, objects) { + if (v->second.find("name") != v->second.not_found() && v->second.get("name") == geometryName) { + return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk"))); + } + } + throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); +} + void ObjectResource::GetLinks(std::vector& links) { GETCONTROLLERIMPL(); @@ -305,7 +335,7 @@ void SceneResource::InstObject::SetTransform(const Transform& t) GETCONTROLLERIMPL(); boost::property_tree::ptree pt; std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); + controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } void SceneResource::InstObject::SetDOFValues() @@ -324,7 +354,7 @@ void SceneResource::InstObject::SetDOFValues() } } ss << "]}"; - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); + controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } @@ -355,7 +385,7 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str ss << "]}"; GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); + controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) @@ -381,7 +411,7 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: ss << "]}"; GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); + controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } } std::stringstream ss; @@ -481,7 +511,7 @@ void SceneResource::SetInstObjectsState(const std::vectorCallPut(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); + controller->CallPutJSON(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname, int options) @@ -911,7 +941,7 @@ void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparame SearchAndReplace(program, taskparameters.program, serachpairs); std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); + controller->CallPutJSON(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } PlanningResultResourcePtr TaskResource::GetResult() @@ -973,7 +1003,7 @@ void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimiz std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; std::string optimizationgoalput = str(boost::format("{\"optimizationtype\":\"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); + controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizationParameters& optparams) @@ -991,7 +1021,7 @@ void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizatio } optimizationgoalput << "} }"; boost::property_tree::ptree pt; - controller->CallPut(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); + controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); } void OptimizationResource::GetResults(std::vector& results, int startoffset, int num) From 7d5f375a30a199e31226a60d5b6346a13b9a0203 Mon Sep 17 00:00:00 2001 From: rosen Date: Sun, 27 Nov 2016 13:34:17 +0900 Subject: [PATCH 185/477] fix msvc compilation --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 6c9d5648..e4cef554 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -875,7 +875,7 @@ int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* p return http_code; } -int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, 30); } From 5135e7c44ffaeb5fd6ef08594637e9ea9b539ccd Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Tue, 29 Nov 2016 14:17:40 +0900 Subject: [PATCH 186/477] documentation and code cleanups --- src/controllerclientimpl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e4cef554..b65a9a9e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -979,21 +979,21 @@ std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string return utf16; } -std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, double timeout) +std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, double timeout) { boost::property_tree::ptree pt; - const std::string geometryData("{\"name\":\"" + name + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"mesh\"}"); - const std::string uri(str(boost::format("object\/%s\/geometry\/") % objectPk)); + const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"mesh\"}"); + const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); CallPost(uri, geometryData, pt, 201, timeout); return pt.get("pk"); } -std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit, double timeout) +std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) { boost::property_tree::ptree pt; - const std::string uri(str(boost::format("object\/%s\/geometry\/%s\/")%objectPk%geometryPk)); - const int status = CallPutSTL(uri, data, pt, 202, timeout); + const std::string uri(str(boost::format("object/%s/geometry/%s/")%objectPk%geometryPk)); + const int status = CallPutSTL(uri, meshData, pt, 202, timeout); assert(status == 202); return pt.get("pk"); } From cefdcf33c2b9f49b1142b587c54a15d6993404da Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 30 Nov 2016 17:38:34 +0900 Subject: [PATCH 187/477] api and sample for creating and deleting an object --- .../mujincontrollerclient.h | 12 +++++++++++- src/mujincontrollerclient.cpp | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 928687b5..5d92a487 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -917,7 +917,17 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetInstObjects(std::vector& instobjects); virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); - virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translate[3]); + /// \brief creates an inst object in scene + /// \param name name of the object to create + /// \param referenceUri uri to reference. Leave empty to reference nothing. + /// \param quaternion quaternion of the object + /// \param translate translation of the object + /// \return pointer to inst object created + virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3]); + + /// \brief deletes an inst object in scene + /// \param pk primary key of the object to delete + virtual void DeleteInstObject(const std::string& pk); virtual SceneResourcePtr Copy(const std::string& name); }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 7e8476fd..2d2687cd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -733,16 +733,29 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO return false; } -SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& reference_uri, Real quaternion[4], Real translation[3]) +SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translation[3]) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallPost(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"reference_uri\":\"%s\",\"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f] }")%name%reference_uri%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translation[0]%translation[1]%translation[2]), pt); + const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey())); + std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translation[0]%translation[1]%translation[2])); + if (!referenceUri.empty()) { + data += ", \"reference_uri\": \"" + referenceUri + "\""; + } + data += "}"; + + controller->CallPost(uri, data, pt); std::string inst_pk = pt.get("pk"); SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); return instobject; } +void SceneResource::DeleteInstObject(const std::string& pk) +{ + GETCONTROLLERIMPL(); + controller->CallDelete(str(boost::format("scene/%s/instobject/%s/")%GetPrimaryKey()%pk)); +} + SceneResourcePtr SceneResource::Copy(const std::string& name) { GETCONTROLLERIMPL(); From 63065c5a52b9ba28ab851f69116064a2f121e7eb Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Wed, 7 Dec 2016 19:39:29 +0900 Subject: [PATCH 188/477] bug fix not respecting unit and timeout --- src/controllerclientimpl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b65a9a9e..1bfef7a0 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -877,7 +877,7 @@ int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* p int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { - return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, 30); + return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, timeout); } int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) @@ -992,7 +992,8 @@ std::string ControllerClientImpl::CreateObjectGeometry(const std::string& object std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) { boost::property_tree::ptree pt; - const std::string uri(str(boost::format("object/%s/geometry/%s/")%objectPk%geometryPk)); + const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); + std::cout << uri << std::endl; const int status = CallPutSTL(uri, meshData, pt, 202, timeout); assert(status == 202); return pt.get("pk"); From b50140ce84aee68168cecdf879d1959bb5bef6a0 Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Tue, 13 Dec 2016 19:18:58 +0900 Subject: [PATCH 189/477] add timeout argument to CreateInstObject --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5d92a487..7ed5d334 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -923,7 +923,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \param quaternion quaternion of the object /// \param translate translation of the object /// \return pointer to inst object created - virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3]); + virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout = 300); /// \brief deletes an inst object in scene /// \param pk primary key of the object to delete diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 2d2687cd..52adb13c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -733,7 +733,7 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO return false; } -SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translation[3]) +SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translation[3], double timeout) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; @@ -744,7 +744,7 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& } data += "}"; - controller->CallPost(uri, data, pt); + controller->CallPost(uri, data, pt, 201, timeout); std::string inst_pk = pt.get("pk"); SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); return instobject; From 2aca549642a0f51f9265d7420c3f7eae262d5077 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 15 Dec 2016 19:45:57 +0900 Subject: [PATCH 190/477] added preempting support to zmqclient; re-organized exceptions --- .../mujincontrollerclient.h | 70 +------------------ 1 file changed, 2 insertions(+), 68 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9d9fe045..1b3560d6 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -58,84 +58,18 @@ #include #include #include +#include namespace mujinclient { #include -enum MujinErrorCode { - MEC_Failed=0, - MEC_InvalidArguments=1, ///< passed in input arguments are not valid - MEC_CommandNotSupported=3, ///< string command could not be parsed or is not supported - MEC_Assert=4, - MEC_NotInitialized=9, ///< when object is used without it getting fully initialized - MEC_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. - MEC_Timeout=11, ///< process timed out - MEC_HTTPClient=12, ///< HTTP client error - MEC_HTTPServer=13, ///< HTTP server error - MEC_UserAuthentication=14, ///< authentication failed - MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated - MEC_BinPickingError=16, ///< BinPicking failed - MEC_HandEyeCalibrationError=17, ///< HandEye Calibration failed - MEC_ZMQNoResponse=20 ///< No response from the zmq server, using REQ-REP -}; enum TaskResourceOptions { TRO_EnableZMQ=1, ///< create a task resource with zeromq client }; -inline const char* GetErrorCodeString(MujinErrorCode error) -{ - switch(error) { - case MEC_Failed: return "Failed"; - case MEC_InvalidArguments: return "InvalidArguments"; - case MEC_CommandNotSupported: return "CommandNotSupported"; - case MEC_Assert: return "Assert"; - case MEC_NotInitialized: return "NotInitialized"; - case MEC_InvalidState: return "InvalidState"; - case MEC_Timeout: return "Timeout"; - case MEC_HTTPClient: return "HTTPClient"; - case MEC_HTTPServer: return "HTTPServer"; - case MEC_UserAuthentication: return "UserAuthentication"; - case MEC_AlreadyExists: return "AlreadyExists"; - case MEC_BinPickingError: return "BinPickingError"; - case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; - case MEC_ZMQNoResponse: return "NoResponse"; - } - // should throw an exception? - return ""; -} - -/// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. -class MUJINCLIENT_API MujinException : public std::exception -{ -public: - MujinException() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { - } - MujinException(const std::string& s, MujinErrorCode error=MEC_Failed) : std::exception() { - _error = error; - _s = "mujin ("; - _s += GetErrorCodeString(_error); - _s += "): "; - _s += s; - } - virtual ~MujinException() throw() { - } - char const* what() const throw() { - return _s.c_str(); - } - const std::string& message() const { - return _s; - } - MujinErrorCode GetCode() const { - return _error; - } -private: - std::string _s; - MujinErrorCode _error; -}; - class ControllerClient; class ObjectResource; class RobotResource; @@ -1065,7 +999,7 @@ MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &trans MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); -} +} // namespace mujinclient #if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) /// Modifications controlling %boost library behavior. From ebd883c49764ebee1a5ebfbb94dc4e8df7bab2b1 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Thu, 15 Dec 2016 19:45:57 +0900 Subject: [PATCH 191/477] added preempting support to zmqclient; re-organized exceptions --- .../mujincontrollerclient/mujinexceptions.h | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 include/mujincontrollerclient/mujinexceptions.h diff --git a/include/mujincontrollerclient/mujinexceptions.h b/include/mujincontrollerclient/mujinexceptions.h new file mode 100644 index 00000000..cc44c816 --- /dev/null +++ b/include/mujincontrollerclient/mujinexceptions.h @@ -0,0 +1,113 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2016 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** \file mujinexceptions.h + \brief Exception definitions. + */ +#ifndef MUJIN_EXCEPTIONS_H +#define MUJIN_EXCEPTIONS_H + +namespace mujinclient { + +#include + +/// \brief exception throw when user interrupts the function +class MUJINCLIENT_API UserInterruptException : public std::exception +{ +public: + UserInterruptException() : std::exception() { + } + UserInterruptException(const std::string& s) : std::exception(), _s(s) { + } + virtual ~UserInterruptException() throw() { + } + char const* what() const throw() { + return _s.c_str(); + } + const std::string& message() const { + return _s; + } + +private: + std::string _s; +}; +enum MujinErrorCode { + MEC_Failed=0, + MEC_InvalidArguments=1, ///< passed in input arguments are not valid + MEC_CommandNotSupported=3, ///< string command could not be parsed or is not supported + MEC_Assert=4, + MEC_NotInitialized=9, ///< when object is used without it getting fully initialized + MEC_InvalidState=10, ///< the state of the object is not consistent with its parameters, or cannot be used. This is usually due to a programming error where a vector is not the correct length, etc. + MEC_Timeout=11, ///< process timed out + MEC_HTTPClient=12, ///< HTTP client error + MEC_HTTPServer=13, ///< HTTP server error + MEC_UserAuthentication=14, ///< authentication failed + MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated + MEC_BinPickingError=16, ///< BinPicking failed + MEC_HandEyeCalibrationError=17, ///< HandEye Calibration failed + MEC_ZMQNoResponse=20 ///< No response from the zmq server, using REQ-REP +}; + +inline const char* GetErrorCodeString(MujinErrorCode error) +{ + switch(error) { + case MEC_Failed: return "Failed"; + case MEC_InvalidArguments: return "InvalidArguments"; + case MEC_CommandNotSupported: return "CommandNotSupported"; + case MEC_Assert: return "Assert"; + case MEC_NotInitialized: return "NotInitialized"; + case MEC_InvalidState: return "InvalidState"; + case MEC_Timeout: return "Timeout"; + case MEC_HTTPClient: return "HTTPClient"; + case MEC_HTTPServer: return "HTTPServer"; + case MEC_UserAuthentication: return "UserAuthentication"; + case MEC_AlreadyExists: return "AlreadyExists"; + case MEC_BinPickingError: return "BinPickingError"; + case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; + case MEC_ZMQNoResponse: return "NoResponse"; + } + // should throw an exception? + return ""; +} + +/// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. +class MUJINCLIENT_API MujinException : public std::exception +{ +public: + MujinException() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { + } + MujinException(const std::string& s, MujinErrorCode error=MEC_Failed) : std::exception() { + _error = error; + _s = "mujin ("; + _s += GetErrorCodeString(_error); + _s += "): "; + _s += s; + } + virtual ~MujinException() throw() { + } + char const* what() const throw() { + return _s.c_str(); + } + const std::string& message() const { + return _s; + } + MujinErrorCode GetCode() const { + return _error; + } +private: + std::string _s; + MujinErrorCode _error; +}; + +} // namespace mujinclient +#endif From 0ad92063a611ebc6c95231ecec9c7adbb650b0dd Mon Sep 17 00:00:00 2001 From: Kei Usui Date: Tue, 17 Jan 2017 00:16:10 +0900 Subject: [PATCH 192/477] reset curl postfield every time --- src/controllerclientimpl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 1bfef7a0..fc93a752 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -758,6 +758,8 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vectorin_avail() > 0 ) { #if defined(_WIN32) || defined(_WIN64) @@ -893,6 +898,8 @@ void ControllerClientImpl::CallDelete(const std::string& relativeuri, double tim _uri += relativeuri; curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); CURLcode res = curl_easy_perform(_curl); curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default CHECKCURLCODE(res, "curl_easy_perform failed"); From a3e3cf3123d7ca50acaae0f73d2bbaa4ac81bdb8 Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 7 Sep 2017 18:31:20 +0900 Subject: [PATCH 193/477] compiles --- .../mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 562 ++++++++---------- 2 files changed, 244 insertions(+), 319 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ba519651..ff843f88 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -59,6 +59,7 @@ #include #include #include +#include namespace mujinclient { diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 52adb13c..f9acc66a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -23,25 +23,27 @@ #endif #include "logging.h" +#include "mujincontrollerclient/mujinjson.h" MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { +using namespace mujinjson; -void ExtractEnvironmentStateFromPTree(const boost::property_tree::ptree& envstatejson, EnvironmentState& envstate) +void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) { + // FIXME: is this a dict or array? envstate.clear(); - FOREACHC(objstatejson, envstatejson) { + for (rapidjson::Document::ConstValueIterator it = envstatejson.Begin(); it != envstatejson.End(); ++it) { InstanceObjectState objstate; - std::string name = objstatejson->second.get("name"); - const boost::property_tree::ptree& quatjson = objstatejson->second.get_child("quat_"); - int iquat=0; + std::string name = GetJsonValueByKey(*it, "name"); + std::vector quat = GetJsonValueByKey >(*it, "quat_"); + BOOST_ASSERT(quat.size() == 4); Real dist2 = 0; - FOREACHC(v, quatjson) { - BOOST_ASSERT(iquat<4); - Real f = boost::lexical_cast(v->second.data()); - dist2 += f * f; - objstate.transform.quaternion[iquat++] = f; + for (int i = 0; i < 4; i ++ ) { + Real f = quat[i] * quat[i]; + dist2 += f; + objstate.transform.quaternion[i] = f; } // normalize the quaternion if( dist2 > 0 ) { @@ -51,17 +53,8 @@ void ExtractEnvironmentStateFromPTree(const boost::property_tree::ptree& envstat objstate.transform.quaternion[2] *= fnorm; objstate.transform.quaternion[3] *= fnorm; } - const boost::property_tree::ptree& translationjson = objstatejson->second.get_child("translation_"); - int itranslation=0; - FOREACHC(v, translationjson) { - objstate.transform.translate[itranslation++] = boost::lexical_cast(v->second.data()); - } - const boost::property_tree::ptree& dofvaluesjson = objstatejson->second.get_child("dofvalues"); - objstate.dofvalues.resize(dofvaluesjson.size()); - unsigned int idof = 0; - FOREACHC(v, dofvaluesjson) { - objstate.dofvalues.at(idof++) = boost::lexical_cast(v->second.data()); - } + LoadJsonValueByKey(*it, "translation_", objstate.transform.translate); + LoadJsonValueByKey(*it, "dofvalues", objstate.dofvalues); envstate[name] = objstate; } } @@ -111,9 +104,9 @@ WebResource::WebResource(ControllerClientPtr controller, const std::string& reso std::string WebResource::Get(const std::string& field, double timeout) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, timeout); - std::string fieldvalue = pt.get(field); + std::string fieldvalue = GetJsonValueByKey(pt, field.c_str()); return fieldvalue; } @@ -163,13 +156,15 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFro ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); controller->CallGet(relativeuri, pt); - boost::property_tree::ptree& objects = pt.get_child("geometries"); - FOREACH(v, objects) { - if (v->second.find("name") != v->second.not_found() && v->second.get("name") == geometryName) { - return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk"))); + if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { + rapidjson::Value& objects = pt["geometries"]; + for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { + if (it->HasMember("name") && (*it)["name"].GetString() == geometryName) { + return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); + } } } throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); @@ -178,24 +173,18 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro void ObjectResource::GetLinks(std::vector& links) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("object/%s/link/?format=json&limit=0&fields=links")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("links"); - links.resize(objects.size()); + rapidjson::Value& objects = pt["links"]; + links.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v->second.get("pk"))); - + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - link->name = v->second.get("name"); - link->pk = v->second.get("pk"); + LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); + link->name = GetJsonValueByKey(*it, "name"); + link->pk = GetJsonValueByKey(*it, "pk"); - boost::property_tree::ptree& jsonattachments = v->second.get_child("attachmentpks"); - link->attachmentpks.resize(jsonattachments.size()); - size_t iattch = 0; - FOREACH(att, jsonattachments) { - link->attachmentpks[iattch++] = att->second.data(); - } + LoadJsonValueByKey(*it, "attchmentpks", link->attachmentpks); //TODO transforms links[i++] = link; @@ -213,36 +202,22 @@ RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const void RobotResource::GetTools(std::vector& tools) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/tool/?format=json&limit=0&fields=tools")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("tools"); - tools.resize(objects.size()); + rapidjson::Value& objects = pt["tools"]; + tools.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), v->second.get("pk"))); - - - tool->name = v->second.get("name"); - tool->pk = v->second.get("pk"); - tool->frame_origin = v->second.get("frame_origin"); - tool->frame_tip = v->second.get("frame_tip"); - - boost::property_tree::ptree& jsondirection = v->second.get_child("direction"); - size_t idir = 0; - FOREACH(vdir, jsondirection) { - tool->direction[idir++] = boost::lexical_cast(vdir->second.data()); - } - - size_t iquaternion = 0; - FOREACH(vquaternion, v->second.get_child("quaternion")) { - BOOST_ASSERT( iquaternion < 4 ); - tool->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); - } - size_t itranslate = 0; - FOREACH(vtranslate, v->second.get_child("translate")) { - BOOST_ASSERT( itranslate < 3 ); - tool->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); - } +// FOREACH(v, objects) { + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); + + LoadJsonValueByKey(*it, "name", tool->name); + LoadJsonValueByKey(*it, "pk", tool->pk); + LoadJsonValueByKey(*it, "frame_orgin", tool->frame_origin); + LoadJsonValueByKey(*it, "frame_tip", tool->frame_tip); + LoadJsonValueByKey(*it, "direction", tool->direction); + LoadJsonValueByKey(*it, "quaternion", tool->quaternion); + LoadJsonValueByKey(*it, "translate", tool->translate); tools[i++] = tool; } @@ -255,55 +230,42 @@ RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPt void RobotResource::GetAttachedSensors(std::vector& attachedsensors) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); - attachedsensors.resize(objects.size()); + //boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); + rapidjson::Value& objects = pt["attachedsensors"]; + attachedsensors.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), v->second.get("pk"))); - - - attachedsensor->name = v->second.get("name"); - attachedsensor->pk = v->second.get("pk"); - attachedsensor->frame_origin = v->second.get("frame_origin"); - attachedsensor->sensortype = v->second.get("sensortype"); - - size_t iquaternion = 0; - FOREACH(vquaternion, v->second.get_child("quaternion")) { - BOOST_ASSERT( iquaternion < 4 ); - attachedsensor->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); + + LoadJsonValueByKey(*it, "name", attachedsensor->name); + LoadJsonValueByKey(*it, "pk", attachedsensor->pk); + LoadJsonValueByKey(*it, "frame_origin", attachedsensor->frame_origin); + LoadJsonValueByKey(*it, "sensortype", attachedsensor->sensortype); + LoadJsonValueByKey(*it, "quaternion", attachedsensor->quaternion); + LoadJsonValueByKey(*it, "translate", attachedsensor->translate); + std::vector distortionCoeffs = GetJsonValueByPath > (*it, "/sensordata/distortion_coeffs"); + BOOST_ASSERT(distortionCoeffs.size() < 5); + for (size_t i = 0; i < distortionCoeffs.size(); i ++) { + attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; } - size_t itranslate = 0; - FOREACH(vtranslate, v->second.get_child("translate")) { - BOOST_ASSERT( itranslate < 3 ); - attachedsensor->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); + attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*it, "/sensordata/distortion_model"); + attachedsensor->sensordata.focal_length = GetJsonValueByPath(*it, "/sensordata/focal_length"); + attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*it, "/sensordata/measurement_time"); + std::vector intrinsics = GetJsonValueByPath >(*it, "/sensordata/intrinsic"); + BOOST_ASSERT(intrinsics.size() < 6); + for (size_t i = 0; i < intrinsics.size(); i++) { + attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; } - - size_t icoeff = 0; - FOREACH(coeff, v->second.get_child("sensordata.distortion_coeffs")) { - BOOST_ASSERT( icoeff < 5 ); - attachedsensor->sensordata.distortion_coeffs[icoeff++] = boost::lexical_cast(coeff->second.data()); + std::vector imgdim = GetJsonValueByPath >(*it, "/sensordata/image_dimensions"); + BOOST_ASSERT(imgdim.size() < 3); + for (size_t i = 0; i < imgdim.size(); i++) { + attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; } - attachedsensor->sensordata.distortion_model = v->second.get("sensordata.distortion_model"); - attachedsensor->sensordata.focal_length = (Real)v->second.get("sensordata.focal_length"); - attachedsensor->sensordata.measurement_time = (Real)v->second.get("sensordata.measurement_time"); - - size_t iintrinsic = 0; - FOREACH(intrinsic, v->second.get_child("sensordata.intrinsic")) { - BOOST_ASSERT( iintrinsic < 6 ); - attachedsensor->sensordata.intrinsic[iintrinsic++] = boost::lexical_cast(intrinsic->second.data()); - } - - size_t idim = 0; - FOREACH(imgdim, v->second.get_child("sensordata.image_dimensions")) { - BOOST_ASSERT( idim < 3 ); - attachedsensor->sensordata.image_dimensions[idim++] = boost::lexical_cast(imgdim->second.data()); - } - - if (boost::optional extra_parameters_ptree = v->second.get_child_optional("sensordata.extra_parameters")) { - std::string parameters_string = extra_parameters_ptree.get().data(); + if (rapidjson::Pointer("/sensordata/extra_parameteres").Get(*it)) { + std::string parameters_string = GetJsonValueByPath(*it, "/sensordata/extra_parameters"); //std::cout << "extra param " << parameters_string << std::endl; std::list results; boost::split(results, parameters_string, boost::is_any_of(" ")); @@ -333,7 +295,7 @@ SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std: void SceneResource::InstObject::SetTransform(const Transform& t) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt; std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } @@ -341,7 +303,6 @@ void SceneResource::InstObject::SetTransform(const Transform& t) void SceneResource::InstObject::SetDOFValues() { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; std::stringstream ss; ss << "{\"dofvalues\":"; ss << "["; @@ -354,6 +315,7 @@ void SceneResource::InstObject::SetDOFValues() } } ss << "]}"; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } @@ -384,7 +346,7 @@ void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::str ss << grab.Serialize(); ss << "]}"; GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } @@ -410,7 +372,7 @@ void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std:: } ss << "]}"; GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); } } @@ -430,22 +392,23 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); // task exists - boost::property_tree::ptree& objects = pt.get_child("objects"); std::string pk; - if( objects.size() > 0 ) { - pk = objects.begin()->second.get("pk"); - std::string currenttasktype = objects.begin()->second.get("tasktype"); + + if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { + rapidjson::Value& objects = pt["objects"]; + pk = GetJsonValueByKey(objects[0], "pk"); + std::string currenttasktype = GetJsonValueByKey(objects[0], "tasktype"); if( currenttasktype != tasktype ) { throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype, MEC_InvalidState); } } else { - pt.clear(); + pt.SetObject(); controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype%GetPrimaryKey()), pt); - pk = pt.get("pk"); + LoadJsonValueByKey(pt, "pk", pk); } if( pk.size() == 0 ) { @@ -490,7 +453,6 @@ void SceneResource::SetInstObjectsState(const std::vectorCallPutJSON(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); } @@ -518,15 +481,15 @@ TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname, { GETCONTROLLERIMPL(); boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); // task exists - boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { + + if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { throw MUJIN_EXCEPTION_FORMAT("could not find task with name %s", taskname, MEC_InvalidState); } - std::string pk = objects.begin()->second.get("pk"); + std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); TaskResourcePtr task(new TaskResource(GetController(), pk)); return task; } @@ -558,13 +521,13 @@ BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16 void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - taskkeys.resize(objects.size()); + rapidjson::Value& objects = pt["objects"]; + taskkeys.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - taskkeys[i++] = v->second.get("pk"); + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + taskkeys[i++] = GetJsonValueByKey(*it, "pk"); } } @@ -572,22 +535,23 @@ void SceneResource::GetSensorMapping(std::map& sensorm { GETCONTROLLERIMPL(); sensormapping.clear(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("instobjects"); - FOREACH(v, objects) { - if ( v->second.find("attachedsensors") != v->second.not_found() ) { - boost::property_tree::ptree& jsonattachedsensors = v->second.get_child("attachedsensors"); - if (jsonattachedsensors.size() > 0) { - std::string object_pk = v->second.get("object_pk"); - std::string cameracontainername = v->second.get("name"); - boost::property_tree::ptree pt_robot; + rapidjson::Value& objects = pt["instobjects"]; + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + if ( it->HasMember("attachedsensors") ) { + rapidjson::Value& jsonattachedsensors = (*it)["attachedsensors"]; + if (jsonattachedsensors.IsArray() && jsonattachedsensors.Size() > 0) { + std::string object_pk = GetJsonValueByKey(*it, "object_pk"); + std::string cameracontainername = GetJsonValueByKey(*it, "name"); + rapidjson::Document pt_robot(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%object_pk), pt_robot); - boost::property_tree::ptree& pt_attachedsensors = pt_robot.get_child("attachedsensors"); - FOREACH(sensor, pt_attachedsensors) { - std::string sensorname = sensor->second.get("name"); + rapidjson::Value& pt_attachedsensors = pt_robot["attachedsensors"]; + for (rapidjson::Document::ValueIterator itsensor = pt_attachedsensors.Begin(); + itsensor != pt_attachedsensors.End(); ++itsensor) { + std::string sensorname = GetJsonValueByKey(*itsensor, "name"); std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); - std::string cameraid = sensor->second.get("sensordata.hardware_id"); + std::string cameraid = GetJsonValueByPath(*itsensor, "/sensordata/hardware_id"); sensormapping[camerafullname] = cameraid; } } @@ -598,120 +562,73 @@ void SceneResource::GetSensorMapping(std::map& sensorm void SceneResource::GetInstObjects(std::vector& instobjects) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("instobjects"); - instobjects.resize(objects.size()); - size_t iobj = 0; - FOREACH(v, objects) { - InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), v->second.get("pk"))); - - instobject->name = v->second.get("name"); - instobject->pk = v->second.get("pk"); - instobject->object_pk = v->second.get("object_pk"); - instobject->reference_uri = v->second.get("reference_uri"); - - boost::property_tree::ptree& jsondofvalues = v->second.get_child("dofvalues"); - instobject->dofvalues.resize(jsondofvalues.size()); - size_t idof = 0; - FOREACH(vdof, jsondofvalues) { - instobject->dofvalues[idof++] = boost::lexical_cast(vdof->second.data()); - } + rapidjson::Value& objects = pt["instobjects"]; - size_t iquaternion = 0; - FOREACH(vquaternion, v->second.get_child("quaternion")) { - BOOST_ASSERT( iquaternion < 4 ); - instobject->quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); - } - size_t itranslate = 0; - FOREACH(vtranslate, v->second.get_child("translate")) { - BOOST_ASSERT( itranslate < 3 ); - instobject->translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); - } - - if( v->second.find("links") != v->second.not_found() ) { - boost::property_tree::ptree& jsonlinks = v->second.get_child("links"); - instobject->links.resize(jsonlinks.size()); + instobjects.resize(objects.Size()); + size_t iobj = 0; + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); + + LoadJsonValueByKey(*it, "name", instobject->name); + LoadJsonValueByKey(*it, "pk", instobject->pk); + LoadJsonValueByKey(*it, "object_pk", instobject->object_pk); + LoadJsonValueByKey(*it, "reference_uri", instobject->reference_uri); + LoadJsonValueByKey(*it, "dofvalues", instobject->dofvalues); + LoadJsonValueByKey(*it, "quaternion", instobject->quaternion); + LoadJsonValueByKey(*it, "translate", instobject->translate); + + if (it->HasMember("links")) { + rapidjson::Value& jsonlinks = (*it)["links"]; + instobject->links.resize(jsonlinks.Size()); size_t ilink = 0; - FOREACH(vlink, jsonlinks) { - instobject->links[ilink].name = vlink->second.get("name"); - - boost::property_tree::ptree& quatjson = vlink->second.get_child("quaternion"); - int iquat=0; - FOREACH(q, quatjson) { - BOOST_ASSERT(iquat<4); - instobject->links[ilink].quaternion[iquat++] = boost::lexical_cast(q->second.data()); - } - - boost::property_tree::ptree& transjson = vlink->second.get_child("translate"); - int itrans=0; - FOREACH(t, transjson) { - BOOST_ASSERT(itrans<3); - instobject->links[ilink].translate[itrans++] = boost::lexical_cast(t->second.data()); - } + for (rapidjson::Document::ValueIterator itlink = jsonlinks.Begin(); itlink != jsonlinks.End(); ++itlink) { + InstObject::Link& link = instobject->links[ilink]; + LoadJsonValueByKey(jsonlinks, "name", link.name); + LoadJsonValueByKey(jsonlinks, "quaternion", link.quaternion); + LoadJsonValueByKey(jsonlinks, "translate", link.translate); ilink++; } } - if( v->second.find("tools") != v->second.not_found() ) { - boost::property_tree::ptree& jsontools = v->second.get_child("tools"); - instobject->tools.resize(jsontools.size()); + if (it->HasMember("tools")) { + rapidjson::Value& jsontools = (*it)["tools"]; + instobject->tools.resize(jsontools.Size()); size_t itool = 0; - FOREACH(vtool, jsontools) { - instobject->tools[itool].name = vtool->second.get("name"); - - boost::property_tree::ptree& quatjson = vtool->second.get_child("quaternion"); - int iquat=0; - FOREACH(q, quatjson) { - BOOST_ASSERT(iquat<4); - instobject->tools[itool].quaternion[iquat++] = boost::lexical_cast(q->second.data()); - } - - boost::property_tree::ptree& transjson = vtool->second.get_child("translate"); - int itrans=0; - FOREACH(t, transjson) { - BOOST_ASSERT(itrans<3); - instobject->tools[itool].translate[itrans++] = boost::lexical_cast(t->second.data()); - } - - boost::property_tree::ptree& directionjson = vtool->second.get_child("direction"); - int idir=0; - FOREACH(d, directionjson) { - BOOST_ASSERT(idir<3); - instobject->tools[itool].direction[idir++] = boost::lexical_cast(d->second.data()); - } + for (rapidjson::Document::ValueIterator ittool = jsontools.Begin(); ittool != jsontools.End(); ++ittool) { + InstObject::Tool &tool = instobject->tools[itool]; + LoadJsonValueByKey(*ittool, "name", tool.name); + LoadJsonValueByKey(*ittool, "quaternion", tool.quaternion); + LoadJsonValueByKey(*ittool, "translate", tool.translate); + LoadJsonValueByKey(*ittool, "direction", tool.direction); itool++; } } - if( v->second.find("grabs") != v->second.not_found() ) { - boost::property_tree::ptree& jsongrabs = v->second.get_child("grabs"); - instobject->grabs.resize(jsongrabs.size()); + if (it->HasMember("grabs")) { + rapidjson::Value& jsongrabs = (*it)["grabs"]; + instobject->grabs.resize(jsongrabs.Size()); size_t igrab = 0; - FOREACH(vgrab, jsongrabs) { - instobject->grabs[igrab].instobjectpk = vgrab->second.get("instobjectpk"); - instobject->grabs[igrab].grabbed_linkpk = vgrab->second.get("grabbed_linkpk"); - instobject->grabs[igrab].grabbing_linkpk = vgrab->second.get("grabbing_linkpk"); + for (rapidjson::Document::ValueIterator itgrab = jsongrabs.Begin(); itgrab != jsongrabs.End(); ++itgrab) { + InstObject::Grab &grab = instobject->grabs[igrab]; + LoadJsonValueByKey(*itgrab, "instobjectpk", grab.instobjectpk); + LoadJsonValueByKey(*itgrab, "grabbed_linkpk", grab.grabbed_linkpk); + LoadJsonValueByKey(*itgrab, "grabbing_linkpk", grab.grabbing_linkpk); igrab++; } } - if ( v->second.find("attachedsensors") != v->second.not_found() ) { - boost::property_tree::ptree& jsonattachedsensors = v->second.get_child("attachedsensors"); - instobject->attachedsensors.resize(jsonattachedsensors.size()); + if (it->HasMember("attachedsensors")) { + rapidjson::Value& jsonattachedsensors = (*it)["attachedsensors"]; + instobject->attachedsensors.resize(jsonattachedsensors.Size()); size_t iattchedsensor = 0; - FOREACH(vattachedsensor, jsonattachedsensors) { - instobject->attachedsensors[iattchedsensor].name = vattachedsensor->second.get("name"); - size_t iquaternion = 0; - FOREACH(vquaternion, vattachedsensor->second.get_child("quaternion")) { - BOOST_ASSERT( iquaternion < 4 ); - instobject->attachedsensors[iattchedsensor].quaternion[iquaternion++] = boost::lexical_cast(vquaternion->second.data()); - } - size_t itranslate = 0; - FOREACH(vtranslate, vattachedsensor->second.get_child("translate")) { - BOOST_ASSERT( itranslate < 3 ); - instobject->attachedsensors[iattchedsensor].translate[itranslate++] = boost::lexical_cast(vtranslate->second.data()); - } + for (rapidjson::Document::ValueIterator itsensor = jsonattachedsensors.Begin(); + itsensor != jsonattachedsensors.End(); ++itsensor) { + InstObject::AttachedSensor& sensor = instobject->attachedsensors[iattchedsensor]; + LoadJsonValueByKey(*itsensor, "name", sensor.name); + LoadJsonValueByKey(*itsensor, "quaternion", sensor.quaternion); + LoadJsonValueByKey(*itsensor, "translate", sensor.translate); iattchedsensor++; } } @@ -736,7 +653,6 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translation[3], double timeout) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey())); std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translation[0]%translation[1]%translation[2])); if (!referenceUri.empty()) { @@ -744,8 +660,9 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& } data += "}"; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallPost(uri, data, pt, 201, timeout); - std::string inst_pk = pt.get("pk"); + std::string inst_pk = GetJsonValueByKey(pt, "pk"); SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); return instobject; } @@ -759,9 +676,9 @@ void SceneResource::DeleteInstObject(const std::string& pk) SceneResourcePtr SceneResource::Copy(const std::string& name) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallPost("scene/?format=json", str(boost::format("{\"name\":\"%s\", \"reference_pk\":\"%s\", \"overwrite\": \"1\"}")%name%GetPrimaryKey()), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); SceneResourcePtr scene(new SceneResource(GetController(), pk)); return scene; } @@ -773,9 +690,9 @@ TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk bool TaskResource::Execute() { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallPost("job/", str(boost::format("{\"resource_type\":\"task\", \"target_pk\":%s}")%GetPrimaryKey()), pt, 200); - _jobpk = pt.get("jobpk"); + _jobpk = GetJsonValueByKey(pt, "jobpk"); return true; } @@ -807,19 +724,20 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) status.code = JSC_Unknown; if( _jobpk.size() > 0 ) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); if( options & 1 ) { url += std::string(",status_text"); } controller->CallGet(url, pt); //pt.get("error_message") - status.pk = pt.get("pk"); - status.code = GetStatusCode(pt.get("status")); - status.type = pt.get("fnname"); - status.elapsedtime = pt.get("elapsedtime"); + LoadJsonValueByKey(pt, "pk", status.pk); + //LoadJsonValueByKey(pt, "status", status.code); + status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); + LoadJsonValueByKey(pt, "elapsedtime", status.elapsedtime); + LoadJsonValueByKey(pt, "fname", status.type); if( options & 1 ) { - status.message = pt.get("status_text"); + LoadJsonValueByKey(pt, "status_text", status.message); } } } @@ -828,13 +746,13 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const { GETCONTROLLERIMPL(); boost::shared_ptr pescapedoptimizationname = controller->GetURLEscapedString(optimizationname); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%pescapedoptimizationname), pt); // optimization exists - boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() > 0 ) { - std::string pk = objects.begin()->second.get("pk"); - std::string currentoptimizationtype = objects.begin()->second.get("optimizationtype"); + if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { + rapidjson::Value& object = pt["objects"][0]; + std::string pk = GetJsonValueByKey(object, "pk"); + std::string currentoptimizationtype = GetJsonValueByKey(object, "optimizationtype"); if( currentoptimizationtype != optimizationtype ) { throw MUJIN_EXCEPTION_FORMAT("optimization pk %s exists and has type %s, expected is %s", pk%currentoptimizationtype%optimizationtype, MEC_InvalidState); } @@ -842,9 +760,9 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const return optimization; } - pt.clear(); + pt.SetObject(); controller->CallPost(str(boost::format("task/%s/optimization/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"optimizationtype\":\"%s\", \"taskpk\":\"%s\"}")%optimizationname%optimizationtype%GetPrimaryKey()), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); return optimization; } @@ -859,64 +777,67 @@ OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF16(cons void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - optimizationkeys.resize(objects.size()); + rapidjson::Value& objects = pt["objects"]; + + optimizationkeys.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - optimizationkeys[i++] = v->second.get("pk"); + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + LoadJsonValueByKey(*it, "pk", optimizationkeys[i++]); } } void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskparameters,tasktype")%GetPrimaryKey()), pt); - std::string tasktype = pt.get("tasktype"); + std::string tasktype = GetJsonValueByKey(pt, "tasktype"); if( tasktype != "itlplanning" ) { throw MUJIN_EXCEPTION_FORMAT("task %s is type %s, expected itlplanning", GetPrimaryKey()%tasktype, MEC_InvalidArguments); } - boost::property_tree::ptree& taskparametersjson = pt.get_child("taskparameters"); + rapidjson::Value& taskparametersjson = pt["taskparameters"]; taskparameters.SetDefaults(); bool bhasreturnmode = false, bhasreturntostart = false, breturntostart = false; - FOREACH(v, taskparametersjson) { - if( v->first == "startfromcurrent" ) { - taskparameters.startfromcurrent = v->second.data() == std::string("True"); + for (rapidjson::Document::MemberIterator v = taskparametersjson.MemberBegin(); v != taskparametersjson.MemberEnd(); ++v) { + if( std::string(v->name.GetString()) == "startfromcurrent" ) { + taskparameters.startfromcurrent = std::string("True") == v->value.GetString(); } - else if( v->first == "returntostart" ) { + else if(std::string(v->name.GetString()) == "returntostart" ) { bhasreturntostart = true; - breturntostart = v->second.data() == std::string("True"); + breturntostart = std::string("True") == v->value.GetString(); } - else if( v->first == "returnmode" ) { - taskparameters.returnmode = v->second.data(); + else if( std::string(v->name.GetString()) == "returnmode" ) { + taskparameters.returnmode = v->value.GetString(); bhasreturnmode = true; } - else if( v->first == "ignorefigure" ) { - taskparameters.ignorefigure = v->second.data() == std::string("True"); + else if( std::string(v->name.GetString()) == "ignorefigure" ) { + taskparameters.ignorefigure = std::string("True") == v->value.GetString(); } - else if( v->first == "vrcruns" ) { - taskparameters.vrcruns = boost::lexical_cast(v->second.data()); + else if( std::string(v->name.GetString()) == "vrcruns" ) { + //taskparameters.vrcruns = boost::lexical_cast(v->value); + LoadJsonValueByKey(taskparametersjson, "vrcruns", taskparameters.vrcruns); } - else if( v->first == "unit" ) { - taskparameters.unit = v->second.data(); + else if( std::string(v->name.GetString()) == "unit" ) { + taskparameters.unit = v->value.GetString(); } - else if( v->first == "optimizationvalue" ) { - taskparameters.optimizationvalue = boost::lexical_cast(v->second.data()); + else if( std::string(v->name.GetString()) == "optimizationvalue" ) { + LoadJsonValueByKey(taskparametersjson, "optimizationvalue", taskparameters.optimizationvalue); + //taskparameters.optimizationvalue = boost::lexical_cast(v->second.data()); } - else if( v->first == "program" ) { - taskparameters.program = v->second.data(); + else if( std::string(v->name.GetString()) == "program" ) { + taskparameters.program = v->value.GetString(); } - else if( v->first == "initial_envstate" ) { - ExtractEnvironmentStateFromPTree(v->second, taskparameters.initial_envstate); + else if( std::string(v->name.GetString()) == "initial_envstate" ) { + ExtractEnvironmentStateFromPTree(v->value, taskparameters.initial_envstate); } - else if( v->first == "final_envstate" ) { - ExtractEnvironmentStateFromPTree(v->second, taskparameters.final_envstate); + else if( std::string(v->name.GetString()) == "final_envstate" ) { + ExtractEnvironmentStateFromPTree(v->value, taskparameters.final_envstate); } else { std::stringstream ss; - ss << "unsupported ITL task parameter " << v->first; + ss << "unsupported ITL task parameter " << v->name.GetString(); MUJIN_LOG_ERROR(ss.str()); } } @@ -953,20 +874,19 @@ void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparame serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; SearchAndReplace(program, taskparameters.program, serachpairs); std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); - boost::property_tree::ptree pt; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } PlanningResultResourcePtr TaskResource::GetResult() { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - if( objects.size() == 0 ) { + if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) ) { return PlanningResultResourcePtr(); } - std::string pk = objects.begin()->second.get("pk"); + std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); PlanningResultResourcePtr result(new PlanningResultResource(GetController(), pk)); return result; } @@ -978,9 +898,9 @@ OptimizationResource::OptimizationResource(ControllerClientPtr controller, const void OptimizationResource::Execute(bool bClearOldResults) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), str(boost::format("{\"clear\":%d}")%bClearOldResults), pt, 200); - _jobpk = pt.get("jobpk"); + _jobpk = GetJsonValueByKey(pt, "jobpk"); } void OptimizationResource::Cancel() @@ -993,19 +913,20 @@ void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) status.code = JSC_Unknown; if( _jobpk.size() > 0 ) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); if( options & 1 ) { url += std::string(",status_text"); } controller->CallGet(url, pt); //pt.get("error_message") - status.pk = pt.get("pk"); - status.code = GetStatusCode(pt.get("status")); - status.type = pt.get("fnname"); - status.elapsedtime = pt.get("elapsedtime"); + LoadJsonValueByKey(pt, "pk", status.pk); + // LoadJsonValueByKey(pt, "status", status.code); + status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); + LoadJsonValueByKey(pt, "fname", status.type); + LoadJsonValueByKey(pt, "elpasedtime", status.elapsedtime); if( options & 1 ) { - status.message = pt.get("status_text"); + LoadJsonValueByKey(pt, "status-text", status.message); } } } @@ -1015,7 +936,7 @@ void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimiz GETCONTROLLERIMPL(); std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; std::string optimizationgoalput = str(boost::format("{\"optimizationtype\":\"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); - boost::property_tree::ptree pt; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); } @@ -1033,7 +954,7 @@ void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizatio optimizationgoalput << str(boost::format(", \"targetname%s\":\"%s\", \"frame%s\":\"%s\", \"ignorebasecollision%s\":\"%s\", , \"maxrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize%s_\":[ %.15f, %.15f, %.15f, %.15f]")%suffix%optparams.targetnames[itarget]%suffix%optparams.framenames[itarget]%suffix%ignorebasecollision%suffix%optparams.maxranges[itarget][0]%optparams.maxranges[itarget][1]%optparams.maxranges[itarget][2]%optparams.maxranges[itarget][3]%suffix%optparams.minranges[itarget][0]%optparams.minranges[itarget][1]%optparams.minranges[itarget][2]%optparams.minranges[itarget][3]%suffix%optparams.stepsizes[itarget][0]%optparams.stepsizes[itarget][1]%optparams.stepsizes[itarget][2]%optparams.stepsizes[itarget][3]); } optimizationgoalput << "} }"; - boost::property_tree::ptree pt; + rapidjson::Document pt; controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); } @@ -1041,13 +962,16 @@ void OptimizationResource::GetResults(std::vector& re { GETCONTROLLERIMPL(); std::string querystring = str(boost::format("optimization/%s/result/?format=json&fields=pk&order_by=task_time&offset=%d&limit=%d")%GetPrimaryKey()%startoffset%num); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(querystring, pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - results.resize(objects.size()); + if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { + return; + } + rapidjson::Value& objects = pt["objects"]; + results.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - results[i++].reset(new PlanningResultResource(controller, v->second.get("pk"))); + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + results[i++].reset(new PlanningResultResource(controller, GetJsonValueByKey(*it, "pk"))); } } @@ -1062,9 +986,9 @@ PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, c void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); - ExtractEnvironmentStateFromPTree(pt.get_child("envstate"), envstate); + ExtractEnvironmentStateFromPTree(pt["envstate"], envstate); } void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) @@ -1082,13 +1006,13 @@ void PlanningResultResource::GetRobotRawProgramData(std::string& outputdata, con void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, const std::string& programtype) { GETCONTROLLERIMPL(); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); programs.programs.clear(); controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), pt); - FOREACH(robotdatajson, pt) { - std::string robotpk = robotdatajson->first; - std::string program = robotdatajson->second.get("program"); - std::string currenttype = robotdatajson->second.get("type"); + for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { + std::string robotpk = it->name.GetString(); + std::string program = GetJsonValueByKey(it->value, "program"); + std::string currenttype = GetJsonValueByKey(it->value, "type"); programs.programs[robotpk] = RobotProgramData(program, currenttype); } } From 8e3b0a53880fdf8237ef065e191ee1a554e986da Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 7 Sep 2017 18:31:20 +0900 Subject: [PATCH 194/477] compiles --- src/controllerclientimpl.cpp | 142 +++++++++++++++-------------------- 1 file changed, 61 insertions(+), 81 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fc93a752..4a259b6a 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -28,6 +28,7 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { +using namespace mujinjson; class CurlTimeoutSetter { public: @@ -319,7 +320,7 @@ ControllerClientImpl::~ControllerClientImpl() std::string ControllerClientImpl::GetVersion() { - return _profile.get("version"); + return GetJsonValueByKey(_profile, "version"); } const std::string& ControllerClientImpl::GetUserName() const @@ -415,22 +416,23 @@ void ControllerClientImpl::CancelAllJobs() void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, int options) { - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; if( options & 1 ) { url += std::string(",status_text"); } CallGet(url, pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); + rapidjson::Value& objects = pt["objects"]; size_t i = 0; - statuses.resize(objects.size()); - FOREACH(v, objects) { - statuses[i].pk = v->second.get("pk"); - statuses[i].code = GetStatusCode(v->second.get("status")); - statuses[i].type = v->second.get("fnname"); - statuses[i].elapsedtime = v->second.get("elapsedtime"); + statuses.resize(objects.Size()); + for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { + + statuses[i].pk = GetJsonValueByKey(*it, "pk"); + statuses[i].code = GetStatusCode(GetJsonValueByKey(*it, "status")); + statuses[i].type = GetJsonValueByKey(*it, "fnname"); + statuses[i].elapsedtime = GetJsonValueByKey(*it, "elapsedtime"); if( options & 1 ) { - statuses[i].message = v->second.get("status_text"); + statuses[i].message = GetJsonValueByKey(*it, "status_text"); } i++; } @@ -438,22 +440,23 @@ void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, void ControllerClientImpl::GetScenePrimaryKeys(std::vector& scenekeys) { - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); CallGet("scene/?format=json&limit=0&fields=pk", pt); - boost::property_tree::ptree& objects = pt.get_child("objects"); - scenekeys.resize(objects.size()); + rapidjson::Value& objects = pt["objects"]; + //boost::property_tree::ptree& objects = pt.get_child("objects"); + scenekeys.resize(objects.Size()); size_t i = 0; - FOREACH(v, objects) { - scenekeys[i++] = v->second.get("pk"); + for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { + scenekeys[i++] = GetJsonValueByKey(*it, "pk"); } } SceneResourcePtr ControllerClientImpl::RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) { BOOST_ASSERT(scenetype.size()>0); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } @@ -461,9 +464,9 @@ SceneResourcePtr ControllerClientImpl::RegisterScene_UTF8(const std::string& uri SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) { BOOST_ASSERT(scenetype.size()>0); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype.c_str()), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } @@ -471,9 +474,9 @@ SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& u SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); CallPost_UTF8(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } @@ -481,9 +484,9 @@ SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::stri SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); CallPost_UTF16(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); - std::string pk = pt.get("pk"); + std::string pk = GetJsonValueByKey(pt, "pk"); SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); return scene; } @@ -662,7 +665,7 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -670,7 +673,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::propert return _CallGet(_uri, pt, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) { CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); @@ -686,15 +689,11 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_t res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); CHECKCURLCODE(res, "curl_easy_getinfo"); if( _buffer.rdbuf()->in_avail() > 0 ) { -#if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); -#else - boost::property_tree::read_json(_buffer, pt); -#endif + mujinjson::ParseJson(pt, _buffer.str()); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; @@ -726,14 +725,10 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp outputdata = _buffer.str(); if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { if( outputdata.size() > 0 ) { - boost::property_tree::ptree pt; -#if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); -#else - boost::property_tree::read_json(_buffer, pt); -#endif - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); + rapidjson::Document d; + ParseJson(d, _buffer.str()); + std::string error_message = GetJsonValueByKey(d, "error_message"); + std::string traceback = GetJsonValueByKey(d, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); @@ -769,23 +764,12 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector 0 ) { + rapidjson::Document d; std::stringstream ss; ss.write((const char*)&outputdata[0], outputdata.size()); - std::string error_message, traceback; - try { - boost::property_tree::ptree pt; -#if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(ss.str(), pt); -#else - boost::property_tree::read_json(ss, pt); -#endif - error_message = pt.get("error_message", std::string()); - traceback = pt.get("traceback", std::string()); - } - catch(const std::exception& ex) { - // probably failed parsing JSON - error_message = str(boost::format("failed to parse json: %s\nerror is %s")%ss.str()%ex.what()); - } + ParseJson(d, ss.str()); + std::string error_message = GetJsonValueByKey(d, "error_message"); + std::string traceback = GetJsonValueByKey(d, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); @@ -794,7 +778,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vectorin_avail() > 0 ) { -#if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); -#else - boost::property_tree::read_json(_buffer, pt); -#endif + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } return http_code; } -int ControllerClientImpl::CallPost_UTF8(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallPost_UTF8(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { return CallPost(relativeuri, encoding::ConvertUTF8ToFileSystemEncoding(data), pt, expectedhttpcode, timeout); } -int ControllerClientImpl::CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { return CallPost(relativeuri, encoding::ConvertUTF16ToFileSystemEncoding(data), pt, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, boost::property_tree::ptree& pt, curl_slist* headers, int expectedhttpcode, double timeout) +int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, rapidjson::Document& pt, curl_slist* headers, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headers);//isJson ? _httpheadersjson : _httpheadersstl); @@ -866,26 +848,24 @@ int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* p CHECKCURLCODE(res, "curl_easy_getinfo failed"); if( _buffer.rdbuf()->in_avail() > 0 ) { -#if defined(_WIN32) || defined(_WIN64) - ParsePropertyTreeWin(_buffer.str(), pt); -#else - boost::property_tree::read_json(_buffer, pt); -#endif + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = pt.get("error_message", std::string()); - std::string traceback = pt.get("traceback", std::string()); + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP PUT to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } return http_code; } -int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, timeout); } -int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { return _CallPut(relativeuri, static_cast(&data), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); } @@ -988,27 +968,27 @@ std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, double timeout) { - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"mesh\"}"); const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); - + CallPost(uri, geometryData, pt, 201, timeout); - return pt.get("pk"); + return GetJsonValueByKey(pt, "pk"); } std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) { - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); std::cout << uri << std::endl; const int status = CallPutSTL(uri, meshData, pt, 202, timeout); assert(status == 202); - return pt.get("pk"); + return GetJsonValueByKey(pt, "pk"); } void ControllerClientImpl::GetProfile() { - _profile.clear(); + _profile.SetObject(); CallGet("profile/", _profile); } From 84da3f28a3fc4c644804f3244554c3114a844303 Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 7 Sep 2017 18:31:20 +0900 Subject: [PATCH 195/477] compiles --- include/mujincontrollerclient/mujinjson.h | 516 ++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 include/mujincontrollerclient/mujinjson.h diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h new file mode 100644 index 00000000..abe7912c --- /dev/null +++ b/include/mujincontrollerclient/mujinjson.h @@ -0,0 +1,516 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012-2017 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** \file mujinjson.h + \brief Wrapper for rapidjson. + */ +#ifndef MUJIN_JSON_H +#define MUJIN_JSON_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace mujinjson { + +enum MujinJSONErrorCode +{ + MJE_Failed=0, +}; + +inline const char* GetErrorCodeString(MujinJSONErrorCode error) +{ + switch(error) { + case MJE_Failed: return "Failed"; + } + // throw an exception? + return ""; +} + +/// \brief Exception that MujinJSON internal methods throw; the error codes are held in \ref MujinJSONErrorCode. +class MujinJSONException : public std::exception +{ +public: + MujinJSONException() : std::exception(), _s(""), _error(MJE_Failed) { + } + MujinJSONException(const std::string& s, MujinJSONErrorCode error=MJE_Failed ) : std::exception() { + _error = error; + _s = "mujin ("; + _s += "): "; + _s += s; + _ssub = s; + } + virtual ~MujinJSONException() throw() { + } + + /// \brief outputs everything + char const* what() const throw() { + return _s.c_str(); + } + + /// \brief outputs everything + const std::string& message() const { + return _s; + } + + /// \briefs just the sub-message + const std::string& GetSubMessage() const { + return _ssub; + } + + MujinJSONErrorCode GetCode() const { + return _error; + } + +private: + std::string _s, _ssub; + MujinJSONErrorCode _error; +}; + + +// using namespace mujinclient; + +/// \brief gets a string of the Value type for debugging purposes +inline std::string GetJsonTypeName(const rapidjson::Value& v) { + int type = v.GetType(); + switch (type) { + case 0: + return "Null"; + case 1: + return "False"; + case 2: + return "True"; + case 3: + return "Object"; + case 4: + return "Array"; + case 5: + return "String"; + case 6: + return "Number"; + default: + return "Unknown"; + } +} + +inline std::string DumpJson(const rapidjson::Value& value) { + rapidjson::StringBuffer stringbuffer; + rapidjson::Writer writer(stringbuffer); + value.Accept(writer); + return std::string(stringbuffer.GetString(), stringbuffer.GetSize()); +} + +inline void ParseJson(rapidjson::Document&d, const std::string& str) { + d.Parse(str.c_str()); + if (d.HasParseError()) { + std::string substr; + if (str.length()> 200) { + substr = str.substr(0, 200); + } else { + substr = str; + } + throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr), MJE_Failed); + } +} + +class JsonSerializable { +public: + virtual void LoadFromJson(const rapidjson::Value& v) = 0; + virtual void SaveToJson(rapidjson::Value& v, rapidjson::Document::AllocatorType& alloc) const = 0; + virtual void SaveToJson(rapidjson::Document& d) const { + SaveToJson(d, d.GetAllocator()); + } +}; + +//store a json value to local data structures +//for compatibility with ptree, type conversion is made. will remove them in the future +inline void LoadJsonValue(const rapidjson::Value& v, JsonSerializable& t) { + t.LoadFromJson(v); +} + +inline void LoadJsonValue(const rapidjson::Value& v, std::string& t) { + if (v.IsString()) { + t = v.GetString(); + } else if (v.IsInt64()) { + //TODO: add warnings on all usages of lexical_cast + t = boost::lexical_cast(v.GetInt64()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to String", MJE_Failed); + } + +} + +inline void LoadJsonValue(const rapidjson::Value& v, int& t) { + if (v.IsInt()) { + t = v.GetInt(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { + if (v.IsUint()) { + t = v.GetUint(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { + if (v.IsUint64()) { + t = v.GetUint64(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int64", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { + if (v.IsUint64()) { + t = v.GetUint64(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int64", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, double& t) { + if (v.IsNumber()) { + t = v.GetDouble(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Double", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, float& t) { + if (v.IsNumber()) { + t = v.GetDouble(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Double", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { + if (v.IsInt()) t = v.GetInt(); + else if (v.IsBool()) t = v.GetBool(); + else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Bool", MJE_Failed); + } +} + +template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t); + +template inline void LoadJsonValue(const rapidjson::Value& v, boost::shared_ptr& ptr) { + T t; + LoadJsonValue(v, t); + ptr = boost::shared_ptr(new T(t)); +} + +template inline void LoadJsonValue(const rapidjson::Value& v, std::pair& t) { + if (v.IsArray()) { + if (v.GetArray().Size() == 2) { + LoadJsonValue(v[0], t.first); + LoadJsonValue(v[1], t.second); + } else { + throw MujinJSONException("List-based map has entry with size != 2", MJE_Failed); + } + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Pair", MJE_Failed); + } +} + +template inline void LoadJsonValue(const rapidjson::Value& v, T (&p)[N]) { + if (v.IsArray()) { + if (v.GetArray().Size() != N) { + throw MujinJSONException("Json array size doesn't match", MJE_Failed); + } + size_t i = 0; + for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { + LoadJsonValue(*it, p[i]); + i++; + } + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + } +} + +template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t) { + if (v.IsArray()) { + t.clear(); + t.resize(v.GetArray().Size()); + size_t i = 0; + for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { + LoadJsonValue(*it, t[i]); + i++; + } + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + } +} + +template inline void LoadJsonValue(const rapidjson::Value& v, std::map& t) { + if (v.IsArray()) { + // list based map + // TODO: is it dangerous? + for (rapidjson::Value::ConstValueIterator itr = v.Begin(); itr != v.End(); ++itr) { + std::pair value; + LoadJsonValue((*itr), value); + t[value.first] = value.second; + } + } else if (v.IsObject()) { + t.clear(); + U value; + for (rapidjson::Value::ConstMemberIterator it = v.MemberBegin(); + it != v.MemberEnd(); ++it) { + LoadJsonValue(it->value, value); + t[it->name.GetString()] = value; + } + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Map", MJE_Failed); + } +} + +//Save a data structure to rapidjson::Value format + +/*template inline void SaveJsonValue(rapidjson::Value& v, const T& t, rapidjson::Document::AllocatorType& alloc) {*/ +/*JsonWrapper::SaveToJson(v, t, alloc);*/ +/*}*/ + +inline void SaveJsonValue(rapidjson::Value& v, const JsonSerializable& t, rapidjson::Document::AllocatorType& alloc) { + t.SaveToJson(v, alloc); +} + +inline void SaveJsonValue(rapidjson::Value& v, const std::string& t, rapidjson::Document::AllocatorType& alloc) { + v.SetString(t.c_str(), alloc); +} + +inline void SaveJsonValue(rapidjson::Value& v, const char* t, rapidjson::Document::AllocatorType& alloc) { + v.SetString(t, alloc); +} + +inline void SaveJsonValue(rapidjson::Value& v, int t, rapidjson::Document::AllocatorType& alloc) { + v.SetInt(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, unsigned int t, rapidjson::Document::AllocatorType& alloc) { + v.SetUint(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, long long t, rapidjson::Document::AllocatorType& alloc) { + v.SetInt64(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, unsigned long long t, rapidjson::Document::AllocatorType& alloc) { + v.SetUint64(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, uint64_t t, rapidjson::Document::AllocatorType& alloc) { + v.SetUint64(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, bool t, rapidjson::Document::AllocatorType& alloc) { + v.SetBool(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, double t, rapidjson::Document::AllocatorType& alloc) { + v.SetDouble(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, float t, rapidjson::Document::AllocatorType& alloc) { + v.SetDouble(t); +} + +inline void SaveJsonValue(rapidjson::Value& v, const rapidjson::Value& t, rapidjson::Document::AllocatorType& alloc) { + v.CopyFrom(t, alloc); +} + +template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc); + +/** do not remove: otherwise boost::shared_ptr could be treated as bool + */ +template inline void SaveJsonValue(rapidjson::Value& v, const boost::shared_ptr& ptr, rapidjson::Document::AllocatorType& alloc) { + SaveJsonValue(v, *ptr, alloc); +} + +template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(t.size(), alloc); + for (size_t i = 0; i < t.size(); ++i) { + rapidjson::Value tmpv; + SaveJsonValue(tmpv, t[i], alloc); + v.PushBack(tmpv, alloc); + } +} + +template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(t.size(), alloc); + for (size_t i = 0; i < t.size(); ++i) { + v.PushBack(t[i], alloc); + } +} + +template inline void SaveJsonValue(rapidjson::Value& v, const std::map& t, rapidjson::Document::AllocatorType& alloc) { + v.SetObject(); + for (typename std::map::const_iterator it = t.begin(); it != t.end(); ++it) { + rapidjson::Value name, value; + SaveJsonValue(name, it->first, alloc); + SaveJsonValue(value, it->second, alloc); + v.AddMember(name, value, alloc); + } +} + +template inline void SaveJsonValue(rapidjson::Document& v, const T& t) { + SaveJsonValue(v, t, v.GetAllocator()); +} + +template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc); + +//get one json value by key, and store it in local data structures +template void inline LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t) { + if (!v.IsObject()) { + throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); + } + if (v.HasMember(key)) { + LoadJsonValue(v[key], t); + } +} +template inline void LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t, const U& d) { + if (!v.IsObject()) { + throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); + } + if (v.HasMember(key)) { + LoadJsonValue(v[key], t); + } + else { + t = d; + } +} + +//work the same as LoadJsonValueByKey, but the value is returned instead of being passed as reference +template T GetJsonValueByKey(const rapidjson::Value& v, const char* key, const U& t) { + if (!v.IsObject()) { + throw MujinJSONException("Cannot get value of non-object.", MJE_Failed); + } + if (v.HasMember(key)) { + T r; + LoadJsonValue(v[key], r); + return r; + } + else { + return T(t); + } +} +template inline T GetJsonValueByKey(const rapidjson::Value& v, const char* key) { + if (!v.IsObject()) { + throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); + } + T r = T(); + if (v.HasMember(key)) { + LoadJsonValue(v[key], r); + } + return r; +} + +template inline T GetJsonValueByPath(const rapidjson::Value& v, const char* key) { + T r; + const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); + if (child) { + LoadJsonValue(*child, r); + } + return r; +} + +template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { + const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); + if (child) { + T r; + LoadJsonValue(*child, r); + return r; + } + else { + return T(t); + } +} + +template inline void SetJsonValueByPath(rapidjson::Document& d, const char* path, const T& t) { + rapidjson::Value v; + SaveJsonValue(v, t, d.GetAllocator()); + rapidjson::Pointer(path).Swap(d, v, d.GetAllocator()); +} + +template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc) +{ + if (!v.IsObject()) { + throw MujinJSONException("Cannot set value for non-object.", MJE_Failed); + } + if (v.HasMember(key)) { + SaveJsonValue(v[key], t, alloc); + } + else { + rapidjson::Value value, name; + SaveJsonValue(name, key, alloc); + SaveJsonValue(value, t, alloc); + v.AddMember(name, value, alloc); + } +} + +template +inline void SetJsonValueByKey(rapidjson::Document& d, const char* key, const T& t) +{ + SetJsonValueByKey(d, key, t, d.GetAllocator()); +} + +template +inline void SetJsonValueByKey(rapidjson::Document& d, const std::string& key, const T& t) +{ + SetJsonValueByKey(d, key.c_str(), t, d.GetAllocator()); +} + +inline void ValidateJsonString(const std::string& str) { + rapidjson::Document d; + if (d.Parse(str.c_str()).HasParseError()) { + throw MujinJSONException("json string " + str + " is invalid." + GetParseError_En(d.GetParseError()), MJE_Failed); + } +} + +template inline std::string GetJsonString(const T& t) { + rapidjson::Document d; + SaveJsonValue(d, t); + return DumpJson(d); +} + +} // namespace mujinjson +#endif From a1c87948dab5a4990cb85a0bc6571091d309ec11 Mon Sep 17 00:00:00 2001 From: jiayu Date: Fri, 8 Sep 2017 09:03:22 +0900 Subject: [PATCH 196/477] fix typos and parse errors --- src/mujincontrollerclient.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f9acc66a..d5294464 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -246,7 +246,7 @@ void RobotResource::GetAttachedSensors(std::vector& a LoadJsonValueByKey(*it, "quaternion", attachedsensor->quaternion); LoadJsonValueByKey(*it, "translate", attachedsensor->translate); std::vector distortionCoeffs = GetJsonValueByPath > (*it, "/sensordata/distortion_coeffs"); - BOOST_ASSERT(distortionCoeffs.size() < 5); + BOOST_ASSERT(distortionCoeffs.size() <= 5); for (size_t i = 0; i < distortionCoeffs.size(); i ++) { attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; } @@ -254,17 +254,17 @@ void RobotResource::GetAttachedSensors(std::vector& a attachedsensor->sensordata.focal_length = GetJsonValueByPath(*it, "/sensordata/focal_length"); attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*it, "/sensordata/measurement_time"); std::vector intrinsics = GetJsonValueByPath >(*it, "/sensordata/intrinsic"); - BOOST_ASSERT(intrinsics.size() < 6); + BOOST_ASSERT(intrinsics.size() <= 6); for (size_t i = 0; i < intrinsics.size(); i++) { attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; } std::vector imgdim = GetJsonValueByPath >(*it, "/sensordata/image_dimensions"); - BOOST_ASSERT(imgdim.size() < 3); + BOOST_ASSERT(imgdim.size() <= 3); for (size_t i = 0; i < imgdim.size(); i++) { attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; } - if (rapidjson::Pointer("/sensordata/extra_parameteres").Get(*it)) { + if (rapidjson::Pointer("/sensordata/extra_parameters").Get(*it)) { std::string parameters_string = GetJsonValueByPath(*it, "/sensordata/extra_parameters"); //std::cout << "extra param " << parameters_string << std::endl; std::list results; @@ -585,9 +585,9 @@ void SceneResource::GetInstObjects(std::vector& in size_t ilink = 0; for (rapidjson::Document::ValueIterator itlink = jsonlinks.Begin(); itlink != jsonlinks.End(); ++itlink) { InstObject::Link& link = instobject->links[ilink]; - LoadJsonValueByKey(jsonlinks, "name", link.name); - LoadJsonValueByKey(jsonlinks, "quaternion", link.quaternion); - LoadJsonValueByKey(jsonlinks, "translate", link.translate); + LoadJsonValueByKey(*itlink, "name", link.name); + LoadJsonValueByKey(*itlink, "quaternion", link.quaternion); + LoadJsonValueByKey(*itlink, "translate", link.translate); ilink++; } } From 23930010b1a51eda7273c3231104b2b8b085ff26 Mon Sep 17 00:00:00 2001 From: jiayu Date: Fri, 8 Sep 2017 09:03:22 +0900 Subject: [PATCH 197/477] fix typos and parse errors --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 4a259b6a..f195956a 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -867,7 +867,7 @@ int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std:: int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { - return _CallPut(relativeuri, static_cast(&data), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); + return _CallPut(relativeuri, static_cast(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); } void ControllerClientImpl::CallDelete(const std::string& relativeuri, double timeout) From 03f47388f13d45b4f4ac6d71d68c24a0a051344b Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 14 Sep 2017 13:33:23 +0900 Subject: [PATCH 198/477] update how instobject resource works --- src/mujincontrollerclient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 52adb13c..35c808d2 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -573,8 +573,8 @@ void SceneResource::GetSensorMapping(std::map& sensorm GETCONTROLLERIMPL(); sensormapping.clear(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("instobjects"); + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); FOREACH(v, objects) { if ( v->second.find("attachedsensors") != v->second.not_found() ) { boost::property_tree::ptree& jsonattachedsensors = v->second.get_child("attachedsensors"); @@ -599,8 +599,8 @@ void SceneResource::GetInstObjects(std::vector& in { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=instobjects")%GetPrimaryKey()), pt); - boost::property_tree::ptree& objects = pt.get_child("instobjects"); + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("objects"); instobjects.resize(objects.size()); size_t iobj = 0; FOREACH(v, objects) { From f1a71cf3f8fe8953aee94d90db6a3faeb6ba6480 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Tue, 19 Sep 2017 18:22:23 +0900 Subject: [PATCH 199/477] Define BOOST_ENABLE_ASSERT_HANDLER in CMakeLists.txt. Move assertion_failed* to a .cpp with hidden visibility --- .../mujincontrollerclient.h | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ba519651..a398291b 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -17,10 +17,6 @@ #ifndef MUJIN_CONTROLLERCLIENT_H #define MUJIN_CONTROLLERCLIENT_H -#ifndef MUJINCLIENT_DISABLE_ASSERT_HANDLER -#define BOOST_ENABLE_ASSERT_HANDLER -#endif - #ifdef _MSC_VER #pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class @@ -1045,25 +1041,6 @@ MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& env } // namespace mujinclient -#if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) -/// Modifications controlling %boost library behavior. -namespace boost -{ -inline void assertion_failed(char const * expr, char const * function, char const * file, long line) -{ - throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr),mujinclient::MEC_Assert); -} - -#if BOOST_VERSION>104600 -inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) -{ - throw mujinclient::MujinException(boost::str(boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg),mujinclient::MEC_Assert); -} -#endif - -} -#endif - BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MAJOR>=0&&MUJINCLIENT_VERSION_MAJOR<=255); BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MINOR>=0&&MUJINCLIENT_VERSION_MINOR<=255); BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_PATCH>=0&&MUJINCLIENT_VERSION_PATCH<=255); From 2a6038410070b8fcf52f3fe27c422ce2be64b1c4 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Thu, 18 Jan 2018 16:00:46 +0900 Subject: [PATCH 200/477] Add != operators to check if the structs are updated --- .../mujincontrollerclient/mujincontrollerclient.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ba519651..f1ffcb1a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -142,6 +142,10 @@ struct Transform quaternion[0] = 1; quaternion[1] = 0; quaternion[2] = 0; quaternion[3] = 0; translate[0] = 0; translate[1] = 0; translate[2] = 0; } + bool operator!=(const Transform& other) const { + return std::memcmp(quaternion, other.quaternion, 4 * sizeof(Real)) != 0 || + std::memcmp(translate, other.translate, 3 * sizeof(Real)) != 0; + } Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] Real translate[3]; ///< translation x,y,z }; @@ -696,8 +700,17 @@ class MUJINCLIENT_API RobotResource : public ObjectResource Real translate[3]; std::string sensortype; - class SensorData { + struct SensorData { public: + bool operator!=(const SensorData& other) const { + return std::memcmp(distortion_coeffs, other.distortion_coeffs, 5 * sizeof(Real)) != 0 || + distortion_model != other.distortion_model || + focal_length != other.focal_length || + std::memcmp(image_dimensions, other.image_dimensions, 3 * sizeof(int)) != 0 || + std::memcmp(intrinsic, other.intrinsic, 6 * sizeof(Real)) != 0 || + measurement_time != other.measurement_time || + extra_parameters != other.extra_parameters; + } Real distortion_coeffs[5]; std::string distortion_model; Real focal_length; From 3807f2980f99e27ac172003cac56c03f5381b3d4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 10 May 2018 17:42:15 +0900 Subject: [PATCH 201/477] Fixed SetTaskParameters --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fc93a752..230012d3 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -887,7 +887,7 @@ int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std:: int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { - return _CallPut(relativeuri, static_cast(&data), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); + return _CallPut(relativeuri, static_cast(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); } void ControllerClientImpl::CallDelete(const std::string& relativeuri, double timeout) From 3db4c63a02e9043565c964b1996c15a76591fc57 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 10 May 2018 17:42:15 +0900 Subject: [PATCH 202/477] Fixed SetTaskParameters --- src/mujincontrollerclient.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 35c808d2..d25d729d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -948,9 +948,10 @@ void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparame // because program will inside string, encode newlines std::string program; - std::vector< std::pair > serachpairs(2); - serachpairs[0].first = "\n"; serachpairs[0].second = "\\n"; - serachpairs[1].first = "\r\n"; serachpairs[1].second = "\\n"; + std::vector< std::pair > serachpairs(3); + serachpairs[0].first = "\""; serachpairs[0].second = "\\\""; + serachpairs[1].first = "\n"; serachpairs[1].second = "\\n"; + serachpairs[2].first = "\r\n"; serachpairs[2].second = "\\n"; SearchAndReplace(program, taskparameters.program, serachpairs); std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); boost::property_tree::ptree pt; From 39a067ee39ca87cffee44e0c27fc2ae2a008c99f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 16 May 2018 18:10:55 +0900 Subject: [PATCH 203/477] fixed GetGeometryFromName --- src/mujincontrollerclient.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d25d729d..1d947c9f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -168,8 +168,11 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro controller->CallGet(relativeuri, pt); boost::property_tree::ptree& objects = pt.get_child("geometries"); FOREACH(v, objects) { - if (v->second.find("name") != v->second.not_found() && v->second.get("name") == geometryName) { - return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk"))); + if (v->second.find("name") != v->second.not_found() && v->second.get("name") == geometryName && v->second.get("linkpk") == this->pk) { + ObjectResource::GeometryResourcePtr geometry(ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk")))); + geometry->name = v->second.get("name"); + geometry->pk = v->second.get("pk"); + return geometry; } } throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); From a1cae62070ab218840717fc0bb478a7493c00861 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 16 May 2018 18:12:48 +0900 Subject: [PATCH 204/477] fixed WebResource::Get --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d25d729d..a3b1b8de 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -112,7 +112,7 @@ std::string WebResource::Get(const std::string& field, double timeout) { GETCONTROLLERIMPL(); boost::property_tree::ptree pt; - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, timeout); + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, 200, timeout); std::string fieldvalue = pt.get(field); return fieldvalue; } From 96f5e0168941d1ef876bc707427d613cc4971fc9 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 17 May 2018 12:11:44 +0900 Subject: [PATCH 205/477] GetGeometryFromName: use pk if name is not defined --- src/mujincontrollerclient.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1d947c9f..3efb05fc 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -168,9 +168,10 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro controller->CallGet(relativeuri, pt); boost::property_tree::ptree& objects = pt.get_child("geometries"); FOREACH(v, objects) { - if (v->second.find("name") != v->second.not_found() && v->second.get("name") == geometryName && v->second.get("linkpk") == this->pk) { + const std::string name = v->second.find("name") != v->second.not_found() ? v->second.get("name") : v->second.get("pk"); + if (name == geometryName && v->second.get("linkpk") == this->pk) { ObjectResource::GeometryResourcePtr geometry(ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk")))); - geometry->name = v->second.get("name"); + geometry->name = name; geometry->pk = v->second.get("pk"); return geometry; } From 6e33a164611fdcef3c493db26e522aa8c76be870 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 17 May 2018 17:37:36 +0900 Subject: [PATCH 206/477] Added GetGeometries/GetIkParams/SetJSON --- .../mujincontrollerclient.h | 36 ++++- src/mujincontrollerclient.cpp | 138 +++++++++++++++++- 2 files changed, 170 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f1ffcb1a..25de5960 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -603,6 +603,9 @@ class MUJINCLIENT_API WebResource /// \brief sets an attribute of this web resource virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); + /// \brief sets an attribute of this web resource + virtual void SetJSON(const std::string& json, double timeout = 5.0); + /// \brief delete the resource and all its child resources virtual void Delete(double timeout = 5.0); @@ -624,9 +627,30 @@ class MUJINCLIENT_API ObjectResource : public WebResource } std::string name; std::string pk; + std::string linkpk; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + bool visible; + Real diffusecolor[4]; + Real transparency; }; typedef boost::shared_ptr GeometryResourcePtr; + class MUJINCLIENT_API IkParamResource : public WebResource { +public: + IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~IkParamResource() { + } + std::string name; + std::string pk; + std::string iktype; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translation[3]; + Real direction[3]; + Real angle; + }; + typedef boost::shared_ptr IkParamResourcePtr; + class MUJINCLIENT_API LinkResource : public WebResource { public: LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); @@ -637,11 +661,15 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); + virtual void GetGeometries(std::vector& links); + std::vector attachmentpks; std::string name; std::string pk; - std::string objectpk; // is this necessary? - //TODO transforms + std::string objectpk; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + bool collision; }; typedef boost::shared_ptr LinkResourcePtr; @@ -650,6 +678,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual ~ObjectResource() { } virtual void GetLinks(std::vector& links); + + virtual void GetIkParams(std::vector& ikparams); std::string name; int nundof; @@ -661,6 +691,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource std::string scenepk; std::string unit; std::string uri; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; protected: ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9aa6107d..66c79dbb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -122,6 +122,13 @@ void WebResource::Set(const std::string& field, const std::string& newvalue, dou throw MujinException("not implemented"); } +void WebResource::SetJSON(const std::string& json, double timeout) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), json, pt, 202, timeout); +} + void WebResource::Delete(double timeout) { GETCONTROLLERIMPL(); @@ -149,6 +156,10 @@ ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controlle { } +ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk), pk) +{ +} + ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); @@ -173,12 +184,79 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro ObjectResource::GeometryResourcePtr geometry(ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk")))); geometry->name = name; geometry->pk = v->second.get("pk"); + geometry->linkpk = v->second.get("linkpk"); + geometry->visible = v->second.get("visible"); + geometry->transparency = v->second.get("transparency"); + + boost::property_tree::ptree& quatjson = v->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + geometry->quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } + + boost::property_tree::ptree& transjson = v->second.get_child("translate"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + geometry->translate[itrans++] = boost::lexical_cast(t->second.data()); + } + + boost::property_tree::ptree& colorjson = v->second.get_child("diffusecolor"); + int icolor=0; + FOREACH(c, colorjson) { + BOOST_ASSERT(icolor<4); + geometry->diffusecolor[icolor++] = boost::lexical_cast(c->second.data()); + } return geometry; } } throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); } +void ObjectResource::LinkResource::GetGeometries(std::vector& geometries) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); + controller->CallGet(relativeuri, pt); + boost::property_tree::ptree& objects = pt.get_child("geometries"); + geometries.clear(); + size_t i = 0; + FOREACH(v, objects) { + if(v->second.get("linkpk") == this->pk){ + ObjectResource::GeometryResourcePtr geometry(ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, v->second.get("pk")))); + geometry->name = v->second.find("name") != v->second.not_found() ? v->second.get("name") : v->second.get("pk"); + geometry->pk = v->second.get("pk"); + geometry->linkpk = v->second.get("linkpk"); + geometry->visible = v->second.get("visible"); + geometry->transparency = v->second.get("transparency"); + + boost::property_tree::ptree& quatjson = v->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + geometry->quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } + + boost::property_tree::ptree& transjson = v->second.get_child("translate"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + geometry->translate[itrans++] = boost::lexical_cast(t->second.data()); + } + + boost::property_tree::ptree& colorjson = v->second.get_child("diffusecolor"); + int icolor=0; + FOREACH(c, colorjson) { + BOOST_ASSERT(icolor<4); + geometry->diffusecolor[icolor++] = boost::lexical_cast(c->second.data()); + } + geometries.push_back(geometry); + } + } +} + void ObjectResource::GetLinks(std::vector& links) { GETCONTROLLERIMPL(); @@ -190,9 +268,9 @@ void ObjectResource::GetLinks(std::vector& link FOREACH(v, objects) { LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), v->second.get("pk"))); - link->name = v->second.get("name"); link->pk = v->second.get("pk"); + link->collision = v->second.get("collision"); boost::property_tree::ptree& jsonattachments = v->second.get_child("attachmentpks"); link->attachmentpks.resize(jsonattachments.size()); @@ -201,8 +279,64 @@ void ObjectResource::GetLinks(std::vector& link link->attachmentpks[iattch++] = att->second.data(); } - //TODO transforms + boost::property_tree::ptree& quatjson = v->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + link->quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } + + boost::property_tree::ptree& transjson = v->second.get_child("translate"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + link->translate[itrans++] = boost::lexical_cast(t->second.data()); + } + links[i++] = link; + + } +} + +void ObjectResource::GetIkParams(std::vector& ikparams) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + controller->CallGet(str(boost::format("object/%s/ikparam/?format=json&limit=0&fields=ikparams")%GetPrimaryKey()), pt); + boost::property_tree::ptree& objects = pt.get_child("ikparams"); + ikparams.resize(objects.size()); + size_t i = 0; + FOREACH(v, objects) { + IkParamResourcePtr ikparam(new IkParamResource(controller, GetPrimaryKey(), v->second.get("pk"))); + + ikparam->name = v->second.get("name"); + ikparam->pk = v->second.get("pk"); + ikparam->iktype = v->second.get("iktype"); + + ikparam->angle = v->second.get("angle"); + + boost::property_tree::ptree& quatjson = v->second.get_child("quaternion"); + int iquat=0; + FOREACH(q, quatjson) { + BOOST_ASSERT(iquat<4); + ikparam->quaternion[iquat++] = boost::lexical_cast(q->second.data()); + } + + boost::property_tree::ptree& transjson = v->second.get_child("translation"); + int itrans=0; + FOREACH(t, transjson) { + BOOST_ASSERT(itrans<3); + ikparam->translation[itrans++] = boost::lexical_cast(t->second.data()); + } + + boost::property_tree::ptree& directionjson = v->second.get_child("direction"); + int idirection=0; + FOREACH(d, directionjson) { + BOOST_ASSERT(idirection<3); + ikparam->translation[idirection++] = boost::lexical_cast(d->second.data()); + } + + ikparams[i++] = ikparam; } } From d6920b52e77c93418db1622dd57d565da5268552 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 17 May 2018 17:37:36 +0900 Subject: [PATCH 207/477] Added GetGeometries/GetIkParams/SetJSON --- src/controllerclientimpl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 230012d3..85d962a6 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -672,6 +672,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, boost::propert int ControllerClientImpl::_CallGet(const std::string& desturi, boost::property_tree::ptree& pt, int expectedhttpcode, double timeout) { + MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); @@ -710,6 +711,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& o int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) { + MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); @@ -751,6 +753,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { + MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); @@ -796,6 +799,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector Date: Thu, 17 May 2018 17:54:18 +0900 Subject: [PATCH 208/477] Added AddIkParam --- include/mujincontrollerclient/mujincontrollerclient.h | 4 +++- src/mujincontrollerclient.cpp | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 25de5960..e2222eae 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -680,7 +680,9 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetLinks(std::vector& links); virtual void GetIkParams(std::vector& ikparams); - + + IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype, double timeout); + std::string name; int nundof; std::string datemodified; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 66c79dbb..38bb31dd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -294,10 +294,18 @@ void ObjectResource::GetLinks(std::vector& link } links[i++] = link; - } } +ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype, double timeout) +{ + GETCONTROLLERIMPL(); + boost::property_tree::ptree pt; + const std::string ikparamPk = controller->CreateIkParam(this->pk, name, iktype, timeout); + + return ObjectResource::IkParamResourcePtr(new IkParamResource(controller, this->pk, ikparamPk)); +} + void ObjectResource::GetIkParams(std::vector& ikparams) { GETCONTROLLERIMPL(); From 08345a36b36bb31a65b6cba7bf0597c0c5856f05 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 17 May 2018 17:54:18 +0900 Subject: [PATCH 209/477] Added AddIkParam --- src/controllerclientimpl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 85d962a6..6192c204 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1002,6 +1002,16 @@ std::string ControllerClientImpl::CreateObjectGeometry(const std::string& object return pt.get("pk"); } +std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, const std::string& name, const std::string& iktype, double timeout) +{ + boost::property_tree::ptree pt; + const std::string ikparamData("{\"name\":\"" + name + "\", \"iktype\":\"" + iktype + "\"}"); + const std::string uri(str(boost::format("object/%s/ikparam/") % objectPk)); + + CallPost(uri, ikparamData, pt, 201, timeout); + return pt.get("pk"); +} + std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) { boost::property_tree::ptree pt; From ef0f94c491c48ced644259142421c5280c545f0a Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 17 May 2018 21:49:33 +0900 Subject: [PATCH 210/477] fix float value comparision --- .../mujincontrollerclient.h | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f1ffcb1a..26a1fdd1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -40,6 +40,7 @@ #define MUJINCLIENT_DEPRECATED #endif +#include #include #include #include @@ -100,6 +101,30 @@ typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef double Real; +inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { + return fabs(double(p - q)) < epsilon; +} + +template inline bool FuzzyEquals(const std::vector& p, const std::vector& q, double epsilon=1e-3) { + if (p.size() != q.size()) { + return false; + } + for (size_t i = 0; i < p.size(); ++i) { + if (!FuzzyEquals(p[i], q[i], epsilon)) { + return false; + } + } + return true; +} + +template inline bool FuzzyEquals(const T (&p)[N], const T (&q)[N], double epsilon=1e-3) { + for (size_t i = 0; i < N; ++i) { + if (!FuzzyEquals(p[i], q[i], epsilon)) { + return false; + } + } + return true; +} /// \brief status code for a job /// /// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html @@ -143,8 +168,7 @@ struct Transform translate[0] = 0; translate[1] = 0; translate[2] = 0; } bool operator!=(const Transform& other) const { - return std::memcmp(quaternion, other.quaternion, 4 * sizeof(Real)) != 0 || - std::memcmp(translate, other.translate, 3 * sizeof(Real)) != 0; + return !FuzzyEquals(quaternion, other.quaternion) || !FuzzyEquals(translate, other.translate); } Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] Real translate[3]; ///< translation x,y,z @@ -1056,6 +1080,7 @@ MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &trans MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); + } // namespace mujinclient #if !defined(MUJINCLIENT_DISABLE_ASSERT_HANDLER) && defined(BOOST_ENABLE_ASSERT_HANDLER) From 1b36171eb3db94e643b0e8b2766609b6f5041696 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Fri, 18 May 2018 07:20:15 +0900 Subject: [PATCH 211/477] make default epsilon smaller --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 26a1fdd1..cb2c9588 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -101,7 +101,7 @@ typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef double Real; -inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { +inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-6) { return fabs(double(p - q)) < epsilon; } From c30e4dc7e5c20a4667ced6a6985eb9672683dac7 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 14:24:28 +0900 Subject: [PATCH 212/477] fix --- src/mujincontrollerclient.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 27532543..ccd7efb4 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -172,7 +172,7 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { rapidjson::Value& objects = pt["geometries"]; for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string name = it->HasMember("name") && (*it)["name"].GetString() : (*it)["pk"].GetString(); + const std::string name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); if (name == geometryName && (*it)["linkpk"].GetString() == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); geometry->name = name; @@ -198,11 +198,11 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorCallGet(relativeuri, pt); if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { rapidjson::Value& objects = pt["geometries"]; - geometries.clear() + geometries.clear(); for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { if ((*it)["linkpk"].GetString() == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = it->HasMember("name") && (*it)["name"].GetString() : (*it)["pk"].GetString(); + geometry->name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); LoadJsonValueByKey(*it,"pk",geometry->pk); LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); @@ -211,6 +211,7 @@ void ObjectResource::LinkResource::GetGeometries(std::vectortranslate); LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); geometries.push_back(geometry); + } } } } @@ -228,7 +229,7 @@ void ObjectResource::GetLinks(std::vector& link LoadJsonValueByKey(*it,"name",link->name); LoadJsonValueByKey(*it,"pk",link->pk); LoadJsonValueByKey(*it,"collision",link->collision); - LoadJsonValueByKey(*it,"attchmentpks",link->attachmentpks); + LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); LoadJsonValueByKey(*it,"quaternion",link->quaternion); LoadJsonValueByKey(*it,"translate",link->translate); links[i++] = link; @@ -249,18 +250,17 @@ void ObjectResource::GetIkParams(std::vector rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("object/%s/ikparam/?format=json&limit=0&fields=ikparams")%GetPrimaryKey()), pt); rapidjson::Value& objects = pt["ikparams"]; - ikparams.resize(objects.size()); + ikparams.resize(objects.Size()); size_t i = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { IkParamResourcePtr ikparam(new IkParamResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - LoadJsonValueByKey(*it,"name",link->name); - LoadJsonValueByKey(*it,"pk",link->pk); - LoadJsonValueByKey(*it,"iktype",link->collision); - LoadJsonValueByKey(*it,"attchmentpks",link->attachmentpks); - LoadJsonValueByKey(*it,"quaternion",link->quaternion); - LoadJsonValueByKey(*it,"direction",link->direction); - LoadJsonValueByKey(*it,"translate",link->translate); - LoadJsonValueByKey(*it,"angle",link->angle); + LoadJsonValueByKey(*it,"name",ikparam->name); + LoadJsonValueByKey(*it,"pk",ikparam->pk); + LoadJsonValueByKey(*it,"iktype",ikparam->iktype); + LoadJsonValueByKey(*it,"quaternion",ikparam->quaternion); + LoadJsonValueByKey(*it,"direction",ikparam->direction); + LoadJsonValueByKey(*it,"translation",ikparam->translation); + LoadJsonValueByKey(*it,"angle",ikparam->angle); ikparams[i++] = ikparam; } } From f23a095b02b442579f85dcd173df5ca229a2ef68 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 14:24:28 +0900 Subject: [PATCH 213/477] fix --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b0d527de..aa292983 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -984,12 +984,12 @@ std::string ControllerClientImpl::CreateObjectGeometry(const std::string& object std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, const std::string& name, const std::string& iktype, double timeout) { - boost::property_tree::ptree pt; + rapidjson::Document pt(rapidjson::kObjectType); const std::string ikparamData("{\"name\":\"" + name + "\", \"iktype\":\"" + iktype + "\"}"); const std::string uri(str(boost::format("object/%s/ikparam/") % objectPk)); CallPost(uri, ikparamData, pt, 201, timeout); - return pt.get("pk"); + return GetJsonValueByKey(pt, "pk"); } std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) From 34ea290fdad58f0d43002811514998b1d538473c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 14:32:51 +0900 Subject: [PATCH 214/477] fix typo --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c3c63274..1e84d572 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -184,7 +184,7 @@ void ObjectResource::GetLinks(std::vector& link link->name = GetJsonValueByKey(*it, "name"); link->pk = GetJsonValueByKey(*it, "pk"); - LoadJsonValueByKey(*it, "attchmentpks", link->attachmentpks); + LoadJsonValueByKey(*it, "attachmentpks", link->attachmentpks); //TODO transforms links[i++] = link; From 5d6248eddb5e446182fb50a1424cf8c9cddd47a9 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 15:25:17 +0900 Subject: [PATCH 215/477] GetMesh test --- .../mujincontrollerclient.h | 3 ++ src/mujincontrollerclient.cpp | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e7222f59..6419a781 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -629,11 +629,14 @@ class MUJINCLIENT_API ObjectResource : public WebResource std::string name; std::string pk; std::string linkpk; + std::string geomtype; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; bool visible; Real diffusecolor[4]; Real transparency; + + virtual void GetMesh(std::vector >& mesh); }; typedef boost::shared_ptr GeometryResourcePtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index ccd7efb4..74b08f5c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -153,6 +153,36 @@ ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, { } +void ObjectResource::GeometryResource::GetMesh(std::vector >& mesh) +{ + GETCONTROLLERIMPL(); + rapidjson::Document pt(rapidjson::kObjectType); + const std::string relativeuri(str(boost::format("%s/%s/?format=json&mesh=true")%GetResourceName()%GetPrimaryKey())); + controller->CallGet(relativeuri, pt); + rapidjson::Value& objects = pt["mesh"]; + puts(GetJsonValueByKey(objects,"primitive").c_str()); +#if 0 + if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { + rapidjson::Value& objects = pt["geometries"]; + geometries.clear(); + for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { + if ((*it)["linkpk"].GetString() == this->pk) { + ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); + geometry->name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); + LoadJsonValueByKey(*it,"pk",geometry->pk); + LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); + LoadJsonValueByKey(*it,"visible",geometry->visible); + LoadJsonValueByKey(*it,"transparency",geometry->transparency); + LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); + LoadJsonValueByKey(*it,"translate",geometry->translate); + LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); + geometries.push_back(geometry); + } + } + } +#endif +} + ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); @@ -179,6 +209,7 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro LoadJsonValueByKey(*it,"pk",geometry->pk); LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); + LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); LoadJsonValueByKey(*it,"transparency",geometry->transparency); LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); LoadJsonValueByKey(*it,"translate",geometry->translate); @@ -206,6 +237,7 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorpk); LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); + LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); LoadJsonValueByKey(*it,"transparency",geometry->transparency); LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); LoadJsonValueByKey(*it,"translate",geometry->translate); From c15341cc1a4592237a2428ba7405fcab25f40531 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 15:26:28 +0900 Subject: [PATCH 216/477] Generalized WebResource::Get --- include/mujincontrollerclient/mujincontrollerclient.h | 9 ++++++++- src/mujincontrollerclient.cpp | 5 +---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6419a781..48b1322c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -599,7 +599,12 @@ class MUJINCLIENT_API WebResource } /// \brief gets an attribute of this web resource - virtual std::string Get(const std::string& field, double timeout = 5.0); + template + T Get(const std::string& field, double timeout = 5.0) { + rapidjson::Document pt(rapidjson::kObjectType); + GetWrap(pt, field, timeout); + return mujinjson::GetJsonValueByKey(pt, field.c_str()); + } /// \brief sets an attribute of this web resource virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); @@ -614,6 +619,8 @@ class MUJINCLIENT_API WebResource virtual void Copy(const std::string& newname, int options, double timeout = 5.0); private: + virtual void GetWrap(rapidjson::Document& pt, const std::string& field, double timeout = 5.0); + ControllerClientPtr __controller; std::string __resourcename, __pk; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 74b08f5c..f1ddc917 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -101,13 +101,10 @@ WebResource::WebResource(ControllerClientPtr controller, const std::string& reso BOOST_ASSERT(__pk.size()>0); } -std::string WebResource::Get(const std::string& field, double timeout) +void WebResource::GetWrap(rapidjson::Document& pt, const std::string& field, double timeout) { GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, 200, timeout); - std::string fieldvalue = GetJsonValueByKey(pt, field.c_str()); - return fieldvalue; } void WebResource::Set(const std::string& field, const std::string& newvalue, double timeout) From 5b94f98ba790a06fe87a556e065a36aa9127bb72 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 15:26:28 +0900 Subject: [PATCH 217/477] Generalized WebResource::Get --- include/mujincontrollerclient/mujincontrollerclient.h | 9 ++++++++- src/mujincontrollerclient.cpp | 7 ++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f5a7587c..248df50a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -599,7 +599,12 @@ class MUJINCLIENT_API WebResource } /// \brief gets an attribute of this web resource - virtual std::string Get(const std::string& field, double timeout = 5.0); + template + T Get(const std::string& field, double timeout = 5.0) { + rapidjson::Document pt(rapidjson::kObjectType); + GetWrap(pt, field, timeout); + return mujinjson::GetJsonValueByKey(pt, field.c_str()); + } /// \brief sets an attribute of this web resource virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); @@ -611,6 +616,8 @@ class MUJINCLIENT_API WebResource virtual void Copy(const std::string& newname, int options, double timeout = 5.0); private: + virtual void GetWrap(rapidjson::Document& pt, const std::string& field, double timeout = 5.0); + ControllerClientPtr __controller; std::string __resourcename, __pk; }; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1e84d572..d3c5b644 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -101,13 +101,10 @@ WebResource::WebResource(ControllerClientPtr controller, const std::string& reso BOOST_ASSERT(__pk.size()>0); } -std::string WebResource::Get(const std::string& field, double timeout) +void WebResource::GetWrap(rapidjson::Document& pt, const std::string& field, double timeout) { GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, timeout); - std::string fieldvalue = GetJsonValueByKey(pt, field.c_str()); - return fieldvalue; + controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, 200, timeout); } void WebResource::Set(const std::string& field, const std::string& newvalue, double timeout) From ba1835a17888e4427f8af216841f9747213cab1d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 18:05:12 +0900 Subject: [PATCH 218/477] Added GetMesh --- .../mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 26 +++---------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 48b1322c..db998bb2 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -643,7 +643,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource Real diffusecolor[4]; Real transparency; - virtual void GetMesh(std::vector >& mesh); + virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); }; typedef boost::shared_ptr GeometryResourcePtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f1ddc917..65067ef3 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -150,34 +150,16 @@ ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, { } -void ObjectResource::GeometryResource::GetMesh(std::vector >& mesh) +void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices) { GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); const std::string relativeuri(str(boost::format("%s/%s/?format=json&mesh=true")%GetResourceName()%GetPrimaryKey())); controller->CallGet(relativeuri, pt); rapidjson::Value& objects = pt["mesh"]; - puts(GetJsonValueByKey(objects,"primitive").c_str()); -#if 0 - if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { - rapidjson::Value& objects = pt["geometries"]; - geometries.clear(); - for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - if ((*it)["linkpk"].GetString() == this->pk) { - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); - LoadJsonValueByKey(*it,"pk",geometry->pk); - LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); - LoadJsonValueByKey(*it,"visible",geometry->visible); - LoadJsonValueByKey(*it,"transparency",geometry->transparency); - LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); - LoadJsonValueByKey(*it,"translate",geometry->translate); - LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); - geometries.push_back(geometry); - } - } - } -#endif + LoadJsonValueByKey(objects,"primitive",primitive); + LoadJsonValueByKey(objects,"indices",indices); + LoadJsonValueByKey(objects,"vertices",vertices); } ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) From 17f63534c01c7c63b0f0e88a468d09f6d933cda8 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 18 May 2018 18:27:31 +0900 Subject: [PATCH 219/477] Add ObjectResource::GeometryResource::SetGeometryFromRawSTL --- .../mujincontrollerclient/mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index db998bb2..63251cd3 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -635,6 +635,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource } std::string name; std::string pk; + std::string objectpk; std::string linkpk; std::string geomtype; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] @@ -644,6 +645,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource Real transparency; virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); + virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout); }; typedef boost::shared_ptr GeometryResourcePtr; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 65067ef3..ff5c63ba 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -142,7 +142,7 @@ ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const { } -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk) +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), objectpk(objectpk) { } @@ -162,14 +162,22 @@ void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vect LoadJsonValueByKey(objects,"vertices",vertices); } +void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout) +{ + GETCONTROLLERIMPL(); + // todo fail if this->geomtype!="mesh" + controller->SetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); +} + ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); const std::string& linkpk = GetPrimaryKey(); const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, timeout); - controller->SetObjectGeometryMesh(this->objectpk, geometryPk, rawstldata, unit, timeout); - return ObjectResource::GeometryResourcePtr(new GeometryResource(controller, this->objectpk, geometryPk)); + ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); + geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); + return geometry; } ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) From e6fb79e4b72b15d861dd2487c1110dcd2855b406 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 12:01:35 +0900 Subject: [PATCH 220/477] Added Object/Link setting visible/collision wrapper --- .../mujincontrollerclient.h | 12 +++ src/mujincontrollerclient.cpp | 76 ++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 63251cd3..bcc24853 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -646,6 +646,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout); + virtual void SetVisible(bool visible); + virtual int GetVisible(); }; typedef boost::shared_ptr GeometryResourcePtr; @@ -676,6 +678,11 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetGeometries(std::vector& links); + virtual void SetCollision(bool collision); + virtual int GetCollision(); + virtual void SetVisible(bool visible); + virtual int GetVisible(); + std::vector attachmentpks; std::string name; std::string pk; @@ -696,6 +703,11 @@ class MUJINCLIENT_API ObjectResource : public WebResource IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype, double timeout); + virtual void SetCollision(bool collision); + virtual int GetCollision(); + virtual void SetVisible(bool visible); + virtual int GetVisible(); + std::string name; int nundof; std::string datemodified; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index ff5c63ba..02d283b5 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -165,7 +165,7 @@ void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vect void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); - // todo fail if this->geomtype!="mesh" + MUJIN_ASSERT_OP_FORMAT(this->geomtype,!=,"mesh", "geomtype is not mesh: %s", this->geomtype, MEC_InvalidArguments); controller->SetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); } @@ -235,6 +235,80 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorSetJSON(mujinjson::GetJsonStringByKey("collision",collision)); + this->collision = collision; +} +void ObjectResource::SetCollision(bool collision) +{ + std::vector links; + this->GetLinks(links); + BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ + link->SetCollision(collision); + } +} +int ObjectResource::LinkResource::GetCollision() +{ + return this->collision; +} +int ObjectResource::GetCollision() +{ + std::vector links; + this->GetLinks(links); + int ret=0; + BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ + ret|=link->GetCollision()+1; + } + return ret-1; +} + +void ObjectResource::GeometryResource::SetVisible(bool visible) +{ + this->SetJSON(mujinjson::GetJsonStringByKey("visible",visible)); + this->visible = visible; +} +void ObjectResource::LinkResource::SetVisible(bool visible) +{ + std::vector geometries; + this->GetGeometries(geometries); + BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ + geometry->SetVisible(visible); + } +} +void ObjectResource::SetVisible(bool visible) +{ + std::vector links; + this->GetLinks(links); + BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ + link->SetVisible(visible); + } +} +int ObjectResource::GeometryResource::GetVisible() +{ + return this->visible; +} +int ObjectResource::LinkResource::GetVisible() +{ + std::vector geometries; + this->GetGeometries(geometries); + int ret=0; + BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ + ret|=geometry->GetVisible()+1; + } + return ret-1; +} +int ObjectResource::GetVisible() +{ + std::vector links; + this->GetLinks(links); + int ret=0; + BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ + ret|=link->GetVisible()+1; + } + return ret-1; +} + void ObjectResource::GetLinks(std::vector& links) { GETCONTROLLERIMPL(); From e2b45168197d0cc4be1efa976729c4e68e26fd3f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 12:01:35 +0900 Subject: [PATCH 221/477] Added Object/Link setting visible/collision wrapper --- include/mujincontrollerclient/mujinjson.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index abe7912c..8ba1b3f4 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -512,5 +512,11 @@ template inline std::string GetJsonString(const T& t) { return DumpJson(d); } +template inline std::string GetJsonStringByKey(const U& key, const T& t) { + rapidjson::Document d; + SetJsonValueByKey(d, key, t); + return DumpJson(d); +} + } // namespace mujinjson #endif From 3a4e8876e198d889c530def65f479cf90e6ae522 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 13:57:17 +0900 Subject: [PATCH 222/477] Added GetScenePKs --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ src/mujincontrollerclient.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index bcc24853..07bf3bf5 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -395,6 +395,9 @@ class MUJINCLIENT_API ControllerClient return RegisterScene_UTF16(uri,GetDefaultSceneType()); } + /// \brief returns a vector list of scene pks. use one of the returned elements to construct SceneResource. + virtual void GetScenePKs(std::vector &pks) = 0; + /** \brief import a scene into COLLADA format using from scene identified by a URI \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 02d283b5..08575b45 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -154,7 +154,7 @@ void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vect { GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("%s/%s/?format=json&mesh=true")%GetResourceName()%GetPrimaryKey())); + const std::string relativeuri(str(boost::format("%s/%s/?format=json&limit=0&mesh=true")%GetResourceName()%GetPrimaryKey())); controller->CallGet(relativeuri, pt); rapidjson::Value& objects = pt["mesh"]; LoadJsonValueByKey(objects,"primitive",primitive); From 5d205e7fda0cf1e51b65463c37a44ed6108503d0 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 13:57:17 +0900 Subject: [PATCH 223/477] Added GetScenePKs --- src/controllerclientimpl.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index aa292983..2f7da986 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -471,6 +471,17 @@ SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& u return scene; } +void ControllerClientImpl::GetScenePKs(std::vector& pks) +{ + rapidjson::Document pt(rapidjson::kObjectType); + CallGet("scene/?format=json&limit=0&fields=pk", pt); + rapidjson::Value &objects=pt["objects"]; + pks.clear(); + BOOST_FOREACH(const rapidjson::Value &value, std::make_pair(objects.Begin(),objects.End())){ + pks.push_back(value["pk"].GetString()); + } +} + SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); From bd50f3be2905d713d76642d7b1954472fde1a72f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 15:14:40 +0900 Subject: [PATCH 224/477] add comment --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 07bf3bf5..5e26259d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -681,6 +681,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetGeometries(std::vector& links); + /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); virtual int GetCollision(); virtual void SetVisible(bool visible); @@ -706,6 +707,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype, double timeout); + /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); virtual int GetCollision(); virtual void SetVisible(bool visible); From 8bc57fb91bfe6d868b2b1214cb0f2f2e27516733 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 18:16:25 +0900 Subject: [PATCH 225/477] Added AddLink --- .../mujincontrollerclient/mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5e26259d..494b0e6f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -705,6 +705,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetIkParams(std::vector& ikparams); + LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3], double timeout); IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype, double timeout); /// 0 -> off, 1 -> on, 2 -> partial diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 08575b45..7107c423 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -329,6 +329,14 @@ void ObjectResource::GetLinks(std::vector& link } } +ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) +{ + GETCONTROLLERIMPL(); + const std::string linkPk = controller->CreateLink(this->pk, name,quaternion, translate, timeout); + + return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->pk, linkPk)); +} + ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype, double timeout) { GETCONTROLLERIMPL(); @@ -817,11 +825,11 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO return false; } -SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translation[3], double timeout) +SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) { GETCONTROLLERIMPL(); const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey())); - std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translation[0]%translation[1]%translation[2])); + std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); if (!referenceUri.empty()) { data += ", \"reference_uri\": \"" + referenceUri + "\""; } From aa6f78abc693353c99d2220e5629bffffd88cf3b Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 18:16:25 +0900 Subject: [PATCH 226/477] Added AddLink --- src/controllerclientimpl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2f7da986..410c7d37 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1003,6 +1003,16 @@ std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, con return GetJsonValueByKey(pt, "pk"); } +std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) +{ + rapidjson::Document pt(rapidjson::kObjectType); + const std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); + const std::string uri(str(boost::format("object/%s/link/") % objectPk)); + + CallPost(uri, data, pt, 201, timeout); + return GetJsonValueByKey(pt, "pk"); +} + std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) { rapidjson::Document pt(rapidjson::kObjectType); From 71c2f9923bf6aa408a09c240534e65e0552b3506 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 21 May 2018 19:05:01 +0900 Subject: [PATCH 227/477] Added SaveJSONValue(array) --- include/mujincontrollerclient/mujinjson.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 8ba1b3f4..75bd1b85 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -382,6 +382,24 @@ template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector inline void SaveJsonValue(rapidjson::Value& v, const T (&t)[N], rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + rapidjson::Value tmpv; + SaveJsonValue(tmpv, t[i], alloc); + v.PushBack(tmpv, alloc); + } +} + +template inline void SaveJsonValue(rapidjson::Value& v, const double (&t)[N], rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + v.PushBack(t[i], alloc); + } +} + template inline void SaveJsonValue(rapidjson::Value& v, const std::map& t, rapidjson::Document::AllocatorType& alloc) { v.SetObject(); for (typename std::map::const_iterator it = t.begin(); it != t.end(); ++it) { @@ -513,7 +531,7 @@ template inline std::string GetJsonString(const T& t) { } template inline std::string GetJsonStringByKey(const U& key, const T& t) { - rapidjson::Document d; + rapidjson::Document d(rapidjson::kObjectType); SetJsonValueByKey(d, key, t); return DumpJson(d); } From b69dd7a86fbf40d9cf67fee532c454290613dd59 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 13:11:50 +0900 Subject: [PATCH 228/477] initialize pk in constructor --- src/mujincontrollerclient.cpp | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 7107c423..22800b19 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -130,23 +130,23 @@ void WebResource::Copy(const std::string& newname, int options, double timeout) throw MujinException("not implemented yet"); } -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "object", pk) +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "object", pk), pk(pk) { } -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk) +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) { } -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), objectpk(objectpk) +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), objectpk(objectpk), pk(pk) { } -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), objectpk(objectpk) +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), objectpk(objectpk), pk(pk) { } -ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk), pk) +ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk), pk), pk(pk) { } @@ -193,7 +193,6 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro if (name == geometryName && (*it)["linkpk"].GetString() == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); geometry->name = name; - LoadJsonValueByKey(*it,"pk",geometry->pk); LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); @@ -221,7 +220,6 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorpk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); geometry->name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); - LoadJsonValueByKey(*it,"pk",geometry->pk); LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); @@ -320,7 +318,6 @@ void ObjectResource::GetLinks(std::vector& link for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); LoadJsonValueByKey(*it,"name",link->name); - LoadJsonValueByKey(*it,"pk",link->pk); LoadJsonValueByKey(*it,"collision",link->collision); LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); LoadJsonValueByKey(*it,"quaternion",link->quaternion); @@ -329,18 +326,18 @@ void ObjectResource::GetLinks(std::vector& link } } -ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) +ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]) { GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->pk, name,quaternion, translate, timeout); + const std::string linkPk = controller->CreateLink(this->pk, name,quaternion, translate); return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->pk, linkPk)); } -ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype, double timeout) +ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype) { GETCONTROLLERIMPL(); - const std::string ikparamPk = controller->CreateIkParam(this->pk, name, iktype, timeout); + const std::string ikparamPk = controller->CreateIkParam(this->pk, name, iktype); return ObjectResource::IkParamResourcePtr(new IkParamResource(controller, this->pk, ikparamPk)); } @@ -356,7 +353,6 @@ void ObjectResource::GetIkParams(std::vector for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { IkParamResourcePtr ikparam(new IkParamResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); LoadJsonValueByKey(*it,"name",ikparam->name); - LoadJsonValueByKey(*it,"pk",ikparam->pk); LoadJsonValueByKey(*it,"iktype",ikparam->iktype); LoadJsonValueByKey(*it,"quaternion",ikparam->quaternion); LoadJsonValueByKey(*it,"direction",ikparam->direction); @@ -370,7 +366,7 @@ RobotResource::RobotResource(ControllerClientPtr controller, const std::string& { } -RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk) +RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk), pk(pk) { } @@ -387,7 +383,6 @@ void RobotResource::GetTools(std::vector& tools) ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); LoadJsonValueByKey(*it, "name", tool->name); - LoadJsonValueByKey(*it, "pk", tool->pk); LoadJsonValueByKey(*it, "frame_orgin", tool->frame_origin); LoadJsonValueByKey(*it, "frame_tip", tool->frame_tip); LoadJsonValueByKey(*it, "direction", tool->direction); @@ -398,7 +393,7 @@ void RobotResource::GetTools(std::vector& tools) } } -RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk) +RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk), pk(pk) { } @@ -415,7 +410,6 @@ void RobotResource::GetAttachedSensors(std::vector& a AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); LoadJsonValueByKey(*it, "name", attachedsensor->name); - LoadJsonValueByKey(*it, "pk", attachedsensor->pk); LoadJsonValueByKey(*it, "frame_origin", attachedsensor->frame_origin); LoadJsonValueByKey(*it, "sensortype", attachedsensor->sensortype); LoadJsonValueByKey(*it, "quaternion", attachedsensor->quaternion); @@ -463,7 +457,7 @@ void RobotResource::GetAttachedSensors(std::vector& a } } -SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk) +SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk), pk(pk) { } @@ -747,7 +741,6 @@ void SceneResource::GetInstObjects(std::vector& in InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); LoadJsonValueByKey(*it, "name", instobject->name); - LoadJsonValueByKey(*it, "pk", instobject->pk); LoadJsonValueByKey(*it, "object_pk", instobject->object_pk); LoadJsonValueByKey(*it, "reference_uri", instobject->reference_uri); LoadJsonValueByKey(*it, "dofvalues", instobject->dofvalues); From 4608eaba7c077e70e3a672add6d139334bb6c30c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 13:12:20 +0900 Subject: [PATCH 229/477] Fixed AddIkParam / AddLink --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 494b0e6f..6c3e98c0 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -705,8 +705,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetIkParams(std::vector& ikparams); - LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3], double timeout); - IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype, double timeout); + virtual LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]); + virtual IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype); /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); From 4a14d735dd3604e218c6f5282181baf350842fbf Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 13:12:20 +0900 Subject: [PATCH 230/477] Fixed AddIkParam / AddLink --- src/controllerclientimpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 410c7d37..c508a99e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1671,6 +1671,7 @@ void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& fil void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) { + MUJIN_LOG_INFO(str(boost::format("upload %s")%uri)) #if defined(_WIN32) || defined(_WIN64) fseek(fd,0,SEEK_END); curl_off_t filesize = ftell(fd); From cfbb1269a14dc1cb4c33aeb10fe25bdc214e99ff Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 14:58:31 +0900 Subject: [PATCH 231/477] added SceneResource::GetTaskNames --- .../mujincontrollerclient/mujincontrollerclient.h | 5 ++--- src/mujincontrollerclient.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6c3e98c0..3cb7a994 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -395,9 +395,6 @@ class MUJINCLIENT_API ControllerClient return RegisterScene_UTF16(uri,GetDefaultSceneType()); } - /// \brief returns a vector list of scene pks. use one of the returned elements to construct SceneResource. - virtual void GetScenePKs(std::vector &pks) = 0; - /** \brief import a scene into COLLADA format using from scene identified by a URI \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext @@ -924,6 +921,8 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief gets a list of all the scene primary keys currently available to the user virtual void GetTaskPrimaryKeys(std::vector& taskkeys); + virtual void GetTaskNames(std::vector& names); + /// \brief gets a list of all the instance objects of the scene virtual void GetSensorMapping(std::map& sensormapping); virtual void GetInstObjects(std::vector& instobjects); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 22800b19..7eb935f1 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -700,6 +700,19 @@ void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) } } +void SceneResource::GetTaskNames(std::vector& taskkeys) +{ + GETCONTROLLERIMPL(); + rapidjson::Document pt(rapidjson::kObjectType); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=name")%GetPrimaryKey()), pt); + rapidjson::Value& objects = pt["objects"]; + taskkeys.resize(objects.Size()); + size_t i = 0; + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + taskkeys[i++] = GetJsonValueByKey(*it, "name"); + } +} + void SceneResource::GetSensorMapping(std::map& sensormapping) { GETCONTROLLERIMPL(); From 2a132a4d9901ca8f0d42b37a64a209f8c6b7ccd4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 14:58:31 +0900 Subject: [PATCH 232/477] added SceneResource::GetTaskNames --- src/controllerclientimpl.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c508a99e..91d11270 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -471,17 +471,6 @@ SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& u return scene; } -void ControllerClientImpl::GetScenePKs(std::vector& pks) -{ - rapidjson::Document pt(rapidjson::kObjectType); - CallGet("scene/?format=json&limit=0&fields=pk", pt); - rapidjson::Value &objects=pt["objects"]; - pks.clear(); - BOOST_FOREACH(const rapidjson::Value &value, std::make_pair(objects.Begin(),objects.End())){ - pks.push_back(value["pk"].GetString()); - } -} - SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) { BOOST_ASSERT(importformat.size()>0); From c89412475476c67ce60a73d89ace355d7748bc7a Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 17:43:31 +0900 Subject: [PATCH 233/477] Fixed GetMesh signature --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3cb7a994..626c50a9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -644,7 +644,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource Real diffusecolor[4]; Real transparency; - virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); + virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout); virtual void SetVisible(bool visible); virtual int GetVisible(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 7eb935f1..50e14feb 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -150,7 +150,7 @@ ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, { } -void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices) +void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices) { GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); From 9ed3a95b53f1abd1eb5f2894b36ce274da3b1c2f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 17:45:50 +0900 Subject: [PATCH 234/477] remove debug --- src/controllerclientimpl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 91d11270..b5f82e5b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1006,7 +1006,6 @@ std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objec { rapidjson::Document pt(rapidjson::kObjectType); const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); - std::cout << uri << std::endl; const int status = CallPutSTL(uri, meshData, pt, 202, timeout); assert(status == 202); return GetJsonValueByKey(pt, "pk"); From 6755ce8c5029158836e70b7c3314c0776a4452a1 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 18:33:37 +0900 Subject: [PATCH 235/477] fixed AddLink (and added AddChildLink) --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 626c50a9..9d4df3e4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -678,6 +678,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetGeometries(std::vector& links); + virtual boost::shared_ptr AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]); + /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); virtual int GetCollision(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 50e14feb..8d40468d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -329,11 +329,19 @@ void ObjectResource::GetLinks(std::vector& link ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]) { GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->pk, name,quaternion, translate); + const std::string linkPk = controller->CreateLink(this->pk, "", name,quaternion, translate); return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->pk, linkPk)); } +ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]) +{ + GETCONTROLLERIMPL(); + const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, name,quaternion, translate); + + return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->objectpk, linkPk)); +} + ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype) { GETCONTROLLERIMPL(); From bb8f00fc9232052eb5e206bc499eb955debe7aff Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 18:33:37 +0900 Subject: [PATCH 236/477] fixed AddLink (and added AddChildLink) --- src/controllerclientimpl.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b5f82e5b..f9931d56 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -992,10 +992,14 @@ std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, con return GetJsonValueByKey(pt, "pk"); } -std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) +std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const std::string& parentlinkPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) { rapidjson::Document pt(rapidjson::kObjectType); - const std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); + std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); + if (!parentlinkPk.empty()) { + data += ", \"parentlinkpk\": \"" + parentlinkPk + "\""; + } + data += "}"; const std::string uri(str(boost::format("object/%s/link/") % objectPk)); CallPost(uri, data, pt, 201, timeout); From 91d9378ff0c661eb6fc9f2ac482ce9315ce64359 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 22 May 2018 18:56:38 +0900 Subject: [PATCH 237/477] added parentlinkpk field --- include/mujincontrollerclient/mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9d4df3e4..88a64cae 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -690,6 +690,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource std::string name; std::string pk; std::string objectpk; + std::string parentlinkpk; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; bool collision; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 8d40468d..d2d1d76a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -317,6 +317,7 @@ void ObjectResource::GetLinks(std::vector& link size_t i = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); + link->parentlinkpk = it->HasMember("parentlinkpk") ? (*it)["parentlinkpk"].GetString() : ""; LoadJsonValueByKey(*it,"name",link->name); LoadJsonValueByKey(*it,"collision",link->collision); LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); From 54b8f236108de736a6709a4d66d5483031c263f1 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Wed, 23 May 2018 07:09:44 +0900 Subject: [PATCH 238/477] temporarily set precision lower --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index cb2c9588..26a1fdd1 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -101,7 +101,7 @@ typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef double Real; -inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-6) { +inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { return fabs(double(p - q)) < epsilon; } From 42497b9fc9cdea4fc320a9cae825c28141a8275f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 23 May 2018 18:21:14 +0900 Subject: [PATCH 239/477] fix Windows compilation --- include/mujincontrollerclient/mujinjson.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 75bd1b85..7fce9c0f 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -180,16 +180,6 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { } } -inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { - if (v.IsUint64()) { - t = v.GetUint64(); - } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); - } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int64", MJE_Failed); - } -} - inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { if (v.IsUint64()) { t = v.GetUint64(); @@ -328,14 +318,10 @@ inline void SaveJsonValue(rapidjson::Value& v, unsigned int t, rapidjson::Docume v.SetUint(t); } -inline void SaveJsonValue(rapidjson::Value& v, long long t, rapidjson::Document::AllocatorType& alloc) { +inline void SaveJsonValue(rapidjson::Value& v, int64_t t, rapidjson::Document::AllocatorType& alloc) { v.SetInt64(t); } -inline void SaveJsonValue(rapidjson::Value& v, unsigned long long t, rapidjson::Document::AllocatorType& alloc) { - v.SetUint64(t); -} - inline void SaveJsonValue(rapidjson::Value& v, uint64_t t, rapidjson::Document::AllocatorType& alloc) { v.SetUint64(t); } From 45c33a91379cbb18e438581d16bd93a923e16070 Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 24 May 2018 15:42:09 +0900 Subject: [PATCH 240/477] resolve namespace conflicts --- include/mujincontrollerclient/mujinjson.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 75bd1b85..495cbfe3 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -14,8 +14,8 @@ /** \file mujinjson.h \brief Wrapper for rapidjson. */ -#ifndef MUJIN_JSON_H -#define MUJIN_JSON_H +#ifndef MUJIN_CONTROLLERCLIENT_JSON_H +#define MUJIN_CONTROLLERCLIENT_JSON_H #include #include @@ -31,7 +31,8 @@ #include #include -namespace mujinjson { +namespace mujinclient { +namespace mujinjson_external { enum MujinJSONErrorCode { @@ -537,4 +538,5 @@ template inline std::string GetJsonStringByKey(const U& key, c } } // namespace mujinjson +} // namespace mujinclient #endif From 6f2da78a2e72ead0c6202dc13f27b46809ec7942 Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 24 May 2018 15:42:09 +0900 Subject: [PATCH 241/477] resolve namespace conflicts --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- src/mujincontrollerclient.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 88a64cae..06bfec94 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -1,4 +1,5 @@ // -*- coding: utf-8 -*- +// // Copyright (C) 2012-2013 MUJIN Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -65,7 +66,6 @@ namespace mujinclient { #include - enum TaskResourceOptions { TRO_EnableZMQ=1, ///< create a task resource with zeromq client @@ -603,7 +603,7 @@ class MUJINCLIENT_API WebResource T Get(const std::string& field, double timeout = 5.0) { rapidjson::Document pt(rapidjson::kObjectType); GetWrap(pt, field, timeout); - return mujinjson::GetJsonValueByKey(pt, field.c_str()); + return mujinjson_external::GetJsonValueByKey(pt, field.c_str()); } /// \brief sets an attribute of this web resource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d2d1d76a..c6a6f9b9 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -28,6 +28,8 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { + +namespace mujinjson = mujinjson_external; using namespace mujinjson; void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) From 56c45cf7fa83aee6ada58e7eb0bed05390e13e2c Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 24 May 2018 15:42:09 +0900 Subject: [PATCH 242/477] resolve namespace conflicts --- src/controllerclientimpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index f9931d56..139de256 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -28,6 +28,7 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { +namespace mujinjson = mujinjson_external; using namespace mujinjson; class CurlTimeoutSetter { From 54fb81ce184f3b13f05afe37d22cc163dd9217ed Mon Sep 17 00:00:00 2001 From: jiayu Date: Fri, 25 May 2018 22:42:57 +0900 Subject: [PATCH 243/477] ignore it when get a null value instead of expected type --- include/mujincontrollerclient/mujinjson.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 495cbfe3..6d8771c4 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -438,19 +438,21 @@ template inline void LoadJsonValueByKey(const rapidjson::Value } } + //work the same as LoadJsonValueByKey, but the value is returned instead of being passed as reference template T GetJsonValueByKey(const rapidjson::Value& v, const char* key, const U& t) { if (!v.IsObject()) { throw MujinJSONException("Cannot get value of non-object.", MJE_Failed); } if (v.HasMember(key)) { - T r; - LoadJsonValue(v[key], r); - return r; - } - else { - return T(t); + const rapidjson::Value& child = v[key]; + if (!child.IsNull()) { + T r; + LoadJsonValue(v[key], r); + return r; + } } + return T(t); } template inline T GetJsonValueByKey(const rapidjson::Value& v, const char* key) { if (!v.IsObject()) { @@ -458,7 +460,10 @@ template inline T GetJsonValueByKey(const rapidjson::Value& v, const ch } T r = T(); if (v.HasMember(key)) { - LoadJsonValue(v[key], r); + const rapidjson::Value& child = v[key]; + if (!child.IsNull()) { + LoadJsonValue(v[key], r); + } } return r; } @@ -466,7 +471,7 @@ template inline T GetJsonValueByKey(const rapidjson::Value& v, const ch template inline T GetJsonValueByPath(const rapidjson::Value& v, const char* key) { T r; const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); - if (child) { + if (child && !child->IsNull()) { LoadJsonValue(*child, r); } return r; @@ -474,7 +479,7 @@ template inline T GetJsonValueByPath(const rapidjson::Value& v, const c template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); - if (child) { + if (child && !child->IsNull()) { T r; LoadJsonValue(*child, r); return r; From 5bedccbd60889fe248a1b2c828a38f2aabe111d8 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 28 May 2018 13:19:07 +0900 Subject: [PATCH 244/477] better use mujinjson --- src/mujincontrollerclient.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c6a6f9b9..65f8e838 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -191,7 +191,7 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { rapidjson::Value& objects = pt["geometries"]; for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); + const std::string name = it->HasMember("name") ? GetJsonValueByKey(*it, "name") : GetJsonValueByKey(*it, "pk"); if (name == geometryName && (*it)["linkpk"].GetString() == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); geometry->name = name; @@ -219,10 +219,11 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorpk) { + const std::string linkpk = GetJsonValueByKey(*it, "linkpk"); + if (linkpk == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = it->HasMember("name") ? (*it)["name"].GetString() : (*it)["pk"].GetString(); - LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); + geometry->linkpk = linkpk; + LoadJsonValueByKey(*it,"name",geometry->name,geometry->pk); LoadJsonValueByKey(*it,"visible",geometry->visible); LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); LoadJsonValueByKey(*it,"transparency",geometry->transparency); @@ -319,7 +320,7 @@ void ObjectResource::GetLinks(std::vector& link size_t i = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - link->parentlinkpk = it->HasMember("parentlinkpk") ? (*it)["parentlinkpk"].GetString() : ""; + LoadJsonValueByKey(*it,"parentlinkpk",link->parentlinkpk); LoadJsonValueByKey(*it,"name",link->name); LoadJsonValueByKey(*it,"collision",link->collision); LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); From 280c994467460b7b438bdc3e7058265f21138c29 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 30 May 2018 14:29:45 +0900 Subject: [PATCH 245/477] Added FileUpload_UTF8/16 API --- src/controllerclientimpl.cpp | 103 ++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 139de256..6f952a60 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -576,6 +576,103 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c */ } +struct curl_slist *ControllerClientImpl::GetCURLHeaderForFileUpload(){ + struct curl_slist *headerlist = NULL; + headerlist = curl_slist_append(headerlist, "Content-Type: multipart/form-data"); + std::string s = str(boost::format("Accept-Language: %s,en-us")%_language); + headerlist = curl_slist_append(headerlist, s.c_str()); //,en;q=0.7,ja;q=0.3',") + s = str(boost::format("Accept-Charset: %s")%_charset); + headerlist = curl_slist_append(headerlist, s.c_str()); + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + headerlist = curl_slist_append(headerlist, s.c_str()); + headerlist = curl_slist_append(headerlist, "Connection: Keep-Alive"); + headerlist = curl_slist_append(headerlist, "Keep-Alive: 20"); // keep alive for 20s? + headerlist = curl_slist_append(headerlist, "Expect:"); + return headerlist; +} + +void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) +{ + MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); + CurlTimeoutSetter timeoutsetter(_curl, 5); + boost::mutex::scoped_lock lock(_mutex); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + _buffer.clear(); + _buffer.str(""); + CurlWriteDataSetter writedata(_curl, &_buffer); + curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); + /// CHECKCURLCODE is not allowed + curl_mime *form = curl_mime_init(_curl); + curl_mimepart *field = curl_mime_addpart(form); + curl_mime_name(field,"files[]"); + curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); + curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + res = curl_easy_perform(_curl); + curl_mime_free(form); + curl_slist_free_all(headerlist); + /// CHECKCURLCODE is allowed + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + rapidjson::Document pt; + if( _buffer.rdbuf()->in_avail() > 0 ) { + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); + } + int expectedhttpcode = 200; + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); + } +} + +void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) +{ + MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); + CurlTimeoutSetter timeoutsetter(_curl, 5); + boost::mutex::scoped_lock lock(_mutex); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + _buffer.clear(); + _buffer.str(""); + CurlWriteDataSetter writedata(_curl, &_buffer); + curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); + /// CHECKCURLCODE is not allowed + curl_mime *form = curl_mime_init(_curl); + curl_mimepart *field = curl_mime_addpart(form); + curl_mime_name(field,"files[]"); + curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); + curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + res = curl_easy_perform(_curl); + curl_mime_free(form); + curl_slist_free_all(headerlist); + /// CHECKCURLCODE is allowed + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + rapidjson::Document pt; + if( _buffer.rdbuf()->in_avail() > 0 ) { + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); + } + int expectedhttpcode = 200; + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); + } +} + void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) { // TODO use curl_multi_perform to allow uploading of multiple files simultaneously @@ -784,7 +881,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector Date: Wed, 30 May 2018 14:29:45 +0900 Subject: [PATCH 246/477] Added FileUpload_UTF8/16 API --- include/mujincontrollerclient/mujincontrollerclient.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 06bfec94..9819f2e6 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -417,7 +417,16 @@ class MUJINCLIENT_API ControllerClient /// \param newuri utf-16 encoded virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; - /** \brief Recommended way of uploading a scene's files into the network filesystem. + /** \brief Upload a scene file using fileupload API. + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. + \throw mujin_exception if the upload fails, will throw an exception + */ + virtual void FileUpload_UTF8(const std::string& sourcefilename) = 0; + + /// \see FileUpload_UTF8 + virtual void FileUpload_UTF16(const std::wstring& sourcefilename) = 0; + + /** \brief Upload a scene's files into the network filesystem. Depending on the scenetype, can upload entire directory trees. \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. From e738d1372516b922036b24d5d8e70e079c85416d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 5 Jun 2018 17:26:29 +0900 Subject: [PATCH 247/477] use curl_formadd rather than curl_mime --- src/controllerclientimpl.cpp | 54 +++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 6f952a60..94008dab 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -603,15 +603,38 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); +#if 0 curl_mime *form = curl_mime_init(_curl); curl_mimepart *field = curl_mime_addpart(form); curl_mime_name(field,"files[]"); curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_mime_free(form); +#else + //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 + const std::string fname = encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename); + std::vectorcontent; + std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "files[]", + CURLFORM_BUFFER, fname.c_str(), + CURLFORM_BUFFERPTR, (char*)&content[0], + CURLFORM_BUFFERLENGTH, content.size(), + CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + res = curl_easy_perform(_curl); + curl_formfree(formpost); +#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -644,15 +667,38 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); +#if 0 curl_mime *form = curl_mime_init(_curl); curl_mimepart *field = curl_mime_addpart(form); curl_mime_name(field,"files[]"); curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_mime_free(form); +#else + //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 + const std::string fname = encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename); + std::vectorcontent; + std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "files[]", + CURLFORM_BUFFER, fname.c_str(), + CURLFORM_BUFFERPTR, (char*)&content[0], + CURLFORM_BUFFERLENGTH, content.size(), + CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + res = curl_easy_perform(_curl); + curl_formfree(formpost); +#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); From da494ffd41a0588a85e3209f85e860a1c1667eb0 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 5 Jun 2018 17:28:17 +0900 Subject: [PATCH 248/477] clean --- src/controllerclientimpl.cpp | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 94008dab..6004f7b5 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -603,18 +603,6 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); -#if 0 - curl_mime *form = curl_mime_init(_curl); - curl_mimepart *field = curl_mime_addpart(form); - curl_mime_name(field,"files[]"); - curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); - curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - res = curl_easy_perform(_curl); - curl_mime_free(form); -#else - //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 const std::string fname = encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename); std::vectorcontent; std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); @@ -632,9 +620,10 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CURLFORM_BUFFERLENGTH, content.size(), CURLFORM_END); curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_formfree(formpost); -#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -667,18 +656,6 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); -#if 0 - curl_mime *form = curl_mime_init(_curl); - curl_mimepart *field = curl_mime_addpart(form); - curl_mime_name(field,"files[]"); - curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); - curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - res = curl_easy_perform(_curl); - curl_mime_free(form); -#else - //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 const std::string fname = encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename); std::vectorcontent; std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); @@ -696,9 +673,10 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CURLFORM_BUFFERLENGTH, content.size(), CURLFORM_END); curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_formfree(formpost); -#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); From 3a363eec47d46bb9a309e862077a558117e156e4 Mon Sep 17 00:00:00 2001 From: Huan Liu Date: Sun, 10 Jun 2018 00:59:12 +0900 Subject: [PATCH 249/477] update mujinjson --- include/mujincontrollerclient/mujinjson.h | 127 +++++++++++++++------- 1 file changed, 86 insertions(+), 41 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 40966b7b..9fc217bb 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -25,11 +25,15 @@ #include #include #include +#include #include #include +#include +#include #include #include +#include namespace mujinclient { namespace mujinjson_external { @@ -88,8 +92,7 @@ class MujinJSONException : public std::exception MujinJSONErrorCode _error; }; - -// using namespace mujinclient; +template inline std::string GetJsonString(const T& t); /// \brief gets a string of the Value type for debugging purposes inline std::string GetJsonTypeName(const rapidjson::Value& v) { @@ -114,15 +117,33 @@ inline std::string GetJsonTypeName(const rapidjson::Value& v) { } } -inline std::string DumpJson(const rapidjson::Value& value) { +inline std::string DumpJson(const rapidjson::Value& value, const unsigned int indent=0) { rapidjson::StringBuffer stringbuffer; - rapidjson::Writer writer(stringbuffer); - value.Accept(writer); + if (indent == 0) { + rapidjson::Writer writer(stringbuffer); + value.Accept(writer); + } else { + rapidjson::PrettyWriter writer(stringbuffer); + writer.SetIndent(' ', indent); + value.Accept(writer); + } return std::string(stringbuffer.GetString(), stringbuffer.GetSize()); } -inline void ParseJson(rapidjson::Document&d, const std::string& str) { - d.Parse(str.c_str()); +inline void DumpJson(const rapidjson::Value& value, std::ostream& os, const unsigned int indent=0) { + rapidjson::OStreamWrapper osw(os); + if (indent == 0) { + rapidjson::Writer writer(osw); + value.Accept(writer); + } else { + rapidjson::PrettyWriter writer(osw); + writer.SetIndent(' ', indent); + value.Accept(writer); + } +} + +inline void ParseJson(rapidjson::Document& d, const std::string& str) { + d.Parse(str.c_str()); // parse float in full precision mode if (d.HasParseError()) { std::string substr; if (str.length()> 200) { @@ -134,6 +155,13 @@ inline void ParseJson(rapidjson::Document&d, const std::string& str) { } } +inline void ParseJson(rapidjson::Document& d, std::istream& is) { + rapidjson::IStreamWrapper isw(is); + d.ParseStream(isw); // parse float in full precision mode + if (d.HasParseError()) { + throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); + } +} class JsonSerializable { public: virtual void LoadFromJson(const rapidjson::Value& v) = 0; @@ -156,7 +184,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, std::string& t) { //TODO: add warnings on all usages of lexical_cast t = boost::lexical_cast(v.GetInt64()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to String", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to String", MJE_Failed); } } @@ -167,7 +195,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int", MJE_Failed); } } @@ -177,7 +205,17 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { + if (v.IsUint64()) { + t = v.GetUint64(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); } } @@ -187,7 +225,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Int64", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); } } @@ -197,7 +235,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, double& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Double", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Double", MJE_Failed); } } @@ -207,7 +245,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, float& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Double", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Double", MJE_Failed); } } @@ -217,7 +255,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Bool", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Bool", MJE_Failed); } } @@ -319,10 +357,13 @@ inline void SaveJsonValue(rapidjson::Value& v, unsigned int t, rapidjson::Docume v.SetUint(t); } -inline void SaveJsonValue(rapidjson::Value& v, int64_t t, rapidjson::Document::AllocatorType& alloc) { +inline void SaveJsonValue(rapidjson::Value& v, long long t, rapidjson::Document::AllocatorType& alloc) { v.SetInt64(t); } +inline void SaveJsonValue(rapidjson::Value& v, unsigned long long t, rapidjson::Document::AllocatorType& alloc) { + v.SetUint64(t); +} inline void SaveJsonValue(rapidjson::Value& v, uint64_t t, rapidjson::Document::AllocatorType& alloc) { v.SetUint64(t); } @@ -369,23 +410,6 @@ template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector inline void SaveJsonValue(rapidjson::Value& v, const T (&t)[N], rapidjson::Document::AllocatorType& alloc) { - v.SetArray(); - v.Reserve(N, alloc); - for (size_t i = 0; i < N; ++i) { - rapidjson::Value tmpv; - SaveJsonValue(tmpv, t[i], alloc); - v.PushBack(tmpv, alloc); - } -} - -template inline void SaveJsonValue(rapidjson::Value& v, const double (&t)[N], rapidjson::Document::AllocatorType& alloc) { - v.SetArray(); - v.Reserve(N, alloc); - for (size_t i = 0; i < N; ++i) { - v.PushBack(t[i], alloc); - } -} template inline void SaveJsonValue(rapidjson::Value& v, const std::map& t, rapidjson::Document::AllocatorType& alloc) { v.SetObject(); @@ -430,13 +454,14 @@ template T GetJsonValueByKey(const rapidjson::Value& v, const throw MujinJSONException("Cannot get value of non-object.", MJE_Failed); } if (v.HasMember(key)) { - T r; - LoadJsonValue(v[key], r); - return r; - } - else { - return T(t); + const rapidjson::Value& child = v[key]; + if (!child.IsNull()) { + T r; + LoadJsonValue(v[key], r); + return r; + } } + return T(t); } template inline T GetJsonValueByKey(const rapidjson::Value& v, const char* key) { if (!v.IsObject()) { @@ -444,15 +469,21 @@ template inline T GetJsonValueByKey(const rapidjson::Value& v, const ch } T r = T(); if (v.HasMember(key)) { - LoadJsonValue(v[key], r); + const rapidjson::Value& child = v[key]; + if (!child.IsNull()) { + LoadJsonValue(v[key], r); + } } return r; } +inline std::string GetStringJsonValueByKey(const rapidjson::Value& v, const char* key, const std::string& defaultValue=std::string()) { + return GetJsonValueByKey(v, key, defaultValue); +} template inline T GetJsonValueByPath(const rapidjson::Value& v, const char* key) { T r; const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); - if (child) { + if (child && !child->IsNull()) { LoadJsonValue(*child, r); } return r; @@ -460,7 +491,7 @@ template inline T GetJsonValueByPath(const rapidjson::Value& v, const c template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); - if (child) { + if (child && !child->IsNull()) { T r; LoadJsonValue(*child, r); return r; @@ -523,6 +554,20 @@ template inline std::string GetJsonStringByKey(const U& key, c return DumpJson(d); } +/** update a json object with another one, new key-value pair will be added, existing ones will be overwritten + */ +inline void UpdateJson(rapidjson::Document& a, const rapidjson::Value& b) { + if (!a.IsObject()) { + throw MujinJSONException("json object should be a dict to be updated: " + GetJsonString(a)); + } + if (!b.IsObject()) { + throw MujinJSONException("json object should be a dict to update another dict: " + GetJsonString(b)); + } + for (rapidjson::Value::ConstMemberIterator it = b.MemberBegin(); it != b.MemberEnd(); ++it) { + SetJsonValueByKey(a, it->name.GetString(), it->value); + } +} + } // namespace mujinjson } // namespace mujinclient #endif From 412ee79fc2defcf30337591194ca19090d006600 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Tue, 26 Jun 2018 10:52:39 +0900 Subject: [PATCH 250/477] Add comparators needed by visionmanager --- include/mujincontrollerclient/mujincontrollerclient.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f1ffcb1a..635f089a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -146,6 +146,9 @@ struct Transform return std::memcmp(quaternion, other.quaternion, 4 * sizeof(Real)) != 0 || std::memcmp(translate, other.translate, 3 * sizeof(Real)) != 0; } + bool operator==(const Transform& other) const { + return !operator!=(other); + } Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] Real translate[3]; ///< translation x,y,z }; @@ -711,6 +714,9 @@ class MUJINCLIENT_API RobotResource : public ObjectResource measurement_time != other.measurement_time || extra_parameters != other.extra_parameters; } + bool operator==(const SensorData& other) const { + return !operator!=(other); + } Real distortion_coeffs[5]; std::string distortion_model; Real focal_length; From 7e60b561764a3789680e1dcfdd9a5a38aa73ec28 Mon Sep 17 00:00:00 2001 From: rosen Date: Fri, 29 Jun 2018 11:24:22 +0900 Subject: [PATCH 251/477] change logs --- src/controllerclientimpl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 139de256..3cb87a6b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -711,7 +711,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& o int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) { - MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); + MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); _buffer.clear(); @@ -749,7 +749,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { - MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); + MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); CurlTimeoutSetter timeoutsetter(_curl, timeout); curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); @@ -784,7 +784,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector Date: Fri, 29 Jun 2018 11:27:36 +0900 Subject: [PATCH 252/477] fix logging --- src/mujincontrollerclient.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c6a6f9b9..a38d4382 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -42,7 +42,7 @@ void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, Envi std::vector quat = GetJsonValueByKey >(*it, "quat_"); BOOST_ASSERT(quat.size() == 4); Real dist2 = 0; - for (int i = 0; i < 4; i ++ ) { + for (int i = 0; i < 4; i++ ) { Real f = quat[i] * quat[i]; dist2 += f; objstate.transform.quaternion[i] = f; @@ -140,7 +140,7 @@ ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string { } -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), objectpk(objectpk), pk(pk) +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), pk(pk), objectpk(objectpk) { } @@ -427,7 +427,7 @@ void RobotResource::GetAttachedSensors(std::vector& a LoadJsonValueByKey(*it, "translate", attachedsensor->translate); std::vector distortionCoeffs = GetJsonValueByPath > (*it, "/sensordata/distortion_coeffs"); BOOST_ASSERT(distortionCoeffs.size() <= 5); - for (size_t i = 0; i < distortionCoeffs.size(); i ++) { + for (size_t i = 0; i < distortionCoeffs.size(); i++) { attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; } attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*it, "/sensordata/distortion_model"); @@ -741,7 +741,7 @@ void SceneResource::GetSensorMapping(std::map& sensorm controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%object_pk), pt_robot); rapidjson::Value& pt_attachedsensors = pt_robot["attachedsensors"]; for (rapidjson::Document::ValueIterator itsensor = pt_attachedsensors.Begin(); - itsensor != pt_attachedsensors.End(); ++itsensor) { + itsensor != pt_attachedsensors.End(); ++itsensor) { std::string sensorname = GetJsonValueByKey(*itsensor, "name"); std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); std::string cameraid = GetJsonValueByPath(*itsensor, "/sensordata/hardware_id"); @@ -816,7 +816,7 @@ void SceneResource::GetInstObjects(std::vector& in instobject->attachedsensors.resize(jsonattachedsensors.Size()); size_t iattchedsensor = 0; for (rapidjson::Document::ValueIterator itsensor = jsonattachedsensors.Begin(); - itsensor != jsonattachedsensors.End(); ++itsensor) { + itsensor != jsonattachedsensors.End(); ++itsensor) { InstObject::AttachedSensor& sensor = instobject->attachedsensors[iattchedsensor]; LoadJsonValueByKey(*itsensor, "name", sensor.name); LoadJsonValueByKey(*itsensor, "quaternion", sensor.quaternion); From 2c400dbbc990c5ede197c108b62ed261e56ae084 Mon Sep 17 00:00:00 2001 From: rosen Date: Fri, 29 Jun 2018 11:34:08 +0900 Subject: [PATCH 253/477] make inline --- .../mujincontrollerclient.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ae3da5e2..2cf4a7e9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -20,9 +20,9 @@ #ifdef _MSC_VER -#pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class -#pragma warning(disable:4190) // C-linkage specified, but returns UDT 'boost::shared_ptr' which is incompatible with C -#pragma warning(disable:4819) //The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss using native typeof +#pragma warning(disable:4251)// needs to have dll-interface to be used by clients of class +#pragma warning(disable:4190)// C-linkage specified, but returns UDT 'boost::shared_ptr' which is incompatible with C +#pragma warning(disable:4819)//The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss using native typeof #ifndef __PRETTY_FUNCTION__ #define __PRETTY_FUNCTION__ __FUNCDNAME__ @@ -206,7 +206,7 @@ class ITLPlanningTaskParameters optimizationvalue = 1; program.clear(); } - + int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. /// specifies the final movement of the robot. There's 3 different modes: @@ -214,7 +214,7 @@ class ITLPlanningTaskParameters /// - \b "start" - robot returns to wherever it started /// - \b "final" - robot returns to the final_envstate std::string returnmode; - + int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc @@ -597,7 +597,7 @@ class MUJINCLIENT_API ControllerClient /// \param objectPk primary key for the object to set mesh data to /// \param geometryPk primary key for the geometry /// \param data stl format binary mesh data - /// \param unit length unit of mesh + /// \param unit length unit of mesh /// \param timeout timeout of uploading mesh /// virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; @@ -623,7 +623,7 @@ class MUJINCLIENT_API WebResource /// \brief gets an attribute of this web resource template - T Get(const std::string& field, double timeout = 5.0) { + inline T Get(const std::string& field, double timeout = 5.0) { rapidjson::Document pt(rapidjson::kObjectType); GetWrap(pt, field, timeout); return mujinjson_external::GetJsonValueByKey(pt, field.c_str()); @@ -960,7 +960,7 @@ class MUJINCLIENT_API SceneResource : public WebResource /// \brief creates an inst object in scene /// \param name name of the object to create /// \param referenceUri uri to reference. Leave empty to reference nothing. - /// \param quaternion quaternion of the object + /// \param quaternion quaternion of the object /// \param translate translation of the object /// \return pointer to inst object created virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout = 300); From b423e08b482fb4d5ba79859dd38194a68da44963 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 29 Jun 2018 12:39:12 +0900 Subject: [PATCH 254/477] add _baseapiuri to log --- src/controllerclientimpl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3cb87a6b..03d66bcb 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -784,7 +784,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector Date: Fri, 29 Jun 2018 12:39:12 +0900 Subject: [PATCH 255/477] add _baseapiuri to log --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9129f2af..ab232039 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -626,7 +626,7 @@ class MUJINCLIENT_API WebResource T Get(const std::string& field, double timeout = 5.0) { rapidjson::Document pt(rapidjson::kObjectType); GetWrap(pt, field, timeout); - return mujinjson::GetJsonValueByKey(pt, field.c_str()); + return mujinjson_external::GetJsonValueByKey(pt, field.c_str()); } /// \brief sets an attribute of this web resource From 185edab5bff6631849b37d0f3b7f0eb0af470b2c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 29 Jun 2018 12:48:16 +0900 Subject: [PATCH 256/477] bad merge --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 9129f2af..2a1e75d6 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -623,7 +623,7 @@ class MUJINCLIENT_API WebResource /// \brief gets an attribute of this web resource template - T Get(const std::string& field, double timeout = 5.0) { + inline T Get(const std::string& field, double timeout = 5.0) { rapidjson::Document pt(rapidjson::kObjectType); GetWrap(pt, field, timeout); return mujinjson::GetJsonValueByKey(pt, field.c_str()); From 8824dde56f1d19ff61814f2af73eadc2f5edd994 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 9 Jul 2018 13:11:19 +0900 Subject: [PATCH 257/477] partially reverted 3a363eec (SaveJsonValue array is required) --- include/mujincontrollerclient/mujinjson.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 8f771e12..2c72ceea 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -410,6 +410,23 @@ template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector inline void SaveJsonValue(rapidjson::Value& v, const T (&t)[N], rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + rapidjson::Value tmpv; + SaveJsonValue(tmpv, t[i], alloc); + v.PushBack(tmpv, alloc); + } +} + +template inline void SaveJsonValue(rapidjson::Value& v, const double (&t)[N], rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + v.PushBack(t[i], alloc); + } +} template inline void SaveJsonValue(rapidjson::Value& v, const std::map& t, rapidjson::Document::AllocatorType& alloc) { v.SetObject(); From 0f7c1a6bfcb4b417df66d456c098c53f83a0ee37 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 18 Jul 2018 10:31:15 +0900 Subject: [PATCH 258/477] fixed CreateInstObject --- src/mujincontrollerclient.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f87ea4f0..1532e069 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -846,7 +846,7 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) { GETCONTROLLERIMPL(); - const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk")%GetPrimaryKey())); + const std::string uri(str(boost::format("scene/%s/instobject/?format=json&field=")%GetPrimaryKey())); std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); if (!referenceUri.empty()) { data += ", \"reference_uri\": \"" + referenceUri + "\""; @@ -857,6 +857,11 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& controller->CallPost(uri, data, pt, 201, timeout); std::string inst_pk = GetJsonValueByKey(pt, "pk"); SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); + LoadJsonValueByKey(pt, "object_pk", instobject->object_pk); + LoadJsonValueByKey(pt, "reference_uri", instobject->reference_uri); + LoadJsonValueByKey(pt, "dofvalues", instobject->dofvalues); + LoadJsonValueByKey(pt, "quaternion", instobject->quaternion); + LoadJsonValueByKey(pt, "translate", instobject->translate); return instobject; } From f459011b3051520b7b7a26b5cb7b61a6c1b883d3 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 30 May 2018 14:29:45 +0900 Subject: [PATCH 259/477] Added FileUpload_UTF8/16 API --- src/controllerclientimpl.cpp | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3cb87a6b..d5ce0747 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -576,6 +576,103 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c */ } +struct curl_slist *ControllerClientImpl::GetCURLHeaderForFileUpload(){ + struct curl_slist *headerlist = NULL; + headerlist = curl_slist_append(headerlist, "Content-Type: multipart/form-data"); + std::string s = str(boost::format("Accept-Language: %s,en-us")%_language); + headerlist = curl_slist_append(headerlist, s.c_str()); //,en;q=0.7,ja;q=0.3',") + s = str(boost::format("Accept-Charset: %s")%_charset); + headerlist = curl_slist_append(headerlist, s.c_str()); + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + headerlist = curl_slist_append(headerlist, s.c_str()); + headerlist = curl_slist_append(headerlist, "Connection: Keep-Alive"); + headerlist = curl_slist_append(headerlist, "Keep-Alive: 20"); // keep alive for 20s? + headerlist = curl_slist_append(headerlist, "Expect:"); + return headerlist; +} + +void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) +{ + MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); + CurlTimeoutSetter timeoutsetter(_curl, 5); + boost::mutex::scoped_lock lock(_mutex); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + _buffer.clear(); + _buffer.str(""); + CurlWriteDataSetter writedata(_curl, &_buffer); + curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); + /// CHECKCURLCODE is not allowed + curl_mime *form = curl_mime_init(_curl); + curl_mimepart *field = curl_mime_addpart(form); + curl_mime_name(field,"files[]"); + curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); + curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + res = curl_easy_perform(_curl); + curl_mime_free(form); + curl_slist_free_all(headerlist); + /// CHECKCURLCODE is allowed + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + rapidjson::Document pt; + if( _buffer.rdbuf()->in_avail() > 0 ) { + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); + } + int expectedhttpcode = 200; + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); + } +} + +void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) +{ + MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); + CurlTimeoutSetter timeoutsetter(_curl, 5); + boost::mutex::scoped_lock lock(_mutex); + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + _buffer.clear(); + _buffer.str(""); + CurlWriteDataSetter writedata(_curl, &_buffer); + curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); + /// CHECKCURLCODE is not allowed + curl_mime *form = curl_mime_init(_curl); + curl_mimepart *field = curl_mime_addpart(form); + curl_mime_name(field,"files[]"); + curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); + curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); + res = curl_easy_perform(_curl); + curl_mime_free(form); + curl_slist_free_all(headerlist); + /// CHECKCURLCODE is allowed + CHECKCURLCODE(res, "curl_easy_perform failed"); + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + rapidjson::Document pt; + if( _buffer.rdbuf()->in_avail() > 0 ) { + ParseJson(pt, _buffer.str()); + } else { + pt.SetObject(); + } + int expectedhttpcode = 200; + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); + } +} + void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) { // TODO use curl_multi_perform to allow uploading of multiple files simultaneously From 7175e3317ed4bfa76f9030f75c5c453d1be2ea3d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 30 May 2018 14:29:45 +0900 Subject: [PATCH 260/477] Added FileUpload_UTF8/16 API --- include/mujincontrollerclient/mujincontrollerclient.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2cf4a7e9..a2183385 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -440,7 +440,16 @@ class MUJINCLIENT_API ControllerClient /// \param newuri utf-16 encoded virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; - /** \brief Recommended way of uploading a scene's files into the network filesystem. + /** \brief Upload a scene file using fileupload API. + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. + \throw mujin_exception if the upload fails, will throw an exception + */ + virtual void FileUpload_UTF8(const std::string& sourcefilename) = 0; + + /// \see FileUpload_UTF8 + virtual void FileUpload_UTF16(const std::wstring& sourcefilename) = 0; + + /** \brief Upload a scene's files into the network filesystem. Depending on the scenetype, can upload entire directory trees. \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. From d12636ec9454387cb71e883b5f93d7379419b9b3 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 5 Jun 2018 17:26:29 +0900 Subject: [PATCH 261/477] use curl_formadd rather than curl_mime --- src/controllerclientimpl.cpp | 54 +++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index d5ce0747..c021cde2 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -603,15 +603,38 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); +#if 0 curl_mime *form = curl_mime_init(_curl); curl_mimepart *field = curl_mime_addpart(form); curl_mime_name(field,"files[]"); curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_mime_free(form); +#else + //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 + const std::string fname = encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename); + std::vectorcontent; + std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "files[]", + CURLFORM_BUFFER, fname.c_str(), + CURLFORM_BUFFERPTR, (char*)&content[0], + CURLFORM_BUFFERLENGTH, content.size(), + CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + res = curl_easy_perform(_curl); + curl_formfree(formpost); +#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -644,15 +667,38 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); +#if 0 curl_mime *form = curl_mime_init(_curl); curl_mimepart *field = curl_mime_addpart(form); curl_mime_name(field,"files[]"); curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_mime_free(form); +#else + //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 + const std::string fname = encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename); + std::vectorcontent; + std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "files[]", + CURLFORM_BUFFER, fname.c_str(), + CURLFORM_BUFFERPTR, (char*)&content[0], + CURLFORM_BUFFERLENGTH, content.size(), + CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + res = curl_easy_perform(_curl); + curl_formfree(formpost); +#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); From 82b7e1393789f88b79faa17b41ccd9099341aa1d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 5 Jun 2018 17:28:17 +0900 Subject: [PATCH 262/477] clean --- src/controllerclientimpl.cpp | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c021cde2..b215255b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -603,18 +603,6 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); -#if 0 - curl_mime *form = curl_mime_init(_curl); - curl_mimepart *field = curl_mime_addpart(form); - curl_mime_name(field,"files[]"); - curl_mime_filedata(field,encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename).c_str()); - curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - res = curl_easy_perform(_curl); - curl_mime_free(form); -#else - //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 const std::string fname = encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename); std::vectorcontent; std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); @@ -632,9 +620,10 @@ void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) CURLFORM_BUFFERLENGTH, content.size(), CURLFORM_END); curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_formfree(formpost); -#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); @@ -667,18 +656,6 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CurlWriteDataSetter writedata(_curl, &_buffer); curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); /// CHECKCURLCODE is not allowed - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); -#if 0 - curl_mime *form = curl_mime_init(_curl); - curl_mimepart *field = curl_mime_addpart(form); - curl_mime_name(field,"files[]"); - curl_mime_filedata(field,encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename).c_str()); - curl_easy_setopt(_curl, CURLOPT_MIMEPOST, form); - res = curl_easy_perform(_curl); - curl_mime_free(form); -#else - //https://stackoverflow.com/questions/37082651/libcurl-post-multipart-upload-with-buffered-image-returning-http-400 const std::string fname = encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename); std::vectorcontent; std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); @@ -696,9 +673,10 @@ void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) CURLFORM_BUFFERLENGTH, content.size(), CURLFORM_END); curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); res = curl_easy_perform(_curl); curl_formfree(formpost); -#endif curl_slist_free_all(headerlist); /// CHECKCURLCODE is allowed CHECKCURLCODE(res, "curl_easy_perform failed"); From 574dc7d0ba7e3ab8701350372f7f726100dcc36c Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Tue, 14 Aug 2018 11:31:17 +0900 Subject: [PATCH 263/477] Add MVR related functions --- include/mujincontrollerclient/mujinjson.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 9fc217bb..a269fb5a 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -199,6 +199,16 @@ inline void LoadJsonValue(const rapidjson::Value& v, int& t) { } } +inline void LoadJsonValue(const rapidjson::Value& v, int64_t& t) { + if (v.IsInt64()) { + t = v.GetInt64(); + } else if (v.IsString()) { + t = boost::lexical_cast(v.GetString()); + } else { + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); + } +} + inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { if (v.IsUint()) { t = v.GetUint(); @@ -215,7 +225,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { } else if (v.IsString()) { t = boost::lexical_cast(v.GetString()); } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); + throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to UInt64", MJE_Failed); } } From 6ca16b0015de5065a31a677703bcb69c51280671 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Thu, 16 Aug 2018 11:14:23 +0900 Subject: [PATCH 264/477] Update MVR info and code to handle std::array --- include/mujincontrollerclient/mujinjson.h | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index a269fb5a..961de989 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -17,6 +17,7 @@ #ifndef MUJIN_CONTROLLERCLIENT_JSON_H #define MUJIN_CONTROLLERCLIENT_JSON_H +#include #include #include #include @@ -271,6 +272,8 @@ inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t); +template inline void LoadJsonValue(const rapidjson::Value& v, std::array& t); + template inline void LoadJsonValue(const rapidjson::Value& v, boost::shared_ptr& ptr) { T t; LoadJsonValue(v, t); @@ -319,6 +322,24 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::vect } } +template inline void LoadJsonValue(const rapidjson::Value& v, std::array& t) { + if (v.IsArray()) { + if (v.GetArray().Size() != N) { + throw MujinJSONException( + (boost::format("Cannot convert json type " + GetJsonTypeName(v) + " to Array. " + "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str(), + MJE_Failed); + } + size_t i = 0; + for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { + LoadJsonValue(*it, t[i]); + i++; + } + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + } +} + template inline void LoadJsonValue(const rapidjson::Value& v, std::map& t) { if (v.IsArray()) { // list based map @@ -396,6 +417,8 @@ inline void SaveJsonValue(rapidjson::Value& v, const rapidjson::Value& t, rapidj template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc); +template inline void SaveJsonValue(rapidjson::Value& v, const std::array& t, rapidjson::Document::AllocatorType& alloc); + /** do not remove: otherwise boost::shared_ptr could be treated as bool */ template inline void SaveJsonValue(rapidjson::Value& v, const boost::shared_ptr& ptr, rapidjson::Document::AllocatorType& alloc) { @@ -412,6 +435,17 @@ template inline void SaveJsonValue(rapidjson::Value& v, const std::vect } } +template inline void SaveJsonValue(rapidjson::Value& v, const std::array& t, rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + rapidjson::Value tmpv; + SaveJsonValue(tmpv, t[i], alloc); + v.PushBack(tmpv, alloc); + } +} + + template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { v.SetArray(); v.Reserve(t.size(), alloc); @@ -420,6 +454,13 @@ template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector inline void SaveJsonValue(rapidjson::Value& v, const std::array& t, rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(N, alloc); + for (size_t i = 0; i < N; ++i) { + v.PushBack(t[i], alloc); + } +} template inline void SaveJsonValue(rapidjson::Value& v, const std::map& t, rapidjson::Document::AllocatorType& alloc) { v.SetObject(); From 276289fb4113027aef7cc01cc373442943f7e43f Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Mon, 20 Aug 2018 20:52:26 +0900 Subject: [PATCH 265/477] AddObjectToObjectSt WIP --- src/controllerclientimpl.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 3cb87a6b..2759bca8 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1387,6 +1387,18 @@ void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); } +void ControllerClientImpl::AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname) +{ + boost::mutex::scoped_lock lock(_mutex); + + rapidjson::Document pt(rapidjson::kObjectType); + CallGet((boost::format("scene/%s.mujin.dae/?format=json&fields=referenceobjectpks") % objectsetname).str(), pt); + rapidjson::Value& objects = pt["referenceobjectpks"]; + rapidjson::Value r; // TODO::::::::::; + + +} + void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) { BOOST_ASSERT(rawuri.size()>0 && copydir_utf8.size()>0); From 3c9781d10d88d899095a1226c1ec609fe567a7b9 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Tue, 21 Aug 2018 09:48:44 +0900 Subject: [PATCH 266/477] Add AddObjectToObjectSet - WIP --- src/controllerclientimpl.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2759bca8..e9865f41 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1393,9 +1393,15 @@ void ControllerClientImpl::AddObjectToObjectSet(const std::string &objectname, c rapidjson::Document pt(rapidjson::kObjectType); CallGet((boost::format("scene/%s.mujin.dae/?format=json&fields=referenceobjectpks") % objectsetname).str(), pt); - rapidjson::Value& objects = pt["referenceobjectpks"]; - rapidjson::Value r; // TODO::::::::::; + rapidjson::Value& refpks = pt["referenceobjectpks"]; + rapidjson::Value rObjectname; + rObjectname = rapidjson::StringRef(objectname.c_str(), objectname.size()); + refpks.PushBack(rObjectname, pt.GetAllocator()); + printf("~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + for (auto& v : refpks.GetArray()) { + printf("%s\n", v.GetString()); + } } From 3437e7d18b1c2bc00e58cc2b4db7ba26fd573d87 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Tue, 21 Aug 2018 09:48:44 +0900 Subject: [PATCH 267/477] Add AddObjectToObjectSet - WIP --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2cf4a7e9..a2bc32d7 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -539,6 +539,8 @@ class MUJINCLIENT_API ControllerClient /// \param uri UTF-16 encoded virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; + virtual void AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname) = 0; + virtual void SetDefaultSceneType(const std::string& scenetype) = 0; virtual const std::string& GetDefaultSceneType() = 0; From 05211a1486bc6e9b8e1f0fdcd7a780b8b4ebd99e Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Tue, 21 Aug 2018 11:58:47 +0900 Subject: [PATCH 268/477] AddObjectToObjectSet is working --- src/controllerclientimpl.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e9865f41..d1baf17b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1387,22 +1387,28 @@ void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); } -void ControllerClientImpl::AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname) +void ControllerClientImpl::AddObjectToObjectSet(const std::string &objectPk, const std::string &objectsetPk, double timeout) { - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - CallGet((boost::format("scene/%s.mujin.dae/?format=json&fields=referenceobjectpks") % objectsetname).str(), pt); + const std::string desturi = (boost::format("scene/%s/?format=json&fields=referenceobjectpks") % objectsetPk).str(); + int http_code = CallGet(desturi, pt, 0); + if (http_code == 404) { + throw MUJIN_EXCEPTION_FORMAT("objsetsetPK=%s cannot be found on the remote server", objectsetPk, MEC_InvalidArguments); + } else if (http_code != 200) { + std::string error_message = GetJsonValueByKey(pt, "error_message"); + std::string traceback = GetJsonValueByKey(pt, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi % http_code % error_message, MEC_HTTPServer); + } + rapidjson::Value& refpks = pt["referenceobjectpks"]; rapidjson::Value rObjectname; - rObjectname = rapidjson::StringRef(objectname.c_str(), objectname.size()); + rObjectname = rapidjson::StringRef(objectPk.c_str(), objectPk.size()); refpks.PushBack(rObjectname, pt.GetAllocator()); - printf("~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); - for (auto& v : refpks.GetArray()) { - printf("%s\n", v.GetString()); - } - + rapidjson::Document pt2(rapidjson::kObjectType); + const std::string uri((boost::format("scene/%s/") % objectsetPk).str()); + const int status = CallPutJSON(uri, DumpJson(pt), pt2, 202, timeout); + assert(status == 202); } void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) From 65a88799fc732d15aefb5c3486f234bd11788a12 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Tue, 21 Aug 2018 11:58:47 +0900 Subject: [PATCH 269/477] AddObjectToObjectSet is working --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a2bc32d7..2e79ec36 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -539,7 +539,7 @@ class MUJINCLIENT_API ControllerClient /// \param uri UTF-16 encoded virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; - virtual void AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname) = 0; + virtual void AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname, double timeout = 5.0) = 0; virtual void SetDefaultSceneType(const std::string& scenetype) = 0; From de537c273a171eb5e141e48f45acf4099e6d5b7f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 22 Aug 2018 01:02:54 +0900 Subject: [PATCH 270/477] added getting/setting ITL parameters --- include/mujincontrollerclient/mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a2183385..85bf10a4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -220,6 +220,7 @@ class ITLPlanningTaskParameters std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) std::string program; ///< itl program + std::string parameters; ///< parameters (json) EnvironmentState initial_envstate; ///< initial environment state to set the ITL task to. EnvironmentState final_envstate; ///< final environment state that describes where the robot should end at. If returnmode is set to final, then use this state. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 1532e069..a6d16409 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1027,6 +1027,9 @@ void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) else if( std::string(v->name.GetString()) == "program" ) { taskparameters.program = v->value.GetString(); } + else if( std::string(v->name.GetString()) == "parameters" ) { + taskparameters.parameters = DumpJson(v->value,2); + } else if( std::string(v->name.GetString()) == "initial_envstate" ) { ExtractEnvironmentStateFromPTree(v->value, taskparameters.initial_envstate); } @@ -1072,7 +1075,7 @@ void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparame serachpairs[1].first = "\n"; serachpairs[1].second = "\\n"; serachpairs[2].first = "\r\n"; serachpairs[2].second = "\\n"; SearchAndReplace(program, taskparameters.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); + std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"parameters\":%s, \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.parameters%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); rapidjson::Document pt; controller->CallPutJSON(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); } From 87774572f54d823256d567fd3ef3f81caeaebab3 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 22 Aug 2018 15:34:24 +0900 Subject: [PATCH 271/477] Set the default values of registerMinViableRegionInfo --- include/mujincontrollerclient/mujinjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 961de989..afe02e45 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -540,7 +540,7 @@ template inline T GetJsonValueByPath(const rapidjson::Value& v, const c return r; } -template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { +template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); if (child && !child->IsNull()) { T r; From 1e5350cf81d6b31f05aa5b5a98e39864ac94c0a1 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 29 Aug 2018 17:34:50 +0900 Subject: [PATCH 272/477] Fix ensure directory --- src/controllerclientimpl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index d1baf17b..cf180499 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1125,6 +1125,10 @@ std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeuri, double timeout) { + if (relativeuri.empty()) { + return; + } + CurlTimeoutSetter timeoutsetter(_curl, timeout); std::list listCreateDirs; std::string output; @@ -1208,6 +1212,8 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); if( nBaseFilenameStartIndex != std::string::npos ) { s = s.substr(0, nBaseFilenameStartIndex); + } else { + s = ""; } } _EnsureWebDAVDirectories(s); @@ -1244,6 +1250,8 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstrin size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); if( nBaseFilenameStartIndex != std::string::npos ) { s = s.substr(0, nBaseFilenameStartIndex); + } else { + s = ""; } } _EnsureWebDAVDirectories(s); From 057c1d6b042a85547c100733c3464d2352e0470a Mon Sep 17 00:00:00 2001 From: jiayu Date: Thu, 20 Sep 2018 12:58:08 +0900 Subject: [PATCH 273/477] fix json --- include/mujincontrollerclient/mujinjson.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 9fc217bb..f356e1d6 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -143,8 +143,12 @@ inline void DumpJson(const rapidjson::Value& value, std::ostream& os, const unsi } inline void ParseJson(rapidjson::Document& d, const std::string& str) { - d.Parse(str.c_str()); // parse float in full precision mode - if (d.HasParseError()) { + // repeatedly calling Parse on the same rapidjson::Document will not release previsouly allocated memory, memory will accumulate until the object is destroyed + // we use a new temporary Document to parse, and swap content with the original one, so that memory in original Document will be released when this function ends + // see: https://github.com/Tencent/rapidjson/issues/1333 + rapidjson::Document tempDoc; + tempDoc.Parse(str.c_str()); // parse float in full precision mode + if (tempDoc.HasParseError()) { std::string substr; if (str.length()> 200) { substr = str.substr(0, 200); @@ -153,15 +157,20 @@ inline void ParseJson(rapidjson::Document& d, const std::string& str) { } throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr), MJE_Failed); } + d.Swap(tempDoc); } inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); - d.ParseStream(isw); // parse float in full precision mode - if (d.HasParseError()) { + // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) + rapidjson::Document(tempDoc); + tempDoc.ParseStream(isw); // parse float in full precision mode + if (tempDoc.HasParseError()) { throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); } + d.Swap(tempDoc); } + class JsonSerializable { public: virtual void LoadFromJson(const rapidjson::Value& v) = 0; @@ -422,7 +431,10 @@ template inline void SaveJsonValue(rapidjson::Value& v, const std::map< } template inline void SaveJsonValue(rapidjson::Document& v, const T& t) { - SaveJsonValue(v, t, v.GetAllocator()); + // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) + rapidjson::Document tempDoc; + SaveJsonValue(tempDoc, t, tempDoc.GetAllocator()); + v.Swap(tempDoc); } template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc); From d287f7cf63c60494c141fb260f247aad697adb61 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 26 Oct 2018 23:24:56 +0900 Subject: [PATCH 274/477] fixed Windows build again --- include/mujincontrollerclient/mujinjson.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 5e5aa0ee..25dbbbc8 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -228,6 +228,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { } } +#ifndef _MSC_VER inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { if (v.IsUint64()) { t = v.GetUint64(); @@ -237,6 +238,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); } } +#endif inline void LoadJsonValue(const rapidjson::Value& v, double& t) { if (v.IsNumber()) { @@ -373,9 +375,12 @@ inline void SaveJsonValue(rapidjson::Value& v, long long t, rapidjson::Document: inline void SaveJsonValue(rapidjson::Value& v, unsigned long long t, rapidjson::Document::AllocatorType& alloc) { v.SetUint64(t); } + +#ifndef _MSC_VER inline void SaveJsonValue(rapidjson::Value& v, uint64_t t, rapidjson::Document::AllocatorType& alloc) { v.SetUint64(t); } +#endif inline void SaveJsonValue(rapidjson::Value& v, bool t, rapidjson::Document::AllocatorType& alloc) { v.SetBool(t); From 519f432203d6924bef60cf6abf99077ea505ba42 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Nov 2018 17:51:05 +0900 Subject: [PATCH 275/477] Added AddPrimitiveGeometry --- .../mujincontrollerclient.h | 6 ++++- src/mujincontrollerclient.cpp | 25 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 85bf10a4..777503a6 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -601,7 +601,7 @@ class MUJINCLIENT_API ControllerClient /// \return utf-16 encoded name virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; - virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, double timeout) = 0; + virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout) = 0; /// \brief set geometry mesh to an object /// \param objectPk primary key for the object to set mesh data to @@ -676,6 +676,9 @@ class MUJINCLIENT_API ObjectResource : public WebResource bool visible; Real diffusecolor[4]; Real transparency; + Real half_extents[3]; + Real height; + Real radius; virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout); @@ -706,6 +709,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource } virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout); + virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout); virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index a6d16409..57fefdb5 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -175,13 +175,23 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFro { GETCONTROLLERIMPL(); const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, timeout); + const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, "mesh", timeout); ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); return geometry; } +ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout) +{ + GETCONTROLLERIMPL(); + const std::string& linkpk = GetPrimaryKey(); + const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, geomtype, timeout); + + ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); + return geometry; +} + ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) { GETCONTROLLERIMPL(); @@ -202,6 +212,15 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); LoadJsonValueByKey(*it,"translate",geometry->translate); LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); + + /// geomtype /// + // mesh + // box: half_extents + // cylinder: height, radius + // sphere: radius + LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); + LoadJsonValueByKey(*it,"height",geometry->height); + LoadJsonValueByKey(*it,"radius",geometry->radius); return geometry; } } @@ -230,6 +249,10 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorquaternion); LoadJsonValueByKey(*it,"translate",geometry->translate); LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); + + LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); + LoadJsonValueByKey(*it,"height",geometry->height); + LoadJsonValueByKey(*it,"radius",geometry->radius); geometries.push_back(geometry); } } From ee5b81a093fa65356542fda3a2dc5a2e1196a695 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Nov 2018 17:51:05 +0900 Subject: [PATCH 276/477] Added AddPrimitiveGeometry --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8bb3f498..645c12a9 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1094,10 +1094,10 @@ std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string return utf16; } -std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, double timeout) +std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout) { rapidjson::Document pt(rapidjson::kObjectType); - const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"mesh\"}"); + const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"" + geomtype + "\"}"); const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); CallPost(uri, geometryData, pt, 201, timeout); From 96d63c089fe5a6b4dc61f6d7d475cf76b7fdd57b Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Nov 2018 18:20:44 +0900 Subject: [PATCH 277/477] add default timeout to most functions --- include/mujincontrollerclient/mujincontrollerclient.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 777503a6..6cda072f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -601,7 +601,7 @@ class MUJINCLIENT_API ControllerClient /// \return utf-16 encoded name virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; - virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout) = 0; + virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout = 5) = 0; /// \brief set geometry mesh to an object /// \param objectPk primary key for the object to set mesh data to @@ -681,7 +681,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource Real radius; virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); - virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout); + virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); virtual void SetVisible(bool visible); virtual int GetVisible(); }; @@ -708,8 +708,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual ~LinkResource() { } - virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout); - virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout); + virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout = 5.0); + virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout = 5.0); virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); From e20700a86af1fef3f2b4001b1294f54b7bb52eb5 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 29 Nov 2018 13:54:17 +0900 Subject: [PATCH 278/477] strip unnecessary info --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6cda072f..d7566a06 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -717,8 +717,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual boost::shared_ptr AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]); - /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); + /// 0 -> off, 1 -> on virtual int GetCollision(); virtual void SetVisible(bool visible); virtual int GetVisible(); @@ -745,8 +745,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]); virtual IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype); - /// 0 -> off, 1 -> on, 2 -> partial virtual void SetCollision(bool collision); + /// 0 -> off, 1 -> on, 2 -> partial virtual int GetCollision(); virtual void SetVisible(bool visible); virtual int GetVisible(); From eb445bb7230572faee33f283f7f3cfc5ea8900a7 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 29 Nov 2018 13:57:46 +0900 Subject: [PATCH 279/477] clarify --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index d7566a06..3b95eb0c 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -683,6 +683,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on virtual int GetVisible(); }; typedef boost::shared_ptr GeometryResourcePtr; @@ -721,6 +722,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource /// 0 -> off, 1 -> on virtual int GetCollision(); virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on, 2 -> partial virtual int GetVisible(); std::vector attachmentpks; @@ -749,6 +751,7 @@ class MUJINCLIENT_API ObjectResource : public WebResource /// 0 -> off, 1 -> on, 2 -> partial virtual int GetCollision(); virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on, 2 -> partial virtual int GetVisible(); std::string name; From aeaaef71d3ae1dcd8679f64789fbb4c9c46d2937 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 14 Dec 2018 17:39:20 +0900 Subject: [PATCH 280/477] Add multipart/form-data way of uploading file. --- src/controllerclientimpl.cpp | 202 ++++++++++++++--------------------- 1 file changed, 79 insertions(+), 123 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b215255b..e9266608 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -146,6 +146,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _httpheadersjson = NULL; _httpheadersstl = NULL; + _httpheadersmultipartformdata = NULL; if( baseuri.size() > 0 ) { _baseuri = baseuri; // ensure trailing slash @@ -299,6 +300,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, MUJIN_LOG_INFO(ss.str()); _SetHTTPHeadersJSON(); _SetHTTPHeadersSTL(); + _SetHTTPHeadersMultipartFormData(); try { GetProfile(); } @@ -316,6 +318,9 @@ ControllerClientImpl::~ControllerClientImpl() if( !!_httpheadersstl ) { curl_slist_free_all(_httpheadersstl); } + if( !!_httpheadersmultipartformdata ) { + curl_slist_free_all(_httpheadersmultipartformdata); + } curl_easy_cleanup(_curl); } @@ -576,127 +581,6 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c */ } -struct curl_slist *ControllerClientImpl::GetCURLHeaderForFileUpload(){ - struct curl_slist *headerlist = NULL; - headerlist = curl_slist_append(headerlist, "Content-Type: multipart/form-data"); - std::string s = str(boost::format("Accept-Language: %s,en-us")%_language); - headerlist = curl_slist_append(headerlist, s.c_str()); //,en;q=0.7,ja;q=0.3',") - s = str(boost::format("Accept-Charset: %s")%_charset); - headerlist = curl_slist_append(headerlist, s.c_str()); - s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - headerlist = curl_slist_append(headerlist, s.c_str()); - headerlist = curl_slist_append(headerlist, "Connection: Keep-Alive"); - headerlist = curl_slist_append(headerlist, "Keep-Alive: 20"); // keep alive for 20s? - headerlist = curl_slist_append(headerlist, "Expect:"); - return headerlist; -} - -void ControllerClientImpl::FileUpload_UTF8(const std::string& _sourcefilename) -{ - MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); - CurlTimeoutSetter timeoutsetter(_curl, 5); - boost::mutex::scoped_lock lock(_mutex); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - _buffer.clear(); - _buffer.str(""); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); - /// CHECKCURLCODE is not allowed - const std::string fname = encoding::ConvertUTF8ToFileSystemEncoding(_sourcefilename); - std::vectorcontent; - std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); - fin.seekg(0, std::ios::end); - content.resize(fin.tellg()); - fin.seekg(0, std::ios::beg); - fin.read((char*)&content[0], content.size()); - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - curl_formadd(&formpost, - &lastptr, - CURLFORM_COPYNAME, "files[]", - CURLFORM_BUFFER, fname.c_str(), - CURLFORM_BUFFERPTR, (char*)&content[0], - CURLFORM_BUFFERLENGTH, content.size(), - CURLFORM_END); - curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); - res = curl_easy_perform(_curl); - curl_formfree(formpost); - curl_slist_free_all(headerlist); - /// CHECKCURLCODE is allowed - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - rapidjson::Document pt; - if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(pt, _buffer.str()); - } else { - pt.SetObject(); - } - int expectedhttpcode = 200; - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); - } -} - -void ControllerClientImpl::FileUpload_UTF16(const std::wstring& _sourcefilename) -{ - MUJIN_LOG_INFO(str(boost::format("POST %s%s")%_baseuri%"fileupload")); - CurlTimeoutSetter timeoutsetter(_curl, 5); - boost::mutex::scoped_lock lock(_mutex); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - _buffer.clear(); - _buffer.str(""); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_URL, (_baseuri+"fileupload").c_str()); - /// CHECKCURLCODE is not allowed - const std::string fname = encoding::ConvertUTF16ToFileSystemEncoding(_sourcefilename); - std::vectorcontent; - std::ifstream fin(fname.c_str(), std::ios::in | std::ios::binary); - fin.seekg(0, std::ios::end); - content.resize(fin.tellg()); - fin.seekg(0, std::ios::beg); - fin.read((char*)&content[0], content.size()); - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - curl_formadd(&formpost, - &lastptr, - CURLFORM_COPYNAME, "files[]", - CURLFORM_BUFFER, fname.c_str(), - CURLFORM_BUFFERPTR, (char*)&content[0], - CURLFORM_BUFFERLENGTH, content.size(), - CURLFORM_END); - curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - struct curl_slist *headerlist = GetCURLHeaderForFileUpload(); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); - res = curl_easy_perform(_curl); - curl_formfree(formpost); - curl_slist_free_all(headerlist); - /// CHECKCURLCODE is allowed - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - rapidjson::Document pt; - if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(pt, _buffer.str()); - } else { - pt.SetObject(); - } - int expectedhttpcode = 200; - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", "/fileupload"%http_code%error_message, MEC_HTTPServer); - } -} - void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) { // TODO use curl_multi_perform to allow uploading of multiple files simultaneously @@ -1200,6 +1084,23 @@ void ControllerClientImpl::_SetHTTPHeadersSTL() //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); } +void ControllerClientImpl::_SetHTTPHeadersMultipartFormData() +{ + // set the header to only send stl + std::string s = std::string("Content-Type: multipart/form-data"); + if( !!_httpheadersmultipartformdata ) { + curl_slist_free_all(_httpheadersmultipartformdata); + } + _httpheadersmultipartformdata = curl_slist_append(NULL, s.c_str()); + //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept:"); // necessary? + s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; + _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, s.c_str()); + _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Connection: Keep-Alive"); + _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Keep-Alive: 20"); // keep alive for 20s? + // test on windows first + //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept-Encoding: gzip, deflate"); +} + std::string ControllerClientImpl::_GetCSRFFromCookies() { struct curl_slist *cookies; CURLcode res = curl_easy_getinfo(_curl, CURLINFO_COOKIELIST, &cookies); @@ -1765,7 +1666,7 @@ void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filen if(!handler._fd) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - _UploadFileToController(handler._fd, uri); + _UploadFileToControllerViaForm(filename, uri); } void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) @@ -1780,7 +1681,7 @@ void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& fil if(!handler._fd) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); } - _UploadFileToController(handler._fd, uri); + _UploadFileToControllerViaForm(filename_fs, uri); } void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) @@ -1836,6 +1737,61 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); } +void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& file, const std::string& uri) +{ + MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) + + // the dest filename of the upload is determined by stripping the leading _basewebdavuri + if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { + throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); + } + std::string filename = uri.substr(_basewebdavuri.size()); + + const std::string& endpoint = _baseuri + "fileupload"; + curl_easy_setopt(_curl, CURLOPT_URL, endpoint.c_str()); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); + curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + + CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); + CHECKCURLCODE(res, "failed to set writer"); + + // prepare form + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "files[]", + CURLFORM_FILE, file.c_str(), + CURLFORM_END); + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "filename", + CURLFORM_COPYCONTENTS, filename.c_str(), + CURLFORM_END); + curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); + + // set header + curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersmultipartformdata); + + res = curl_easy_perform(_curl); + + // reset the headers before any exceptions are thrown + _SetHTTPHeadersJSON(); + + // free form before exception + curl_formfree(formpost); + + CHECKCURLCODE(res, "curl_easy_perform failed"); + + // get http status + long http_code = 0; + res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo failed"); + + // 204 is when it overwrites the file? + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%uri%http_code, MEC_HTTPServer); + } +} + void ControllerClientImpl::_UploadDataToController(const std::vector& vdata, const std::string& desturi) { curl_off_t filesize = vdata.size(); From 48a6cb55de2b18229cc20cd7311637db05e6d2cc Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 14 Dec 2018 17:39:20 +0900 Subject: [PATCH 281/477] Add multipart/form-data way of uploading file. --- include/mujincontrollerclient/mujincontrollerclient.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a2183385..2cf4a7e9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -440,16 +440,7 @@ class MUJINCLIENT_API ControllerClient /// \param newuri utf-16 encoded virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; - /** \brief Upload a scene file using fileupload API. - \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. - \throw mujin_exception if the upload fails, will throw an exception - */ - virtual void FileUpload_UTF8(const std::string& sourcefilename) = 0; - - /// \see FileUpload_UTF8 - virtual void FileUpload_UTF16(const std::wstring& sourcefilename) = 0; - - /** \brief Upload a scene's files into the network filesystem. + /** \brief Recommended way of uploading a scene's files into the network filesystem. Depending on the scenetype, can upload entire directory trees. \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. From 582fa11341b176704463074ed529a65d9bfe445b Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 17 Dec 2018 13:38:31 +0900 Subject: [PATCH 282/477] No need to create directory since fileupload endpoint will handle that. --- src/controllerclientimpl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e9266608..d049a634 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1289,13 +1289,13 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstrin void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF8(filename, _PrepareDestinationURI_UTF8(desturi)); + _UploadFileToController_UTF8(filename, _PrepareDestinationURI_UTF8(desturi, false)); } void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& filename_utf16, const std::wstring& desturi_utf16) { boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16)); + _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16, false)); } void ControllerClientImpl::UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) @@ -1751,9 +1751,11 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& fil curl_easy_setopt(_curl, CURLOPT_URL, endpoint.c_str()); curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - + _buffer.clear(); + _buffer.str(""); CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); CHECKCURLCODE(res, "failed to set writer"); + CurlWriteDataSetter writedata(_curl, &_buffer); // prepare form struct curl_httppost *formpost = NULL; From 0f20a9579dafdf347cb63728b92c9325f5bd7ee3 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 24 Dec 2018 11:19:39 +0900 Subject: [PATCH 283/477] Remove unnecessary django login requests. --- src/controllerclientimpl.cpp | 74 +++--------------------------------- 1 file changed, 5 insertions(+), 69 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index d049a634..dd29ab4e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -237,54 +237,11 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, res = curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1); CHECKCURLCODE(res, "failed to set no signal"); - if( !(options & 1) ) { - // specify a reasonable timeout for the login calls - CurlTimeoutSetter timeoutsetter(_curl, timeout); - - // make an initial GET call to get the CSRF token - std::string loginuri = _baseuri + "login/"; - curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code == 302 ) { - // most likely apache2-only authentication and login page isn't needed, however need to send another GET for the csrftoken - loginuri = _baseuri + "api/v1/"; // pick some neutral page that is easy to load - curl_easy_setopt(_curl, CURLOPT_URL, loginuri.c_str()); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); - } - _csrfmiddlewaretoken = _GetCSRFFromCookies(); - curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); // necessary for SSL to work - } - else if( http_code == 200 ) { - _csrfmiddlewaretoken = _GetCSRFFromCookies(); - std::string data = str(boost::format("username=%s&password=%s&this_is_the_login_form=1&next=%%2F&csrfmiddlewaretoken=%s")%_username%password%_csrfmiddlewaretoken); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.c_str()); - curl_easy_setopt(_curl, CURLOPT_REFERER, loginuri.c_str()); - //std::cout << "---performing post---" << std::endl; - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 && http_code != 302 ) { - throw MUJIN_EXCEPTION_FORMAT("User login failed. HTTP POST %s returned HTTP status %s", loginuri%http_code, MEC_UserAuthentication); - } - } - else { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET %s returned HTTP error code %s", loginuri%http_code, MEC_HTTPServer); - } - } + // csrftoken can be any non-empty string + _csrfmiddlewaretoken = "csrftoken"; + std::string cookie = "Set-Cookie: csrftoken=" + _csrfmiddlewaretoken; + res=curl_easy_setopt (_curl, CURLOPT_COOKIELIST, cookie.c_str()); + CHECKCURLCODE(res, "failed to set csrftoken cookie"); _charset = "utf-8"; _language = "en-us"; @@ -1101,27 +1058,6 @@ void ControllerClientImpl::_SetHTTPHeadersMultipartFormData() //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept-Encoding: gzip, deflate"); } -std::string ControllerClientImpl::_GetCSRFFromCookies() { - struct curl_slist *cookies; - CURLcode res = curl_easy_getinfo(_curl, CURLINFO_COOKIELIST, &cookies); - CHECKCURLCODE(res, "curl_easy_getinfo CURLINFO_COOKIELIST"); - struct curl_slist *nc = cookies; - int i = 1; - std::string csrfmiddlewaretoken; - while (nc) { - //std::cout << str(boost::format("[%d]: %s")%i%nc->data) << std::endl; - char* csrftokenstart = strstr(nc->data, "csrftoken"); - if( !!csrftokenstart ) { - std::stringstream ss(csrftokenstart+10); - ss >> csrfmiddlewaretoken; - } - nc = nc->next; - i++; - } - curl_slist_free_all(cookies); - return csrfmiddlewaretoken; -} - std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw) { std::string output; From 03c7c66c130322e37021cf34b15603c3b04ec8c6 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 25 Dec 2018 08:11:15 +0900 Subject: [PATCH 284/477] Remove network call from controllerclientcpp constructor. --- src/controllerclientimpl.cpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index dd29ab4e..a4946b02 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -252,19 +252,10 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _charset = itcodepage->second; } #endif - std::stringstream ss; - ss << "setting character set to " << _charset; - MUJIN_LOG_INFO(ss.str()); + MUJIN_LOG_INFO("setting character set to " << _charset); _SetHTTPHeadersJSON(); _SetHTTPHeadersSTL(); _SetHTTPHeadersMultipartFormData(); - try { - GetProfile(); - } - catch(const MujinException&) { - // most likely username or password are - throw MujinException(str(boost::format("failed to get controller profile, check username/password or if controller is active at %s")%_baseuri), MEC_UserAuthentication); - } } ControllerClientImpl::~ControllerClientImpl() @@ -283,6 +274,11 @@ ControllerClientImpl::~ControllerClientImpl() std::string ControllerClientImpl::GetVersion() { + boost::mutex::scoped_lock lock(_mutex); + if (!_profile.IsObject()) { + _profile.SetObject(); + CallGet("profile/", _profile); + } return GetJsonValueByKey(_profile, "version"); } @@ -978,12 +974,6 @@ std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objec return GetJsonValueByKey(pt, "pk"); } -void ControllerClientImpl::GetProfile() -{ - _profile.SetObject(); - CallGet("profile/", _profile); -} - int ControllerClientImpl::_WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData) { if (writerData == NULL) { From e00313372fe0bfa944d189fef18607cb308e898d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 1 Feb 2019 09:48:12 +0900 Subject: [PATCH 285/477] bad merge --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 7544cae9..3a5636fc 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -470,6 +470,10 @@ class MUJINCLIENT_API ControllerClient SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); } + virtual void FileUpload_UTF8(const std::string& sourcefilename) = 0; + + virtual void FileUpload_UTF16(const std::wstring& sourcefilename) = 0; + /// \brief Uploads a single file to the controller network filesystem. /// /// Overwrites the file if it already exists From ba1db2bb0141b520863bdab0fe9c75918c1263b7 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 20 Feb 2019 14:29:36 +0900 Subject: [PATCH 286/477] fixes for FileUpload wrapper --- src/controllerclientimpl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c09abbf2..e601c7a4 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1223,15 +1223,15 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstrin void ControllerClientImpl::FileUpload_UTF8(const std::string& filename) { size_t nBaseFilenameStartIndex = filename.find_last_of(s_filesep); - std::string basename = nBaseFilenameStartIndex == std::string::npos ? "" : filename.substr(nBaseFilenameStartIndex+1); - UploadFileToController_UTF8(filename, std::string("mujin:/")+filename); + std::string basename = nBaseFilenameStartIndex == std::string::npos ? filename : filename.substr(nBaseFilenameStartIndex+1); + UploadFileToController_UTF8(filename, std::string("mujin:/")+basename); } void ControllerClientImpl::FileUpload_UTF16(const std::wstring& filename) { size_t nBaseFilenameStartIndex = filename.find_last_of(s_wfilesep); - std::wstring basename = nBaseFilenameStartIndex == std::string::npos ? L"" : filename.substr(nBaseFilenameStartIndex+1); - UploadFileToController_UTF16(filename, std::wstring(L"mujin:/")+filename); + std::wstring basename = nBaseFilenameStartIndex == std::string::npos ? filename : filename.substr(nBaseFilenameStartIndex+1); + UploadFileToController_UTF16(filename, std::wstring(L"mujin:/")+basename); } void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) From 6aed9c61fa67ab3d7fb0b66b54a70016ad07947d Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 1 Mar 2019 10:22:22 +0900 Subject: [PATCH 287/477] Implement ModifySceneAddReferenceObjectPK and ModifySceneRemoveReferenceObjectPK. --- include/mujincontrollerclient/mujincontrollerclient.h | 4 +++- src/mujincontrollerclient.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2e79ec36..aa2acfe8 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -539,7 +539,9 @@ class MUJINCLIENT_API ControllerClient /// \param uri UTF-16 encoded virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; - virtual void AddObjectToObjectSet(const std::string &objectname, const std::string &objectsetname, double timeout = 5.0) = 0; + virtual void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; + + virtual void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; virtual void SetDefaultSceneType(const std::string& scenetype) = 0; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index a38d4382..6b4cca36 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -144,7 +144,7 @@ ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const { } -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), objectpk(objectpk), pk(pk) +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), pk(pk), objectpk(objectpk) { } From 278b156a97701822496bd6dbe8711a601da621aa Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 1 Mar 2019 10:22:22 +0900 Subject: [PATCH 288/477] Implement ModifySceneAddReferenceObjectPK and ModifySceneRemoveReferenceObjectPK. --- src/controllerclientimpl.cpp | 66 ++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8a9df288..2396cae0 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -742,13 +742,19 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector(pt, "error_message"); std::string traceback = GetJsonValueByKey(pt, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; } @@ -969,8 +975,7 @@ std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objec { rapidjson::Document pt(rapidjson::kObjectType); const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); - const int status = CallPutSTL(uri, meshData, pt, 202, timeout); - assert(status == 202); + CallPutSTL(uri, meshData, pt, 202, timeout); return GetJsonValueByKey(pt, "pk"); } @@ -1343,30 +1348,39 @@ void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); } -void ControllerClientImpl::AddObjectToObjectSet(const std::string &objectPk, const std::string &objectsetPk, double timeout) +void ControllerClientImpl::ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) { - rapidjson::Document pt(rapidjson::kObjectType); - const std::string desturi = (boost::format("scene/%s/?format=json&fields=referenceobjectpks") % objectsetPk).str(); - int http_code = CallGet(desturi, pt, 0); - if (http_code == 404) { - throw MUJIN_EXCEPTION_FORMAT("objsetsetPK=%s cannot be found on the remote server", objectsetPk, MEC_InvalidArguments); - } else if (http_code != 200) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi % http_code % error_message, MEC_HTTPServer); - } + rapidjson::Document pt, pt2; + rapidjson::Value value; + + pt.SetObject(); - rapidjson::Value& refpks = pt["referenceobjectpks"]; - rapidjson::Value rObjectname; - rObjectname = rapidjson::StringRef(objectPk.c_str(), objectPk.size()); - refpks.PushBack(rObjectname, pt.GetAllocator()); + value.SetString(scenepk.c_str(), pt.GetAllocator()); + pt.AddMember("scenepk", value, pt.GetAllocator()); - rapidjson::Document pt2(rapidjson::kObjectType); - const std::string uri((boost::format("scene/%s/") % objectsetPk).str()); - const int status = CallPutJSON(uri, DumpJson(pt), pt2, 202, timeout); - assert(status == 202); + value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); + pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); + + boost::mutex::scoped_lock lock(_mutex); + _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, 200, timeout); } +void ControllerClientImpl::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) +{ + rapidjson::Document pt, pt2; + rapidjson::Value value; + + pt.SetObject(); + + value.SetString(scenepk.c_str(), pt.GetAllocator()); + pt.AddMember("scenepk", value, pt.GetAllocator()); + + value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); + pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); + + boost::mutex::scoped_lock lock(_mutex); + _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, 200, timeout); +} void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) { From 57bef3619d9e322eb7d8aab263ef2a8332c7a544 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 20 Mar 2019 13:37:22 +0900 Subject: [PATCH 289/477] Add GetModifiedTime func --- src/controllerclientimpl.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2396cae0..318bb40d 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1285,6 +1285,29 @@ void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata, timeout); } +long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + CurlTimeoutSetter timeoutsetter(_curl, timeout); + CURL_OPTION_SAVER(_curl, CURLOPT_NOBODY, 1, long); + CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 1, long); + + std::vector dummy; + long http_code = _CallGet(uri, dummy, 0); + if ((http_code != 200 && http_code != 304)) { + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", uri % http_code, MEC_HTTPServer); + } + + if (http_code == 304) { + return 0; + } + + long mtime; + CURLcode res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &mtime); + CHECKCURLCODE(res, "curl_easy_getinfo"); + return mtime; +} + void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) { CurlTimeoutSetter timeoutsetter(_curl, timeout); From 00d7a8daef40c75eabb487c55e4509314c28f41b Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 20 Mar 2019 13:37:22 +0900 Subject: [PATCH 290/477] Add GetModifiedTime func --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index aa2acfe8..e802b371 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -519,6 +519,8 @@ class MUJINCLIENT_API ControllerClient /// \param vdata filled with the contents of the file on the controller filesystem virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; + virtual long GetModifiedTime(const std::string& uri, double timeout = 5.0) = 0; + /// \brief Deletes a file on the controller network filesystem. /// /// \param uri UTF-8 encoded file in the network filesystem to delete. From 6caa8aaedffb429cf77cfb1713fcdec9468f8c0c Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Wed, 20 Mar 2019 14:50:53 +0900 Subject: [PATCH 291/477] GetModifiedTime - still debugging --- src/controllerclientimpl.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 318bb40d..92635a39 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1291,9 +1291,22 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou CurlTimeoutSetter timeoutsetter(_curl, timeout); CURL_OPTION_SAVER(_curl, CURLOPT_NOBODY, 1, long); CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 1, long); + CURL_OPTION_SAVER(_curl, CURLOPT_HEADER, 0L, long); + CURL_OPTION_SAVER(_curl, CURLOPT_VERBOSE, 1L, long); std::vector dummy; - long http_code = _CallGet(uri, dummy, 0); + MUJIN_LOG_INFO(_PrepareDestinationURI_UTF8(uri, false)); + + long http_code = 0; + curl_easy_setopt(_curl, CURLOPT_URL, _PrepareDestinationURI_UTF8(uri, false).c_str()); + + curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + CURLcode res = curl_easy_perform(_curl); + CHECKCURLCODE(res, "curl_easy_perform failed"); + + res = curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &http_code); + CHECKCURLCODE(res, "curl_easy_getinfo"); + if ((http_code != 200 && http_code != 304)) { throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", uri % http_code, MEC_HTTPServer); } @@ -1303,7 +1316,7 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou } long mtime; - CURLcode res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &mtime); + res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &mtime); CHECKCURLCODE(res, "curl_easy_getinfo"); return mtime; } From 9bc4957d2157a4930b593f47acde757e7bb175e9 Mon Sep 17 00:00:00 2001 From: "woody.chow" Date: Wed, 20 Mar 2019 17:31:51 +0900 Subject: [PATCH 292/477] Working GetModifiedTime --- src/controllerclientimpl.cpp | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 92635a39..9a0dac22 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1288,37 +1288,19 @@ void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeout) { boost::mutex::scoped_lock lock(_mutex); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - CURL_OPTION_SAVER(_curl, CURLOPT_NOBODY, 1, long); - CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 1, long); - CURL_OPTION_SAVER(_curl, CURLOPT_HEADER, 0L, long); - CURL_OPTION_SAVER(_curl, CURLOPT_VERBOSE, 1L, long); - - std::vector dummy; - MUJIN_LOG_INFO(_PrepareDestinationURI_UTF8(uri, false)); - long http_code = 0; + // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html + long filetime=-1; curl_easy_setopt(_curl, CURLOPT_URL, _PrepareDestinationURI_UTF8(uri, false).c_str()); - - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(_curl, CURLOPT_FILETIME, 1L); CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); - - res = curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); - - if ((http_code != 200 && http_code != 304)) { - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", uri % http_code, MEC_HTTPServer); - } - - if (http_code == 304) { - return 0; + if (CURLE_OK == res) { + res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &filetime); + if((CURLE_OK == res) && (filetime >= 0)) { + time_t file_time = (time_t)filetime; + } } - - long mtime; - res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &mtime); - CHECKCURLCODE(res, "curl_easy_getinfo"); - return mtime; + return filetime; } void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) From e45f80642d3016c7fe35d3759e132a4196dc6463 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Wed, 27 Mar 2019 11:09:35 +0900 Subject: [PATCH 293/477] Fix GetModifiedTime --- src/controllerclientimpl.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 9a0dac22..aaaa2e4b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1293,12 +1293,13 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou long filetime=-1; curl_easy_setopt(_curl, CURLOPT_URL, _PrepareDestinationURI_UTF8(uri, false).c_str()); curl_easy_setopt(_curl, CURLOPT_FILETIME, 1L); + curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); CURLcode res = curl_easy_perform(_curl); if (CURLE_OK == res) { res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &filetime); - if((CURLE_OK == res) && (filetime >= 0)) { - time_t file_time = (time_t)filetime; - } + } else { + MUJIN_LOG_INFO("Failed to get the timestamp of " + _PrepareDestinationURI_UTF8(uri, false)); } return filetime; } From 20365349a6eb672a1a13075bf08e69832ab33a84 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sat, 30 Mar 2019 14:55:09 +0900 Subject: [PATCH 294/477] Always set CURLOPT_FOLLOWLOCATION to 1. Reset options used in GetModifiedTime. --- src/controllerclientimpl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index aaaa2e4b..fd5b4dfb 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -230,7 +230,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, res = curl_easy_setopt(_curl, CURLOPT_USERAGENT, useragent.c_str()); CHECKCURLCODE(res, "failed to set user-agent"); - res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 0); // do not bounce through pages since we need to detect when login sessions expired + res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1); // we can always follow redirect now, we don't need to detect login page CHECKCURLCODE(res, "failed to set follow location"); res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); CHECKCURLCODE(res, "failed to set max redirs"); @@ -1289,11 +1289,14 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou { boost::mutex::scoped_lock lock(_mutex); + // on exit, reset the curl options we are going to set + CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 0, long); + CURL_OPTION_SAVER(_curl, CURLOPT_NOBODY, 0, long); + // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html long filetime=-1; curl_easy_setopt(_curl, CURLOPT_URL, _PrepareDestinationURI_UTF8(uri, false).c_str()); curl_easy_setopt(_curl, CURLOPT_FILETIME, 1L); - curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); CURLcode res = curl_easy_perform(_curl); if (CURLE_OK == res) { From 11c3bd9300908bd8409a986d6c0e10e7732fca7e Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sat, 30 Mar 2019 16:40:35 +0900 Subject: [PATCH 295/477] Scope all curl options. --- src/controllerclientimpl.cpp | 510 ++++++++++++----------------------- 1 file changed, 177 insertions(+), 333 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fd5b4dfb..a7ade7bd 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -23,64 +23,17 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); -#define CURL_OPTION_SAVER(curl, curlopt, curvalue, curltype) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)); - +#define CURL_OPTION_SAVER(curl, curlopt, curvalue) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)); +#define CURL_OPTION_SETTER(curl, curlopt, newvalue) CHECKCURLCODE(curl_easy_setopt(curl, curlopt, newvalue), "curl_easy_setopt " # curlopt); +#define CURL_OPTION_SAVE_SETTER(curl, curlopt, curvalue, newvalue) CURL_OPTION_SAVER(curl, curlopt, curvalue); CURL_OPTION_SETTER(curl, curlopt, newvalue); +#define CURL_INFO_GETTER(curl, curlinfo, outvalue) CHECKCURLCODE(curl_easy_getinfo(curl, curlinfo, outvalue), "curl_easy_getinfo " # curlinfo) +#define CURL_PERFORM(curl) CHECKCURLCODE(curl_easy_perform(curl), "curl_easy_perform") +#define CURL_FORM_RELEASER(form) boost::shared_ptr __curlformreleaser ## form((void*)0, boost::bind(boost::function(curl_formfree), form)); namespace mujinclient { namespace mujinjson = mujinjson_external; using namespace mujinjson; -class CurlTimeoutSetter -{ -public: - CurlTimeoutSetter(CURL *curl, double timeout) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_TIMEOUT_MS, (long)(timeout * 1000)); - } - ~CurlTimeoutSetter() { - curl_easy_setopt(_curl, CURLOPT_TIMEOUT_MS, 0); - } -protected: - CURL* _curl; -}; - -class CurlCustomRequestSetter -{ -public: - CurlCustomRequestSetter(CURL *curl, const char* method) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, method); - } - ~CurlCustomRequestSetter() { - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); - } -protected: - CURL* _curl; -}; - -class CurlWriteDataSetter -{ -public: - CurlWriteDataSetter(CURL *curl, const void* pdata) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_WRITEDATA, pdata); - } - ~CurlWriteDataSetter() { - curl_easy_setopt(_curl, CURLOPT_WRITEDATA, NULL); - } -protected: - CURL* _curl; -}; - -class CurlUploadSetter -{ -public: - CurlUploadSetter(CURL *curl) : _curl(curl) { - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 1L); - } - ~CurlUploadSetter() { - curl_easy_setopt(_curl, CURLOPT_UPLOAD, 0L); - } -protected: - CURL* _curl; -}; template std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) @@ -173,12 +126,11 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, BOOST_ASSERT(!!_curl); #ifdef _DEBUG - //curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L); + // CURL_OPTION_SETTER(_curl, CURLOPT_VERBOSE, 1L); #endif _errormessage.resize(CURL_ERROR_SIZE); - curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); + CURL_OPTION_SETTER(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); - CURLcode res; #ifdef SKIP_PEER_VERIFICATION /* * if you want to connect to a site who isn't using a certificate that is @@ -190,7 +142,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, * default bundle, then the curlopt_capath option might come handy for * you. */ - curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0l); + CURL_OPTION_SETTER(_curl, CURLOPT_SSL_VERIFYPEER, 0L); #endif #ifdef SKIP_HOSTNAME_VERIFICATION @@ -200,17 +152,15 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, * subjectAltName) fields, libcurl will refuse to connect. You can skip * this check, but this will make the connection less secure. */ - curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L); + CURL_OPTION_SETTER(_curl, CURLOPT_SSL_VERIFYHOST, 0L); #endif if( proxyserverport.size() > 0 ) { SetProxy(proxyserverport, proxyuserpw); } - res = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - CHECKCURLCODE(res, "failed to set auth"); - res = curl_easy_setopt(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); - CHECKCURLCODE(res, "failed to set userpw"); + CURL_OPTION_SETTER(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + CURL_OPTION_SETTER(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); // need to set the following? //CURLOPT_USERAGENT @@ -218,30 +168,27 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, //CURLOPT_TCP_KEEPALIVE //CURLOPT_TCP_KEEPINTVL - curl_easy_setopt(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine + CURL_OPTION_SETTER(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout - res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - res = curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &_buffer); - CHECKCURLCODE(res, "failed to set write data"); + // these should be set on individual calls + // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); // just to start the cookie engine + // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEDATA, &_buffer); std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; - res = curl_easy_setopt(_curl, CURLOPT_USERAGENT, useragent.c_str()); - CHECKCURLCODE(res, "failed to set user-agent"); + CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, useragent.c_str()); + + CURL_OPTION_SETTER(_curl, CURLOPT_FOLLOWLOCATION, 1L); // we can always follow redirect now, we don't need to detect login page + CURL_OPTION_SETTER(_curl, CURLOPT_MAXREDIRS, 10L); + CURL_OPTION_SETTER(_curl, CURLOPT_NOSIGNAL, 1L); - res = curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1); // we can always follow redirect now, we don't need to detect login page - CHECKCURLCODE(res, "failed to set follow location"); - res = curl_easy_setopt(_curl, CURLOPT_MAXREDIRS, 10); - CHECKCURLCODE(res, "failed to set max redirs"); - res = curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1); - CHECKCURLCODE(res, "failed to set no signal"); + CURL_OPTION_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0L); + CURL_OPTION_SETTER(_curl, CURLOPT_POSTFIELDS, NULL); // csrftoken can be any non-empty string _csrfmiddlewaretoken = "csrftoken"; std::string cookie = "Set-Cookie: csrftoken=" + _csrfmiddlewaretoken; - res=curl_easy_setopt (_curl, CURLOPT_COOKIELIST, cookie.c_str()); - CHECKCURLCODE(res, "failed to set csrftoken cookie"); + CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); _charset = "utf-8"; _language = "en-us"; @@ -253,9 +200,9 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } #endif MUJIN_LOG_INFO("setting character set to " << _charset); - _SetHTTPHeadersJSON(); - _SetHTTPHeadersSTL(); - _SetHTTPHeadersMultipartFormData(); + _SetupHTTPHeadersJSON(); + _SetupHTTPHeadersSTL(); + _SetupHTTPHeadersMultipartFormData(); } ControllerClientImpl::~ControllerClientImpl() @@ -291,13 +238,16 @@ void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); _charset = newencoding; - _SetHTTPHeadersJSON(); + _SetupHTTPHeadersJSON(); + // the following two format does not need charset + // _SetupHTTPHeadersSTL(); + // _SetupHTTPHeadersMultipartFormData(); } void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) { - curl_easy_setopt(_curl, CURLOPT_PROXY, serverport.c_str()); - curl_easy_setopt(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); + CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, serverport.c_str()); + CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); } void ControllerClientImpl::SetLanguage(const std::string& language) @@ -306,26 +256,25 @@ void ControllerClientImpl::SetLanguage(const std::string& language) if (language!= "") { _language = language; } - _SetHTTPHeadersJSON(); + _SetupHTTPHeadersJSON(); + // the following two format does not need language + // _SetupHTTPHeadersSTL(); + // _SetupHTTPHeadersMultipartFormData(); } void ControllerClientImpl::RestartServer(double timeout) { boost::mutex::scoped_lock lock(_mutex); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - _uri = _baseuri + std::string("ajax/restartserver/"); - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_POST, 1); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + _uri = _baseuri + std::string("restartserver/"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_PERFORM(_curl); long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( http_code != 200 ) { throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); } @@ -333,39 +282,7 @@ void ControllerClientImpl::RestartServer(double timeout) void ControllerClientImpl::Upgrade(const std::vector& vdata) { - BOOST_ASSERT(vdata.size()>0); - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseuri + std::string("upgrade/"); - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - - // set new headers and remove the Expect: 100-continue - struct curl_slist *headerlist=NULL; - headerlist = curl_slist_append(headerlist, "Expect:"); - std::string s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - headerlist = curl_slist_append(headerlist, s.c_str()); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headerlist); - - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - - // Fill in the file upload field - struct curl_httppost *formpost=NULL, *lastptr=NULL; - curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "mujinpatch", CURLFORM_BUFFERPTR, &vdata[0], CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); - curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - res = curl_easy_perform(_curl); - curl_formfree(formpost); - // reset the headers before any exceptions are thrown - _SetHTTPHeadersJSON(); - CHECKCURLCODE(res, "curl_easy_perform failed"); - long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, please try again or contact MUJIN support", MEC_HTTPServer); - } + throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, deprecated", MEC_HTTPServer); } void ControllerClientImpl::CancelAllJobs() @@ -635,19 +552,17 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Doc int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) { MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { mujinjson::ParseJson(pt, _buffer.str()); } @@ -670,19 +585,16 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& o int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); outputdata = _buffer.str(); if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { if( outputdata.size() > 0 ) { @@ -708,22 +620,18 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteVectorCallback); - CHECKCURLCODE(res, "failed to set writer"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteVectorCallback); outputdata.resize(0); - CurlWriteDataSetter writedata(_curl, &outputdata); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); // necessary? - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); // necessary? + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &outputdata); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { if( outputdata.size() > 0 ) { rapidjson::Document d; @@ -752,22 +660,19 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st int ControllerClientImpl::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { MUJIN_LOG_DEBUG(str(boost::format("POST %s")%desturi)); - CurlTimeoutSetter timeoutsetter(_curl, timeout); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersjson); - curl_easy_setopt(_curl, CURLOPT_URL, desturi.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_POST, 1); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, data.size() > 0 ? data.c_str() : NULL); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0, data.size()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDS, NULL, data.size() > 0 ? data.c_str() : NULL); + CURL_PERFORM(_curl); long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { ParseJson(pt, _buffer.str()); } else { @@ -795,28 +700,21 @@ int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* p { MUJIN_LOG_DEBUG(str(boost::format("PUT %s")%relativeuri)); boost::mutex::scoped_lock lock(_mutex); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headers);//isJson ? _httpheadersjson : _httpheadersstl); - CurlTimeoutSetter timeoutsetter(_curl, timeout); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, headers); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); _uri = _baseapiuri; _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, nDataSize);//data.size()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, pdata);//data.size() > 0 ? data.c_str() : NULL); - res = curl_easy_perform(_curl); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "PUT"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0, nDataSize); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDS, NULL, pdata); + CURL_PERFORM(_curl); long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); - - CHECKCURLCODE(res, "curl_easy_getinfo failed"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { ParseJson(pt, _buffer.str()); } else { @@ -844,19 +742,15 @@ void ControllerClientImpl::CallDelete(const std::string& relativeuri, double tim { MUJIN_LOG_DEBUG(str(boost::format("DELETE %s")%relativeuri)); boost::mutex::scoped_lock lock(_mutex); - CurlTimeoutSetter timeoutsetter(_curl, timeout); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); _uri = _baseapiuri; _uri += relativeuri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, 0); - CURLcode res = curl_easy_perform(_curl); - curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, NULL); // have to restore the default - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "DELETE"); + CURL_PERFORM(_curl); long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( http_code != 204 ) { // or 200 or 202 or 201? throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); } @@ -997,7 +891,7 @@ int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t n return size * nmemb; } -void ControllerClientImpl::_SetHTTPHeadersJSON() +void ControllerClientImpl::_SetupHTTPHeadersJSON() { // set the header to only send json std::string s = std::string("Content-Type: application/json; charset=") + _charset; @@ -1016,10 +910,9 @@ void ControllerClientImpl::_SetHTTPHeadersJSON() _httpheadersjson = curl_slist_append(_httpheadersjson, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept-Encoding: gzip, deflate"); - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersjson); } -void ControllerClientImpl::_SetHTTPHeadersSTL() +void ControllerClientImpl::_SetupHTTPHeadersSTL() { // set the header to only send stl std::string s = std::string("Content-Type: application/sla"); @@ -1036,7 +929,7 @@ void ControllerClientImpl::_SetHTTPHeadersSTL() //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); } -void ControllerClientImpl::_SetHTTPHeadersMultipartFormData() +void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() { // set the header to only send stl std::string s = std::string("Content-Type: multipart/form-data"); @@ -1082,7 +975,7 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeu return; } - CurlTimeoutSetter timeoutsetter(_curl, timeout); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); std::list listCreateDirs; std::string output; size_t startindex = 0; @@ -1102,18 +995,9 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeu curl_free(pescaped); } - // Check that the directory exists - //curl_easy_setopt(_curl, CURLOPT_URL, buff); - //curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); - //res = curl_easy_perform(self->send_handle); - //if(res != 0) { - // // does not exist - //} - - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); - CurlCustomRequestSetter setter(_curl, "MKCOL"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); std::string totaluri = ""; for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { @@ -1123,13 +1007,13 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeu } totaluri += *itdir; _uri = _basewebdavuri + totaluri; - curl_easy_setopt(_curl, CURLOPT_URL, _uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); /* creating directories Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. @@ -1289,43 +1173,30 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou { boost::mutex::scoped_lock lock(_mutex); - // on exit, reset the curl options we are going to set - CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 0, long); - CURL_OPTION_SAVER(_curl, CURLOPT_NOBODY, 0, long); - // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _PrepareDestinationURI_UTF8(uri, false).c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_NOBODY, 0L, 1L); + CURL_PERFORM(_curl); + long filetime=-1; - curl_easy_setopt(_curl, CURLOPT_URL, _PrepareDestinationURI_UTF8(uri, false).c_str()); - curl_easy_setopt(_curl, CURLOPT_FILETIME, 1L); - curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); - CURLcode res = curl_easy_perform(_curl); - if (CURLE_OK == res) { - res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &filetime); - } else { - MUJIN_LOG_INFO("Failed to get the timestamp of " + _PrepareDestinationURI_UTF8(uri, false)); - } + CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &filetime); return filetime; } void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) { - CurlTimeoutSetter timeoutsetter(_curl, timeout); - - // on exit, reset the curl options we are going to set - CURL_OPTION_SAVER(_curl, CURLOPT_FILETIME, 0, long); - CURL_OPTION_SAVER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, curl_TimeCond); - CURL_OPTION_SAVER(_curl, CURLOPT_TIMEVALUE, 0, long); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); remotetimeval = 0; // ask for remote file time - curl_easy_setopt(_curl, CURLOPT_FILETIME, 1); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); // use if modified since if local file time is provided - if (localtimeval > 0) { - curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); - curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, localtimeval); - } + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, localtimeval > 0 ? CURL_TIMECOND_IFMODSINCE : CURL_TIMECOND_NONE); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEVALUE, 0L, localtimeval > 0 ? localtimeval : 0L); // do the get call long http_code = _CallGet(desturi, outputdata, 0); @@ -1341,8 +1212,7 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur // retrieve remote file time if (http_code != 304) { // got the entire file so fill in the timestamp of that file - CURLcode res = curl_easy_getinfo(_curl, CURLINFO_FILETIME, &remotetimeval); - CHECKCURLCODE(res, "curl_easy_getinfo"); + CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &remotetimeval); } } @@ -1435,18 +1305,17 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& uri = rawuri; } - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); { // make sure the directory is created - CurlCustomRequestSetter setter(_curl, "MKCOL"); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( http_code != 201 && http_code != 301 ) { throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); } @@ -1556,18 +1425,17 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring uri = rawuri; } - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); { // make sure the directory is created - CurlCustomRequestSetter setter(_curl, "MKCOL"); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( http_code != 201 && http_code != 301 ) { throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); } @@ -1696,26 +1564,24 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& #endif // tell it to "upload" to the URL - CurlUploadSetter uploadsetter(_curl); - curl_easy_setopt(_curl, CURLOPT_HTTPGET, 0L); - curl_easy_setopt(_curl, CURLOPT_URL, uri.c_str()); - curl_easy_setopt(_curl, CURLOPT_READDATA, fd); - curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); - //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_UPLOAD, 0L, 1L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 0L); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_INFILESIZE_LARGE, -1, filesize); #if defined(_WIN32) || defined(_WIN64) - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadUploadCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadUploadCallback); #else - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, NULL); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, NULL); #endif + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READDATA, NULL, fd); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); // 204 is when it overwrites the file? if( http_code != 201 && http_code != 204 ) { if( http_code == 400 ) { @@ -1727,8 +1593,8 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& } // now extract transfer info //double speed_upload, total_time; - //curl_easy_getinfo(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); - //curl_easy_getinfo(_curl, CURLINFO_TOTAL_TIME, &total_time); + //CURL_INFO_GETTER(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); + //CURL_INFO_GETTER(_curl, CURLINFO_TOTAL_TIME, &total_time); //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); } @@ -1743,18 +1609,16 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& fil std::string filename = uri.substr(_basewebdavuri.size()); const std::string& endpoint = _baseuri + "fileupload"; - curl_easy_setopt(_curl, CURLOPT_URL, endpoint.c_str()); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, NULL); - curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, NULL); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); _buffer.clear(); _buffer.str(""); - CURLcode res = curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); - CHECKCURLCODE(res, "failed to set writer"); - CurlWriteDataSetter writedata(_curl, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); // prepare form struct curl_httppost *formpost = NULL; struct curl_httppost *lastptr = NULL; + CURL_FORM_RELEASER(formpost); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "files[]", CURLFORM_FILE, file.c_str(), @@ -1763,25 +1627,12 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& fil CURLFORM_COPYNAME, "filename", CURLFORM_COPYCONTENTS, filename.c_str(), CURLFORM_END); - curl_easy_setopt(_curl, CURLOPT_HTTPPOST, formpost); - - // set header - curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _httpheadersmultipartformdata); - - res = curl_easy_perform(_curl); - - // reset the headers before any exceptions are thrown - _SetHTTPHeadersJSON(); - - // free form before exception - curl_formfree(formpost); - - CHECKCURLCODE(res, "curl_easy_perform failed"); - + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); + CURL_PERFORM(_curl); // get http status long http_code = 0; - res = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - CHECKCURLCODE(res, "curl_easy_getinfo failed"); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); // 204 is when it overwrites the file? if( http_code != 200 ) { @@ -1794,28 +1645,22 @@ void ControllerClientImpl::_UploadDataToController(const std::vector::const_iterator, size_t> streamdata; streamdata.first = vdata.begin(); streamdata.second = vdata.size(); - curl_easy_setopt(_curl, CURLOPT_READDATA, &streamdata); - curl_easy_setopt(_curl, CURLOPT_INFILESIZE_LARGE, filesize); - //curl_easy_setopt(_curl, CURLOPT_NOBODY, 1L); - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, _ReadInMemoryUploadCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_INFILESIZE_LARGE, -1, filesize); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadInMemoryUploadCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READDATA, NULL, &streamdata); - res = curl_easy_perform(_curl); - CHECKCURLCODE(res, "curl_easy_perform failed"); + CURL_PERFORM(_curl); long http_code = 0; - res=curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // reset the read state - curl_easy_setopt(_curl, CURLOPT_READDATA, NULL); - curl_easy_setopt(_curl, CURLOPT_READFUNCTION, NULL); + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); // 204 is when it overwrites the file? if( http_code != 201 && http_code != 204 ) { @@ -1830,13 +1675,12 @@ void ControllerClientImpl::_UploadDataToController(const std::vector Date: Sat, 30 Mar 2019 17:28:32 +0900 Subject: [PATCH 296/477] Simplify curl_easy_escape and unescape usage. --- src/controllerclientimpl.cpp | 78 ++++++++++-------------------------- 1 file changed, 21 insertions(+), 57 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index a7ade7bd..beccfe9e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -23,12 +23,12 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); -#define CURL_OPTION_SAVER(curl, curlopt, curvalue) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)); -#define CURL_OPTION_SETTER(curl, curlopt, newvalue) CHECKCURLCODE(curl_easy_setopt(curl, curlopt, newvalue), "curl_easy_setopt " # curlopt); -#define CURL_OPTION_SAVE_SETTER(curl, curlopt, curvalue, newvalue) CURL_OPTION_SAVER(curl, curlopt, curvalue); CURL_OPTION_SETTER(curl, curlopt, newvalue); +#define CURL_OPTION_SAVER(curl, curlopt, curvalue) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)) +#define CURL_OPTION_SETTER(curl, curlopt, newvalue) CHECKCURLCODE(curl_easy_setopt(curl, curlopt, newvalue), "curl_easy_setopt " # curlopt) +#define CURL_OPTION_SAVE_SETTER(curl, curlopt, curvalue, newvalue) CURL_OPTION_SAVER(curl, curlopt, curvalue); CURL_OPTION_SETTER(curl, curlopt, newvalue) #define CURL_INFO_GETTER(curl, curlinfo, outvalue) CHECKCURLCODE(curl_easy_getinfo(curl, curlinfo, outvalue), "curl_easy_getinfo " # curlinfo) #define CURL_PERFORM(curl) CHECKCURLCODE(curl_easy_perform(curl), "curl_easy_perform") -#define CURL_FORM_RELEASER(form) boost::shared_ptr __curlformreleaser ## form((void*)0, boost::bind(boost::function(curl_formfree), form)); +#define CURL_FORM_RELEASER(form) boost::shared_ptr __curlformreleaser ## form((void*)0, boost::bind(boost::function(curl_formfree), form)) namespace mujinclient { @@ -437,9 +437,7 @@ void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, c } // sourcefilenamebase is utf-8 - char* pescapeddir = curl_easy_escape(_curl, sourcefilename.substr(nBaseFilenameStartIndex).c_str(), 0); - std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); - curl_free(pescapeddir); + std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilename.substr(nBaseFilenameStartIndex)); _UploadFileToController_UTF8(sourcefilename, uploadfileuri); /* webdav operations @@ -534,9 +532,7 @@ void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_ // sourcefilenamebase is utf-8 std::string sourcefilenamedir_utf8; utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); - char* pescapeddir = curl_easy_escape(_curl, sourcefilenamedir_utf8.c_str(), 0); - std::string uploadfileuri = baseuploaduri + std::string(pescapeddir); - curl_free(pescapeddir); + std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilenamedir_utf8); _UploadFileToController_UTF16(sourcefilename_utf16, uploadfileuri); } @@ -785,11 +781,7 @@ std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF8(const std::stri { size_t index = uri.find(":/"); MUJIN_ASSERT_OP_FORMAT(index,!=,std::string::npos, "bad URI: %s", uri, MEC_InvalidArguments); - uri.substr(index+2); - char* pcurlresult = curl_easy_escape(_curl, uri.c_str()+index+2,uri.size()-index-2); - std::string sresult(pcurlresult); - curl_free(pcurlresult); // have to release the result - return sresult; + return EscapeString(uri.substr(index+2)); } std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) @@ -801,10 +793,7 @@ std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wst std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF8(const std::string& name) { - char* pcurlresult = curl_easy_escape(_curl, name.c_str(), name.size()); - std::string sresult(pcurlresult); - curl_free(pcurlresult); // have to release the result - return sresult; + return EscapeString(name); } std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring& name) @@ -816,11 +805,7 @@ std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) { - int outlength = 0; - char* punescaped = curl_easy_unescape(_curl, pk.c_str(), pk.size(), &outlength); - std::string utf8(punescaped, outlength); - curl_free(punescaped); // have to release the result - return utf8; + return UnescapeString(pk); } std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) @@ -953,18 +938,14 @@ std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw for(size_t i = 0; i < raw.size(); ++i) { if( raw[i] == '/' ) { if( startindex != i ) { - char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, i-startindex); - output += std::string(pescaped); - curl_free(pescaped); + output += EscapeString(raw.substr(startindex, i-startindex)); startindex = i+1; } output += '/'; } } if( startindex != raw.size() ) { - char* pescaped = curl_easy_escape(_curl, raw.c_str()+startindex, raw.size()-startindex); - output += std::string(pescaped); - curl_free(pescaped); + output += EscapeString(raw.substr(startindex)); } return output; } @@ -982,17 +963,13 @@ void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeu for(size_t i = 0; i < relativeuri.size(); ++i) { if( relativeuri[i] == '/' ) { if( startindex != i ) { - char* pescaped = curl_easy_escape(_curl, relativeuri.c_str()+startindex, i-startindex); - listCreateDirs.push_back(std::string(pescaped)); - curl_free(pescaped); + listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex, i-startindex))); startindex = i+1; } } } if( startindex != relativeuri.size() ) { - char* pescaped = curl_easy_escape(_curl, relativeuri.c_str()+startindex, relativeuri.size()-startindex); - listCreateDirs.push_back(std::string(pescaped)); - curl_free(pescaped); + listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex))); } CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); @@ -1291,9 +1268,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& else { nBaseFilenameStartIndex++; } - char* pescapeddir = curl_easy_escape(_curl, copydir_utf8.substr(nBaseFilenameStartIndex).c_str(), 0); - uri = rawuri + std::string(pescapeddir); - curl_free(pescapeddir); + uri = rawuri + EscapeString(copydir_utf8.substr(nBaseFilenameStartIndex)); } else { // copydir also ends in a fileseparator, so remove the file separator from rawuri @@ -1352,9 +1327,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& else { newcopydir_utf8 = str(boost::format("%s%c%s")%copydir_utf8%s_filesep%filename_utf8); } - char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); + std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { _UploadDirectoryToController_UTF8(newcopydir_utf8, newuri); @@ -1379,9 +1352,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& #else std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); #endif - char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); + std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); if( boost::filesystem::is_directory(itdir->status()) ) { _UploadDirectoryToController_UTF8(itdir->path().string(), newuri); } @@ -1411,9 +1382,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring } std::string name_utf8; utf8::utf16to8(copydir_utf16.begin()+nBaseFilenameStartIndex, copydir_utf16.end(), std::back_inserter(name_utf8)); - char* pescapeddir = curl_easy_escape(_curl, name_utf8.c_str(), 0); - uri = rawuri + std::string(pescapeddir); - curl_free(pescapeddir); + uri = rawuri + EscapeString(name_utf8); } else { // copydir also ends in a fileseparator, so remove the file separator from rawuri @@ -1467,9 +1436,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring std::string filename_utf8; utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir_utf16%filename); - char* pescapeddir = curl_easy_escape(_curl, filename_utf8.c_str(), filename_utf8.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); + std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { _UploadDirectoryToController_UTF16(newcopydir, newuri); @@ -1492,9 +1459,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring std::wstring dirfilename_utf16 = itdir->path().filename().wstring(); std::string dirfilename; utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); + std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); if( boost::filesystem::is_directory(itdir->status()) ) { _UploadDirectoryToController_UTF16(itdir->path().wstring(), newuri); } @@ -1509,9 +1474,7 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring std::wstring dirfilename_utf16 = itdir->path().filename(); std::string dirfilename; utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - char* pescapeddir = curl_easy_escape(_curl, dirfilename.c_str(), dirfilename.size()); - std::string newuri = str(boost::format("%s/%s")%uri%pescapeddir); - curl_free(pescapeddir); + std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); if( boost::filesystem::is_directory(itdir->status()) ) { _UploadDirectoryToController_UTF16(itdir->path().string(), newuri); } @@ -1727,3 +1690,4 @@ size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, } } // end namespace mujinclient + From 31163881932260b6cfb78b6d21f5e2b6cb209b2f Mon Sep 17 00:00:00 2001 From: Ziyan Date: Sat, 30 Mar 2019 17:35:09 +0900 Subject: [PATCH 297/477] Remove some old impl. --- src/mujincontrollerclient.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 6b4cca36..bb6bc0b8 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -571,9 +571,8 @@ SceneResource::SceneResource(ControllerClientPtr controller, const std::string& TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) { GETCONTROLLERIMPL(); - boost::shared_ptr pescapedtaskname = controller->GetURLEscapedString(taskname); rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); // task exists std::string pk; @@ -660,9 +659,8 @@ void SceneResource::SetInstObjectsState(const std::vector pescapedtaskname = controller->GetURLEscapedString(taskname); rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%pescapedtaskname), pt); + controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); // task exists if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { @@ -937,9 +935,8 @@ void TaskResource::GetRunTimeStatus(JobStatus& status, int options) OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype) { GETCONTROLLERIMPL(); - boost::shared_ptr pescapedoptimizationname = controller->GetURLEscapedString(optimizationname); rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%pescapedoptimizationname), pt); + controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%controller->EscapeString(optimizationname)), pt); // optimization exists if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { rapidjson::Value& object = pt["objects"][0]; From ae492196bb4ef7a4f782ef68566050d1747bc518 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 10 May 2019 16:16:00 +0900 Subject: [PATCH 298/477] Comment the return type of GetModifiedTime. --- include/mujincontrollerclient/mujincontrollerclient.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e802b371..c59f2122 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -519,6 +519,7 @@ class MUJINCLIENT_API ControllerClient /// \param vdata filled with the contents of the file on the controller filesystem virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; + /// \brief returns seconds since epoch, last modified time from server header virtual long GetModifiedTime(const std::string& uri, double timeout = 5.0) = 0; /// \brief Deletes a file on the controller network filesystem. From 238bebcc2b5893006c3b32f6861cf099748356ea Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 13 May 2019 15:06:03 +0900 Subject: [PATCH 299/477] change GetModifiedTime to resolve cache correctly --- src/controllerclientimpl.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index beccfe9e..6d0afd78 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -831,7 +831,7 @@ std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, con rapidjson::Document pt(rapidjson::kObjectType); const std::string ikparamData("{\"name\":\"" + name + "\", \"iktype\":\"" + iktype + "\"}"); const std::string uri(str(boost::format("object/%s/ikparam/") % objectPk)); - + CallPost(uri, ikparamData, pt, 201, timeout); return GetJsonValueByKey(pt, "pk"); } @@ -845,7 +845,7 @@ std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const } data += "}"; const std::string uri(str(boost::format("object/%s/link/") % objectPk)); - + CallPost(uri, data, pt, 201, timeout); return GetJsonValueByKey(pt, "pk"); } @@ -1152,11 +1152,24 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _PrepareDestinationURI_UTF8(uri, false).c_str()); + + // in order to resolve cache correctly, need to go thorugh file/download endpoint + std::string apiendpoint = _baseuri + "file/download/?filename="; + if( uri.size() >= 7 && uri.substr(0,7) == "mujin:/" ) { + apiendpoint += _EncodeWithoutSeparator(uri.substr(7)); + } + + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, apiendpoint.c_str()); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_NOBODY, 0L, 1L); CURL_PERFORM(_curl); + long http_code = 0; + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT("Cannot get modified date of %s for HTTP HEAD call: return is %s", uri%http_code, MEC_HTTPServer); + } + long filetime=-1; CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &filetime); return filetime; From 05170ee3698dd2be4d234800dcabd226d001eb91 Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 25 Jun 2019 15:35:11 +0900 Subject: [PATCH 300/477] remove unnecessary FileUpload --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 559b771e..3fb2685e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -470,10 +470,6 @@ class MUJINCLIENT_API ControllerClient SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); } - virtual void FileUpload_UTF8(const std::string& sourcefilename) = 0; - - virtual void FileUpload_UTF16(const std::wstring& sourcefilename) = 0; - /// \brief Uploads a single file to the controller network filesystem. /// /// Overwrites the file if it already exists From 93a5bf303eb21e2a73d473032bb71a4dec28352c Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 25 Jun 2019 15:35:11 +0900 Subject: [PATCH 301/477] remove unnecessary FileUpload --- src/controllerclientimpl.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index d10856fe..caaef692 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1087,20 +1087,6 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstrin return baseuploaduri; } -void ControllerClientImpl::FileUpload_UTF8(const std::string& filename) -{ - size_t nBaseFilenameStartIndex = filename.find_last_of(s_filesep); - std::string basename = nBaseFilenameStartIndex == std::string::npos ? filename : filename.substr(nBaseFilenameStartIndex+1); - UploadFileToController_UTF8(filename, std::string("mujin:/")+basename); -} - -void ControllerClientImpl::FileUpload_UTF16(const std::wstring& filename) -{ - size_t nBaseFilenameStartIndex = filename.find_last_of(s_wfilesep); - std::wstring basename = nBaseFilenameStartIndex == std::string::npos ? filename : filename.substr(nBaseFilenameStartIndex+1); - UploadFileToController_UTF16(filename, std::wstring(L"mujin:/")+basename); -} - void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); From ce75205ba70fc47d27d07f119e216d99e5787cf4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 25 Jun 2019 16:06:05 +0900 Subject: [PATCH 302/477] CreateInstObject will receive required fields (from web server) --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index b8c69523..480dcbe4 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -867,7 +867,7 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) { GETCONTROLLERIMPL(); - const std::string uri(str(boost::format("scene/%s/instobject/?format=json&field=")%GetPrimaryKey())); + const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk,object_pk,reference_uri,dofvalues,quaternion,translate")%GetPrimaryKey())); std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); if (!referenceUri.empty()) { data += ", \"reference_uri\": \"" + referenceUri + "\""; From 6e6e0256761b81363f834cb953abda6677d1ad89 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 15 Jul 2019 18:23:55 +0900 Subject: [PATCH 303/477] Added SaveBackup/RestoreBackup --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 3fb2685e..28f7f484 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -490,6 +490,10 @@ class MUJINCLIENT_API ControllerClient /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. virtual void UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) = 0; + virtual void SaveBackup(std::vector& vdata, bool config = true, bool media = true, double timeout = 60.0) = 0; + virtual void RestoreBackup_UTF8(const std::string& filename_utf8, bool config = true, bool media = true) = 0; + virtual void RestoreBackup_UTF16(const std::wstring& filename_utf16, bool config = true, bool media = true) = 0; + /** \brief Recursively uploads a directory to the controller network filesystem. Creates directories along the way if they don't exist. From e05b1f112800fca25d0b5d60ba1e7386cf7c4c25 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 15 Jul 2019 18:23:55 +0900 Subject: [PATCH 304/477] Added SaveBackup/RestoreBackup --- src/controllerclientimpl.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index caaef692..fe085282 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1207,6 +1207,27 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur } } +void ControllerClientImpl::SaveBackup(std::vector& vdata, bool config, bool media, double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); + _CallGet(_baseuri+"backup/"+query, vdata, 200, timeout); +} + +void ControllerClientImpl::RestoreBackup_UTF8(const std::string& filename_utf8, bool config, bool media) +{ + boost::mutex::scoped_lock lock(_mutex); + std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); + _UploadFileToControllerViaForm2(encoding::ConvertUTF8ToFileSystemEncoding(filename_utf8), "backup.tar", _baseuri+"backup/"+query); +} + +void ControllerClientImpl::RestoreBackup_UTF16(const std::wstring& filename_utf16, bool config, bool media) +{ + boost::mutex::scoped_lock lock(_mutex); + std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); + _UploadFileToControllerViaForm2(encoding::ConvertUTF16ToFileSystemEncoding(filename_utf16), "backup.tar", _baseuri+"backup/"+query); +} + void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); @@ -1585,7 +1606,11 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& fil } std::string filename = uri.substr(_basewebdavuri.size()); - const std::string& endpoint = _baseuri + "fileupload"; + _UploadFileToControllerViaForm2(file, filename, _baseuri + "fileupload"); +} + +void ControllerClientImpl::_UploadFileToControllerViaForm2(const std::string& file, const std::string& filename, const std::string& endpoint) +{ CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); _buffer.clear(); _buffer.str(""); @@ -1613,7 +1638,7 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& fil // 204 is when it overwrites the file? if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%uri%http_code, MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); } } @@ -1704,4 +1729,3 @@ size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, } } // end namespace mujinclient - From fb83e61616c9b53cb5dc559f25ce4d273b84852c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 19 Jul 2019 16:53:43 +0900 Subject: [PATCH 305/477] bumped version and added document --- .../mujincontrollerclient/mujincontrollerclient.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 28f7f484..1bfcb068 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -490,8 +490,21 @@ class MUJINCLIENT_API ControllerClient /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. virtual void UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) = 0; + /// \brief Build a backup of config/media and download it. + /// + /// \param vdata filled with the contents of the backup. the backup is tar.gz format. + /// \param config whether to backup config. By default true. + /// \param media whether to backup media. By default true. virtual void SaveBackup(std::vector& vdata, bool config = true, bool media = true, double timeout = 60.0) = 0; + + /// \brief Restore backup archive into controller. Restaring might be required after restoration. + /// + /// \param filename_utf8 utf-8 encoded path of the backup file on the system. tar/tar.gz/tar.bz2 formats are accepted. + /// \param config whether to restore config. By default true (if the backup file has config). + /// \param media whether to restore media. By default true (if the backup file has media). virtual void RestoreBackup_UTF8(const std::string& filename_utf8, bool config = true, bool media = true) = 0; + + /// \param filename_utf16 utf-16 encoded path of the backup file on the system. tar/tar.gz/tar.bz2 formats are accepted. virtual void RestoreBackup_UTF16(const std::wstring& filename_utf16, bool config = true, bool media = true) = 0; /** \brief Recursively uploads a directory to the controller network filesystem. From eaae22e327ca9dca5d431724b9a792a5252198d4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 23 Jul 2019 14:33:54 +0900 Subject: [PATCH 306/477] code review --- src/controllerclientimpl.cpp | 75 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fe085282..8c4361db 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1214,18 +1214,11 @@ void ControllerClientImpl::SaveBackup(std::vector& vdata, bool co _CallGet(_baseuri+"backup/"+query, vdata, 200, timeout); } -void ControllerClientImpl::RestoreBackup_UTF8(const std::string& filename_utf8, bool config, bool media) +void ControllerClientImpl::RestoreBackup(const std::vector& vdata, bool config, bool media) { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm2(encoding::ConvertUTF8ToFileSystemEncoding(filename_utf8), "backup.tar", _baseuri+"backup/"+query); -} - -void ControllerClientImpl::RestoreBackup_UTF16(const std::wstring& filename_utf16, bool config, bool media) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm2(encoding::ConvertUTF16ToFileSystemEncoding(filename_utf16), "backup.tar", _baseuri+"backup/"+query); + _UploadFileToControllerViaForm(vdata, "backup.tar", _baseuri+"backup/"+query); } void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) @@ -1522,27 +1515,48 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filename, const std::string& uri) { + // the dest filename of the upload is determined by stripping the leading _basewebdavuri + if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { + throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); + } + std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); + std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - FileHandler handler(sFilename_FS.c_str()); - if(!handler._fd) { + std::vectorcontent; + std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); + if(!fin.good()) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - _UploadFileToControllerViaForm(filename, uri); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + + MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) + _UploadFileToControllerViaForm(content, filenameoncontroller, _baseuri + "fileupload"); } void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) { - std::string filename_fs = encoding::ConvertUTF16ToFileSystemEncoding(filename); -#if defined(_WIN32) || defined(_WIN64) - FileHandler handler(filename.c_str()); -#else - // linux does not support wide-char fopen - FileHandler handler(filename_fs.c_str()); -#endif - if(!handler._fd) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", filename_fs, MEC_InvalidArguments); + // the dest filename of the upload is determined by stripping the leading _basewebdavuri + if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { + throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); + } + std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); + + std::string sFilename_FS = encoding::ConvertUTF16ToFileSystemEncoding(filename); + std::vectorcontent; + std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); + if(!fin.good()) { + throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - _UploadFileToControllerViaForm(filename_fs, uri); + fin.seekg(0, std::ios::end); + content.resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read((char*)&content[0], content.size()); + + MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) + _UploadFileToControllerViaForm(content, filenameoncontroller, _baseuri + "fileupload"); } void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) @@ -1596,20 +1610,9 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); } -void ControllerClientImpl::_UploadFileToControllerViaForm(const std::string& file, const std::string& uri) -{ - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); - } - std::string filename = uri.substr(_basewebdavuri.size()); - - _UploadFileToControllerViaForm2(file, filename, _baseuri + "fileupload"); -} -void ControllerClientImpl::_UploadFileToControllerViaForm2(const std::string& file, const std::string& filename, const std::string& endpoint) +void ControllerClientImpl::_UploadFileToControllerViaForm(const std::vector& vdata, const std::string& filename, const std::string& endpoint) { CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); _buffer.clear(); @@ -1623,7 +1626,9 @@ void ControllerClientImpl::_UploadFileToControllerViaForm2(const std::string& fi CURL_FORM_RELEASER(formpost); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "files[]", - CURLFORM_FILE, file.c_str(), + CURLFORM_BUFFER, filename.c_str(), + CURLFORM_BUFFERPTR, (char*)&vdata[0], + CURLFORM_BUFFERLENGTH, vdata.size(), CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "filename", From 80e0cc3321745a85c89763611c89f40ae51ac9dc Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 23 Jul 2019 14:33:54 +0900 Subject: [PATCH 307/477] code review --- include/mujincontrollerclient/mujincontrollerclient.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1bfcb068..bef64408 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -499,13 +499,10 @@ class MUJINCLIENT_API ControllerClient /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// - /// \param filename_utf8 utf-8 encoded path of the backup file on the system. tar/tar.gz/tar.bz2 formats are accepted. + /// \param vdata the contents of the backup. tar/tar.gz/tar.bz2 formats are accepted. /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). - virtual void RestoreBackup_UTF8(const std::string& filename_utf8, bool config = true, bool media = true) = 0; - - /// \param filename_utf16 utf-16 encoded path of the backup file on the system. tar/tar.gz/tar.bz2 formats are accepted. - virtual void RestoreBackup_UTF16(const std::wstring& filename_utf16, bool config = true, bool media = true) = 0; + virtual void RestoreBackup(const std::vector& vdata, bool config = true, bool media = true) = 0; /** \brief Recursively uploads a directory to the controller network filesystem. From 399909165aa920512c078d54f1cc1738835e1b51 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:04:00 +0900 Subject: [PATCH 308/477] RestoreBackup now uses inputStream --- src/controllerclientimpl.cpp | 58 +++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8c4361db..926f38de 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -868,6 +868,15 @@ int ControllerClientImpl::_WriteStringStreamCallback(char *data, size_t size, si return size * nmemb; } +int ControllerClientImpl::_WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData) +{ + if (writerData == NULL) { + return 0; + } + writerData->write(data, size*nmemb); + return size * nmemb; +} + int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData) { if (writerData == NULL) { @@ -877,6 +886,15 @@ int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t n return size * nmemb; } +int ControllerClientImpl::_ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *readerData) +{ + if (readerData == NULL) { + return 0; + } + std::cout << size*nmemb << std::endl; + return readerData->read(data, size*nmemb).gcount(); +} + void ControllerClientImpl::_SetupHTTPHeadersJSON() { // set the header to only send json @@ -1214,11 +1232,11 @@ void ControllerClientImpl::SaveBackup(std::vector& vdata, bool co _CallGet(_baseuri+"backup/"+query, vdata, 200, timeout); } -void ControllerClientImpl::RestoreBackup(const std::vector& vdata, bool config, bool media) +void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media) { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm(vdata, "backup.tar", _baseuri+"backup/"+query); + _UploadFileToControllerViaForm(inputStream, "backup"/*".tar"*/, _baseuri+"backup/"+query); } void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) @@ -1522,18 +1540,13 @@ void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filen std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - std::vectorcontent; std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); if(!fin.good()) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - fin.seekg(0, std::ios::end); - content.resize(fin.tellg()); - fin.seekg(0, std::ios::beg); - fin.read((char*)&content[0], content.size()); MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(content, filenameoncontroller, _baseuri + "fileupload"); + _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); } void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) @@ -1550,13 +1563,9 @@ void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& fil if(!fin.good()) { throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); } - fin.seekg(0, std::ios::end); - content.resize(fin.tellg()); - fin.seekg(0, std::ios::beg); - fin.read((char*)&content[0], content.size()); MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(content, filenameoncontroller, _baseuri + "fileupload"); + _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); } void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) @@ -1612,7 +1621,7 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& -void ControllerClientImpl::_UploadFileToControllerViaForm(const std::vector& vdata, const std::string& filename, const std::string& endpoint) +void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint) { CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); _buffer.clear(); @@ -1620,15 +1629,30 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(const std::vector Date: Wed, 24 Jul 2019 16:04:00 +0900 Subject: [PATCH 309/477] RestoreBackup now uses inputStream --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index bef64408..6c388887 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -499,10 +499,10 @@ class MUJINCLIENT_API ControllerClient /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// - /// \param vdata the contents of the backup. tar/tar.gz/tar.bz2 formats are accepted. + /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). tar/tar.gz/tar.bz2 formats are accepted. /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). - virtual void RestoreBackup(const std::vector& vdata, bool config = true, bool media = true) = 0; + virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true) = 0; /** \brief Recursively uploads a directory to the controller network filesystem. From 38cb6a48a941a3e979477ac755f25d3a285ac8cb Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:40:34 +0900 Subject: [PATCH 310/477] added timeout to _UploadFileToControllerViaForm --- src/controllerclientimpl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 926f38de..ca2c7a39 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1232,11 +1232,11 @@ void ControllerClientImpl::SaveBackup(std::vector& vdata, bool co _CallGet(_baseuri+"backup/"+query, vdata, 200, timeout); } -void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media) +void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media, double timeout) { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm(inputStream, "backup"/*".tar"*/, _baseuri+"backup/"+query); + _UploadFileToControllerViaForm(inputStream, "backup"/*".tar"*/, _baseuri+"backup/"+query, timeout); } void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) @@ -1621,13 +1621,15 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& -void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint) +void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout) { CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); _buffer.clear(); _buffer.str(""); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + //timeout is default to 0 (never) + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); inputStream.seekg(0, std::ios::end); if(inputStream.fail()) { From 2d248831ec49e6eb8ca02e91519d6b567ac56967 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:40:34 +0900 Subject: [PATCH 311/477] added timeout to _UploadFileToControllerViaForm --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 6c388887..05b6f175 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -502,7 +502,7 @@ class MUJINCLIENT_API ControllerClient /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). tar/tar.gz/tar.bz2 formats are accepted. /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). - virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true) = 0; + virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; /** \brief Recursively uploads a directory to the controller network filesystem. From ac6252adfa300b11fbe53f151f63daeff4ea9f51 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:49:31 +0900 Subject: [PATCH 312/477] fixed _CallGet string overload --- src/controllerclientimpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ca2c7a39..e1ac7d3d 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -588,6 +588,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp _buffer.str(""); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); CURL_PERFORM(_curl); long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); From be27fac1f4b959db17e950c85e3388ab35f7dad8 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:50:34 +0900 Subject: [PATCH 313/477] SaveBackup now uses ostream --- src/controllerclientimpl.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e1ac7d3d..5dff2b2b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -606,6 +606,25 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp return http_code; } +int ControllerClientImpl::_CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode, double timeout) +{ + MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteOStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &outputStream); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); + CURL_PERFORM(_curl); + long http_code = 0; + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { + // outputStream is not always seekable; ignore any error message. + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s (outputStream might have information)", desturi%http_code, MEC_HTTPServer); + } + return http_code; +} + int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); @@ -1226,11 +1245,11 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur } } -void ControllerClientImpl::SaveBackup(std::vector& vdata, bool config, bool media, double timeout) +void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, bool media, double timeout) { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _CallGet(_baseuri+"backup/"+query, vdata, 200, timeout); + _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); } void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media, double timeout) From 6a5946d9f1994164db54145f3b44355e684cc4aa Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:50:34 +0900 Subject: [PATCH 314/477] SaveBackup now uses ostream --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 05b6f175..22c0ca86 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -492,10 +492,10 @@ class MUJINCLIENT_API ControllerClient /// \brief Build a backup of config/media and download it. /// - /// \param vdata filled with the contents of the backup. the backup is tar.gz format. + /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. /// \param config whether to backup config. By default true. /// \param media whether to backup media. By default true. - virtual void SaveBackup(std::vector& vdata, bool config = true, bool media = true, double timeout = 60.0) = 0; + virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// From 553cbcd86ffbb5ef53bb275a314ade766517602f Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 16:54:57 +0900 Subject: [PATCH 315/477] remove debug --- src/controllerclientimpl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 5dff2b2b..9071be3b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -911,7 +911,6 @@ int ControllerClientImpl::_ReadIStreamCallback(char *data, size_t size, size_t n if (readerData == NULL) { return 0; } - std::cout << size*nmemb << std::endl; return readerData->read(data, size*nmemb).gcount(); } @@ -1663,7 +1662,6 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT("failed to rewind inputStream (%s)", filename, MEC_InvalidArguments); } - std::cout << contentLength << std::endl; CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadIStreamCallback); // prepare form From af8841c5d2e76c790e3bf8b119ba1645f71e4196 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 17:00:56 +0900 Subject: [PATCH 316/477] do not send filename= parameter when restoring --- src/controllerclientimpl.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 9071be3b..02c8790e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1255,7 +1255,7 @@ void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm(inputStream, "backup"/*".tar"*/, _baseuri+"backup/"+query, timeout); + _UploadFileToControllerViaForm(inputStream, "", _baseuri+"backup/"+query, timeout); } void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) @@ -1652,15 +1652,15 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr inputStream.seekg(0, std::ios::end); if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT("failed to seek inputStream (%s) to get the length", filename, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); } size_t contentLength = inputStream.tellg(); if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT("failed to tell the length of inputStream (%s)", filename, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); } inputStream.seekg(0, std::ios::beg); if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT("failed to rewind inputStream (%s)", filename, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); } CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadIStreamCallback); @@ -1670,14 +1670,16 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr CURL_FORM_RELEASER(formpost); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "files[]", - CURLFORM_FILENAME, filename.c_str(), + CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), CURLFORM_STREAM, &inputStream, CURLFORM_CONTENTSLENGTH, contentLength, CURLFORM_END); - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "filename", - CURLFORM_COPYCONTENTS, filename.c_str(), - CURLFORM_END); + if(!filename.empty()) { + curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "filename", + CURLFORM_COPYCONTENTS, filename.c_str(), + CURLFORM_END); + } CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); CURL_PERFORM(_curl); From 36d663fd65549dd38c55d88fbda3bf5210439473 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 24 Jul 2019 18:16:09 +0900 Subject: [PATCH 317/477] remove extra comment --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 22c0ca86..1869741f 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -499,7 +499,7 @@ class MUJINCLIENT_API ControllerClient /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). tar/tar.gz/tar.bz2 formats are accepted. + /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; From 57a3480bd745f61a085777fa846a312c84b245f9 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 2 Aug 2019 10:38:42 +0900 Subject: [PATCH 318/477] eliminated initializer-list --- include/mujincontrollerclient/mujinjson.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 9919e716..cddbfecd 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -534,6 +534,21 @@ template inline void LoadJsonValueByKey(const rapidjson::Value } } +template inline void LoadJsonValueByPath(const rapidjson::Value& v, const char* key, T& t) { + const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); + if (child && !child->IsNull()) { + LoadJsonValue(*child, t); + } +} +template inline void LoadJsonValueByPath(const rapidjson::Value& v, const char* key, T& t, const U& d) { + const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); + if (child && !child->IsNull()) { + LoadJsonValue(*child, t); + } + else { + t = d; + } +} //work the same as LoadJsonValueByKey, but the value is returned instead of being passed as reference template T GetJsonValueByKey(const rapidjson::Value& v, const char* key, const U& t) { @@ -576,7 +591,12 @@ template inline T GetJsonValueByPath(const rapidjson::Value& v, const c return r; } -template T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { +#if __cplusplus >= 201103 +template +#else +template +#endif +T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); if (child && !child->IsNull()) { T r; From d6b54d3d88c02fa88dd90a013bc2be0c77b6b708 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 27 Aug 2019 17:50:13 +0900 Subject: [PATCH 319/477] Added Upgrade/GetUpgradeStatus/Reboot --- src/controllerclientimpl.cpp | 37 +++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 02c8790e..509a94eb 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -280,11 +280,6 @@ void ControllerClientImpl::RestartServer(double timeout) } } -void ControllerClientImpl::Upgrade(const std::vector& vdata) -{ - throw MUJIN_EXCEPTION_FORMAT0("Failed to upgrade server, deprecated", MEC_HTTPServer); -} - void ControllerClientImpl::CancelAllJobs() { CallDelete("job/?format=json"); @@ -1258,6 +1253,38 @@ void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, _UploadFileToControllerViaForm(inputStream, "", _baseuri+"backup/"+query, timeout); } +void ControllerClientImpl::Upgrade(std::istream* inputStream, bool autorestart, bool uploadonly, double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + std::string query=std::string("?autorestart=")+(autorestart ? "1" : "0")+("&uploadonly=")+(uploadonly ? "1" : "0"); + if(inputStream) { + _UploadFileToControllerViaForm(*inputStream, "", _baseuri+"upgrade/"+query, timeout); + } else { + rapidjson::Document pt(rapidjson::kObjectType); + _CallPost(_baseuri+"upgrade/"+query, "", pt, 200, timeout); + } +} + +bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progress, double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + rapidjson::Document pt(rapidjson::kObjectType); + _CallGet(_baseuri+"upgrade/", pt, 200, timeout); + if(pt.IsNull()){ + return false; + } + status = GetJsonValueByKey(pt, "status"); + progress = GetJsonValueByKey(pt, "progress"); + return true; +} + +void ControllerClientImpl::Reboot(double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + rapidjson::Document pt(rapidjson::kObjectType); + _CallPost(_baseuri+"reboot/", "", pt, 200, timeout); +} + void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); From 6c9748e067427485c4241d01a42888802db7f3e3 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 27 Aug 2019 17:50:13 +0900 Subject: [PATCH 320/477] Added Upgrade/GetUpgradeStatus/Reboot --- .../mujincontrollerclient.h | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1869741f..39eb711a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -369,9 +369,6 @@ class MUJINCLIENT_API ControllerClient /// The method is blocking, when it returns the MUJIN Controller would have been restarted. virtual void RestartServer(double timeout = 5.0) = 0; - /// \brief Upgrade the controller with this data - virtual void Upgrade(const std::vector& vdata) = 0; - /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; @@ -499,11 +496,30 @@ class MUJINCLIENT_API ControllerClient /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). + /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable for files). /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; + /// \brief Upgrade controller's software. + /// + /// \param inputStream the stream represententing the software file provided by MUJIN. + /// It needs to be seekable to get the size (ifstream subclass is applicable for files). + /// NULL means using previously uploaded file. + /// \param autorestart whether to restart automatically after upgrading. if false, Reboot() can be called later. + /// \param uploadonly whether to upload only (so that upgrade can be continued later without uploading). + virtual void Upgrade(std::istream* inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; + + /// \brief Get upgrade status. + /// + /// \param status upgrade status + /// \param progress progress 0 to 1 + /// \return true if the status was received (false means upgrade was not started yet). + virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout = 5.0) = 0; + + /// \brief (Request to) reboot controller. + virtual void Reboot(double timeout = 5.0) = 0; + /** \brief Recursively uploads a directory to the controller network filesystem. Creates directories along the way if they don't exist. From 696b449fd41f52936affdec1cd2bf3c118fdd34b Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 27 Aug 2019 18:11:17 +0900 Subject: [PATCH 321/477] Added CancelUpgrade --- src/controllerclientimpl.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 509a94eb..c93850c3 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -282,7 +282,7 @@ void ControllerClientImpl::RestartServer(double timeout) void ControllerClientImpl::CancelAllJobs() { - CallDelete("job/?format=json"); + CallDelete("job/?format=json", 204); } void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, int options) @@ -750,7 +750,7 @@ int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std: return _CallPut(relativeuri, static_cast(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); } -void ControllerClientImpl::CallDelete(const std::string& relativeuri, double timeout) +void ControllerClientImpl::CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout) { MUJIN_LOG_DEBUG(str(boost::format("DELETE %s%s")%_baseapiuri%relativeuri)); boost::mutex::scoped_lock lock(_mutex); @@ -763,7 +763,7 @@ void ControllerClientImpl::CallDelete(const std::string& relativeuri, double tim CURL_PERFORM(_curl); long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 204 ) { // or 200 or 202 or 201? + if( http_code != expectedhttpcode ) { throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); } } @@ -1278,6 +1278,13 @@ bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progres return true; } +void ControllerClientImpl::CancelUpgrade(double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + rapidjson::Document pt(rapidjson::kObjectType); + CallDelete(_baseuri+"upgrade/", 200, timeout); +} + void ControllerClientImpl::Reboot(double timeout) { boost::mutex::scoped_lock lock(_mutex); From 533cb43d4fe11f75a9b6ad4938cd16ae247676f4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 27 Aug 2019 18:11:17 +0900 Subject: [PATCH 322/477] Added CancelUpgrade --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 39eb711a..b06a7d31 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -517,6 +517,9 @@ class MUJINCLIENT_API ControllerClient /// \return true if the status was received (false means upgrade was not started yet). virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout = 5.0) = 0; + /// \brief Cancel the current upgrade process. + virtual void CancelUpgrade(double timeout = 5.0) = 0; + /// \brief (Request to) reboot controller. virtual void Reboot(double timeout = 5.0) = 0; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 480dcbe4..fc4ab149 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -124,7 +124,7 @@ void WebResource::SetJSON(const std::string& json, double timeout) void WebResource::Delete(double timeout) { GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey()), timeout); + controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey()), 204, timeout); } void WebResource::Copy(const std::string& newname, int options, double timeout) @@ -889,7 +889,7 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& void SceneResource::DeleteInstObject(const std::string& pk) { GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("scene/%s/instobject/%s/")%GetPrimaryKey()%pk)); + controller->CallDelete(str(boost::format("scene/%s/instobject/%s/")%GetPrimaryKey()%pk), 204); } SceneResourcePtr SceneResource::Copy(const std::string& name) From 52ed1dbe7a682aa252c5749d942793f74c6f28c2 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Aug 2019 13:11:35 +0900 Subject: [PATCH 323/477] Use inputStream size to determine whether to use pre-uploaded file --- src/controllerclientimpl.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c93850c3..f715d06b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1253,12 +1253,26 @@ void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, _UploadFileToControllerViaForm(inputStream, "", _baseuri+"backup/"+query, timeout); } -void ControllerClientImpl::Upgrade(std::istream* inputStream, bool autorestart, bool uploadonly, double timeout) +void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout) { boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?autorestart=")+(autorestart ? "1" : "0")+("&uploadonly=")+(uploadonly ? "1" : "0"); - if(inputStream) { - _UploadFileToControllerViaForm(*inputStream, "", _baseuri+"upgrade/"+query, timeout); + + inputStream.seekg(0, std::ios::end); + if(inputStream.fail()) { + throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); + } + size_t contentLength = inputStream.tellg(); + if(inputStream.fail()) { + throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); + } + inputStream.seekg(0, std::ios::beg); + if(inputStream.fail()) { + throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); + } + + if(!contentLength) { + _UploadFileToControllerViaForm(inputStream, "", _baseuri+"upgrade/"+query, timeout); } else { rapidjson::Document pt(rapidjson::kObjectType); _CallPost(_baseuri+"upgrade/"+query, "", pt, 200, timeout); From b9956bc1c36cdb4bda298e6697919729b6eb25af Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Aug 2019 13:11:35 +0900 Subject: [PATCH 324/477] Use inputStream size to determine whether to use pre-uploaded file --- include/mujincontrollerclient/mujincontrollerclient.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b06a7d31..c3c85c1d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -496,7 +496,7 @@ class MUJINCLIENT_API ControllerClient /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable for files). + /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). /// \param config whether to restore config. By default true (if the backup file has config). /// \param media whether to restore media. By default true (if the backup file has media). virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; @@ -504,11 +504,11 @@ class MUJINCLIENT_API ControllerClient /// \brief Upgrade controller's software. /// /// \param inputStream the stream represententing the software file provided by MUJIN. - /// It needs to be seekable to get the size (ifstream subclass is applicable for files). - /// NULL means using previously uploaded file. + /// It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). + /// Pass stream with size 0 to use previously uploaded file. /// \param autorestart whether to restart automatically after upgrading. if false, Reboot() can be called later. /// \param uploadonly whether to upload only (so that upgrade can be continued later without uploading). - virtual void Upgrade(std::istream* inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; + virtual void Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; /// \brief Get upgrade status. /// From bf151a79855bc639accef4c13d1f750024e7f526 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Aug 2019 14:42:30 +0900 Subject: [PATCH 325/477] keep inputStream position --- src/controllerclientimpl.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index f715d06b..ec0b217a 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1258,15 +1258,16 @@ void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, boost::mutex::scoped_lock lock(_mutex); std::string query=std::string("?autorestart=")+(autorestart ? "1" : "0")+("&uploadonly=")+(uploadonly ? "1" : "0"); + std::streampos originalPos = inputStream.tellg(); inputStream.seekg(0, std::ios::end); if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); } - size_t contentLength = inputStream.tellg(); + std::streampos contentLength = inputStream.tellg() - originalPos; if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); } - inputStream.seekg(0, std::ios::beg); + inputStream.seekg(originalPos, std::ios::beg); if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); } @@ -1698,15 +1699,16 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr //timeout is default to 0 (never) CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + std::streampos originalPos = inputStream.tellg(); inputStream.seekg(0, std::ios::end); if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); } - size_t contentLength = inputStream.tellg(); + std::streampos contentLength = inputStream.tellg() - originalPos; if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); } - inputStream.seekg(0, std::ios::beg); + inputStream.seekg(originalPos, std::ios::beg); if(inputStream.fail()) { throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); } From d2b71c7ccce03040b53d3090e96eb59dc6de9922 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 28 Aug 2019 16:03:45 +0900 Subject: [PATCH 326/477] fix form upload --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ec0b217a..24d5979b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1272,7 +1272,7 @@ void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); } - if(!contentLength) { + if(contentLength) { _UploadFileToControllerViaForm(inputStream, "", _baseuri+"upgrade/"+query, timeout); } else { rapidjson::Document pt(rapidjson::kObjectType); @@ -1722,7 +1722,7 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr CURLFORM_COPYNAME, "files[]", CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), CURLFORM_STREAM, &inputStream, - CURLFORM_CONTENTSLENGTH, contentLength, + CURLFORM_CONTENTSLENGTH, (std::streamoff)contentLength, CURLFORM_END); if(!filename.empty()) { curl_formadd(&formpost, &lastptr, From 221e229f02e98fc4f6e38c5357e6a8d1c45c0468 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 29 Aug 2019 15:54:11 +0900 Subject: [PATCH 327/477] fix GetVersion() mutex --- src/controllerclientimpl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 24d5979b..330dde02 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -221,7 +221,6 @@ ControllerClientImpl::~ControllerClientImpl() std::string ControllerClientImpl::GetVersion() { - boost::mutex::scoped_lock lock(_mutex); if (!_profile.IsObject()) { _profile.SetObject(); CallGet("profile/", _profile); From f4a5c76650f0227678d0055f04d49b8decaf3855 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 29 Aug 2019 15:56:52 +0900 Subject: [PATCH 328/477] Add DebugLog API --- src/controllerclientimpl.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 330dde02..7daacd6f 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -600,6 +600,14 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp return http_code; } +int ControllerClientImpl::CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode, double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseapiuri; + _uri += relativeuri; + return _CallGet(_uri, outputStream, expectedhttpcode, timeout); +} + int ControllerClientImpl::_CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); @@ -1828,4 +1836,26 @@ size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, return nBytesToRead; } +void ControllerClientImpl::GetDebugLogInfos(std::vector& debugloginfos, double timeout) +{ + rapidjson::Document pt(rapidjson::kObjectType); + CallGet(str(boost::format("debug/?format=json&limit=0")), pt, 200, timeout); + rapidjson::Value& objects = pt["objects"]; + + debugloginfos.resize(objects.Size()); + size_t iobj = 0; + for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { + DebugLogResourcePtr debugloginfo(new DebugLogResource(shared_from_this(), GetJsonValueByKey(*it, "pk"))); + + //LoadJsonValueByKey(*it, "datemodified", debugloginfo->datemodified); + LoadJsonValueByKey(*it, "description", debugloginfo->description); + //LoadJsonValueByKey(*it, "downloadUri", debugloginfo->downloadUri); + LoadJsonValueByKey(*it, "name", debugloginfo->name); + //LoadJsonValueByKey(*it, "resource_uri", debugloginfo->resource_uri); + LoadJsonValueByKey(*it, "size", debugloginfo->size); + + debugloginfos.at(iobj++) = debugloginfo; + } +} + } // end namespace mujinclient From c3e6379a4584415090d144f96e58b0870b58d14d Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 29 Aug 2019 15:56:52 +0900 Subject: [PATCH 329/477] Add DebugLog API --- .../mujincontrollerclient.h | 27 +++++++++++++++++++ src/mujincontrollerclient.cpp | 14 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c3c85c1d..67bcef56 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -77,6 +77,7 @@ class BinPickingTaskResource; class OptimizationResource; class PlanningResultResource; class BinPickingResultResource; +class DebugLogResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; @@ -96,6 +97,8 @@ typedef boost::shared_ptr PlanningResultResourcePtr; typedef boost::weak_ptr PlanningResultResourceWeakPtr; typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; +typedef boost::shared_ptr DebugLogResourcePtr; +typedef boost::weak_ptr DebugLogResourceWeakPtr; typedef double Real; inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { @@ -643,6 +646,8 @@ class MUJINCLIENT_API ControllerClient /// virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; + /// \brief get debug log infos + virtual void GetDebugLogInfos(std::vector& debugloginfos, double timeout = 5) = 0; }; class MUJINCLIENT_API WebResource @@ -1149,6 +1154,28 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); }; +class MUJINCLIENT_API DebugLogResource : public WebResource +{ +public: + DebugLogResource(ControllerClientPtr controller, const std::string& pk); + virtual ~DebugLogResource() { + } + + /// \brief download the encrypted debug log to outputStream + virtual void Download(std::ostream &outputStream, double timeout = 60.0); + + //std::string datemodified; + std::string description; + //std::string downloadUri; + std::string name; + std::string pk; + std::string resource_uri; + size_t size; + +protected: + DebugLogResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); +}; + /** \en \brief creates the controller with an account. This function is not thread safe. You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index fc4ab149..ea70f5b7 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1239,6 +1239,20 @@ void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, cons } } +DebugLogResource::DebugLogResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "debug", pk), pk(pk) +{ +} + +DebugLogResource::DebugLogResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) +{ +} + +void DebugLogResource::Download(std::ostream& outputStream, double timeout) +{ + GETCONTROLLERIMPL(); + controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); +} + ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); From f800efc0aec4ce8ab7d95bd6754acc2883fd95ea Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 11 Sep 2019 13:30:17 +0900 Subject: [PATCH 330/477] fix FileUploadToControllerViaForm on Windows --- src/controllerclientimpl.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 24d5979b..57909914 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1722,7 +1722,16 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr CURLFORM_COPYNAME, "files[]", CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), CURLFORM_STREAM, &inputStream, - CURLFORM_CONTENTSLENGTH, (std::streamoff)contentLength, +#if LIBCURL_VERSION_MAJOR<=7 && (LIBCURL_VERSION_MAJOR==7&&LIBCURLVERSION_MINOR<46) + // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. + // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. + // streamoff can be directly converted to streamoff, but it does not correspond on 32bit machines. + CURLFORM_CONTENTSLENGTH, (long)contentLength, +#else + // Actually we should use CURLFORM_CONTENTLEN, whose argument type is curl_off_t, which is 64bit. + // However, it was added in curl 1.46 and cannot be used in official Windows build. + CURLFORM_CONTENTLEN, (curl_off_t)contentLength, +#endif CURLFORM_END); if(!filename.empty()) { curl_formadd(&formpost, &lastptr, From b705bb6e90c914b284747495ef01de68d8ed20d8 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 11 Sep 2019 17:49:01 +0900 Subject: [PATCH 331/477] minor --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 57909914..e66c4589 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1722,14 +1722,14 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr CURLFORM_COPYNAME, "files[]", CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), CURLFORM_STREAM, &inputStream, -#if LIBCURL_VERSION_MAJOR<=7 && (LIBCURL_VERSION_MAJOR==7&&LIBCURLVERSION_MINOR<46) +#if LIBCURL_VERSION_MAJOR<7 || (LIBCURL_VERSION_MAJOR==7&&LIBCURLVERSION_MINOR<46) // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. // streamoff can be directly converted to streamoff, but it does not correspond on 32bit machines. CURLFORM_CONTENTSLENGTH, (long)contentLength, #else // Actually we should use CURLFORM_CONTENTLEN, whose argument type is curl_off_t, which is 64bit. - // However, it was added in curl 1.46 and cannot be used in official Windows build. + // However, it was added in curl 7.46 and cannot be used in official Windows build. CURLFORM_CONTENTLEN, (curl_off_t)contentLength, #endif CURLFORM_END); From 42b11dcfb301eec87e57b3d42d087cc5f57218bf Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 11 Sep 2019 18:03:46 +0900 Subject: [PATCH 332/477] found better ident --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e66c4589..cd57f0dc 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1722,7 +1722,7 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr CURLFORM_COPYNAME, "files[]", CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), CURLFORM_STREAM, &inputStream, -#if LIBCURL_VERSION_MAJOR<7 || (LIBCURL_VERSION_MAJOR==7&&LIBCURLVERSION_MINOR<46) +#if !CURL_AT_LEAST_VERSION(7,46,0) // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. // streamoff can be directly converted to streamoff, but it does not correspond on 32bit machines. From 937c452ab0b45283b02096f7ea036b6870f9172b Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 12 Sep 2019 08:55:58 +0900 Subject: [PATCH 333/477] fix comment --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index cd57f0dc..b7c45650 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1725,7 +1725,7 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr #if !CURL_AT_LEAST_VERSION(7,46,0) // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. - // streamoff can be directly converted to streamoff, but it does not correspond on 32bit machines. + // streampos can be directly converted to streamoff, but it does not correspond on 32bit machines. CURLFORM_CONTENTSLENGTH, (long)contentLength, #else // Actually we should use CURLFORM_CONTENTLEN, whose argument type is curl_off_t, which is 64bit. From 434e22cf4f871d014817e94f0ff24d748b342f92 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 17 Sep 2019 17:45:22 +0900 Subject: [PATCH 334/477] add deletefile sample --- src/controllerclientimpl.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b7c45650..b82bb9ee 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1687,8 +1687,6 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); } - - void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout) { CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); @@ -1787,21 +1785,16 @@ void ControllerClientImpl::_UploadDataToController(const std::vector(*it, "pk"))); + DebugResourcePtr debuginfo(new DebugResource(shared_from_this(), GetJsonValueByKey(*it, "pk"))); - //LoadJsonValueByKey(*it, "datemodified", debugloginfo->datemodified); - LoadJsonValueByKey(*it, "description", debugloginfo->description); - //LoadJsonValueByKey(*it, "downloadUri", debugloginfo->downloadUri); - LoadJsonValueByKey(*it, "name", debugloginfo->name); - //LoadJsonValueByKey(*it, "resource_uri", debugloginfo->resource_uri); - LoadJsonValueByKey(*it, "size", debugloginfo->size); + //LoadJsonValueByKey(*it, "datemodified", debuginfo->datemodified); + LoadJsonValueByKey(*it, "description", debuginfo->description); + //LoadJsonValueByKey(*it, "downloadUri", debuginfo->downloadUri); + LoadJsonValueByKey(*it, "name", debuginfo->name); + //LoadJsonValueByKey(*it, "resource_uri", debuginfo->resource_uri); + LoadJsonValueByKey(*it, "size", debuginfo->size); - debugloginfos.at(iobj++) = debugloginfo; + debuginfos.at(iobj++) = debuginfo; } } From c6ffad2284affd2ffb1ff920f86f8562146b96d6 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Fri, 20 Sep 2019 09:33:27 +0900 Subject: [PATCH 336/477] rename DebugLog -> Debug --- .../mujincontrollerclient.h | 18 +++++++++--------- src/mujincontrollerclient.cpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 67bcef56..78060911 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -77,7 +77,7 @@ class BinPickingTaskResource; class OptimizationResource; class PlanningResultResource; class BinPickingResultResource; -class DebugLogResource; +class DebugResource; typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; @@ -97,8 +97,8 @@ typedef boost::shared_ptr PlanningResultResourcePtr; typedef boost::weak_ptr PlanningResultResourceWeakPtr; typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; -typedef boost::shared_ptr DebugLogResourcePtr; -typedef boost::weak_ptr DebugLogResourceWeakPtr; +typedef boost::shared_ptr DebugResourcePtr; +typedef boost::weak_ptr DebugResourceWeakPtr; typedef double Real; inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { @@ -646,8 +646,8 @@ class MUJINCLIENT_API ControllerClient /// virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; - /// \brief get debug log infos - virtual void GetDebugLogInfos(std::vector& debugloginfos, double timeout = 5) = 0; + /// \brief get debug infos + virtual void GetDebugInfos(std::vector& debuginfos, double timeout = 5) = 0; }; class MUJINCLIENT_API WebResource @@ -1154,11 +1154,11 @@ class MUJINCLIENT_API PlanningResultResource : public WebResource virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); }; -class MUJINCLIENT_API DebugLogResource : public WebResource +class MUJINCLIENT_API DebugResource : public WebResource { public: - DebugLogResource(ControllerClientPtr controller, const std::string& pk); - virtual ~DebugLogResource() { + DebugResource(ControllerClientPtr controller, const std::string& pk); + virtual ~DebugResource() { } /// \brief download the encrypted debug log to outputStream @@ -1173,7 +1173,7 @@ class MUJINCLIENT_API DebugLogResource : public WebResource size_t size; protected: - DebugLogResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); + DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); }; /** \en \brief creates the controller with an account. This function is not thread safe. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index ea70f5b7..49834aab 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1239,15 +1239,15 @@ void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, cons } } -DebugLogResource::DebugLogResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "debug", pk), pk(pk) +DebugResource::DebugResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "debug", pk), pk(pk) { } -DebugLogResource::DebugLogResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) +DebugResource::DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) { } -void DebugLogResource::Download(std::ostream& outputStream, double timeout) +void DebugResource::Download(std::ostream& outputStream, double timeout) { GETCONTROLLERIMPL(); controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); From c67763add56de3c65912ac67a2aaef1c5e1ab1b4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 2 Oct 2019 12:03:14 +0900 Subject: [PATCH 337/477] avoid SIGSEGV when DELETE fails, where error message was written in uninitialized FILE* --- src/controllerclientimpl.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ebff0fd6..7b579e93 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -767,11 +767,19 @@ void ControllerClientImpl::CallDelete(const std::string& relativeuri, int expect CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "DELETE"); + _buffer.clear(); + _buffer.str(""); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); CURL_PERFORM(_curl); long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( http_code != expectedhttpcode ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s", relativeuri%http_code, MEC_HTTPServer); + rapidjson::Document d; + ParseJson(d, _buffer.str()); + std::string error_message = GetJsonValueByKey(d, "error_message"); + std::string traceback = GetJsonValueByKey(d, "traceback"); + throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); } } From c4d460a6994d9c14e12c40c19bb5ea27d2703ccf Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 2 Oct 2019 12:07:55 +0900 Subject: [PATCH 338/477] make sure to clear _buffer --- src/controllerclientimpl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 7b579e93..0e27d122 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -269,6 +269,8 @@ void ControllerClientImpl::RestartServer(double timeout) CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); + _buffer.clear(); + _buffer.str(""); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); CURL_PERFORM(_curl); @@ -1680,6 +1682,8 @@ void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& #endif CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READDATA, NULL, fd); + _buffer.clear(); + _buffer.str(""); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); @@ -1771,6 +1775,8 @@ void ControllerClientImpl::_UploadDataToController(const std::vector Date: Tue, 8 Oct 2019 09:49:15 +0900 Subject: [PATCH 339/477] add getting the base uri --- src/controllerclientimpl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ebff0fd6..8ba82a87 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -233,6 +233,11 @@ const std::string& ControllerClientImpl::GetUserName() const return _username; } +const std::string& ControllerClientImpl::GetBaseURI() const +{ + return _baseuri; +} + void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); @@ -1292,7 +1297,7 @@ bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progres boost::mutex::scoped_lock lock(_mutex); rapidjson::Document pt(rapidjson::kObjectType); _CallGet(_baseuri+"upgrade/", pt, 200, timeout); - if(pt.IsNull()){ + if(pt.IsNull()) { return false; } status = GetJsonValueByKey(pt, "status"); From 5c5ac3c34075b135692ce7bf2f233a1a9a38c40b Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 8 Oct 2019 09:49:15 +0900 Subject: [PATCH 340/477] add getting the base uri --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 78060911..f2582e20 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -360,6 +360,9 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the username logged into this controller virtual const std::string& GetUserName() const = 0; + /// \brief returns the URI used to setup the connection + virtual const std::string& GetBaseURI() const = 0; + /// \brief If necessary, changes the proxy to communicate to the controller server /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. From 2ad3cb0278cba075624315b5c9049ff0edba9de4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 8 Oct 2019 17:15:17 +0900 Subject: [PATCH 341/477] add ListFilesInController API --- .../mujincontrollerclient/mujincontrollerclient.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index f2582e20..24f16c93 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -79,6 +79,13 @@ class PlanningResultResource; class BinPickingResultResource; class DebugResource; +struct FileEntry +{ + std::string filename; + double modified; + size_t size; +}; + typedef boost::shared_ptr ControllerClientPtr; typedef boost::weak_ptr ControllerClientWeakPtr; typedef boost::shared_ptr ObjectResourcePtr; @@ -99,6 +106,8 @@ typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef boost::shared_ptr DebugResourcePtr; typedef boost::weak_ptr DebugResourceWeakPtr; +typedef boost::shared_ptr FileEntryPtr; +typedef boost::weak_ptr FileEntryWeakPtr; typedef double Real; inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { @@ -577,6 +586,11 @@ class MUJINCLIENT_API ControllerClient /// \param uri UTF-8 encoded file in the network filesystem to delete. virtual void DeleteDirectoryOnController_UTF8(const std::string& uri) = 0; + /// \brief Get file list in specified directory. + /// + /// \param dirname UTF-8 encoded dirname to query. + virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; + /// \brief \see DeleteDirectoryOnController_UTF8 /// /// \param uri UTF-16 encoded From 45990348c30ea8d27b5416e636626791e6458913 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 8 Oct 2019 17:15:17 +0900 Subject: [PATCH 342/477] add ListFilesInController API --- src/controllerclientimpl.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c58f58e5..92ed7df6 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1879,4 +1879,21 @@ void ControllerClientImpl::GetDebugInfos(std::vector& debuginf } } +void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) +{ + rapidjson::Document pt(rapidjson::kObjectType); + _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, 200, timeout); + fileentries.resize(pt.MemberCount()); + size_t iobj = 0; + for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { + FileEntryPtr fileentry(new FileEntry); + + fileentry->filename = it->name.GetString(); + LoadJsonValueByKey(it->value, "modified", fileentry->modified); + LoadJsonValueByKey(it->value, "size", fileentry->size); + + fileentries.at(iobj++) = fileentry; + } +} + } // end namespace mujinclient From 9de7eb8542932f8af0259d658b919b7e401a08f0 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 16 Oct 2019 14:49:07 +0900 Subject: [PATCH 343/477] code review --- include/mujincontrollerclient/mujincontrollerclient.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 24f16c93..30e65fa2 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -79,10 +79,11 @@ class PlanningResultResource; class BinPickingResultResource; class DebugResource; +/// \brief (scene) file entry in mujin controller struct FileEntry { std::string filename; - double modified; + double modified; // in epoch seconds size_t size; }; @@ -106,8 +107,6 @@ typedef boost::shared_ptr BinPickingResultResourcePtr; typedef boost::weak_ptr BinPickingResultResourceWeakPtr; typedef boost::shared_ptr DebugResourcePtr; typedef boost::weak_ptr DebugResourceWeakPtr; -typedef boost::shared_ptr FileEntryPtr; -typedef boost::weak_ptr FileEntryWeakPtr; typedef double Real; inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { @@ -589,7 +588,7 @@ class MUJINCLIENT_API ControllerClient /// \brief Get file list in specified directory. /// /// \param dirname UTF-8 encoded dirname to query. - virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; + virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; /// \brief \see DeleteDirectoryOnController_UTF8 /// From 9023116b5cb8c0e09baed761b78dafcdd488f60c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 16 Oct 2019 14:49:07 +0900 Subject: [PATCH 344/477] code review --- src/controllerclientimpl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 92ed7df6..da5494aa 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1879,20 +1879,20 @@ void ControllerClientImpl::GetDebugInfos(std::vector& debuginf } } -void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) +void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) { rapidjson::Document pt(rapidjson::kObjectType); _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, 200, timeout); fileentries.resize(pt.MemberCount()); size_t iobj = 0; for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { - FileEntryPtr fileentry(new FileEntry); + FileEntry &fileentry = fileentries.at(iobj); - fileentry->filename = it->name.GetString(); - LoadJsonValueByKey(it->value, "modified", fileentry->modified); - LoadJsonValueByKey(it->value, "size", fileentry->size); + fileentry.filename = it->name.GetString(); + LoadJsonValueByKey(it->value, "modified", fileentry.modified); + LoadJsonValueByKey(it->value, "size", fileentry.size); - fileentries.at(iobj++) = fileentry; + iobj++; } } From 7db3e5ee451c440d06d6beaf02e6fc28f1ccb7e1 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 23 Oct 2019 13:55:28 +0900 Subject: [PATCH 345/477] add comment to struct FileEntry --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 30e65fa2..1cd1adaa 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -84,7 +84,7 @@ struct FileEntry { std::string filename; double modified; // in epoch seconds - size_t size; + size_t size; // file size in bytes }; typedef boost::shared_ptr ControllerClientPtr; From 01c5813cae9caf9d96d99f5c766b032113172242 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 13 Mar 2020 08:40:04 +0900 Subject: [PATCH 346/477] Clean up MUJIN_ASSERT, everyone else is using BOOST_ASSERT. --- src/mujincontrollerclient.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 49834aab..f57aeee4 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -167,7 +167,9 @@ void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vect void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); - MUJIN_ASSERT_OP_FORMAT(this->geomtype,!=,"mesh", "geomtype is not mesh: %s", this->geomtype, MEC_InvalidArguments); + if (this->geomtype != "mesh") { + throw MUJIN_EXCEPTION_FORMAT("geomtype is not mesh: %s", this->geomtype, MEC_InvalidArguments); + } controller->SetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); } @@ -655,7 +657,9 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) { GETCONTROLLERIMPL(); - MUJIN_ASSERT_OP_FORMAT(instobjects.size(), ==, states.size(), "the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); + if (instobjects.size() != states.size()) { + throw MUJIN_EXCEPTION_FORMAT("the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); + } boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); std::string datastring, sdofvalues; for(size_t i = 0; i < instobjects.size(); ++i) { From 998f1210708dfec516aa910524a7d7f38980905f Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 13 Mar 2020 08:40:04 +0900 Subject: [PATCH 347/477] Clean up MUJIN_ASSERT, everyone else is using BOOST_ASSERT. --- src/controllerclientimpl.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index da5494aa..6453fad2 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -818,7 +818,9 @@ const std::string& ControllerClientImpl::GetDefaultTaskType() std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) { size_t index = uri.find(":/"); - MUJIN_ASSERT_OP_FORMAT(index,!=,std::string::npos, "bad URI: %s", uri, MEC_InvalidArguments); + if (index == std::string::npos) { + throw MUJIN_EXCEPTION_FORMAT("bad URI: %s", uri, MEC_InvalidArguments); + } return EscapeString(uri.substr(index+2)); } @@ -1412,7 +1414,9 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& } } else { - MUJIN_ASSERT_OP_FORMAT(copydir_utf8.at(copydir_utf8.size()-1),!=,s_filesep,"copydir '%s' cannot end in slash '%s'", copydir_utf8%s_filesep, MEC_InvalidArguments); + if (copydir_utf8.at(copydir_utf8.size()-1) == s_filesep) { + throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", copydir_utf8%s_filesep, MEC_InvalidArguments); + } uri = rawuri; } @@ -1526,7 +1530,9 @@ void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring } } else { - MUJIN_ASSERT_OP_FORMAT(copydir_utf16.at(copydir_utf16.size()-1),!=,s_wfilesep,"copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); + if (copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep) { + throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); + } uri = rawuri; } From 1c00368c885ab5be414e59a639aa8c10d0c0989a Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 26 May 2020 19:14:39 +0900 Subject: [PATCH 348/477] add new PickPlaceHistoryItem that will be published the planning slave --- include/mujincontrollerclient/mujincontrollerclient.h | 1 - src/mujincontrollerclient.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 1cd1adaa..dd5b5ab0 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -55,7 +55,6 @@ #include #include #include -#include #include #include diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index f57aeee4..9c08470d 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -439,7 +439,6 @@ void RobotResource::GetAttachedSensors(std::vector& a GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); - //boost::property_tree::ptree& objects = pt.get_child("attachedsensors"); rapidjson::Value& objects = pt["attachedsensors"]; attachedsensors.resize(objects.Size()); size_t i = 0; From ce3f5d6c2d6712f9632c158fb2657ed60ae6ef04 Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 26 May 2020 19:14:39 +0900 Subject: [PATCH 349/477] add new PickPlaceHistoryItem that will be published the planning slave --- src/controllerclientimpl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 6453fad2..b3eeb192 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -16,6 +16,8 @@ #include +#include + #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION @@ -320,7 +322,6 @@ void ControllerClientImpl::GetScenePrimaryKeys(std::vector& sceneke rapidjson::Document pt(rapidjson::kObjectType); CallGet("scene/?format=json&limit=0&fields=pk", pt); rapidjson::Value& objects = pt["objects"]; - //boost::property_tree::ptree& objects = pt.get_child("objects"); scenekeys.resize(objects.Size()); size_t i = 0; for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { From f70445b872794f1b9d124f8d19e2a512719745e3 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 28 May 2020 13:57:41 +0900 Subject: [PATCH 350/477] Initialize return value of AddLink/AddGeometry. Fix AddGeometryFromRawSTL as well. --- src/mujincontrollerclient.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9c08470d..09a09b0a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -180,6 +180,9 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFro const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, "mesh", timeout); ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); + geometry->name = name; + geometry->geomtype = "mesh"; + geometry->linkpk = linkpk; geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); return geometry; } @@ -191,6 +194,9 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGe const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, geomtype, timeout); ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); + geometry->name = name; + geometry->geomtype = geomtype; + geometry->linkpk = linkpk; return geometry; } @@ -360,7 +366,10 @@ ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, GETCONTROLLERIMPL(); const std::string linkPk = controller->CreateLink(this->pk, "", name,quaternion, translate); - return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->pk, linkPk)); + ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->pk, linkPk)); + link->name = name; + link->parentlinkpk = ""; + return link; } ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]) @@ -368,7 +377,10 @@ ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const GETCONTROLLERIMPL(); const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, name,quaternion, translate); - return ObjectResource::LinkResourcePtr(new LinkResource(controller, this->objectpk, linkPk)); + ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->objectpk, linkPk)); + link->name = name; + link->parentlinkpk = this->pk; + return link; } ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype) From 9057566f338526084664c57afea2db207565d7f9 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 14 Jul 2020 16:43:55 +0900 Subject: [PATCH 351/477] migrate realtimeitlplanning to realtimeitlplanning3 --- src/mujincontrollerclient.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 9c08470d..c997538a 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -601,17 +601,22 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t // task exists std::string pk; + std::string tasktype_internal = tasktype; + if( tasktype == "realtimeitlplanning" ) { + tasktype_internal = "realtimeitlplanning3"; + } + if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { rapidjson::Value& objects = pt["objects"]; pk = GetJsonValueByKey(objects[0], "pk"); std::string currenttasktype = GetJsonValueByKey(objects[0], "tasktype"); - if( currenttasktype != tasktype ) { - throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype, MEC_InvalidState); + if( currenttasktype != tasktype_internal && (currenttasktype != "realtimeitlplanning" || tasktype_internal != "realtimeitlplanning3")) { + throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype_internal, MEC_InvalidState); } } else { pt.SetObject(); - controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype%GetPrimaryKey()), pt); + controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype_internal%GetPrimaryKey()), pt); LoadJsonValueByKey(pt, "pk", pk); } @@ -619,11 +624,11 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t return TaskResourcePtr(); } - if( tasktype == "binpicking" || tasktype == "realtimeitlplanning") { + if( tasktype_internal == "binpicking" || tasktype_internal == "realtimeitlplanning3") { BinPickingTaskResourcePtr task; if( options & 1 ) { #ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey(), tasktype)); + task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey(), tasktype_internal)); #else throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); #endif @@ -633,7 +638,7 @@ TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& t } return task; } - else if( tasktype == "cablepicking" ) { // TODO create CablePickingTaskResource + else if( tasktype_internal == "cablepicking" ) { // TODO create CablePickingTaskResource BinPickingTaskResourcePtr task; if( options & 1 ) { #ifdef MUJIN_USEZMQ From 373078abb365e8dc1060ed3473d31bc6604b19de Mon Sep 17 00:00:00 2001 From: rosen Date: Wed, 5 Aug 2020 22:17:16 +0900 Subject: [PATCH 352/477] have correct isContainerEmptyMap format --- include/mujincontrollerclient/mujinjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index cddbfecd..3f59f370 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -291,7 +291,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, boost::sh ptr = boost::shared_ptr(new T(t)); } -template inline void LoadJsonValue(const rapidjson::Value& v, std::pair& t) { +template inline void LoadJsonValue(const rapidjson::Value& v, std::pair& t) { if (v.IsArray()) { if (v.GetArray().Size() == 2) { LoadJsonValue(v[0], t.first); From 846dd952eb2cb2b63079e255ebc30cc633460fc4 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 8 Oct 2020 14:15:14 +0900 Subject: [PATCH 353/477] Fixed DeleteFileOnController webstack2 CallPost uses "content-type:application/json" and putting raw parameter in data is not ok. need to use query string. --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b3eeb192..413ab31e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1827,7 +1827,7 @@ void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) std::string filename = desturi.substr(_basewebdavuri.size()); rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"file/delete/", std::string("filename=")+filename, pt, 200, 5.0); + _CallPost(_baseuri+"file/delete/?filename="+filename, "", pt, 200, 5.0); } void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) From d8583fc5c9cae5e10bbc37ecbec90c97c9ac7908 Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 21 Dec 2020 15:22:22 +0900 Subject: [PATCH 354/477] improved json templates --- include/mujincontrollerclient/mujinjson.h | 137 +++++++++++++++------- 1 file changed, 94 insertions(+), 43 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 3f59f370..f4354f3c 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -87,7 +87,7 @@ class MujinJSONException : public std::exception MujinJSONErrorCode GetCode() const { return _error; } - + private: std::string _s, _ssub; MujinJSONErrorCode _error; @@ -95,26 +95,26 @@ class MujinJSONException : public std::exception template inline std::string GetJsonString(const T& t); -/// \brief gets a string of the Value type for debugging purposes +/// \brief gets a string of the Value type for debugging purposes inline std::string GetJsonTypeName(const rapidjson::Value& v) { int type = v.GetType(); switch (type) { - case 0: - return "Null"; - case 1: - return "False"; - case 2: - return "True"; - case 3: - return "Object"; - case 4: - return "Array"; - case 5: - return "String"; - case 6: - return "Number"; - default: - return "Unknown"; + case 0: + return "Null"; + case 1: + return "False"; + case 2: + return "True"; + case 3: + return "Object"; + case 4: + return "Array"; + case 5: + return "String"; + case 6: + return "Number"; + default: + return "Unknown"; } } @@ -181,6 +181,18 @@ class JsonSerializable { } }; +template inline T LexicalCast(const S& v, const std::string& typeName) { + try { + T t = boost::lexical_cast(v); + return t; + } + catch (const boost::bad_lexical_cast& ex) { + std::stringstream ss; + ss << v; + throw MujinJSONException("Cannot convert \"" + ss.str() + "\" to type " + typeName, MJE_Failed); + } +} + //store a json value to local data structures //for compatibility with ptree, type conversion is made. will remove them in the future inline void LoadJsonValue(const rapidjson::Value& v, JsonSerializable& t) { @@ -202,20 +214,43 @@ inline void LoadJsonValue(const rapidjson::Value& v, std::string& t) { inline void LoadJsonValue(const rapidjson::Value& v, int& t) { if (v.IsInt()) { t = v.GetInt(); + } else if (v.IsUint()) { + t = v.GetUint(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "Int"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int", MJE_Failed); } } -inline void LoadJsonValue(const rapidjson::Value& v, int64_t& t) { - if (v.IsInt64()) { - t = v.GetInt64(); +inline void LoadJsonValue(const rapidjson::Value& v, int8_t& t) { + if (v.IsInt()) { + t = v.GetInt(); + } + else if (v.IsUint()) { + t = v.GetUint(); + } + else if (v.IsString()) { + t = LexicalCast(v.GetString(), "Int8"); + } + else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int8", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, uint8_t& t) { + if (v.IsUint()) { + t = v.GetUint(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "UInt8"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt8", MJE_Failed); } } @@ -223,9 +258,11 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { if (v.IsUint()) { t = v.GetUint(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "UInt"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt", MJE_Failed); } } @@ -233,31 +270,45 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { if (v.IsUint64()) { t = v.GetUint64(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "ULongLong"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to UInt64", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to ULongLong", MJE_Failed); } } -#ifndef _MSC_VER inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { if (v.IsUint64()) { t = v.GetUint64(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "UInt64"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Int64", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt64", MJE_Failed); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, int64_t& t) { + if (v.IsInt64()) { + t = v.GetInt64(); + } else if (v.IsString()) { + t = LexicalCast(v.GetString(), "Int64"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int64", MJE_Failed); } } -#endif inline void LoadJsonValue(const rapidjson::Value& v, double& t) { if (v.IsNumber()) { t = v.GetDouble(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "Double"); } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Double", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Double", MJE_Failed); } } @@ -265,9 +316,9 @@ inline void LoadJsonValue(const rapidjson::Value& v, float& t) { if (v.IsNumber()) { t = v.GetDouble(); } else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "Float"); } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Double", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Float", MJE_Failed); } } @@ -275,9 +326,9 @@ inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { if (v.IsInt()) t = v.GetInt(); else if (v.IsBool()) t = v.GetBool(); else if (v.IsString()) { - t = boost::lexical_cast(v.GetString()); + t = LexicalCast(v.GetString(), "Bool"); } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to Bool", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Bool", MJE_Failed); } } @@ -337,9 +388,9 @@ template inline void LoadJsonValue(const rapidjson::Value& v, if (v.IsArray()) { if (v.GetArray().Size() != N) { throw MujinJSONException( - (boost::format("Cannot convert json type " + GetJsonTypeName(v) + " to Array. " - "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str(), - MJE_Failed); + (boost::format("Cannot convert json type " + GetJsonTypeName(v) + " to Array. " + "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str(), + MJE_Failed); } size_t i = 0; for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { @@ -364,7 +415,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::map< t.clear(); U value; for (rapidjson::Value::ConstMemberIterator it = v.MemberBegin(); - it != v.MemberEnd(); ++it) { + it != v.MemberEnd(); ++it) { LoadJsonValue(it->value, value); t[it->name.GetString()] = value; } From 70afceac05366c097ee9fd084444790af21c63ac Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 5 Feb 2021 16:30:39 +0900 Subject: [PATCH 355/477] Add support for querying sensors in connected body. --- src/mujincontrollerclient.cpp | 57 ++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 05511ea3..60accdc4 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -770,24 +770,45 @@ void SceneResource::GetSensorMapping(std::map& sensorm { GETCONTROLLERIMPL(); sensormapping.clear(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - if ( it->HasMember("attachedsensors") ) { - rapidjson::Value& jsonattachedsensors = (*it)["attachedsensors"]; - if (jsonattachedsensors.IsArray() && jsonattachedsensors.Size() > 0) { - std::string object_pk = GetJsonValueByKey(*it, "object_pk"); - std::string cameracontainername = GetJsonValueByKey(*it, "name"); - rapidjson::Document pt_robot(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%object_pk), pt_robot); - rapidjson::Value& pt_attachedsensors = pt_robot["attachedsensors"]; - for (rapidjson::Document::ValueIterator itsensor = pt_attachedsensors.Begin(); - itsensor != pt_attachedsensors.End(); ++itsensor) { - std::string sensorname = GetJsonValueByKey(*itsensor, "name"); - std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); - std::string cameraid = GetJsonValueByPath(*itsensor, "/sensordata/hardware_id"); - sensormapping[camerafullname] = cameraid; + rapidjson::Document rInstObjects(rapidjson::kObjectType); + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,connectedBodies,object_pk,name")%GetPrimaryKey()), rInstObjects); + for (rapidjson::Document::ConstValueIterator itInstObject = rInstObjects["objects"].Begin(); itInstObject != rInstObjects["objects"].End(); ++itInstObject) { + std::string cameracontainername = GetJsonValueByKey(*itInstObject, "name"); + std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); + if ( itInstObject->HasMember("attachedsensors") && (*itInstObject)["attachedsensors"].IsArray() && (*itInstObject)["attachedsensors"].Size() > 0) { + rapidjson::Document rRobotAttachedSensors(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%objectPk), rRobotAttachedSensors); + const rapidjson::Value& rAttachedSensors = rRobotAttachedSensors["attachedsensors"]; + for (rapidjson::Document::ConstValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { + std::string sensorname = GetJsonValueByKey(*itAttachedSensor, "name"); + std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); + std::string cameraid = GetJsonValueByPath(*itAttachedSensor, "/sensordata/hardware_id"); + sensormapping[camerafullname] = cameraid; + } + } + if ( itInstObject->HasMember("connectedBodies") && (*itInstObject)["connectedBodies"].IsArray() && (*itInstObject)["connectedBodies"].Size() > 0 ) { + rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%objectPk), rRobotConnectedBodies); + rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; + for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { + std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); + std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); + rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); + for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { + if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { + continue; + } + std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); + rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); + rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; + for (rapidjson::Document::ConstValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { + std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); + std::string camerafullname = str(boost::format("%s/%s_%s")%cameracontainername%connectedBodyName%sensorname); + std::string cameraid = GetJsonValueByPath(*itConnectedBodyAttachedSensor, "/sensordata/hardware_id"); + sensormapping[camerafullname] = cameraid; + } } } } From b38ff6bd126edd8cb960d73edac912edfd8c6066 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 10 Feb 2021 17:19:24 +0900 Subject: [PATCH 356/477] Fixed CancelUpgrade; CallDelete must not be wrapped by scoped_lock --- src/controllerclientimpl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 413ab31e..c07cc6fe 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1320,8 +1320,6 @@ bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progres void ControllerClientImpl::CancelUpgrade(double timeout) { - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); CallDelete(_baseuri+"upgrade/", 200, timeout); } From 335bb6b920d31137d508af1ee3abcd4814c49651 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 25 Jun 2021 09:37:20 +0900 Subject: [PATCH 357/477] Raise correct json error. --- include/mujincontrollerclient/mujinjson.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index f4354f3c..88fe75b8 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -156,7 +156,7 @@ inline void ParseJson(rapidjson::Document& d, const std::string& str) { } else { substr = str; } - throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr), MJE_Failed); + throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)tempDoc.GetErrorOffset())%GetParseError_En(tempDoc.GetParseError())%substr), MJE_Failed); } d.Swap(tempDoc); } @@ -167,7 +167,7 @@ inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::Document(tempDoc); tempDoc.ParseStream(isw); // parse float in full precision mode if (tempDoc.HasParseError()) { - throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); + throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)tempDoc.GetErrorOffset())%GetParseError_En(tempDoc.GetParseError())), MJE_Failed); } d.Swap(tempDoc); } From e5d1e2a23c9a1ff37423e178f2ad6786fa0660ff Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Thu, 19 Aug 2021 18:41:54 +0900 Subject: [PATCH 358/477] add reference_object_pk --- include/mujincontrollerclient/mujincontrollerclient.h | 1 + src/mujincontrollerclient.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index dd5b5ab0..00bf230d 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -962,6 +962,7 @@ class MUJINCLIENT_API SceneResource : public WebResource std::string name; std::string pk; std::string object_pk; + std::string reference_object_pk; std::string reference_uri; Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] Real translate[3]; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 60accdc4..c1297373 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -829,6 +829,7 @@ void SceneResource::GetInstObjects(std::vector& in LoadJsonValueByKey(*it, "name", instobject->name); LoadJsonValueByKey(*it, "object_pk", instobject->object_pk); + LoadJsonValueByKey(*it, "reference_object_pk", instobject->reference_object_pk, std::string()); LoadJsonValueByKey(*it, "reference_uri", instobject->reference_uri); LoadJsonValueByKey(*it, "dofvalues", instobject->dofvalues); LoadJsonValueByKey(*it, "quaternion", instobject->quaternion); @@ -908,7 +909,7 @@ bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstO SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) { GETCONTROLLERIMPL(); - const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk,object_pk,reference_uri,dofvalues,quaternion,translate")%GetPrimaryKey())); + const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk,object_pk,reference_object_pk,reference_uri,dofvalues,quaternion,translate")%GetPrimaryKey())); std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); if (!referenceUri.empty()) { data += ", \"reference_uri\": \"" + referenceUri + "\""; @@ -920,6 +921,7 @@ SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& std::string inst_pk = GetJsonValueByKey(pt, "pk"); SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); LoadJsonValueByKey(pt, "object_pk", instobject->object_pk); + LoadJsonValueByKey(pt, "reference_object_pk", instobject->reference_object_pk, std::string()); LoadJsonValueByKey(pt, "reference_uri", instobject->reference_uri); LoadJsonValueByKey(pt, "dofvalues", instobject->dofvalues); LoadJsonValueByKey(pt, "quaternion", instobject->quaternion); From 9538f39c03d3b6f352a7892839d051b795ebfa07 Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Fri, 17 Sep 2021 16:40:11 +0900 Subject: [PATCH 359/477] Add the ability to backup only selected scene --- include/mujincontrollerclient/mujincontrollerclient.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index dd5b5ab0..a027ba45 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -504,8 +504,9 @@ class MUJINCLIENT_API ControllerClient /// /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. /// \param config whether to backup config. By default true. - /// \param media whether to backup media. By default true. - virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; + /// \param media whether to include all, current, or none of the media in the backup. By default 'all' + /// \param media pk of the current scene in use. By default empty. + virtual void SaveBackup(std::ostream& outputStream, bool config = true, const std::string& media = "all", const std::string& currentscenepk = "", double timeout = 60.0) = 0; /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// From a7e91a1832a3bb3cfef3a775c2a6ae99ef9e0233 Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Fri, 17 Sep 2021 16:40:11 +0900 Subject: [PATCH 360/477] Add the ability to backup only selected scene --- src/controllerclientimpl.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c07cc6fe..cf41b7af 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1264,10 +1264,15 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur } } -void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, bool media, double timeout) +void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, const std::string& media, const std::string& currentscenepk, double timeout) { boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); + std::string query; + if(media.empty()) { + query=std::string("?config=")+(config ? "true" : "false"); + } else { + query=std::string("?config=")+(config ? "true" : "false")+"&media="+media+"¤tscenepk="+currentscenepk; + } _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); } From eb2861bf39b8b09abbb0612d5bbf283307202e86 Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Wed, 22 Sep 2021 18:19:19 +0900 Subject: [PATCH 361/477] Rename currentscenepk to currentscenename --- include/mujincontrollerclient/mujincontrollerclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a027ba45..8f76c757 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -505,8 +505,8 @@ class MUJINCLIENT_API ControllerClient /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. /// \param config whether to backup config. By default true. /// \param media whether to include all, current, or none of the media in the backup. By default 'all' - /// \param media pk of the current scene in use. By default empty. - virtual void SaveBackup(std::ostream& outputStream, bool config = true, const std::string& media = "all", const std::string& currentscenepk = "", double timeout = 60.0) = 0; + /// \param currentscenename name of the current scene in use. By default empty. + virtual void SaveBackup(std::ostream& outputStream, bool config = true, const std::string& media = "all", const std::string& currentscenename = "", double timeout = 60.0) = 0; /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// From ed829d615ae11fb127b3e152f5f9383c5583e0dd Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Wed, 22 Sep 2021 18:19:19 +0900 Subject: [PATCH 362/477] Rename currentscenepk to currentscenename --- src/controllerclientimpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index cf41b7af..5c546554 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1264,14 +1264,14 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur } } -void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, const std::string& media, const std::string& currentscenepk, double timeout) +void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, const std::string& media, const std::string& currentscenename, double timeout) { boost::mutex::scoped_lock lock(_mutex); std::string query; if(media.empty()) { query=std::string("?config=")+(config ? "true" : "false"); } else { - query=std::string("?config=")+(config ? "true" : "false")+"&media="+media+"¤tscenepk="+currentscenepk; + query=std::string("?config=")+(config ? "true" : "false")+"&media="+media+"¤tscenename="+currentscenename; } _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); } From 025703f2785db9c836451567066a4493ea37cbeb Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Fri, 1 Oct 2021 10:52:38 +0900 Subject: [PATCH 363/477] Rename currentscenename to backupscenepks --- include/mujincontrollerclient/mujincontrollerclient.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 8f76c757..33f2db0b 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -504,9 +504,9 @@ class MUJINCLIENT_API ControllerClient /// /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. /// \param config whether to backup config. By default true. - /// \param media whether to include all, current, or none of the media in the backup. By default 'all' - /// \param currentscenename name of the current scene in use. By default empty. - virtual void SaveBackup(std::ostream& outputStream, bool config = true, const std::string& media = "all", const std::string& currentscenename = "", double timeout = 60.0) = 0; + /// \param media whether to include media files in the backup. By default true + /// \param backupscenepks comma separated list of scenes to backup. By default empty. + virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, const std::string& backupscenepks = "", double timeout = 60.0) = 0; /// \brief Restore backup archive into controller. Restaring might be required after restoration. /// From 9a186cf4bee2431588613abf790ac742c6e5533e Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Fri, 1 Oct 2021 10:52:38 +0900 Subject: [PATCH 364/477] Rename currentscenename to backupscenepks --- src/controllerclientimpl.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 5c546554..a5f17afc 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1264,15 +1264,10 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur } } -void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, const std::string& media, const std::string& currentscenename, double timeout) +void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, bool media, const std::string& backupscenepks, double timeout) { boost::mutex::scoped_lock lock(_mutex); - std::string query; - if(media.empty()) { - query=std::string("?config=")+(config ? "true" : "false"); - } else { - query=std::string("?config=")+(config ? "true" : "false")+"&media="+media+"¤tscenename="+currentscenename; - } + std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false")+"&backupscenepks="+backupscenepks; _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); } From f7a4b9c6172600638ca3414fbdd4acacd7d01086 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 27 Dec 2021 21:46:50 +0900 Subject: [PATCH 365/477] Set cookie domain Starting in 7.43.0 any-domain cookies will not be exported --- src/controllerclientimpl.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index c07cc6fe..50c9b234 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -190,6 +190,25 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, // csrftoken can be any non-empty string _csrfmiddlewaretoken = "csrftoken"; std::string cookie = "Set-Cookie: csrftoken=" + _csrfmiddlewaretoken; + if(_baseuri.find('/') == _baseuri.size()-1) { + // _baseuri should be hostname with trailing slash + cookie += "; domain="; + cookie += _baseuri.substr(0,_baseuri.size()-1); + } else { + CURLUcode rc; + CURLU *url = curl_url(); + rc = curl_url_set(url, CURLUPART_URL, _baseuri.c_str(), 0); + if(!rc) { + char *host; + rc = curl_url_get(url, CURLUPART_HOST, &host, 0); + if(!rc) { + cookie += "; domain="; + cookie += host; + curl_free(host); + } + } + curl_url_cleanup(url); + } CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); _charset = "utf-8"; From ddddb7f161879dcfa5961357fe7946746af7fc8c Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 27 Dec 2021 22:17:43 +0900 Subject: [PATCH 366/477] add version conditional --- src/controllerclientimpl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 50c9b234..8b2f0075 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -190,6 +190,8 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, // csrftoken can be any non-empty string _csrfmiddlewaretoken = "csrftoken"; std::string cookie = "Set-Cookie: csrftoken=" + _csrfmiddlewaretoken; +#if CURL_AT_LEAST_VERSION(7,60,0) + // with https://github.com/curl/curl/commit/b8d5036ec9b702d6392c97a6fc2e141d6c7cce1f, setting domain param to cookie is required. if(_baseuri.find('/') == _baseuri.size()-1) { // _baseuri should be hostname with trailing slash cookie += "; domain="; @@ -209,6 +211,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } curl_url_cleanup(url); } +#endif CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); _charset = "utf-8"; From 975fa545557c97f27bec0bda1c3b8e93b4e94291 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 28 Dec 2021 13:23:38 +0900 Subject: [PATCH 367/477] automatically cleanup curl resource --- src/controllerclientimpl.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8b2f0075..a18d9b41 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -15,7 +15,7 @@ #include "controllerclientimpl.h" #include - +#include #include #define SKIP_PEER_VERIFICATION // temporary @@ -199,17 +199,23 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, } else { CURLUcode rc; CURLU *url = curl_url(); + BOOST_SCOPE_EXIT_ALL(&url) { + curl_url_cleanup(url); + }; rc = curl_url_set(url, CURLUPART_URL, _baseuri.c_str(), 0); if(!rc) { - char *host; + char *host = NULL; + BOOST_SCOPE_EXIT_ALL(&host) { + if(host) { + curl_free(host); + } + }; rc = curl_url_get(url, CURLUPART_HOST, &host, 0); if(!rc) { cookie += "; domain="; cookie += host; - curl_free(host); } } - curl_url_cleanup(url); } #endif CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); From dbc177d6840fd360476e08be36697194c9706f2a Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Tue, 28 Dec 2021 16:43:05 +0900 Subject: [PATCH 368/477] check curl_url status --- src/controllerclientimpl.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index a18d9b41..16c4bb47 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -197,25 +197,20 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, cookie += "; domain="; cookie += _baseuri.substr(0,_baseuri.size()-1); } else { - CURLUcode rc; CURLU *url = curl_url(); BOOST_SCOPE_EXIT_ALL(&url) { curl_url_cleanup(url); }; - rc = curl_url_set(url, CURLUPART_URL, _baseuri.c_str(), 0); - if(!rc) { - char *host = NULL; - BOOST_SCOPE_EXIT_ALL(&host) { - if(host) { - curl_free(host); - } - }; - rc = curl_url_get(url, CURLUPART_HOST, &host, 0); - if(!rc) { - cookie += "; domain="; - cookie += host; + CHECKCURLUCODE(curl_url_set(url, CURLUPART_URL, _baseuri.c_str(), 0), "cannot parse url"); + char *host = NULL; + BOOST_SCOPE_EXIT_ALL(&host) { + if(host) { + curl_free(host); } - } + }; + CHECKCURLUCODE(curl_url_get(url, CURLUPART_HOST, &host, 0), "cannot determine hostname from url"); + cookie += "; domain="; + cookie += host; } #endif CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); From 646bc503a2b0ff2fe0f6694e820ee4734807fcb5 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Sat, 1 Jan 2022 18:58:47 +0900 Subject: [PATCH 369/477] _PrepareDestinationURI_UTF16 should not lock mutex, safe to assume it is already locked --- src/controllerclientimpl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 16c4bb47..04060614 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1131,7 +1131,6 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstring& rawuri_utf16, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) { - boost::mutex::scoped_lock lock(_mutex); std::string baseuploaduri; std::string desturi_utf8; utf8::utf16to8(rawuri_utf16.begin(), rawuri_utf16.end(), std::back_inserter(desturi_utf8)); From da2203f76efadd03850f90c297dad48beaafa026 Mon Sep 17 00:00:00 2001 From: mujin Date: Fri, 7 Jan 2022 09:37:32 +0900 Subject: [PATCH 370/477] Silence unnecessary parentheses warning. --- include/mujincontrollerclient/mujinjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index f4354f3c..90cae29f 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -164,7 +164,7 @@ inline void ParseJson(rapidjson::Document& d, const std::string& str) { inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) - rapidjson::Document(tempDoc); + rapidjson::Document tempDoc; tempDoc.ParseStream(isw); // parse float in full precision mode if (tempDoc.HasParseError()) { throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); From 26d57b2b7e1c7b61c77a2bc8db6a2818a9e3ed2e Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 10 Feb 2021 16:16:17 +0900 Subject: [PATCH 371/477] Add DeleteAllScenes --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index dd5b5ab0..b25b8fb7 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -536,6 +536,9 @@ class MUJINCLIENT_API ControllerClient /// \brief (Request to) reboot controller. virtual void Reboot(double timeout = 5.0) = 0; + /// \brief Delete all scenes. + virtual void DeleteAllScenes(double timeout = 5.0) = 0; + /** \brief Recursively uploads a directory to the controller network filesystem. Creates directories along the way if they don't exist. From c998a83a26897e4e9be5779239021adcc5c9f386 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 10 Feb 2021 16:16:17 +0900 Subject: [PATCH 372/477] Add DeleteAllScenes --- src/controllerclientimpl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 04060614..cea9ecfb 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1352,6 +1352,13 @@ void ControllerClientImpl::Reboot(double timeout) _CallPost(_baseuri+"reboot/", "", pt, 200, timeout); } +void ControllerClientImpl::DeleteAllScenes(double timeout) +{ + boost::mutex::scoped_lock lock(_mutex); + rapidjson::Document pt(rapidjson::kObjectType); + CallDelete("scene/", 204, timeout); +} + void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); From 2ec0489084670d8221fee3c27ade4330bba3532a Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 10 Jan 2022 09:21:51 +0900 Subject: [PATCH 373/477] add DeleteAllITLPrograms --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b25b8fb7..25a287c9 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -539,6 +539,9 @@ class MUJINCLIENT_API ControllerClient /// \brief Delete all scenes. virtual void DeleteAllScenes(double timeout = 5.0) = 0; + /// \brief Delete all itl programs. + virtual void DeleteAllITLPrograms(double timeout = 5.0) = 0; + /** \brief Recursively uploads a directory to the controller network filesystem. Creates directories along the way if they don't exist. From 060c30c357e9089ee8f3867ad8decafa2f47c412 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Mon, 10 Jan 2022 09:21:51 +0900 Subject: [PATCH 374/477] add DeleteAllITLPrograms --- src/controllerclientimpl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index cea9ecfb..df7ca6b2 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1359,6 +1359,11 @@ void ControllerClientImpl::DeleteAllScenes(double timeout) CallDelete("scene/", 204, timeout); } +void ControllerClientImpl::DeleteAllITLPrograms(double timeout) +{ + CallDelete("itl/", 204, timeout); +} + void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); From 9037438883b11bbda240fbde5cd217fe95b69740 Mon Sep 17 00:00:00 2001 From: Ziyan Zhou Date: Tue, 8 Mar 2022 00:16:08 +0900 Subject: [PATCH 375/477] Revert "Silence ZMQ related warnings" --- include/mujincontrollerclient/mujinjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 90cae29f..f4354f3c 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -164,7 +164,7 @@ inline void ParseJson(rapidjson::Document& d, const std::string& str) { inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) - rapidjson::Document tempDoc; + rapidjson::Document(tempDoc); tempDoc.ParseStream(isw); // parse float in full precision mode if (tempDoc.HasParseError()) { throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); From 94305f3f9cd859eb9765d0d08a598b875ad67ea4 Mon Sep 17 00:00:00 2001 From: Leonid Terenin Date: Thu, 24 Mar 2022 14:57:29 +0900 Subject: [PATCH 376/477] fix shadowed variables, take 1 --- .../mujincontrollerclient.h | 2 +- src/mujincontrollerclient.cpp | 66 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 33078627..78b69484 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -317,7 +317,7 @@ class RobotProgramData public: RobotProgramData() { } - RobotProgramData(const std::string& programdata, const std::string& type) : programdata(programdata), type(type) { + RobotProgramData(const std::string& programdata_, const std::string& type_) : programdata(programdata_), type(type_) { } std::string programdata; ///< the program data std::string type; ///< the type of program diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c1297373..46acf10f 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -132,23 +132,23 @@ void WebResource::Copy(const std::string& newname, int options, double timeout) throw MujinException("not implemented yet"); } -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "object", pk), pk(pk) +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "object", pk_), pk(pk_) { } -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) +ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) { } -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/link")%objectpk), pk), pk(pk), objectpk(objectpk) +ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/link")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) { } -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk), pk(pk), objectpk(objectpk) +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk_), pk(pk_), objectpk(objectpk_) { } -ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk), pk), pk(pk) +ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk_), pk_), pk(pk_) { } @@ -173,28 +173,28 @@ void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vectorSetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); } -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout) +ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& geomname, const std::string& unit, double timeout) { GETCONTROLLERIMPL(); const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, "mesh", timeout); + const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, "mesh", timeout); ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = name; + geometry->name = geomname; geometry->geomtype = "mesh"; geometry->linkpk = linkpk; geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); return geometry; } -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout) +ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGeometry(const std::string& geomname, const std::string& geomtype, double timeout) { GETCONTROLLERIMPL(); const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, name, linkpk, geomtype, timeout); + const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, geomtype, timeout); ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = name; + geometry->name = geomname; geometry->geomtype = geomtype; geometry->linkpk = linkpk; return geometry; @@ -209,10 +209,10 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { rapidjson::Value& objects = pt["geometries"]; for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string name = it->HasMember("name") ? GetJsonValueByKey(*it, "name") : GetJsonValueByKey(*it, "pk"); - if (name == geometryName && (*it)["linkpk"].GetString() == this->pk) { + const std::string geomname = it->HasMember("name") ? GetJsonValueByKey(*it, "name") : GetJsonValueByKey(*it, "pk"); + if (geomname == geometryName && (*it)["linkpk"].GetString() == this->pk) { ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = name; + geometry->name = geomname; LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); LoadJsonValueByKey(*it,"visible",geometry->visible); LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); @@ -233,7 +233,7 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro } } } - throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->geomname%geometryName, MEC_InvalidArguments); } void ObjectResource::LinkResource::GetGeometries(std::vector& geometries) @@ -267,10 +267,10 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorSetJSON(mujinjson::GetJsonStringByKey("collision",collision)); - this->collision = collision; + this->SetJSON(mujinjson::GetJsonStringByKey("collision", hasCollision)); + this->collision = hasCollision; } void ObjectResource::SetCollision(bool collision) { @@ -295,10 +295,10 @@ int ObjectResource::GetCollision() return ret-1; } -void ObjectResource::GeometryResource::SetVisible(bool visible) +void ObjectResource::GeometryResource::SetVisible(bool isVisible) { - this->SetJSON(mujinjson::GetJsonStringByKey("visible",visible)); - this->visible = visible; + this->SetJSON(mujinjson::GetJsonStringByKey("visible",isVisible)); + this->visible = isVisible; } void ObjectResource::LinkResource::SetVisible(bool visible) { @@ -361,32 +361,32 @@ void ObjectResource::GetLinks(std::vector& link } } -ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]) +ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) { GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->pk, "", name,quaternion, translate); + const std::string linkPk = controller->CreateLink(this->pk, "", objname, quaternion_, translate_); ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->pk, linkPk)); - link->name = name; + link->name = objname; link->parentlinkpk = ""; return link; } -ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]) +ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) { GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, name,quaternion, translate); + const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, objname, quaternion_, translate_); ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->objectpk, linkPk)); - link->name = name; + link->name = objname; link->parentlinkpk = this->pk; return link; } -ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& name, const std::string& iktype) +ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& objname, const std::string& iktype) { GETCONTROLLERIMPL(); - const std::string ikparamPk = controller->CreateIkParam(this->pk, name, iktype); + const std::string ikparamPk = controller->CreateIkParam(this->pk, objname, iktype); return ObjectResource::IkParamResourcePtr(new IkParamResource(controller, this->pk, ikparamPk)); } @@ -411,11 +411,11 @@ void ObjectResource::GetIkParams(std::vector } } -RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk) : ObjectResource(controller, "robot", pk) +RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk_) : ObjectResource(controller, "robot", pk_) { } -RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk), pk(pk) +RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk_), pk(pk_) { } @@ -453,7 +453,7 @@ void RobotResource::GetAttachedSensors(std::vector& a controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); rapidjson::Value& objects = pt["attachedsensors"]; attachedsensors.resize(objects.Size()); - size_t i = 0; + //size_t i = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); @@ -505,7 +505,7 @@ void RobotResource::GetAttachedSensors(std::vector& a } } -SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk), pk(pk) +SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk_) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk_), pk(pk_) { } From d8ed331d87676cf09cfff4fff4f4a524c1ee34af Mon Sep 17 00:00:00 2001 From: Leonid Terenin Date: Thu, 24 Mar 2022 15:04:20 +0900 Subject: [PATCH 377/477] fix shadowed variables, take 2 --- src/mujincontrollerclient.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 46acf10f..1ede982b 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -233,7 +233,7 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro } } } - throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->geomname%geometryName, MEC_InvalidArguments); + throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); } void ObjectResource::LinkResource::GetGeometries(std::vector& geometries) @@ -442,7 +442,7 @@ void RobotResource::GetTools(std::vector& tools) } } -RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk), pk(pk) +RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk_), pk(pk_) { } @@ -453,7 +453,7 @@ void RobotResource::GetAttachedSensors(std::vector& a controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); rapidjson::Value& objects = pt["attachedsensors"]; attachedsensors.resize(objects.Size()); - //size_t i = 0; + size_t sensorNum = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); @@ -501,7 +501,7 @@ void RobotResource::GetAttachedSensors(std::vector& a //std::cout << "no asus param" << std::endl; } - attachedsensors[i++] = attachedsensor; + attachedsensors[sensorNum++] = attachedsensor; } } @@ -1282,11 +1282,11 @@ void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, cons } } -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "debug", pk), pk(pk) +DebugResource::DebugResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "debug", pk_), pk(pk_) { } -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk) : WebResource(controller, resource, pk), pk(pk) +DebugResource::DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) { } From fed77b03a5fa2f183fc368adef3c2721bb1a1e36 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 7 Apr 2022 11:13:41 +0900 Subject: [PATCH 378/477] fix: gather attachedsensors from connectedBodies in RobotResource::GetAttachedSensors before populating attachedsensors vector --- src/mujincontrollerclient.cpp | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c1297373..809ba538 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -450,9 +450,39 @@ void RobotResource::GetAttachedSensors(std::vector& a { GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%GetPrimaryKey()), pt); rapidjson::Value& objects = pt["attachedsensors"]; - attachedsensors.resize(objects.Size()); + size_t attachedSensorsSize = objects.Size(); + + rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%GetPrimaryKey()), rRobotConnectedBodies); + rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; + if (rConnectedBodies.IsArray() && rConnectedBodies.Size() > 0) { + for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { + std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); + std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); + rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); + controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); + for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { + if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { + continue; + } + std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); + rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); + rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; + for (rapidjson::Document::ValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { + std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); + std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%sensorname); + SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyRobotAttachedSensors.GetAllocator()); + objects.PushBack(*itConnectedBodyAttachedSensor, pt.GetAllocator()); + attachedSensorsSize++; + } + } + } + } + + attachedsensors.resize(attachedSensorsSize); size_t i = 0; for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); From 4d95fb71bede73f6eec797e8cdf9999ee035f3e9 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Mon, 11 Apr 2022 17:16:36 +0900 Subject: [PATCH 379/477] refactor: trim some redundant code from RobotResource::GetAttachedSensors and utils::GetSensorTransform flows --- src/mujincontrollerclient.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 809ba538..d6201459 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -463,18 +463,15 @@ void RobotResource::GetAttachedSensors(std::vector& a std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { + for (rapidjson::Document::ValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { continue; } - std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); - rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; + rapidjson::Value& rConnectedBodyAttachedSensors = (*itConnectedBodyInstObject)["attachedsensors"]; for (rapidjson::Document::ValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%sensorname); - SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyRobotAttachedSensors.GetAllocator()); + SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyInstObjects.GetAllocator()); objects.PushBack(*itConnectedBodyAttachedSensor, pt.GetAllocator()); attachedSensorsSize++; } From 0a988ad902625e9a16bad3083c0265c459546432 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 12 Apr 2022 17:10:40 +0900 Subject: [PATCH 380/477] refactor: replace RobotResource::GetAttachedSensors queue accumulating (suffers from memory allocation bugs) with direct helper function call --- .../mujincontrollerclient.h | 3 + src/mujincontrollerclient.cpp | 114 +++++++++--------- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 33078627..4a48ef94 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -901,6 +901,9 @@ class MUJINCLIENT_API RobotResource : public ObjectResource // images int numdof; std::string simulation_file; + +private: + virtual void PushAttachedSensor(std::vector& attachedsensors, rapidjson::Value& attachedSensor); }; class MUJINCLIENT_API SceneResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d6201459..84401b02 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -451,8 +451,12 @@ void RobotResource::GetAttachedSensors(std::vector& a GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["attachedsensors"]; - size_t attachedSensorsSize = objects.Size(); + + attachedsensors.clear(); + + for (rapidjson::Document::ValueIterator itAttachedSensor = pt["attachedsensors"].Begin(); itAttachedSensor != pt["attachedsensors"].End(); ++itAttachedSensor) { + PushAttachedSensor(attachedsensors, *itAttachedSensor); + } rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%GetPrimaryKey()), rRobotConnectedBodies); @@ -463,73 +467,75 @@ void RobotResource::GetAttachedSensors(std::vector& a std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { + for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { continue; } - rapidjson::Value& rConnectedBodyAttachedSensors = (*itConnectedBodyInstObject)["attachedsensors"]; + std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); + rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); + controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); + + rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; for (rapidjson::Document::ValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%sensorname); - SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyInstObjects.GetAllocator()); - objects.PushBack(*itConnectedBodyAttachedSensor, pt.GetAllocator()); - attachedSensorsSize++; + SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyRobotAttachedSensors.GetAllocator()); + PushAttachedSensor(attachedsensors, *itConnectedBodyAttachedSensor); } } } } +} - attachedsensors.resize(attachedSensorsSize); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - - LoadJsonValueByKey(*it, "name", attachedsensor->name); - LoadJsonValueByKey(*it, "frame_origin", attachedsensor->frame_origin); - LoadJsonValueByKey(*it, "sensortype", attachedsensor->sensortype); - LoadJsonValueByKey(*it, "quaternion", attachedsensor->quaternion); - LoadJsonValueByKey(*it, "translate", attachedsensor->translate); - std::vector distortionCoeffs = GetJsonValueByPath > (*it, "/sensordata/distortion_coeffs"); - BOOST_ASSERT(distortionCoeffs.size() <= 5); - for (size_t i = 0; i < distortionCoeffs.size(); i++) { - attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; - } - attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*it, "/sensordata/distortion_model"); - attachedsensor->sensordata.focal_length = GetJsonValueByPath(*it, "/sensordata/focal_length"); - attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*it, "/sensordata/measurement_time"); - std::vector intrinsics = GetJsonValueByPath >(*it, "/sensordata/intrinsic"); - BOOST_ASSERT(intrinsics.size() <= 6); - for (size_t i = 0; i < intrinsics.size(); i++) { - attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; - } - std::vector imgdim = GetJsonValueByPath >(*it, "/sensordata/image_dimensions"); - BOOST_ASSERT(imgdim.size() <= 3); - for (size_t i = 0; i < imgdim.size(); i++) { - attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; - } +void RobotResource::PushAttachedSensor(std::vector& attachedsensors, rapidjson::Value& attachedSensor) { + GETCONTROLLERIMPL(); + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(attachedSensor, "pk"))); + + LoadJsonValueByKey(attachedSensor, "name", attachedsensor->name); + LoadJsonValueByKey(attachedSensor, "frame_origin", attachedsensor->frame_origin); + LoadJsonValueByKey(attachedSensor, "sensortype", attachedsensor->sensortype); + LoadJsonValueByKey(attachedSensor, "quaternion", attachedsensor->quaternion); + LoadJsonValueByKey(attachedSensor, "translate", attachedsensor->translate); + std::vector distortionCoeffs = GetJsonValueByPath > (attachedSensor, "/sensordata/distortion_coeffs"); + BOOST_ASSERT(distortionCoeffs.size() <= 5); + for (size_t i = 0; i < distortionCoeffs.size(); i++) { + attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; + } + attachedsensor->sensordata.distortion_model = GetJsonValueByPath(attachedSensor, "/sensordata/distortion_model"); + attachedsensor->sensordata.focal_length = GetJsonValueByPath(attachedSensor, "/sensordata/focal_length"); + attachedsensor->sensordata.measurement_time= GetJsonValueByPath(attachedSensor, "/sensordata/measurement_time"); + std::vector intrinsics = GetJsonValueByPath >(attachedSensor, "/sensordata/intrinsic"); + BOOST_ASSERT(intrinsics.size() <= 6); + for (size_t i = 0; i < intrinsics.size(); i++) { + attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; + } + std::vector imgdim = GetJsonValueByPath >(attachedSensor, "/sensordata/image_dimensions"); + BOOST_ASSERT(imgdim.size() <= 3); + for (size_t i = 0; i < imgdim.size(); i++) { + attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; + } - if (rapidjson::Pointer("/sensordata/extra_parameters").Get(*it)) { - std::string parameters_string = GetJsonValueByPath(*it, "/sensordata/extra_parameters"); - //std::cout << "extra param " << parameters_string << std::endl; - std::list results; - boost::split(results, parameters_string, boost::is_any_of(" ")); - results.remove(""); - attachedsensor->sensordata.extra_parameters.resize(results.size()); - size_t iparam = 0; - BOOST_FOREACH(std::string p, results) { - //std::cout << "'"<< p << "'"<< std::endl; - try { - attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); - } catch (...) { - //lexical_cast fails... - } + if (rapidjson::Pointer("/sensordata/extra_parameters").Get(attachedSensor)) { + std::string parameters_string = GetJsonValueByPath(attachedSensor, "/sensordata/extra_parameters"); + //std::cout << "extra param " << parameters_string << std::endl; + std::list results; + boost::split(results, parameters_string, boost::is_any_of(" ")); + results.remove(""); + attachedsensor->sensordata.extra_parameters.resize(results.size()); + size_t iparam = 0; + BOOST_FOREACH(std::string p, results) { + //std::cout << "'"<< p << "'"<< std::endl; + try { + attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); + } catch (...) { + //lexical_cast fails... } - } else { - //std::cout << "no asus param" << std::endl; } - - attachedsensors[i++] = attachedsensor; + } else { + //std::cout << "no asus param" << std::endl; } + + attachedsensors.push_back(attachedsensor); } SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk), pk(pk) From 4529f6c5a5c950baca13b7f00f3da2db53335626 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 12 Apr 2022 18:30:12 +0900 Subject: [PATCH 381/477] refactor: simplify RobotResource::GetAttachedSensors to use recursion for connected bodies --- .../mujincontrollerclient.h | 5 +- src/mujincontrollerclient.cpp | 127 +++++++++--------- 2 files changed, 64 insertions(+), 68 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 4a48ef94..7115be58 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -894,16 +894,13 @@ class MUJINCLIENT_API RobotResource : public ObjectResource } virtual void GetTools(std::vector& tools); - virtual void GetAttachedSensors(std::vector& attachedsensors); + virtual void GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies = true); // attachments // ikparams // images int numdof; std::string simulation_file; - -private: - virtual void PushAttachedSensor(std::vector& attachedsensors, rapidjson::Value& attachedSensor); }; class MUJINCLIENT_API SceneResource : public WebResource diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 84401b02..bd7c62f9 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -446,22 +446,70 @@ RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPt { } -void RobotResource::GetAttachedSensors(std::vector& attachedsensors) +void RobotResource::GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies) { GETCONTROLLERIMPL(); rapidjson::Document pt(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%GetPrimaryKey()), pt); - attachedsensors.clear(); + rapidjson::Value& rAttachedSensors = pt["attachedsensors"]; + attachedsensors.resize(rAttachedSensors.Size()); + + size_t attachedSensorIdx = 0; + for (rapidjson::Document::ValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { + AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*itAttachedSensor, "pk"))); + + LoadJsonValueByKey(*itAttachedSensor, "name", attachedsensor->name); + LoadJsonValueByKey(*itAttachedSensor, "frame_origin", attachedsensor->frame_origin); + LoadJsonValueByKey(*itAttachedSensor, "sensortype", attachedsensor->sensortype); + LoadJsonValueByKey(*itAttachedSensor, "quaternion", attachedsensor->quaternion); + LoadJsonValueByKey(*itAttachedSensor, "translate", attachedsensor->translate); + std::vector distortionCoeffs = GetJsonValueByPath > (*itAttachedSensor, "/sensordata/distortion_coeffs"); + BOOST_ASSERT(distortionCoeffs.size() <= 5); + for (size_t i = 0; i < distortionCoeffs.size(); i++) { + attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; + } + attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*itAttachedSensor, "/sensordata/distortion_model"); + attachedsensor->sensordata.focal_length = GetJsonValueByPath(*itAttachedSensor, "/sensordata/focal_length"); + attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*itAttachedSensor, "/sensordata/measurement_time"); + std::vector intrinsics = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/intrinsic"); + BOOST_ASSERT(intrinsics.size() <= 6); + for (size_t i = 0; i < intrinsics.size(); i++) { + attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; + } + std::vector imgdim = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/image_dimensions"); + BOOST_ASSERT(imgdim.size() <= 3); + for (size_t i = 0; i < imgdim.size(); i++) { + attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; + } + + if (rapidjson::Pointer("/sensordata/extra_parameters").Get(*itAttachedSensor)) { + std::string parameters_string = GetJsonValueByPath(*itAttachedSensor, "/sensordata/extra_parameters"); + //std::cout << "extra param " << parameters_string << std::endl; + std::list results; + boost::split(results, parameters_string, boost::is_any_of(" ")); + results.remove(""); + attachedsensor->sensordata.extra_parameters.resize(results.size()); + size_t iparam = 0; + BOOST_FOREACH(std::string p, results) { + //std::cout << "'"<< p << "'"<< std::endl; + try { + attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); + } catch (...) { + //lexical_cast fails... + } + } + } else { + //std::cout << "no asus param" << std::endl; + } - for (rapidjson::Document::ValueIterator itAttachedSensor = pt["attachedsensors"].Begin(); itAttachedSensor != pt["attachedsensors"].End(); ++itAttachedSensor) { - PushAttachedSensor(attachedsensors, *itAttachedSensor); + attachedsensors[attachedSensorIdx++] = attachedsensor; } rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%GetPrimaryKey()), rRobotConnectedBodies); rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; - if (rConnectedBodies.IsArray() && rConnectedBodies.Size() > 0) { + if (useConnectedBodies && rConnectedBodies.IsArray() && rConnectedBodies.Size() > 0) { for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); @@ -472,70 +520,21 @@ void RobotResource::GetAttachedSensors(std::vector& a continue; } std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); - - rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; - for (rapidjson::Document::ValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { - std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); - std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%sensorname); - SetJsonValueByKey(*itConnectedBodyAttachedSensor, "name", resolvedSensorName, rConnectedBodyRobotAttachedSensors.GetAllocator()); - PushAttachedSensor(attachedsensors, *itConnectedBodyAttachedSensor); - } - } - } - } -} + RobotResourcePtr connectedbodyrobot(new RobotResource(controller,connectedBodyObjectPk)); + std::vector connectedbodyattachedsensors; -void RobotResource::PushAttachedSensor(std::vector& attachedsensors, rapidjson::Value& attachedSensor) { - GETCONTROLLERIMPL(); - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(attachedSensor, "pk"))); - - LoadJsonValueByKey(attachedSensor, "name", attachedsensor->name); - LoadJsonValueByKey(attachedSensor, "frame_origin", attachedsensor->frame_origin); - LoadJsonValueByKey(attachedSensor, "sensortype", attachedsensor->sensortype); - LoadJsonValueByKey(attachedSensor, "quaternion", attachedsensor->quaternion); - LoadJsonValueByKey(attachedSensor, "translate", attachedsensor->translate); - std::vector distortionCoeffs = GetJsonValueByPath > (attachedSensor, "/sensordata/distortion_coeffs"); - BOOST_ASSERT(distortionCoeffs.size() <= 5); - for (size_t i = 0; i < distortionCoeffs.size(); i++) { - attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; - } - attachedsensor->sensordata.distortion_model = GetJsonValueByPath(attachedSensor, "/sensordata/distortion_model"); - attachedsensor->sensordata.focal_length = GetJsonValueByPath(attachedSensor, "/sensordata/focal_length"); - attachedsensor->sensordata.measurement_time= GetJsonValueByPath(attachedSensor, "/sensordata/measurement_time"); - std::vector intrinsics = GetJsonValueByPath >(attachedSensor, "/sensordata/intrinsic"); - BOOST_ASSERT(intrinsics.size() <= 6); - for (size_t i = 0; i < intrinsics.size(); i++) { - attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; - } - std::vector imgdim = GetJsonValueByPath >(attachedSensor, "/sensordata/image_dimensions"); - BOOST_ASSERT(imgdim.size() <= 3); - for (size_t i = 0; i < imgdim.size(); i++) { - attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; - } + connectedbodyrobot->GetAttachedSensors(connectedbodyattachedsensors, false); + + for (size_t i = 0; i < connectedbodyattachedsensors.size(); i++) { + std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%connectedbodyattachedsensors[i]->name); + connectedbodyattachedsensors[i]->name = resolvedSensorName; + } - if (rapidjson::Pointer("/sensordata/extra_parameters").Get(attachedSensor)) { - std::string parameters_string = GetJsonValueByPath(attachedSensor, "/sensordata/extra_parameters"); - //std::cout << "extra param " << parameters_string << std::endl; - std::list results; - boost::split(results, parameters_string, boost::is_any_of(" ")); - results.remove(""); - attachedsensor->sensordata.extra_parameters.resize(results.size()); - size_t iparam = 0; - BOOST_FOREACH(std::string p, results) { - //std::cout << "'"<< p << "'"<< std::endl; - try { - attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); - } catch (...) { - //lexical_cast fails... + attachedsensors.reserve(attachedsensors.size() + connectedbodyattachedsensors.size()); + attachedsensors.insert(attachedsensors.end(), connectedbodyattachedsensors.begin(), connectedbodyattachedsensors.end()); } } - } else { - //std::cout << "no asus param" << std::endl; } - - attachedsensors.push_back(attachedsensor); } SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk), pk(pk) From 3604f6e2b887fcec8d4dc55b3e639aa2e57dbe41 Mon Sep 17 00:00:00 2001 From: Tan Li Boon Date: Mon, 25 Apr 2022 16:59:51 +0900 Subject: [PATCH 382/477] mujinjson: LoadJsonValue: T must be default constructible, also use make_shared. --- include/mujincontrollerclient/mujinjson.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index f4354f3c..aec5a62b 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -337,9 +338,9 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::vect template inline void LoadJsonValue(const rapidjson::Value& v, std::array& t); template inline void LoadJsonValue(const rapidjson::Value& v, boost::shared_ptr& ptr) { - T t; - LoadJsonValue(v, t); - ptr = boost::shared_ptr(new T(t)); + static_assert(std::is_default_constructible::value, "Shared pointer of type must be default-constructible."); + ptr = boost::make_shared(); + LoadJsonValue(v, *ptr); } template inline void LoadJsonValue(const rapidjson::Value& v, std::pair& t) { From e93c49467c2450b33928ebef19505f251963e245 Mon Sep 17 00:00:00 2001 From: Taiju Yamada Date: Wed, 27 Apr 2022 21:32:56 +0900 Subject: [PATCH 383/477] fix GeometryResource ctor --- src/mujincontrollerclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 765331fa..83667775 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -144,7 +144,7 @@ ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const { } -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk), pk_), pk(pk_), objectpk(objectpk_) +ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) { } From c4714dfc14c082ce05ea4b5f17c3a0e63bf32238 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Wed, 4 May 2022 10:01:49 +0900 Subject: [PATCH 384/477] Reuse allocated memory in rapidjson::Document when parsing new doc. --- include/mujincontrollerclient/mujinjson.h | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index ec09eaa1..b9ea3ec8 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -148,29 +148,30 @@ inline void ParseJson(rapidjson::Document& d, const std::string& str) { // repeatedly calling Parse on the same rapidjson::Document will not release previsouly allocated memory, memory will accumulate until the object is destroyed // we use a new temporary Document to parse, and swap content with the original one, so that memory in original Document will be released when this function ends // see: https://github.com/Tencent/rapidjson/issues/1333 - rapidjson::Document tempDoc; - tempDoc.Parse(str.c_str()); // parse float in full precision mode - if (tempDoc.HasParseError()) { + // a newer solution that allows reuse of allocated memory is to clear the previous document first + d.SetNull(); + d.GetAllocator().Clear(); + d.Parse(str.c_str()); // parse float in full precision mode + if (d.HasParseError()) { std::string substr; if (str.length()> 200) { substr = str.substr(0, 200); } else { substr = str; } - throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)tempDoc.GetErrorOffset())%GetParseError_En(tempDoc.GetParseError())%substr), MJE_Failed); + throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr), MJE_Failed); } - d.Swap(tempDoc); } inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) - rapidjson::Document(tempDoc); - tempDoc.ParseStream(isw); // parse float in full precision mode - if (tempDoc.HasParseError()) { - throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)tempDoc.GetErrorOffset())%GetParseError_En(tempDoc.GetParseError())), MJE_Failed); + d.SetNull(); + d.GetAllocator().Clear(); + d.ParseStream(isw); // parse float in full precision mode + if (d.HasParseError()) { + throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); } - d.Swap(tempDoc); } class JsonSerializable { @@ -558,9 +559,9 @@ template inline void SaveJsonValue(rapidjson::Value& v, const std::map< template inline void SaveJsonValue(rapidjson::Document& v, const T& t) { // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) - rapidjson::Document tempDoc; - SaveJsonValue(tempDoc, t, tempDoc.GetAllocator()); - v.Swap(tempDoc); + v.SetNull(); + v.GetAllocator().Clear(); + SaveJsonValue(v, t, v.GetAllocator()); } template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc); From f57cb59c7b4c50275a9f259bcec330d0827b38ef Mon Sep 17 00:00:00 2001 From: Ziyan Date: Thu, 8 Sep 2022 19:03:35 +0900 Subject: [PATCH 385/477] Add ExecuteGraphQuery API. --- src/controllerclientimpl.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 1ac8e47b..ec7b1ebd 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -291,6 +291,41 @@ void ControllerClientImpl::SetLanguage(const std::string& language) // _SetupHTTPHeadersMultipartFormData(); } +void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +{ + // use the callers allocator to construct the request body + rResult.SetNull(); + rAlloc.Clear(); + + rapidjson::StringBuffer rRequestStringBuffer; // TODO: use cached string buffer in member + rRequestStringBuffer.Clear(); + + { + rapidjson::Value rRequest, rValue; + rRequest.SetObject(); + rValue.SetString(operationName, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); + rValue.SetString(query, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); + rValue.CopyFrom(rVariables, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); + + rapidjson::Writer writer(rRequestStringBuffer); + rRequest.Accept(writer); + } + + // since we used the callers allocator, clear it before using it for response data + rAlloc.Clear(); + rapidjson::Document docResult(&rAlloc); + + { + boost::mutex::scoped_lock lock(_mutex); + _uri = _baseuri + "api/v2/graphql"; + _CallPost(_uri, rRequestStringBuffer.GetString(), docResult, 200, timeout); + } + rResult = docResult[operationName]; +} + void ControllerClientImpl::RestartServer(double timeout) { boost::mutex::scoped_lock lock(_mutex); From 4a6ef09f8b8b7474c1d83246db994138d1f986fe Mon Sep 17 00:00:00 2001 From: Ziyan Date: Thu, 8 Sep 2022 19:03:35 +0900 Subject: [PATCH 386/477] Add ExecuteGraphQuery API. --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index b3f05484..c94f9366 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -382,6 +382,9 @@ class MUJINCLIENT_API ControllerClient /// The method is blocking, when it returns the MUJIN Controller would have been restarted. virtual void RestartServer(double timeout = 5.0) = 0; + /// \brief Execute GraphQL query or mutation against Mujin Controller. + virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0); + /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; From ae1f74abc85da83728ef236cb1eb96106dd76295 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 9 Sep 2022 10:51:31 +0900 Subject: [PATCH 387/477] Handle graph query errors. --- src/controllerclientimpl.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ec7b1ebd..9f40299d 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -323,7 +323,34 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch _uri = _baseuri + "api/v2/graphql"; _CallPost(_uri, rRequestStringBuffer.GetString(), docResult, 200, timeout); } - rResult = docResult[operationName]; + + // parse response + if (!docResult.IsObject()) { + MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + } + + // look for errors in response + const rapidjson::Value::ConstMemberIterator itErrors = docResult.FindMember("errors"); + if (itErrors != docResult.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { + MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); + for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { + const rapidjson::Value& rError = *itError; + if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { + throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\": %s", operationName%rError["message"].GetString(), MEC_HTTPServer); + } + } + throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + } + + // should have data member + if (!docResult.HasMember("data")) { + MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + } + + // set output + rResult = docResult["data"]; } void ControllerClientImpl::RestartServer(double timeout) From 1a08283aab585797346708484f6c99fbd9e73b2c Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 9 Sep 2022 12:46:37 +0900 Subject: [PATCH 388/477] Perhaps it is not ideal to clear caller allocator. --- src/controllerclientimpl.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 9f40299d..b21c149c 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -293,14 +293,13 @@ void ControllerClientImpl::SetLanguage(const std::string& language) void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - // use the callers allocator to construct the request body - rResult.SetNull(); - rAlloc.Clear(); + rResult.SetNull(); // zero output rapidjson::StringBuffer rRequestStringBuffer; // TODO: use cached string buffer in member rRequestStringBuffer.Clear(); { + // use the callers allocator to construct the request body rapidjson::Value rRequest, rValue; rRequest.SetObject(); rValue.SetString(operationName, rAlloc); @@ -314,8 +313,6 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch rRequest.Accept(writer); } - // since we used the callers allocator, clear it before using it for response data - rAlloc.Clear(); rapidjson::Document docResult(&rAlloc); { From 684836686af23449fc1be53ab5ec7e2cb517d817 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Fri, 9 Sep 2022 15:31:30 +0900 Subject: [PATCH 389/477] Fix abstract declaration. --- include/mujincontrollerclient/mujincontrollerclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index c94f9366..55aead94 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -383,7 +383,7 @@ class MUJINCLIENT_API ControllerClient virtual void RestartServer(double timeout = 5.0) = 0; /// \brief Execute GraphQL query or mutation against Mujin Controller. - virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0); + virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; From 46afe8adf276de75dfe6aeabdb0af1d29bfbb183 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Thu, 22 Sep 2022 18:00:56 +0900 Subject: [PATCH 390/477] Reuse StringBuffer cache. --- src/controllerclientimpl.cpp | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index b21c149c..190b43e8 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -295,42 +295,43 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch { rResult.SetNull(); // zero output - rapidjson::StringBuffer rRequestStringBuffer; // TODO: use cached string buffer in member - rRequestStringBuffer.Clear(); - - { - // use the callers allocator to construct the request body - rapidjson::Value rRequest, rValue; - rRequest.SetObject(); - rValue.SetString(operationName, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); - rValue.SetString(query, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); - rValue.CopyFrom(rVariables, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); - - rapidjson::Writer writer(rRequestStringBuffer); - rRequest.Accept(writer); - } - rapidjson::Document docResult(&rAlloc); { boost::mutex::scoped_lock lock(_mutex); + + rapidjson::StringBuffer& rRequestStringBuffer = _rRequestStringBufferCache; + rRequestStringBuffer.Clear(); + + { + // use the callers allocator to construct the request body + rapidjson::Value rRequest, rValue; + rRequest.SetObject(); + rValue.SetString(operationName, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); + rValue.SetString(query, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); + rValue.CopyFrom(rVariables, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); + + rapidjson::Writer writer(rRequestStringBuffer); + rRequest.Accept(writer); + } + _uri = _baseuri + "api/v2/graphql"; _CallPost(_uri, rRequestStringBuffer.GetString(), docResult, 200, timeout); } // parse response if (!docResult.IsObject()) { - MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // look for errors in response const rapidjson::Value::ConstMemberIterator itErrors = docResult.FindMember("errors"); if (itErrors != docResult.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); + MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { const rapidjson::Value& rError = *itError; if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { @@ -342,7 +343,7 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch // should have data member if (!docResult.HasMember("data")) { - MUJIN_LOG_DEBUG(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } From a2bb29739f355cc5e09deabbfd7ed0c8c2a2ab57 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 11 Oct 2022 09:46:33 +0900 Subject: [PATCH 391/477] Add MujinGraphQueryError. --- src/controllerclientimpl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 190b43e8..1f2687d6 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -335,7 +335,12 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { const rapidjson::Value& rError = *itError; if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { - throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\": %s", operationName%rError["message"].GetString(), MEC_HTTPServer); + const char* errorCode = "unknown"; + const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); + if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { + errorCode = itExtensions->value["errorCode"].GetString(); + } + throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] Failed to execute graph query \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } } throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); From 02edc53096f456e73496aa3efae3acd0e3aaeec1 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 11 Oct 2022 09:46:33 +0900 Subject: [PATCH 392/477] Add MujinGraphQueryError. --- .../mujincontrollerclient/mujinexceptions.h | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinexceptions.h b/include/mujincontrollerclient/mujinexceptions.h index cc44c816..d38e52da 100644 --- a/include/mujincontrollerclient/mujinexceptions.h +++ b/include/mujincontrollerclient/mujinexceptions.h @@ -55,7 +55,8 @@ enum MujinErrorCode { MEC_AlreadyExists=15, ///< the resource already exists and overwriting terminated MEC_BinPickingError=16, ///< BinPicking failed MEC_HandEyeCalibrationError=17, ///< HandEye Calibration failed - MEC_ZMQNoResponse=20 ///< No response from the zmq server, using REQ-REP + MEC_ZMQNoResponse=20, ///< No response from the zmq server, using REQ-REP + MEC_GraphQueryError=21, ///< GraphQL failed to execute }; inline const char* GetErrorCodeString(MujinErrorCode error) @@ -75,6 +76,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) case MEC_BinPickingError: return "BinPickingError"; case MEC_HandEyeCalibrationError: return "HandEyeCalibrationError"; case MEC_ZMQNoResponse: return "NoResponse"; + case MEC_GraphQueryError: return "GraphQueryError"; } // should throw an exception? return ""; @@ -109,5 +111,23 @@ class MUJINCLIENT_API MujinException : public std::exception MujinErrorCode _error; }; +/// \brief Error that can be thrown by ExecuteGraphQuery API, use GetGraphQueryErrorCode to get detailed error code +class MUJINCLIENT_API MujinGraphQueryError : public MujinException +{ +public: + MujinGraphQueryError(const std::string& s, const std::string& graphQueryErrorCode) : MujinGraphQueryError(s, graphQueryErrorCode.c_str()) {} + MujinGraphQueryError(const std::string& s, const char* graphQueryErrorCode) : MujinException(s, MEC_GraphQueryError) { + _graphQueryErrorCode = graphQueryErrorCode; + } + + /// \brief GraphQL error code, such as "not-found" + const std::string& GetGraphQueryErrorCode() const { + return _graphQueryErrorCode; + } + +private: + std::string _graphQueryErrorCode; +}; + } // namespace mujinclient #endif From 51c67d5c3b0f4803bed3bc0635eda6889941351d Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 1 Nov 2022 13:19:05 +0900 Subject: [PATCH 393/477] Fix UploadDataToController. --- .../mujincontrollerclient.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 55aead94..997d3e0e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -503,6 +503,26 @@ class MUJINCLIENT_API ControllerClient /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. virtual void UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) = 0; + /// \brief \see UploadDataToController_UTF8 + /// + /// \param data binary data to upload to the uri + /// \param desturi UTF-16 encoded + virtual void UploadDataToController_UTF16(const std::vector& vdata, const std::wstring& desturi) = 0; + + /// \brief \see UploadDataToController_UTF8 + /// + /// \param data binary data to upload to the uri + /// \param size binary data size in bytes + /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. + virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) = 0; + + /// \brief \see UploadDataToController_UTF8 + /// + /// \param data binary data to upload to the uri + /// \param size binary data size in bytes + /// \param desturi UTF-16 encoded + virtual void UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) = 0; + /// \brief Build a backup of config/media and download it. /// /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. From e18f1c29d37cfc1585e5d6a7d603b8d8893cacf3 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 1 Nov 2022 13:19:05 +0900 Subject: [PATCH 394/477] Fix UploadDataToController. --- src/controllerclientimpl.cpp | 110 +++++++---------------------------- 1 file changed, 21 insertions(+), 89 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 1f2687d6..ed408201 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION @@ -1246,25 +1247,37 @@ void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& file void ControllerClientImpl::UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(vdata, _PrepareDestinationURI_UTF8(desturi)); + _UploadDataToController(vdata.data(), vdata.size(), _PrepareDestinationURI_UTF8(desturi, false)); } void ControllerClientImpl::UploadDataToController_UTF16(const std::vector& vdata, const std::wstring& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(vdata, _PrepareDestinationURI_UTF16(desturi)); + _UploadDataToController(vdata.data(), vdata.size(), _PrepareDestinationURI_UTF16(desturi, false)); +} + +void ControllerClientImpl::UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDataToController(data, size, _PrepareDestinationURI_UTF8(desturi, false)); +} + +void ControllerClientImpl::UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) +{ + boost::mutex::scoped_lock lock(_mutex); + _UploadDataToController(data, size, _PrepareDestinationURI_UTF16(desturi, false)); } void ControllerClientImpl::UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF8(copydir, _PrepareDestinationURI_UTF8(desturi, true, false, true)); + _UploadDirectoryToController_UTF8(copydir, _PrepareDestinationURI_UTF8(desturi, false, false, true)); } void ControllerClientImpl::UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF16(copydir, _PrepareDestinationURI_UTF16(desturi, true, false, true)); + _UploadDirectoryToController_UTF16(copydir, _PrepareDestinationURI_UTF16(desturi, false, false, true)); } void ControllerClientImpl::DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) @@ -1762,59 +1775,6 @@ void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& fil _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); } -void ControllerClientImpl::_UploadFileToController(FILE* fd, const std::string& uri) -{ - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) -#if defined(_WIN32) || defined(_WIN64) - fseek(fd,0,SEEK_END); - curl_off_t filesize = ftell(fd); - fseek(fd,0,SEEK_SET); -#else - // to get the file size - struct stat file_info; - if(fstat(fileno(fd), &file_info) != 0) { - throw MUJIN_EXCEPTION_FORMAT("failed to stat %s for filesize", uri, MEC_InvalidArguments); - } - curl_off_t filesize = (curl_off_t)file_info.st_size; -#endif - - // tell it to "upload" to the URL - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_UPLOAD, 0L, 1L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 0L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_INFILESIZE_LARGE, -1, filesize); -#if defined(_WIN32) || defined(_WIN64) - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadUploadCallback); -#else - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, NULL); -#endif - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READDATA, NULL, fd); - - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - // 204 is when it overwrites the file? - if( http_code != 201 && http_code != 204 ) { - if( http_code == 400 ) { - throw MUJIN_EXCEPTION_FORMAT("upload to %s failed with HTTP status %s, perhaps file exists already?", uri%http_code, MEC_HTTPServer); - } - else { - throw MUJIN_EXCEPTION_FORMAT("upload to %s failed with HTTP status %s", uri%http_code, MEC_HTTPServer); - } - } - // now extract transfer info - //double speed_upload, total_time; - //CURL_INFO_GETTER(_curl, CURLINFO_SPEED_UPLOAD, &speed_upload); - //CURL_INFO_GETTER(_curl, CURLINFO_TOTAL_TIME, &total_time); - //printf("http code: %d, Speed: %.3f bytes/sec during %.3f seconds\n", http_code, speed_upload, total_time); -} - void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout) { CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); @@ -1878,39 +1838,11 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr } } -void ControllerClientImpl::_UploadDataToController(const std::vector& vdata, const std::string& desturi) +void ControllerClientImpl::_UploadDataToController(const void* data, size_t size, const std::string& desturi) { - curl_off_t filesize = vdata.size(); - - // tell it to "upload" to the URL - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_UPLOAD, 0L, 1L); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 0L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - std::pair::const_iterator, size_t> streamdata; - streamdata.first = vdata.begin(); - streamdata.second = vdata.size(); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_INFILESIZE_LARGE, -1, filesize); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadInMemoryUploadCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READDATA, NULL, &streamdata); - - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // 204 is when it overwrites the file? - if( http_code != 201 && http_code != 204 ) { - if( http_code == 400 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of to failed with HTTP status %s, perhaps file exists already?", desturi%http_code, MEC_HTTPServer); - } - else { - throw MUJIN_EXCEPTION_FORMAT("upload of to failed with HTTP status %s", desturi%http_code, MEC_HTTPServer); - } - } + const std::string filenameoncontroller = desturi.substr(_basewebdavuri.size()); + std::istrstream stream(reinterpret_cast(data), size); + _UploadFileToControllerViaForm(stream, filenameoncontroller, _baseuri + "fileupload"); } void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) From ed958d6d5431890b6d3e7592c0c7041f565de7bb Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 1 Nov 2022 14:56:41 +0900 Subject: [PATCH 395/477] Make upload data to controller more efficient. --- .../mujincontrollerclient.h | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 997d3e0e..5374d7f4 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -364,6 +364,11 @@ class MUJINCLIENT_API ControllerClient /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; + /// \brief sets additional http headers to be included on all requests + /// + /// \param additionalHeaders expect each value to be in the format of "Header-Name: header-value" + virtual void SetAdditionalHeaders(const std::vector& additionalHeaders) = 0; + /// \brief returns the username logged into this controller virtual const std::string& GetUserName() const = 0; @@ -500,18 +505,6 @@ class MUJINCLIENT_API ControllerClient /// /// Overwrites the destination uri if it already exists /// \param data binary data to upload to the uri - /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. - virtual void UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) = 0; - - /// \brief \see UploadDataToController_UTF8 - /// - /// \param data binary data to upload to the uri - /// \param desturi UTF-16 encoded - virtual void UploadDataToController_UTF16(const std::vector& vdata, const std::wstring& desturi) = 0; - - /// \brief \see UploadDataToController_UTF8 - /// - /// \param data binary data to upload to the uri /// \param size binary data size in bytes /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) = 0; From d5745e9923e407ce5bfff4cffa54ec2a031f2295 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 1 Nov 2022 14:56:41 +0900 Subject: [PATCH 396/477] Make upload data to controller more efficient. --- src/controllerclientimpl.cpp | 75 +++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index ed408201..6aad2369 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -292,6 +292,15 @@ void ControllerClientImpl::SetLanguage(const std::string& language) // _SetupHTTPHeadersMultipartFormData(); } +void ControllerClientImpl::SetAdditionalHeaders(const std::vector& additionalHeaders) +{ + boost::mutex::scoped_lock lock(_mutex); + _additionalHeaders = additionalHeaders; + _SetupHTTPHeadersJSON(); + _SetupHTTPHeadersSTL(); + _SetupHTTPHeadersMultipartFormData(); +} + void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { rResult.SetNull(); // zero output @@ -1042,6 +1051,9 @@ void ControllerClientImpl::_SetupHTTPHeadersJSON() _httpheadersjson = curl_slist_append(_httpheadersjson, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept-Encoding: gzip, deflate"); + for (const std::string& additionalHeader : _additionalHeaders) { + _httpheadersjson = curl_slist_append(_httpheadersjson, additionalHeader.c_str()); + } } void ControllerClientImpl::_SetupHTTPHeadersSTL() @@ -1059,6 +1071,9 @@ void ControllerClientImpl::_SetupHTTPHeadersSTL() _httpheadersstl = curl_slist_append(_httpheadersstl, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); + for (const std::string& additionalHeader : _additionalHeaders) { + _httpheadersstl = curl_slist_append(_httpheadersstl, additionalHeader.c_str()); + } } void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() @@ -1076,6 +1091,9 @@ void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept-Encoding: gzip, deflate"); + for (const std::string& additionalHeader : _additionalHeaders) { + _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, additionalHeader.c_str()); + } } std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw) @@ -1244,28 +1262,18 @@ void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& file _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16, false)); } -void ControllerClientImpl::UploadDataToController_UTF8(const std::vector& vdata, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(vdata.data(), vdata.size(), _PrepareDestinationURI_UTF8(desturi, false)); -} - -void ControllerClientImpl::UploadDataToController_UTF16(const std::vector& vdata, const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(vdata.data(), vdata.size(), _PrepareDestinationURI_UTF16(desturi, false)); -} - void ControllerClientImpl::UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(data, size, _PrepareDestinationURI_UTF8(desturi, false)); + const std::string filename = _PrepareDestinationURI_UTF8(desturi, false).substr(_basewebdavuri.size()); + _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); } void ControllerClientImpl::UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) { boost::mutex::scoped_lock lock(_mutex); - _UploadDataToController(data, size, _PrepareDestinationURI_UTF16(desturi, false)); + const std::string filename = _PrepareDestinationURI_UTF16(desturi, false).substr(_basewebdavuri.size()); + _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); } void ControllerClientImpl::UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) @@ -1838,11 +1846,42 @@ void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStr } } -void ControllerClientImpl::_UploadDataToController(const void* data, size_t size, const std::string& desturi) +void ControllerClientImpl::_UploadDataToControllerViaForm(const void* data, size_t size, const std::string& filename, const std::string& endpoint, double timeout) { - const std::string filenameoncontroller = desturi.substr(_basewebdavuri.size()); - std::istrstream stream(reinterpret_cast(data), size); - _UploadFileToControllerViaForm(stream, filenameoncontroller, _baseuri + "fileupload"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); + _buffer.clear(); + _buffer.str(""); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + //timeout is default to 0 (never) + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + + // prepare form + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + CURL_FORM_RELEASER(formpost); + curl_formadd(&formpost, &lastptr, + CURLFORM_PTRNAME, "files[]", + CURLFORM_BUFFER, filename.empty() ? "unused" : filename.c_str(), + CURLFORM_BUFFERPTR, data, + CURLFORM_END); + if(!filename.empty()) { + curl_formadd(&formpost, &lastptr, + CURLFORM_PTRNAME, "filename", + CURLFORM_PTRCONTENTS, filename.c_str(), + CURLFORM_END); + } + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); + CURL_PERFORM(_curl); + // get http status + long http_code = 0; + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + + // 204 is when it overwrites the file? + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); + } } void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) From e93003ff328b93829262279edade3d7af5b4e87d Mon Sep 17 00:00:00 2001 From: Yoshiki Kanemoto Date: Mon, 21 Nov 2022 13:58:14 +0900 Subject: [PATCH 397/477] moved SensorSelectionInfo to mujincontrollerclient.h, changed GetSensorMapping to GetAllSensorSelectionInfos --- .../mujincontrollerclient.h | 22 +++++++++- src/mujincontrollerclient.cpp | 40 ++++++++++++------- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5374d7f4..c0d57156 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -330,6 +330,26 @@ class RobotControllerPrograms std::map programs; ///< the keys are the robot instance primary keys of the scene }; +struct MUJINCLIENT_API SensorSelectionInfo +{ + std::string sensorName; + std::string sensorLinkName; + SensorSelectionInfo() = default; + SensorSelectionInfo(const std::string& sensorNameIn, const std::string& sensorLinkNameIn) : sensorName(sensorNameIn), sensorLinkName(sensorLinkNameIn) { + } + bool operator<(const SensorSelectionInfo& rhs) const { + if( sensorName == rhs.sensorName ) { + return sensorLinkName < rhs.sensorLinkName; + } + return sensorName < rhs.sensorName; + } + bool operator==(const SensorSelectionInfo& rhs) const { + return sensorName == rhs.sensorName && sensorLinkName == rhs.sensorLinkName; + } +}; +MUJINCLIENT_API void LoadJsonValue(const rapidjson::Value& v, SensorSelectionInfo& sensorSelectionInfos); +MUJINCLIENT_API void SaveJsonValue(rapidjson::Value& v, const SensorSelectionInfo& sensorSelectionInfo, rapidjson::Document::AllocatorType& alloc); + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -1045,7 +1065,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetTaskNames(std::vector& names); /// \brief gets a list of all the instance objects of the scene - virtual void GetSensorMapping(std::map& sensormapping); + virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); virtual void GetInstObjects(std::vector& instobjects); virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 83667775..70e7a924 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -98,6 +98,22 @@ void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostr os << "]"; } +void LoadJsonValue(const rapidjson::Value& v, SensorSelectionInfo& sensorSelectionInfo) +{ + if( !v.IsObject() || !v.HasMember("sensorName") || !v.HasMember("sensorLinkName") ) { + MUJIN_LOG_INFO(str(boost::format("Invalid SensorSelectionInfo in %s")%mujinjson::DumpJson(v))); + return; + } + sensorSelectionInfo.sensorName = mujinjson::GetStringJsonValueByKey(v, "sensorName"); + sensorSelectionInfo.sensorLinkName = mujinjson::GetStringJsonValueByKey(v, "sensorLinkName"); +} + +void SaveJsonValue(rapidjson::Value& v, const SensorSelectionInfo& sensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) { + v.SetObject(); + v.AddMember(rapidjson::Document::StringRefType("sensorName"), rapidjson::Document::StringRefType(sensorSelectionInfo.sensorName.c_str()), alloc); + v.AddMember(rapidjson::Document::StringRefType("sensorLinkName"), rapidjson::Document::StringRefType(sensorSelectionInfo.sensorLinkName.c_str()), alloc); +} + WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) { BOOST_ASSERT(__pk.size()>0); @@ -798,24 +814,22 @@ void SceneResource::GetTaskNames(std::vector& taskkeys) } } -void SceneResource::GetSensorMapping(std::map& sensormapping) +void SceneResource::GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos) { GETCONTROLLERIMPL(); - sensormapping.clear(); + allSensorSelectionInfos.clear(); rapidjson::Document rInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,connectedBodies,object_pk,name")%GetPrimaryKey()), rInstObjects); for (rapidjson::Document::ConstValueIterator itInstObject = rInstObjects["objects"].Begin(); itInstObject != rInstObjects["objects"].End(); ++itInstObject) { - std::string cameracontainername = GetJsonValueByKey(*itInstObject, "name"); - std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); + const std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); if ( itInstObject->HasMember("attachedsensors") && (*itInstObject)["attachedsensors"].IsArray() && (*itInstObject)["attachedsensors"].Size() > 0) { rapidjson::Document rRobotAttachedSensors(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%objectPk), rRobotAttachedSensors); const rapidjson::Value& rAttachedSensors = rRobotAttachedSensors["attachedsensors"]; for (rapidjson::Document::ConstValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - std::string sensorname = GetJsonValueByKey(*itAttachedSensor, "name"); - std::string camerafullname = str(boost::format("%s/%s")%cameracontainername%sensorname); - std::string cameraid = GetJsonValueByPath(*itAttachedSensor, "/sensordata/hardware_id"); - sensormapping[camerafullname] = cameraid; + const std::string sensorName = GetJsonValueByKey(*itAttachedSensor, "name"); + const std::string sensorLinkName = GetJsonValueByKey(*itAttachedSensor, "linkName"); + allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); } } if ( itInstObject->HasMember("connectedBodies") && (*itInstObject)["connectedBodies"].IsArray() && (*itInstObject)["connectedBodies"].Size() > 0 ) { @@ -823,8 +837,7 @@ void SceneResource::GetSensorMapping(std::map& sensorm controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%objectPk), rRobotConnectedBodies); rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { - std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); - std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); + const std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { @@ -836,10 +849,9 @@ void SceneResource::GetSensorMapping(std::map& sensorm controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; for (rapidjson::Document::ConstValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { - std::string sensorname = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); - std::string camerafullname = str(boost::format("%s/%s_%s")%cameracontainername%connectedBodyName%sensorname); - std::string cameraid = GetJsonValueByPath(*itConnectedBodyAttachedSensor, "/sensordata/hardware_id"); - sensormapping[camerafullname] = cameraid; + const std::string sensorName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); + const std::string sensorLinkName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "linkName"); + allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); } } } From aa896769d866c055fdc1e5a004e8044fe3bfa222 Mon Sep 17 00:00:00 2001 From: Yoshiki Kanemoto Date: Mon, 21 Nov 2022 17:32:02 +0900 Subject: [PATCH 398/477] set sensorName --- src/mujincontrollerclient.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 70e7a924..99d2c7ab 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -821,13 +821,13 @@ void SceneResource::GetAllSensorSelectionInfos(std::vector& rapidjson::Document rInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,connectedBodies,object_pk,name")%GetPrimaryKey()), rInstObjects); for (rapidjson::Document::ConstValueIterator itInstObject = rInstObjects["objects"].Begin(); itInstObject != rInstObjects["objects"].End(); ++itInstObject) { + const std::string sensorName = GetJsonValueByKey(*itInstObject, "name"); const std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); if ( itInstObject->HasMember("attachedsensors") && (*itInstObject)["attachedsensors"].IsArray() && (*itInstObject)["attachedsensors"].Size() > 0) { rapidjson::Document rRobotAttachedSensors(rapidjson::kObjectType); controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%objectPk), rRobotAttachedSensors); const rapidjson::Value& rAttachedSensors = rRobotAttachedSensors["attachedsensors"]; for (rapidjson::Document::ConstValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - const std::string sensorName = GetJsonValueByKey(*itAttachedSensor, "name"); const std::string sensorLinkName = GetJsonValueByKey(*itAttachedSensor, "linkName"); allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); } @@ -849,7 +849,6 @@ void SceneResource::GetAllSensorSelectionInfos(std::vector& controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; for (rapidjson::Document::ConstValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { - const std::string sensorName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "name"); const std::string sensorLinkName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "linkName"); allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); } From c1f0d53681875e1cc96238ce32c8353cce350273 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 5 Dec 2022 08:45:13 +0900 Subject: [PATCH 399/477] Add SetUserAgent. --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5374d7f4..c1bf5e39 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -364,6 +364,9 @@ class MUJINCLIENT_API ControllerClient /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes virtual void SetLanguage(const std::string& language) = 0; + /// \brief sets the user agent to be sent with each http request + virtual void SetUserAgent(const std::string& userAgent) = 0; + /// \brief sets additional http headers to be included on all requests /// /// \param additionalHeaders expect each value to be in the format of "Header-Name: header-value" From be1c516ee1fe5681da4f8306ecc076cbaee6ac5b Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 5 Dec 2022 08:45:13 +0900 Subject: [PATCH 400/477] Add SetUserAgent. --- src/controllerclientimpl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 6aad2369..dafdcb81 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -292,6 +292,11 @@ void ControllerClientImpl::SetLanguage(const std::string& language) // _SetupHTTPHeadersMultipartFormData(); } +void ControllerClientImpl::SetUserAgent(const std::string& userAgent) +{ + CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, userAgent.c_str()); +} + void ControllerClientImpl::SetAdditionalHeaders(const std::vector& additionalHeaders) { boost::mutex::scoped_lock lock(_mutex); From c20da2ab09842cc55937b7464bb6eac57a04d5af Mon Sep 17 00:00:00 2001 From: pico Date: Tue, 20 Dec 2022 10:29:29 +0900 Subject: [PATCH 401/477] pass timeout to _CallGet --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 1f2687d6..0812a220 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1334,7 +1334,7 @@ void ControllerClientImpl::_DownloadFileFromController(const std::string& destur CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEVALUE, 0L, localtimeval > 0 ? localtimeval : 0L); // do the get call - long http_code = _CallGet(desturi, outputdata, 0); + long http_code = _CallGet(desturi, outputdata, 0, timeout); if ((http_code != 200 && http_code != 304)) { if (outputdata.size() > 0) { std::stringstream ss; From 43ef201ce70d25844643dc2253941762cf6f6151 Mon Sep 17 00:00:00 2001 From: pico Date: Tue, 20 Dec 2022 10:50:02 +0900 Subject: [PATCH 402/477] do not set curl timeout in _DownloadFileFromController --- src/controllerclientimpl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 0812a220..3d778c5b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -1322,8 +1322,6 @@ long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeou void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) { - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - remotetimeval = 0; // ask for remote file time From 6f7d421c76ee0c28f864a784c86a859a369ebf1c Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 20 Dec 2022 15:54:45 +0900 Subject: [PATCH 403/477] Fix StringRefType usage. --- src/mujincontrollerclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 99d2c7ab..73053674 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -110,8 +110,8 @@ void LoadJsonValue(const rapidjson::Value& v, SensorSelectionInfo& sensorSelecti void SaveJsonValue(rapidjson::Value& v, const SensorSelectionInfo& sensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) { v.SetObject(); - v.AddMember(rapidjson::Document::StringRefType("sensorName"), rapidjson::Document::StringRefType(sensorSelectionInfo.sensorName.c_str()), alloc); - v.AddMember(rapidjson::Document::StringRefType("sensorLinkName"), rapidjson::Document::StringRefType(sensorSelectionInfo.sensorLinkName.c_str()), alloc); + mujinjson::SetJsonValueByKey(v, "sensorName", sensorSelectionInfo.sensorName, alloc); + mujinjson::SetJsonValueByKey(v, "sensorLinkName", sensorSelectionInfo.sensorLinkName, alloc); } WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) From 44fa03ec7f9a5ba97006dabab0adda25c5a7c60d Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 5 Jan 2023 17:32:57 +0900 Subject: [PATCH 404/477] update mujinjson.h to make it compatible with internal coe, add a common definitions file --- .../mujincontrollerclient/mujindefinitions.h | 136 +++++++++ include/mujincontrollerclient/mujinjson.h | 286 ++++++++++++++---- src/mujindefinitions.cpp | 21 ++ 3 files changed, 379 insertions(+), 64 deletions(-) create mode 100644 include/mujincontrollerclient/mujindefinitions.h create mode 100644 src/mujindefinitions.cpp diff --git a/include/mujincontrollerclient/mujindefinitions.h b/include/mujincontrollerclient/mujindefinitions.h new file mode 100644 index 00000000..4b2cf7c9 --- /dev/null +++ b/include/mujincontrollerclient/mujindefinitions.h @@ -0,0 +1,136 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012-2023 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** \file mujindefinitions.h + + Includes basic struct, enum, and other definitions that are used throughout the Mujin Controller system. + */ +#ifndef MUJIN_CONTROLLERCLIENT_DEFINITIONS_H +#define MUJIN_CONTROLLERCLIENT_DEFINITIONS_H + +#include +#include + +#include + +namespace mujin { + +typedef double Real; + +inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { + return fabs(double(p - q)) < epsilon; +} + +template inline bool FuzzyEquals(const std::vector& p, const std::vector& q, double epsilon=1e-3) { + if (p.size() != q.size()) { + return false; + } + for (size_t i = 0; i < p.size(); ++i) { + if (!FuzzyEquals(p[i], q[i], epsilon)) { + return false; + } + } + return true; +} + +template inline bool FuzzyEquals(const T (&p)[N], const T (&q)[N], double epsilon=1e-3) { + for (size_t i = 0; i < N; ++i) { + if (!FuzzyEquals(p[i], q[i], epsilon)) { + return false; + } + } + return true; +} + +/// \brief an affine transform +struct Transform +{ + Transform() { + quaternion[0] = 1; quaternion[1] = 0; quaternion[2] = 0; quaternion[3] = 0; + translate[0] = 0; translate[1] = 0; translate[2] = 0; + } + inline bool operator!=(const Transform& other) const { + return !FuzzyEquals(quaternion, other.quaternion) || !FuzzyEquals(translate, other.translate); + } + inline bool operator==(const Transform& other) const { + return !operator!=(other); + } + Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] + Real translate[3]; ///< translation x,y,z +}; + +struct MUJINCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable +{ + SensorSelectionInfo() = default; + SensorSelectionInfo(const std::string& sensorNameIn, const std::string& sensorLinkNameIn) : sensorName(sensorNameIn), sensorLinkName(sensorLinkNameIn) { + } + inline bool operator<(const SensorSelectionInfo& rhs) const { + if( sensorName == rhs.sensorName ) { + return sensorLinkName < rhs.sensorLinkName; + } + return sensorName < rhs.sensorName; + } + inline bool operator==(const SensorSelectionInfo& rhs) const { + return sensorName == rhs.sensorName && sensorLinkName == rhs.sensorLinkName; + } + inline bool operator!=(const SensorSelectionInfo& rhs) const { + return sensorName != rhs.sensorName || sensorLinkName != rhs.sensorLinkName; + } + + void LoadFromJson(const rapidjson::Value& rSensorSelectionInfo) override; + void SaveToJson(rapidjson::Value& rSensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) const override; + + std::string sensorName; + std::string sensorLinkName; +}; + + +/// \brief the picking history being published from the slave. Anytime the robot goes inside of the source container, its pick history will be udpated. +struct MUJINCLIENT_API PickPlaceHistoryItem +{ + std::string pickPlaceType; ///< the type of action that ocurred can be: "picked", "placed", "touched" + std::string locationName; ///< the name of the region where picking occurred for "picked", where placing occurred when "placed", and where touching occurred for "touched" + unsigned long long eventTimeStampUS; ///< time that the event ocurred in us (from Linux epoch). For "picked" this is the chuck time, for "placed this is the unchuck time, for "touched" this is the time when the robot supposedly stopped touching/disturbing the object. + std::string object_uri; ///< the object uri + Transform objectpose; ///< 7-values in world, unit is usually mm + unsigned long long sensorTimeStampUS; ///< sensor timestamp in us (from Linux epoch) of when the object was detected in the scene +}; + +/// \brief Holds the state of each region coming from the planning side. +struct LocationTrackingInfo +{ + std::string locationName; ///< name of the location tracking + std::string containerId; ///< containerId currently in the location + std::string containerName; ///< name of the container tracking + std::string containerUsage; ///< how the container is used + std::string cycleIndex; ///< unique cycleIndex that is tracking this location +}; + +struct LocationExecutionInfo +{ + std::string locationName; ///< name of the location tracking + std::string containerId; ///< containerId currently in the location + uint64_t forceRequestStampMS=0; ///< ms, (linux epoch) of when the requestion for results (detection or point cloud) came in. If there is no request, then this will be 0 + uint64_t lastInsideContainerStampMS = 0; ///< ms, (linux epoch) of when the robot (or something else) was inside the container and could have potentially disturbed the contents. + std::string needContainerState; ///< one of: Unknown, NewContainerNeeded, ContainerNeeded, ContainerNotNeeded. If empty, then not initialized yet, so can assume Unknown. +}; + +inline std::ostream& operator<<(std::ostream& os, const SensorSelectionInfo& rhs) +{ + os << rhs.sensorName << ":" << rhs.sensorLinkName; + return os; +} + +} // end namespace mujin + +#endif diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index b9ea3ec8..084a6a02 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -37,14 +37,28 @@ #include #include -namespace mujinclient { -namespace mujinjson_external { +#include + +#ifndef MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY +#define MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY(rValue, key, param) \ + { \ + if (!(mujinjson::LoadJsonValueByKey(rValue, key, param))) \ + { \ + throw MujinJSONException(boost::str(boost::format(("[%s, %u] assert(mujinjson::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ + } \ + } +#endif // MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY + +namespace mujinjson { + +#ifndef MujinJSONException enum MujinJSONErrorCode { MJE_Failed=0, }; +// define a MujinJSONException class inline const char* GetErrorCodeString(MujinJSONErrorCode error) { switch(error) { @@ -94,6 +108,8 @@ class MujinJSONException : public std::exception MujinJSONErrorCode _error; }; +#endif + template inline std::string GetJsonString(const T& t); /// \brief gets a string of the Value type for debugging purposes @@ -119,6 +135,8 @@ inline std::string GetJsonTypeName(const rapidjson::Value& v) { } } +template inline std::string GetJsonString(const T& t); + inline std::string DumpJson(const rapidjson::Value& value, const unsigned int indent=0) { rapidjson::StringBuffer stringbuffer; if (indent == 0) { @@ -144,25 +162,25 @@ inline void DumpJson(const rapidjson::Value& value, std::ostream& os, const unsi } } -inline void ParseJson(rapidjson::Document& d, const std::string& str) { +inline void ParseJson(rapidjson::Document& d, const char* str, size_t length) { // repeatedly calling Parse on the same rapidjson::Document will not release previsouly allocated memory, memory will accumulate until the object is destroyed // we use a new temporary Document to parse, and swap content with the original one, so that memory in original Document will be released when this function ends // see: https://github.com/Tencent/rapidjson/issues/1333 // a newer solution that allows reuse of allocated memory is to clear the previous document first d.SetNull(); d.GetAllocator().Clear(); - d.Parse(str.c_str()); // parse float in full precision mode + d.Parse(str, length); // parse float in full precision mode if (d.HasParseError()) { - std::string substr; - if (str.length()> 200) { - substr = str.substr(0, 200); - } else { - substr = str; - } - throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s str=%s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr), MJE_Failed); + const std::string substr(str, length < 200 ? length : 200); + + throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s data is '%s'.")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr)); } } +inline void ParseJson(rapidjson::Document& d, const std::string& str) { + ParseJson(d, str.c_str(), str.size()); +} + inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) @@ -170,10 +188,34 @@ inline void ParseJson(rapidjson::Document& d, std::istream& is) { d.GetAllocator().Clear(); d.ParseStream(isw); // parse float in full precision mode if (d.HasParseError()) { - throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())), MJE_Failed); + throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError()))); } } +template +MUJINCLIENT_API void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer); + +inline void ParseJsonFile(rapidjson::Document& d, const char* filename) +{ + std::vector buffer; + + return ParseJsonFile(d, filename, buffer); +} + +template +void ParseJsonFile(rapidjson::Document& d, const std::string& filename, Container& buffer) +{ + return ParseJsonFile(d, filename.c_str(), buffer); +} + +inline void ParseJsonFile(rapidjson::Document& d, const std::string& filename) +{ + std::vector buffer; + + return ParseJsonFile(d, filename.c_str(), buffer); +} + + class JsonSerializable { public: virtual void LoadFromJson(const rapidjson::Value& v) = 0; @@ -191,7 +233,7 @@ template inline T LexicalCast(const S& v, const std::string& t catch (const boost::bad_lexical_cast& ex) { std::stringstream ss; ss << v; - throw MujinJSONException("Cannot convert \"" + ss.str() + "\" to type " + typeName, MJE_Failed); + throw MujinJSONException("Cannot convert \"" + ss.str() + "\" to type " + typeName); } } @@ -203,12 +245,12 @@ inline void LoadJsonValue(const rapidjson::Value& v, JsonSerializable& t) { inline void LoadJsonValue(const rapidjson::Value& v, std::string& t) { if (v.IsString()) { - t = v.GetString(); + t.assign(v.GetString(), v.GetStringLength()); // specify size to allow null characters } else if (v.IsInt64()) { //TODO: add warnings on all usages of lexical_cast - t = boost::lexical_cast(v.GetInt64()); + t = LexicalCast(v.GetInt64(), "String"); } else { - throw MujinJSONException("Cannot convert json value " + GetJsonString(v) + " to String", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to String"); } } @@ -223,7 +265,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int"); } } @@ -240,7 +282,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int8_t& t) { else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int8", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int8"); } } @@ -252,7 +294,19 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint8_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt8", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt8"); + } +} + +inline void LoadJsonValue(const rapidjson::Value& v, uint16_t& t) { + if (v.IsUint()) { + t = v.GetUint(); + } else if (v.IsString()) { + t = LexicalCast(v.GetString(), "UInt"); + } else if (v.IsBool()) { + t = v.GetBool() ? 1 : 0; + } else { + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt"); } } @@ -264,7 +318,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt"); } } @@ -276,7 +330,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to ULongLong", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to ULongLong"); } } @@ -288,7 +342,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt64", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt64"); } } @@ -300,7 +354,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int64_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int64", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int64"); } } @@ -310,7 +364,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, double& t) { } else if (v.IsString()) { t = LexicalCast(v.GetString(), "Double"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Double", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Double"); } } @@ -320,7 +374,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, float& t) { } else if (v.IsString()) { t = LexicalCast(v.GetString(), "Float"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Float", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Float"); } } @@ -330,11 +384,11 @@ inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { else if (v.IsString()) { t = LexicalCast(v.GetString(), "Bool"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Bool", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Bool"); } } -template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t); +template > inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t); template inline void LoadJsonValue(const rapidjson::Value& v, std::array& t); @@ -350,17 +404,17 @@ template inline void LoadJsonValue(const rapidjson::Valu LoadJsonValue(v[0], t.first); LoadJsonValue(v[1], t.second); } else { - throw MujinJSONException("List-based map has entry with size != 2", MJE_Failed); + throw MujinJSONException("List-based map has entry with size != 2"); } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Pair", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Pair"); } } template inline void LoadJsonValue(const rapidjson::Value& v, T (&p)[N]) { if (v.IsArray()) { if (v.GetArray().Size() != N) { - throw MujinJSONException("Json array size doesn't match", MJE_Failed); + throw MujinJSONException("Json array size doesn't match"); } size_t i = 0; for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { @@ -368,11 +422,11 @@ template inline void LoadJsonValue(const rapidjson::Value& v, i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); } } -template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t) { +template inline void LoadJsonValue(const rapidjson::Value& v, std::vector& t) { if (v.IsArray()) { t.clear(); t.resize(v.GetArray().Size()); @@ -382,7 +436,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::vect i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Vector"); } } @@ -391,8 +445,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, if (v.GetArray().Size() != N) { throw MujinJSONException( (boost::format("Cannot convert json type " + GetJsonTypeName(v) + " to Array. " - "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str(), - MJE_Failed); + "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str()); } size_t i = 0; for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { @@ -400,7 +453,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); } } @@ -419,10 +472,10 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::map< for (rapidjson::Value::ConstMemberIterator it = v.MemberBegin(); it != v.MemberEnd(); ++it) { LoadJsonValue(it->value, value); - t[it->name.GetString()] = value; + t[std::string(it->name.GetString(), it->name.GetStringLength())] = value; // string can contain null character } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Map", MJE_Failed); + throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Map"); } } @@ -456,6 +509,10 @@ inline void SaveJsonValue(rapidjson::Value& v, long long t, rapidjson::Document: v.SetInt64(t); } +inline void SaveJsonValue(rapidjson::Value& v, int64_t t, rapidjson::Document::AllocatorType& alloc) { + v.SetInt64(t); +} + inline void SaveJsonValue(rapidjson::Value& v, unsigned long long t, rapidjson::Document::AllocatorType& alloc) { v.SetUint64(t); } @@ -470,6 +527,10 @@ inline void SaveJsonValue(rapidjson::Value& v, bool t, rapidjson::Document::Allo v.SetBool(t); } +inline void SaveJsonValue(rapidjson::Value& v, int8_t t, rapidjson::Document::AllocatorType& alloc) { + v.SetInt(t); +} + inline void SaveJsonValue(rapidjson::Value& v, double t, rapidjson::Document::AllocatorType& alloc) { v.SetDouble(t); } @@ -482,7 +543,7 @@ inline void SaveJsonValue(rapidjson::Value& v, const rapidjson::Value& t, rapidj v.CopyFrom(t, alloc); } -template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc); +template > inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc); template inline void SaveJsonValue(rapidjson::Value& v, const std::array& t, rapidjson::Document::AllocatorType& alloc); @@ -492,7 +553,18 @@ template inline void SaveJsonValue(rapidjson::Value& v, const boost::sh SaveJsonValue(v, *ptr, alloc); } -template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { +template inline void SaveJsonValue(rapidjson::Value& v, const std::pair& t, rapidjson::Document::AllocatorType& alloc) { + v.SetArray(); + v.Reserve(2, alloc); + rapidjson::Value rFirst; + SaveJsonValue(rFirst, t.first, alloc); + v.PushBack(rFirst, alloc); + rapidjson::Value rSecond; + SaveJsonValue(rSecond, t.second, alloc); + v.PushBack(rSecond, alloc); +} + +template inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { v.SetArray(); v.Reserve(t.size(), alloc); for (size_t i = 0; i < t.size(); ++i) { @@ -512,8 +584,7 @@ template inline void SaveJsonValue(rapidjson::Value& v, const } } - -template<> inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { +template > inline void SaveJsonValue(rapidjson::Value& v, const std::vector& t, rapidjson::Document::AllocatorType& alloc) { v.SetArray(); v.Reserve(t.size(), alloc); for (size_t i = 0; i < t.size(); ++i) { @@ -558,6 +629,7 @@ template inline void SaveJsonValue(rapidjson::Value& v, const std::map< } template inline void SaveJsonValue(rapidjson::Document& v, const T& t) { + // rapidjson::Value::CopyFrom also doesn't free up memory, need to clear memory // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) v.SetNull(); v.GetAllocator().Clear(); @@ -567,20 +639,40 @@ template inline void SaveJsonValue(rapidjson::Document& v, const T& t) template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc); //get one json value by key, and store it in local data structures -template void inline LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t) { +//return true if key is present. Will return false if the key is not present or the member is Null +template bool inline LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); - } - if (v.HasMember(key)) { - LoadJsonValue(v[key], t); + throw MujinJSONException("Cannot load value of non-object."); + } + rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); + if( itMember != v.MemberEnd() ) { + const rapidjson::Value& rMember = itMember->value; + if( !rMember.IsNull() ) { + try { + LoadJsonValue(rMember, t); + return true; + } + catch (const MujinJSONException& ex) { + throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + } + } } + // Return false if member is null or non-existent + return false; } template inline void LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t, const U& d) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); + throw MujinJSONException("Cannot load value of non-object."); } - if (v.HasMember(key)) { - LoadJsonValue(v[key], t); + + rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); + if( itMember != v.MemberEnd() && !itMember->value.IsNull() ) { + try { + LoadJsonValue(itMember->value, t); + } + catch (const MujinJSONException& ex) { + throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + } } else { t = d; @@ -603,16 +695,24 @@ template inline void LoadJsonValueByPath(const rapidjson::Valu } } + //work the same as LoadJsonValueByKey, but the value is returned instead of being passed as reference template T GetJsonValueByKey(const rapidjson::Value& v, const char* key, const U& t) { if (!v.IsObject()) { - throw MujinJSONException("Cannot get value of non-object.", MJE_Failed); + throw MujinJSONException("Cannot get value of non-object."); } - if (v.HasMember(key)) { - const rapidjson::Value& child = v[key]; + + rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); + if (itMember != v.MemberEnd() ) { + const rapidjson::Value& child = itMember->value; if (!child.IsNull()) { T r; - LoadJsonValue(v[key], r); + try { + LoadJsonValue(v[key], r); + } + catch (const MujinJSONException& ex) { + throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + } return r; } } @@ -620,13 +720,19 @@ template T GetJsonValueByKey(const rapidjson::Value& v, const } template inline T GetJsonValueByKey(const rapidjson::Value& v, const char* key) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object.", MJE_Failed); + throw MujinJSONException("Cannot load value of non-object."); } T r = T(); - if (v.HasMember(key)) { - const rapidjson::Value& child = v[key]; + rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); + if (itMember != v.MemberEnd() ) { + const rapidjson::Value& child = itMember->value; if (!child.IsNull()) { - LoadJsonValue(v[key], r); + try { + LoadJsonValue(v[key], r); + } + catch (const MujinJSONException& ex) { + throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + } } } return r; @@ -635,6 +741,7 @@ template inline T GetJsonValueByKey(const rapidjson::Value& v, const ch inline std::string GetStringJsonValueByKey(const rapidjson::Value& v, const char* key, const std::string& defaultValue=std::string()) { return GetJsonValueByKey(v, key, defaultValue); } + template inline T GetJsonValueByPath(const rapidjson::Value& v, const char* key) { T r; const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); @@ -661,16 +768,35 @@ T GetJsonValueByPath(const rapidjson::Value& v, const char* key, const U& t) { } } -template inline void SetJsonValueByPath(rapidjson::Document& d, const char* path, const T& t) { +inline const rapidjson::Value* GetJsonPointerByPath(const rapidjson::Value& value) +{ + return &value; +} + +template const rapidjson::Value* GetJsonPointerByPath(const rapidjson::Value& value, const char (& key)[N], Ps&&... ps) +{ + const rapidjson::Value::ConstMemberIterator it = value.FindMember(rapidjson::Value(key, N - 1)); + if (it != value.MemberEnd()) { + return GetJsonPointerByPath(it->value, static_cast(ps)...); + } else { + return nullptr; + } +} + +template inline void SetJsonValueByPath(rapidjson::Value& d, const char* path, const T& t, rapidjson::Document::AllocatorType& alloc) { rapidjson::Value v; - SaveJsonValue(v, t, d.GetAllocator()); - rapidjson::Pointer(path).Swap(d, v, d.GetAllocator()); + SaveJsonValue(v, t, alloc); + rapidjson::Pointer(path).Swap(d, v, alloc); +} + +template inline void SetJsonValueByPath(rapidjson::Document& d, const char* path, const T& t) { + SetJsonValueByPath(d, path, t, d.GetAllocator()); } template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc) { if (!v.IsObject()) { - throw MujinJSONException("Cannot set value for non-object.", MJE_Failed); + throw MujinJSONException("Cannot set value for non-object."); } if (v.HasMember(key)) { SaveJsonValue(v[key], t, alloc); @@ -698,7 +824,7 @@ inline void SetJsonValueByKey(rapidjson::Document& d, const std::string& key, co inline void ValidateJsonString(const std::string& str) { rapidjson::Document d; if (d.Parse(str.c_str()).HasParseError()) { - throw MujinJSONException("json string " + str + " is invalid." + GetParseError_En(d.GetParseError()), MJE_Failed); + throw MujinJSONException("json string " + str + " is invalid." + GetParseError_En(d.GetParseError())); } } @@ -728,6 +854,38 @@ inline void UpdateJson(rapidjson::Document& a, const rapidjson::Value& b) { } } +/// \brief One way merge overrideValue into sourceValue. sourceValue will be overwritten. When both sourceValue and overrideValue are objects and a member of overrideValue is a rapidjson object and the corresponding member of sourceValue is also a rapidjson object, call this function recursivelly inside this function. +/// \param sourceValue json value to be updated +/// \param overrideValue read-only json value used to update contents of sourceValue +/// \return true if sourceValue has changed +inline bool UpdateJsonRecursively(rapidjson::Value& sourceValue, const rapidjson::Value& overrideValue, rapidjson::Document::AllocatorType& alloc) { + if (sourceValue == overrideValue) { + return false; + } + + if (!sourceValue.IsObject() || !overrideValue.IsObject()) { + sourceValue.CopyFrom(overrideValue, alloc, true); + return true; + } + + bool hasChanged = false; + for (rapidjson::Value::ConstMemberIterator itOverrideMember = overrideValue.MemberBegin(); itOverrideMember != overrideValue.MemberEnd(); ++itOverrideMember) { + const rapidjson::Value& overrideMemberValue = itOverrideMember->value; + rapidjson::Value::MemberIterator itSourceMember = sourceValue.FindMember(itOverrideMember->name); + if (itSourceMember != sourceValue.MemberEnd()) { // found corresponding member in sourceObject + hasChanged |= UpdateJsonRecursively(itSourceMember->value, overrideMemberValue, alloc); + } + else { // not found corresponding member in sourceObject, so just copy it + rapidjson::Value key(itOverrideMember->name, alloc); + rapidjson::Value val; + val.CopyFrom(overrideMemberValue, alloc, true); + sourceValue.AddMember(key, val, alloc); + hasChanged = true; + } + } + return hasChanged; +} + } // namespace mujinjson -} // namespace mujinclient + #endif diff --git a/src/mujindefinitions.cpp b/src/mujindefinitions.cpp new file mode 100644 index 00000000..27256694 --- /dev/null +++ b/src/mujindefinitions.cpp @@ -0,0 +1,21 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012-2023 MUJIN Inc. +#include + +namespace mujin { + + +void SensorSelectionInfo::LoadFromJson(const rapidjson::Value& rSensorSelectionInfo) +{ + mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName); + mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName); +} + +void SensorSelectionInfo::SaveToJson(rapidjson::Value& rSensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) const +{ + rSensorSelectionInfo.SetObject(); + mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName, alloc); + mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName, alloc); +} + +} // end namespace mujin From b3b5a4c81a694e05d0d0b1f47e8858e56f51c145 Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 5 Jan 2023 17:32:57 +0900 Subject: [PATCH 405/477] update mujinjson.h to make it compatible with internal coe, add a common definitions file --- .../mujincontrollerclient.h | 70 ++----------------- src/mujincontrollerclient.cpp | 19 +---- 2 files changed, 7 insertions(+), 82 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 5f56b484..2eac5abd 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -55,12 +55,15 @@ #include #include #include +#include #include #include +#include + namespace mujinclient { -#include +typedef mujin::Transform Transform; enum TaskResourceOptions { @@ -108,30 +111,6 @@ typedef boost::shared_ptr DebugResourcePtr; typedef boost::weak_ptr DebugResourceWeakPtr; typedef double Real; -inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { - return fabs(double(p - q)) < epsilon; -} - -template inline bool FuzzyEquals(const std::vector& p, const std::vector& q, double epsilon=1e-3) { - if (p.size() != q.size()) { - return false; - } - for (size_t i = 0; i < p.size(); ++i) { - if (!FuzzyEquals(p[i], q[i], epsilon)) { - return false; - } - } - return true; -} - -template inline bool FuzzyEquals(const T (&p)[N], const T (&q)[N], double epsilon=1e-3) { - for (size_t i = 0; i < N; ++i) { - if (!FuzzyEquals(p[i], q[i], epsilon)) { - return false; - } - } - return true; -} /// \brief status code for a job /// /// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html @@ -167,23 +146,6 @@ struct JobStatus std::string pk; ///< the primary key to differentiate this job }; -/// \brief an affine transform -struct Transform -{ - Transform() { - quaternion[0] = 1; quaternion[1] = 0; quaternion[2] = 0; quaternion[3] = 0; - translate[0] = 0; translate[1] = 0; translate[2] = 0; - } - bool operator!=(const Transform& other) const { - return !FuzzyEquals(quaternion, other.quaternion) || !FuzzyEquals(translate, other.translate); - } - bool operator==(const Transform& other) const { - return !operator!=(other); - } - Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] - Real translate[3]; ///< translation x,y,z -}; - struct InstanceObjectState { Transform transform; ///< the transform of this instance object @@ -330,26 +292,6 @@ class RobotControllerPrograms std::map programs; ///< the keys are the robot instance primary keys of the scene }; -struct MUJINCLIENT_API SensorSelectionInfo -{ - std::string sensorName; - std::string sensorLinkName; - SensorSelectionInfo() = default; - SensorSelectionInfo(const std::string& sensorNameIn, const std::string& sensorLinkNameIn) : sensorName(sensorNameIn), sensorLinkName(sensorLinkNameIn) { - } - bool operator<(const SensorSelectionInfo& rhs) const { - if( sensorName == rhs.sensorName ) { - return sensorLinkName < rhs.sensorLinkName; - } - return sensorName < rhs.sensorName; - } - bool operator==(const SensorSelectionInfo& rhs) const { - return sensorName == rhs.sensorName && sensorLinkName == rhs.sensorLinkName; - } -}; -MUJINCLIENT_API void LoadJsonValue(const rapidjson::Value& v, SensorSelectionInfo& sensorSelectionInfos); -MUJINCLIENT_API void SaveJsonValue(rapidjson::Value& v, const SensorSelectionInfo& sensorSelectionInfo, rapidjson::Document::AllocatorType& alloc); - /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -733,7 +675,7 @@ class MUJINCLIENT_API WebResource inline T Get(const std::string& field, double timeout = 5.0) { rapidjson::Document pt(rapidjson::kObjectType); GetWrap(pt, field, timeout); - return mujinjson_external::GetJsonValueByKey(pt, field.c_str()); + return mujinjson::GetJsonValueByKey(pt, field.c_str()); } /// \brief sets an attribute of this web resource @@ -1068,7 +1010,7 @@ class MUJINCLIENT_API SceneResource : public WebResource virtual void GetTaskNames(std::vector& names); /// \brief gets a list of all the instance objects of the scene - virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); + virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); virtual void GetInstObjects(std::vector& instobjects); virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 73053674..78f45e22 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -29,7 +29,6 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { -namespace mujinjson = mujinjson_external; using namespace mujinjson; void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) @@ -98,22 +97,6 @@ void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostr os << "]"; } -void LoadJsonValue(const rapidjson::Value& v, SensorSelectionInfo& sensorSelectionInfo) -{ - if( !v.IsObject() || !v.HasMember("sensorName") || !v.HasMember("sensorLinkName") ) { - MUJIN_LOG_INFO(str(boost::format("Invalid SensorSelectionInfo in %s")%mujinjson::DumpJson(v))); - return; - } - sensorSelectionInfo.sensorName = mujinjson::GetStringJsonValueByKey(v, "sensorName"); - sensorSelectionInfo.sensorLinkName = mujinjson::GetStringJsonValueByKey(v, "sensorLinkName"); -} - -void SaveJsonValue(rapidjson::Value& v, const SensorSelectionInfo& sensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) { - v.SetObject(); - mujinjson::SetJsonValueByKey(v, "sensorName", sensorSelectionInfo.sensorName, alloc); - mujinjson::SetJsonValueByKey(v, "sensorLinkName", sensorSelectionInfo.sensorLinkName, alloc); -} - WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) { BOOST_ASSERT(__pk.size()>0); @@ -814,7 +797,7 @@ void SceneResource::GetTaskNames(std::vector& taskkeys) } } -void SceneResource::GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos) +void SceneResource::GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos) { GETCONTROLLERIMPL(); allSensorSelectionInfos.clear(); From f52621974108bbf4a4250ccd0914d754a9423f1e Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 5 Jan 2023 17:32:57 +0900 Subject: [PATCH 406/477] update mujinjson.h to make it compatible with internal coe, add a common definitions file --- src/controllerclientimpl.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 8ed759ab..e24758df 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -35,7 +35,6 @@ MUJIN_LOGGER("mujin.controllerclientcpp"); namespace mujinclient { -namespace mujinjson = mujinjson_external; using namespace mujinjson; template From 3dfdac865f77b0c5b4e79ef146dc793ac063060a Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 5 Jan 2023 17:54:15 +0900 Subject: [PATCH 407/477] added file --- src/mujinjson.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/mujinjson.cpp diff --git a/src/mujinjson.cpp b/src/mujinjson.cpp new file mode 100644 index 00000000..2654a946 --- /dev/null +++ b/src/mujinjson.cpp @@ -0,0 +1,113 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2012-2022 MUJIN Inc. +#include + +#include +#include +#include + +namespace mujinjson { + +template +void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer) +{ + static_assert(sizeof(typename Container::value_type) == sizeof(char), "buffer must contain byte-sized elements"); + + const int fd = ::open(filename, O_RDONLY); + if (fd < 0) { + throw MujinJSONException(boost::str(boost::format("Could not open Json file %s") % filename)); + } + + struct stat fs; + if (::fstat(fd, &fs) != 0) { + ::close(fd); + throw MujinJSONException(boost::str(boost::format("Could not get file stats of Json file %s") % filename)); + } + + if( fs.st_size == 0 ) { + // webstack files can report size 0 even though there is content in there, so have to have a growing buffer to compensate for this + size_t nChunkSize = 4096; + size_t nBufferSize = nChunkSize; + char* pbuffer = (char*)::malloc(nBufferSize); + if( !pbuffer ) { + throw MujinJSONException("Could not allocate memory"); + } + size_t nFileSize = 0; + + while(1) { + size_t nTotalToRead = nBufferSize - nFileSize; + if( nTotalToRead < nChunkSize ) { + nBufferSize += nChunkSize; + pbuffer = (char*)::realloc(pbuffer, nBufferSize); + if( !pbuffer ) { + throw MujinJSONException("Could not allocate memory"); + } + nTotalToRead = nBufferSize - nFileSize; + } + ssize_t count = ::read(fd, pbuffer + nFileSize, nBufferSize - nFileSize); + if (count < 0) { + if (errno == EINTR) { + continue; // retry if interrupted + } + ::close(fd); + ::free(pbuffer); + throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); + } + if( count == 0 ) { + break; // EOF + } + nFileSize += count; + } + + ::close(fd); + + if( nFileSize == 0 ) { + ::free(pbuffer); + throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); + } + + try { + ParseJson(d, pbuffer, nFileSize); + } + catch(const std::exception& ex) { + ::free(pbuffer); + throw; + } + + ::free(pbuffer); + return; + } + + buffer.resize(fs.st_size); + ssize_t offset = 0; + do { + ssize_t count = ::read(fd, buffer.data() + offset, fs.st_size - offset); + if (count < 0) { + if (errno == EINTR) { + continue; // retry if interrupted + } + ::close(fd); + throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); + } + if( count == 0 ) { + break; // EOF + } + offset += count; + } while (offset < fs.st_size); + + ::close(fd); + if( offset == 0 ) { + throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); + } + + ParseJson(d, reinterpret_cast(buffer.data()), offset); +} + +// used for declaration of the specialization +void __InternalParseJsonFile(rapidjson::Document& d, const char* filename) +{ + std::vector buffer; + return ParseJsonFile(d, filename, buffer); +} + +} // end namespace mujinjson From 3e667183c1f7fdf1ded37aa6dff7753ca857cef0 Mon Sep 17 00:00:00 2001 From: rosen Date: Thu, 5 Jan 2023 18:05:15 +0900 Subject: [PATCH 408/477] add namespace context --- include/mujincontrollerclient/mujinjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 084a6a02..081c4a42 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -44,7 +44,7 @@ { \ if (!(mujinjson::LoadJsonValueByKey(rValue, key, param))) \ { \ - throw MujinJSONException(boost::str(boost::format(("[%s, %u] assert(mujinjson::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ + throw mujinjson::MujinJSONException(boost::str(boost::format(("[%s, %u] assert(mujinjson::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ } \ } #endif // MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY From a86f08d82a7974ed4222512fad820b145f145f33 Mon Sep 17 00:00:00 2001 From: rosen Date: Sat, 7 Jan 2023 17:18:39 +0900 Subject: [PATCH 409/477] have to prefix with the connected body name --- src/mujincontrollerclient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 78f45e22..c2ad77ff 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -821,6 +821,7 @@ void SceneResource::GetAllSensorSelectionInfos(std::vectorGetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); + const std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { @@ -833,7 +834,7 @@ void SceneResource::GetAllSensorSelectionInfos(std::vector(*itConnectedBodyAttachedSensor, "linkName"); - allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); + allSensorSelectionInfos.emplace_back(sensorName, connectedBodyName+"_"+sensorLinkName); } } } From df666eb22ea49de0cc9218b79d499c3815721b88 Mon Sep 17 00:00:00 2001 From: rosen Date: Sat, 4 Feb 2023 13:53:54 -0500 Subject: [PATCH 410/477] add ExecuteGraphQueryRaw --- src/controllerclientimpl.cpp | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index e24758df..496a4c45 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -338,14 +338,14 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch // parse response if (!docResult.IsObject()) { - MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + //MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // look for errors in response const rapidjson::Value::ConstMemberIterator itErrors = docResult.FindMember("errors"); if (itErrors != docResult.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); + MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { const rapidjson::Value& rError = *itError; if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { @@ -354,22 +354,64 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { errorCode = itExtensions->value["errorCode"].GetString(); } - throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] Failed to execute graph query \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); + throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } } - throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // should have data member if (!docResult.HasMember("data")) { - MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); - throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + //MUJIN_LOG_ERROR(str(boost::format("graph query does not have data \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); + throw MUJIN_EXCEPTION_FORMAT("graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // set output rResult = docResult["data"]; } +void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +{ + rResult.SetNull(); // zero output + + rapidjson::Document rResultDoc(&rAlloc); + + { + boost::mutex::scoped_lock lock(_mutex); + + rapidjson::StringBuffer& rRequestStringBuffer = _rRequestStringBufferCache; + rRequestStringBuffer.Clear(); + + { + // use the callers allocator to construct the request body + rapidjson::Value rRequest, rValue; + rRequest.SetObject(); + rValue.SetString(operationName, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); + rValue.SetString(query, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); + rValue.CopyFrom(rVariables, rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); + + rapidjson::Writer writer(rRequestStringBuffer); + rRequest.Accept(writer); + } + + _uri = _baseuri + "api/v2/graphql"; + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); + } + + // parse response + if (!rResultDoc.IsObject()) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + } + if (rResultDoc.FindMember("data") == rResultDoc.MemberEnd() ) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + } + + rResult.Swap(rResultDoc); +} + void ControllerClientImpl::RestartServer(double timeout) { boost::mutex::scoped_lock lock(_mutex); From 13be8119452b475d03662dbe959f0f1142434877 Mon Sep 17 00:00:00 2001 From: rosen Date: Sat, 4 Feb 2023 13:53:54 -0500 Subject: [PATCH 411/477] add ExecuteGraphQueryRaw --- include/mujincontrollerclient/mujincontrollerclient.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 2eac5abd..a39f05bd 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -353,7 +353,15 @@ class MUJINCLIENT_API ControllerClient virtual void RestartServer(double timeout = 5.0) = 0; /// \brief Execute GraphQL query or mutation against Mujin Controller. - virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + /// + /// Throws an exception if there are any errors + /// \param rResultData The "data" field of the result if the query returns without problems + virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResultData, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + + /// \brief Execute the GraphQL query or mutation against Mujin Controller and return any output as-is without doing any error processing + /// + /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". + virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; From b0b65e2faf45577ff89d818dae0e082fe049e992 Mon Sep 17 00:00:00 2001 From: rosen Date: Sat, 4 Feb 2023 15:44:35 -0500 Subject: [PATCH 412/477] change log level --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 496a4c45..f714b637 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -830,7 +830,7 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception int ControllerClientImpl::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) { - MUJIN_LOG_DEBUG(str(boost::format("POST %s")%desturi)); + MUJIN_LOG_VERBOSE(str(boost::format("POST %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); From 2fccdd181c23e0de72d969021ddc7a1d3b869c57 Mon Sep 17 00:00:00 2001 From: Yoshiki Kanemoto Date: Wed, 1 Mar 2023 15:02:08 -0500 Subject: [PATCH 413/477] add localaabb to PickPlaceHistoryItem --- .../mujincontrollerclient/mujindefinitions.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/mujincontrollerclient/mujindefinitions.h b/include/mujincontrollerclient/mujindefinitions.h index 4b2cf7c9..5f7ea44c 100644 --- a/include/mujincontrollerclient/mujindefinitions.h +++ b/include/mujincontrollerclient/mujindefinitions.h @@ -69,6 +69,22 @@ struct Transform Real translate[3]; ///< translation x,y,z }; +struct AABB +{ + AABB() { + pos[0] = 1; pos[1] = 0; pos[2] = 0; + extents[0] = 0; extents[1] = 0; extents[2] = 0; + } + inline bool operator!=(const AABB& other) const { + return !FuzzyEquals(pos, other.pos) || !FuzzyEquals(pos, other.pos); + } + inline bool operator==(const AABB& other) const { + return !operator!=(other); + } + Real pos[3]; ///< center of AABB + Real extents[3]; ///< half extents of AABB +}; + struct MUJINCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable { SensorSelectionInfo() = default; @@ -103,6 +119,7 @@ struct MUJINCLIENT_API PickPlaceHistoryItem unsigned long long eventTimeStampUS; ///< time that the event ocurred in us (from Linux epoch). For "picked" this is the chuck time, for "placed this is the unchuck time, for "touched" this is the time when the robot supposedly stopped touching/disturbing the object. std::string object_uri; ///< the object uri Transform objectpose; ///< 7-values in world, unit is usually mm + AABB localaabb; ///< AABB of object in object frame. unsigned long long sensorTimeStampUS; ///< sensor timestamp in us (from Linux epoch) of when the object was detected in the scene }; From a7cd10750bd70d1967325b4e83c3b79c12d469ae Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Thu, 23 Mar 2023 17:13:47 +0900 Subject: [PATCH 414/477] Refactor ExecuteGraphQuery, ExecuteGraphQueryRaw --- src/controllerclientimpl.cpp | 98 +++++++++++++----------------------- 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index f714b637..fceff2b9 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -305,11 +305,11 @@ void ControllerClientImpl::SetAdditionalHeaders(const std::vector& _SetupHTTPHeadersMultipartFormData(); } -void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) { rResult.SetNull(); // zero output - rapidjson::Document docResult(&rAlloc); + rapidjson::Document rResultDoc(&rAlloc); { boost::mutex::scoped_lock lock(_mutex); @@ -333,83 +333,55 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch } _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), docResult, 200, timeout); + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); } // parse response - if (!docResult.IsObject()) { - //MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); - throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); - } - - // look for errors in response - const rapidjson::Value::ConstMemberIterator itErrors = docResult.FindMember("errors"); - if (itErrors != docResult.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); - for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { - const rapidjson::Value& rError = *itError; - if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { - const char* errorCode = "unknown"; - const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); - if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { - errorCode = itExtensions->value["errorCode"].GetString(); + if (!rResultDoc.IsObject()) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + } + + if (checkForErrors) { + // look for errors in response + const rapidjson::Value::ConstMemberIterator itErrors = rResultDoc.FindMember("errors"); + if (itErrors != rResultDoc.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { + MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(rResultDoc))); + for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { + const rapidjson::Value& rError = *itError; + if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { + const char* errorCode = "unknown"; + const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); + if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { + errorCode = itExtensions->value["errorCode"].GetString(); + } + throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } - throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } + throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); } - throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // should have data member - if (!docResult.HasMember("data")) { - //MUJIN_LOG_ERROR(str(boost::format("graph query does not have data \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); - throw MUJIN_EXCEPTION_FORMAT("graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + if (!rResultDoc.HasMember("data")) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); } // set output - rResult = docResult["data"]; + if (returnRawResponse) { + rResult.Swap(rResultDoc); + } else { + rResult = rResultDoc["data"]; + } } -void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - rResult.SetNull(); // zero output - - rapidjson::Document rResultDoc(&rAlloc); - - { - boost::mutex::scoped_lock lock(_mutex); - - rapidjson::StringBuffer& rRequestStringBuffer = _rRequestStringBufferCache; - rRequestStringBuffer.Clear(); - - { - // use the callers allocator to construct the request body - rapidjson::Value rRequest, rValue; - rRequest.SetObject(); - rValue.SetString(operationName, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); - rValue.SetString(query, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); - rValue.CopyFrom(rVariables, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); - - rapidjson::Writer writer(rRequestStringBuffer); - rRequest.Accept(writer); - } - - _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); - } - - // parse response - if (!rResultDoc.IsObject()) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } - if (rResultDoc.FindMember("data") == rResultDoc.MemberEnd() ) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); +} - rResult.Swap(rResultDoc); +void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +{ + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); } void ControllerClientImpl::RestartServer(double timeout) From 5d347e72fdc9d4cfad0968185394df6ac5d5f697 Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Thu, 23 Mar 2023 17:13:47 +0900 Subject: [PATCH 415/477] Refactor ExecuteGraphQuery, ExecuteGraphQueryRaw --- src/controllerclientimpl.cpp | 98 +++++++++++++----------------------- 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index f714b637..fceff2b9 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -305,11 +305,11 @@ void ControllerClientImpl::SetAdditionalHeaders(const std::vector& _SetupHTTPHeadersMultipartFormData(); } -void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) { rResult.SetNull(); // zero output - rapidjson::Document docResult(&rAlloc); + rapidjson::Document rResultDoc(&rAlloc); { boost::mutex::scoped_lock lock(_mutex); @@ -333,83 +333,55 @@ void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const ch } _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), docResult, 200, timeout); + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); } // parse response - if (!docResult.IsObject()) { - //MUJIN_LOG_ERROR(str(boost::format("Failed to execute graph query \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); - throw MUJIN_EXCEPTION_FORMAT("Failed to execute graph query \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); - } - - // look for errors in response - const rapidjson::Value::ConstMemberIterator itErrors = docResult.FindMember("errors"); - if (itErrors != docResult.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(docResult))); - for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { - const rapidjson::Value& rError = *itError; - if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { - const char* errorCode = "unknown"; - const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); - if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { - errorCode = itExtensions->value["errorCode"].GetString(); + if (!rResultDoc.IsObject()) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + } + + if (checkForErrors) { + // look for errors in response + const rapidjson::Value::ConstMemberIterator itErrors = rResultDoc.FindMember("errors"); + if (itErrors != rResultDoc.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { + MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(rResultDoc))); + for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { + const rapidjson::Value& rError = *itError; + if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { + const char* errorCode = "unknown"; + const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); + if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { + errorCode = itExtensions->value["errorCode"].GetString(); + } + throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } - throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } + throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); } - throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); } // should have data member - if (!docResult.HasMember("data")) { - //MUJIN_LOG_ERROR(str(boost::format("graph query does not have data \"%s\", invalid response: %s")%operationName%mujinjson::DumpJson(docResult))); - throw MUJIN_EXCEPTION_FORMAT("graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(docResult), MEC_HTTPServer); + if (!rResultDoc.HasMember("data")) { + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); } // set output - rResult = docResult["data"]; + if (returnRawResponse) { + rResult.Swap(rResultDoc); + } else { + rResult = rResultDoc["data"]; + } } -void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - rResult.SetNull(); // zero output - - rapidjson::Document rResultDoc(&rAlloc); - - { - boost::mutex::scoped_lock lock(_mutex); - - rapidjson::StringBuffer& rRequestStringBuffer = _rRequestStringBufferCache; - rRequestStringBuffer.Clear(); - - { - // use the callers allocator to construct the request body - rapidjson::Value rRequest, rValue; - rRequest.SetObject(); - rValue.SetString(operationName, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); - rValue.SetString(query, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); - rValue.CopyFrom(rVariables, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); - - rapidjson::Writer writer(rRequestStringBuffer); - rRequest.Accept(writer); - } - - _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); - } - - // parse response - if (!rResultDoc.IsObject()) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } - if (rResultDoc.FindMember("data") == rResultDoc.MemberEnd() ) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); +} - rResult.Swap(rResultDoc); +void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +{ + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); } void ControllerClientImpl::RestartServer(double timeout) From 03c521cb4723ce196898a9e8435c30db27d67ad2 Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Thu, 23 Mar 2023 11:13:29 +0900 Subject: [PATCH 416/477] Add ZMQ route --- src/controllerclientimpl.cpp | 67 +++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fceff2b9..4a018d35 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -123,6 +123,16 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_username); } + _mujinControllerIp = _baseuri.substr(_baseuri.find("//")+2, _baseuri.size()); + _mujinControllerIp.erase(remove(_mujinControllerIp.begin(), _mujinControllerIp.end(), '/'), _mujinControllerIp.end()); // Remove / from string + // Remove port + int idx = _mujinControllerIp.find(':'); + if (idx != std::string::npos) { + _mujinControllerIp = _mujinControllerIp.substr(0, idx); + } + boost::shared_ptr zmqcontext(new zmq::context_t(1)); + InitializeZMQ(7801, zmqcontext); + //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); @@ -244,6 +254,20 @@ ControllerClientImpl::~ControllerClientImpl() curl_easy_cleanup(_curl); } +void ControllerClientImpl::InitializeZMQ(const int zmqPort, boost::shared_ptr zmqcontext) { + _zmqPort = zmqPort; + _zmqcontext = zmqcontext; + _zmqIsInitialized = true; + + _zmqMujinGraphQLClient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); + if (!_zmqMujinGraphQLClient) { + // Not throwing an Exception so old controllers do not cause problems + MUJIN_LOG_ERROR(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort)); + // throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); + _zmqIsInitialized = false; + } +} + std::string ControllerClientImpl::GetVersion() { if (!_profile.IsObject()) { @@ -305,7 +329,7 @@ void ControllerClientImpl::SetAdditionalHeaders(const std::vector& _SetupHTTPHeadersMultipartFormData(); } -void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) +void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse, bool useZmq) { rResult.SetNull(); // zero output @@ -327,13 +351,40 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); rValue.CopyFrom(rVariables, rAlloc); rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); + if (useZmq) { + rValue.SetString("/api/v2/graphql", rAlloc); + rRequest.AddMember(rapidjson::Document::StringRefType("path"), rValue, rAlloc); + } rapidjson::Writer writer(rRequestStringBuffer); rRequest.Accept(writer); } _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); + if (useZmq) { + std::string result_ss; + try { + result_ss = _zmqMujinGraphQLClient->Call(rRequestStringBuffer.GetString(), timeout); + ParseJson(rResultDoc, result_ss); + } + catch (const MujinException& e) { + MUJIN_LOG_ERROR(e.what()); + if (e.GetCode() == MEC_ZMQNoResponse) { + MUJIN_LOG_INFO("reinitializing zmq connection with webstack"); + _zmqMujinGraphQLClient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); + if (!_zmqMujinGraphQLClient) { + throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); + } + } else if (e.GetCode() == MEC_Timeout) { + throw MujinException("Failed to call GraphQL over ZMQ (timeout)"); + } + else { + throw; + } + } + } else { + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); + } } // parse response @@ -376,12 +427,20 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false, false); } void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true, false); +} + +void ControllerClientImpl::ExecuteGraphQueryZmq(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +{ + if (!_zmqIsInitialized) { + throw MUJIN_EXCEPTION_FORMAT0("ExecuteGraphQuery via ZMQ called, but no ZMQ connection is available", MEC_NotInitialized); + } + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true, true); } void ControllerClientImpl::RestartServer(double timeout) From d3c95519cda09f7c53fc08eed2c77f563e35c7d5 Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Thu, 23 Mar 2023 11:13:29 +0900 Subject: [PATCH 417/477] Add ZMQ route --- include/mujincontrollerclient/mujincontrollerclient.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a39f05bd..ffe1b3af 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -59,6 +59,7 @@ #include #include #include +#include "mujincontrollerclient/mujinzmqclient.h" namespace mujinclient { @@ -363,6 +364,12 @@ class MUJINCLIENT_API ControllerClient /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + /// \brief Sends a GraphQL query or mutation to the Mujin Controller via ZMQ (not HTTP). + /// + /// Throws an exception if there are any errors + /// \param rResultData The "data" field of the result if the query returns without problems + virtual void ExecuteGraphQueryZmq(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; From a7fb461c4392d8091776a1c4b1638a8dad38da05 Mon Sep 17 00:00:00 2001 From: rosen Date: Mon, 27 Mar 2023 13:19:55 -0400 Subject: [PATCH 418/477] fix default --- include/mujincontrollerclient/mujindefinitions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujindefinitions.h b/include/mujincontrollerclient/mujindefinitions.h index 5f7ea44c..0dafedfd 100644 --- a/include/mujincontrollerclient/mujindefinitions.h +++ b/include/mujincontrollerclient/mujindefinitions.h @@ -72,7 +72,7 @@ struct Transform struct AABB { AABB() { - pos[0] = 1; pos[1] = 0; pos[2] = 0; + pos[0] = 0; pos[1] = 0; pos[2] = 0; extents[0] = 0; extents[1] = 0; extents[2] = 0; } inline bool operator!=(const AABB& other) const { From 82ce2b17f84d74cdd432bd0ea978546756ed8ba0 Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Fri, 14 Apr 2023 14:54:17 +0900 Subject: [PATCH 419/477] Revert "Merge pull request #124 from mujin/add-zmq-route" This reverts commit cf0734bcb2ed6097240b246ba762d73c1830ef8c, reversing changes made to a09fe39aa5b05828e4f9100cabf9524c2469f3de. --- src/controllerclientimpl.cpp | 67 +++--------------------------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 4a018d35..fceff2b9 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -123,16 +123,6 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_username); } - _mujinControllerIp = _baseuri.substr(_baseuri.find("//")+2, _baseuri.size()); - _mujinControllerIp.erase(remove(_mujinControllerIp.begin(), _mujinControllerIp.end(), '/'), _mujinControllerIp.end()); // Remove / from string - // Remove port - int idx = _mujinControllerIp.find(':'); - if (idx != std::string::npos) { - _mujinControllerIp = _mujinControllerIp.substr(0, idx); - } - boost::shared_ptr zmqcontext(new zmq::context_t(1)); - InitializeZMQ(7801, zmqcontext); - //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); _curl = curl_easy_init(); BOOST_ASSERT(!!_curl); @@ -254,20 +244,6 @@ ControllerClientImpl::~ControllerClientImpl() curl_easy_cleanup(_curl); } -void ControllerClientImpl::InitializeZMQ(const int zmqPort, boost::shared_ptr zmqcontext) { - _zmqPort = zmqPort; - _zmqcontext = zmqcontext; - _zmqIsInitialized = true; - - _zmqMujinGraphQLClient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); - if (!_zmqMujinGraphQLClient) { - // Not throwing an Exception so old controllers do not cause problems - MUJIN_LOG_ERROR(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort)); - // throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); - _zmqIsInitialized = false; - } -} - std::string ControllerClientImpl::GetVersion() { if (!_profile.IsObject()) { @@ -329,7 +305,7 @@ void ControllerClientImpl::SetAdditionalHeaders(const std::vector& _SetupHTTPHeadersMultipartFormData(); } -void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse, bool useZmq) +void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) { rResult.SetNull(); // zero output @@ -351,40 +327,13 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); rValue.CopyFrom(rVariables, rAlloc); rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); - if (useZmq) { - rValue.SetString("/api/v2/graphql", rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("path"), rValue, rAlloc); - } rapidjson::Writer writer(rRequestStringBuffer); rRequest.Accept(writer); } _uri = _baseuri + "api/v2/graphql"; - if (useZmq) { - std::string result_ss; - try { - result_ss = _zmqMujinGraphQLClient->Call(rRequestStringBuffer.GetString(), timeout); - ParseJson(rResultDoc, result_ss); - } - catch (const MujinException& e) { - MUJIN_LOG_ERROR(e.what()); - if (e.GetCode() == MEC_ZMQNoResponse) { - MUJIN_LOG_INFO("reinitializing zmq connection with webstack"); - _zmqMujinGraphQLClient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); - if (!_zmqMujinGraphQLClient) { - throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); - } - } else if (e.GetCode() == MEC_Timeout) { - throw MujinException("Failed to call GraphQL over ZMQ (timeout)"); - } - else { - throw; - } - } - } else { - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); - } + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); } // parse response @@ -427,20 +376,12 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false, false); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); } void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true, false); -} - -void ControllerClientImpl::ExecuteGraphQueryZmq(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) -{ - if (!_zmqIsInitialized) { - throw MUJIN_EXCEPTION_FORMAT0("ExecuteGraphQuery via ZMQ called, but no ZMQ connection is available", MEC_NotInitialized); - } - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true, true); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); } void ControllerClientImpl::RestartServer(double timeout) From 8016e0649c93bb56bb218f9bc19f0b0ca38796df Mon Sep 17 00:00:00 2001 From: Felix von Drigalski Date: Fri, 14 Apr 2023 14:54:17 +0900 Subject: [PATCH 420/477] Revert "Merge pull request #124 from mujin/add-zmq-route" This reverts commit 8e87a345f0bf64acf2380315d04a68c346c56540, reversing changes made to a09fe39aa5b05828e4f9100cabf9524c2469f3de. --- include/mujincontrollerclient/mujincontrollerclient.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ffe1b3af..a39f05bd 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -59,7 +59,6 @@ #include #include #include -#include "mujincontrollerclient/mujinzmqclient.h" namespace mujinclient { @@ -364,12 +363,6 @@ class MUJINCLIENT_API ControllerClient /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; - /// \brief Sends a GraphQL query or mutation to the Mujin Controller via ZMQ (not HTTP). - /// - /// Throws an exception if there are any errors - /// \param rResultData The "data" field of the result if the query returns without problems - virtual void ExecuteGraphQueryZmq(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; - /// \brief returns the mujin controller version virtual std::string GetVersion() = 0; From 7f6929d463523a6b4f4449b98938419bae5f97f6 Mon Sep 17 00:00:00 2001 From: Hanbang Wang Date: Fri, 14 Apr 2023 13:41:40 +0900 Subject: [PATCH 421/477] Support using Unix domain sockets as connection endpoint --- src/controllerclientimpl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index fceff2b9..7386c72e 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -91,7 +91,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } -ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout, const std::string& unixendpoint) { size_t usernameindex = 0; usernameindex = usernamepassword.find_first_of(':'); @@ -164,6 +164,10 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, CURL_OPTION_SETTER(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CURL_OPTION_SETTER(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); + if( !unixendpoint.empty() ) { + CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); + } + // need to set the following? //CURLOPT_USERAGENT //CURLOPT_TCP_KEEPIDLE From 892328420c9c7eb0b790de4a81bb1e815a42d524 Mon Sep 17 00:00:00 2001 From: Hanbang Wang Date: Fri, 14 Apr 2023 13:41:40 +0900 Subject: [PATCH 422/477] Support using Unix domain sockets as connection endpoint --- include/mujincontrollerclient/mujincontrollerclient.h | 3 ++- src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a39f05bd..73974a05 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -1206,8 +1206,9 @@ class MUJINCLIENT_API DebugResource : public WebResource \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests + \param unixendpoint if not empty, will use unix socket to connect to the controller */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0, const std::string& unixendpoint=std::string()); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c2ad77ff..a3f53c35 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1323,9 +1323,9 @@ void DebugResource::Download(std::ostream& outputStream, double timeout) controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); } -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout, const std::string& unixendpoint) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout, unixendpoint)); } void ControllerClientDestroy() From b387dac563713e19dc7915f9947befe449bd69b7 Mon Sep 17 00:00:00 2001 From: Hanbang Wang Date: Thu, 20 Apr 2023 14:13:57 +0900 Subject: [PATCH 423/477] remove url default parameter --- src/controllerclientimpl.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 7386c72e..f3e3897c 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -93,6 +93,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout, const std::string& unixendpoint) { + BOOST_ASSERT( !baseuri.empty() ); size_t usernameindex = 0; usernameindex = usernamepassword.find_first_of(':'); BOOST_ASSERT(usernameindex != std::string::npos ); @@ -102,16 +103,10 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _httpheadersjson = NULL; _httpheadersstl = NULL; _httpheadersmultipartformdata = NULL; - if( baseuri.size() > 0 ) { - _baseuri = baseuri; - // ensure trailing slash - if( _baseuri[_baseuri.size()-1] != '/' ) { - _baseuri.push_back('/'); - } - } - else { - // use the default - _baseuri = "https://controller.mujin.co.jp/"; + _baseuri = baseuri; + // ensure trailing slash + if( _baseuri[_baseuri.size()-1] != '/' ) { + _baseuri.push_back('/'); } _baseapiuri = _baseuri + std::string("api/v1/"); // hack for now since webdav server and api server could be running on different ports From f1b810a92ee7e4dd9dcb6c1b87144e5f480472e0 Mon Sep 17 00:00:00 2001 From: Hanbang Wang Date: Thu, 20 Apr 2023 14:13:57 +0900 Subject: [PATCH 424/477] remove url default parameter --- include/mujincontrollerclient/mujincontrollerclient.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 73974a05..4e5117cb 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -1192,7 +1192,7 @@ class MUJINCLIENT_API DebugResource : public WebResource You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. \param usernamepassword user:password - \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. If not specified, will use the default mujin controller URL + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. @@ -1201,14 +1201,14 @@ class MUJINCLIENT_API DebugResource : public WebResource この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。指定されていなければデフォールトのMUJINコントローラURLが使用されます。 + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests \param unixendpoint if not empty, will use unix socket to connect to the controller */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url=std::string(), const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0, const std::string& unixendpoint=std::string()); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0, const std::string& unixendpoint=std::string()); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); From 63606fff113830291c5582958e6dcacd269cb7d1 Mon Sep 17 00:00:00 2001 From: Hanbang Wang Date: Wed, 10 May 2023 10:00:15 +0900 Subject: [PATCH 425/477] review pass # Conflicts: # python/mujincommon/__init__.py --- .../createwebstackclient.h | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/include/mujincontrollercommon/createwebstackclient.h diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h new file mode 100644 index 00000000..2ba0cb5c --- /dev/null +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -0,0 +1,62 @@ +// -*- coding: utf-8 -*- +// Copyright (C) MUJIN Inc. +// Do not distribute this file outside of Mujin + +#pragma once + +#include + +namespace mujincontrollercommon { + +static bool IsHostnameLocal(const std::string& hostname) +{ + static char hostnamebuf[256]; + static int status = gethostname(hostnamebuf, sizeof(hostnamebuf)); + + return hostname == "localhost" || hostname == "127.0.0.1" || hostname == hostnamebuf; +} + +// \brief Transparently diverge to private webstack if url is localhost +static inline mujinclient::ControllerClientPtr CreateWebstackClient( + std::string usernamepassword, + const std::string& url, + const std::string& proxyserverport = std::string(), + const std::string& proxyuserpw = std::string(), + int options = 0, + double timeout = 3.0, + std::string unixendpoint = std::string()) +{ + while (unixendpoint.empty()) { + std::size_t start = url.find("://"); + if (start == std::string::npos) { + break; + } + start += std::strlen("://"); + + const std::size_t end = url.find("/", start); // not find is ok + + std::string host = url.substr(start, end == std::string::npos ? end : end - start); + const std::size_t port = host.find(":"); + if (port != std::string::npos) { + if (host.substr(port + 1) != "80") { + break; + } + host.erase(port); + } + + if (IsHostnameLocal(host)) { + unixendpoint = "/run/webstack/http.sock"; + + const char *const username = std::getenv("MUJIN_WEBSTACK_PRIVATE_USERNAME"); + const char *const password = std::getenv("MUJIN_WEBSTACK_PRIVATE_PASSWORD"); + if (username != nullptr && password != nullptr) { + usernamepassword = std::string(username) + ":" + password; + } + } + break; + } + + return mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout, unixendpoint); +} + +} From f2739b85ee751571314b84c17ab93ef35db514b1 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 15 May 2023 20:18:27 -0400 Subject: [PATCH 426/477] Reduce copying of string, use MUJIN_WEBSTACK_UNIX_ENDPOINT. --- .../createwebstackclient.h | 74 +++++++++++++------ 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 2ba0cb5c..d8965f51 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -8,15 +8,33 @@ namespace mujincontrollercommon { -static bool IsHostnameLocal(const std::string& hostname) +/// \brief determine if hostname is local, if len is not given, then use strlen to determine string length +static bool IsHostnameLocal(const char* hostname, std::ssize_t len = -1) { - static char hostnamebuf[256]; - static int status = gethostname(hostnamebuf, sizeof(hostnamebuf)); - - return hostname == "localhost" || hostname == "127.0.0.1" || hostname == hostnamebuf; + if (len == -1) { + len = std::strlen(hostname); + } + if (len == sizeof("127.0.0.1") - 1 && strncmp(hostname, "127.0.0.1", len) == 0) { + return true; + } + if (len == sizeof("localhost") - 1 && strncmp(hostname, "localhost", len) == 0) { + return true; + } + char localHostname[HOST_NAME_MAX + 1] = {}; + if (gethostname(localHostname, sizeof(localHostname)) != 0) { + return false; + } + // If the null-terminated hostname is too large to fit, then the name is truncated, and no error is returned (but see NOTES below). + // POSIX.1 says that if such truncation occurs, then it is unspecified whether the returned buffer includes a terminating null byte. + localHostname[HOST_NAME_MAX] = '\0'; + const std::size_t localHostnameLen = std::strlen(localHostname); + if (len == localHostnameLen && strncmp(hostname, localHostname, len) == 0) { + return true; + } + return false; } -// \brief Transparently diverge to private webstack if url is localhost +/// \brief Transparently diverge to private webstack if url is localhost static inline mujinclient::ControllerClientPtr CreateWebstackClient( std::string usernamepassword, const std::string& url, @@ -31,26 +49,38 @@ static inline mujinclient::ControllerClientPtr CreateWebstackClient( if (start == std::string::npos) { break; } - start += std::strlen("://"); - - const std::size_t end = url.find("/", start); // not find is ok + start += sizeof("://") - 1; + const std::size_t port = url.find(":", start); // not found is ok + const std::size_t slash = url.find("/", start); // not found is ok + std::ssize_t len = -1; - std::string host = url.substr(start, end == std::string::npos ? end : end - start); - const std::size_t port = host.find(":"); - if (port != std::string::npos) { - if (host.substr(port + 1) != "80") { - break; + if (slash == std::string::npos) { + if (port == std::string::npos) { + // no port, no slash + len = -1; // use the null-terminator + } else { + // has port, no slash + len = port - start - 1; + } + } else { + if (port != std::string::npos && port < slash) { + // has port before slash + len = port - start - 1; + } else { + // no port, but has slash + len = slash - start - 1; } - host.erase(port); } - if (IsHostnameLocal(host)) { - unixendpoint = "/run/webstack/http.sock"; - - const char *const username = std::getenv("MUJIN_WEBSTACK_PRIVATE_USERNAME"); - const char *const password = std::getenv("MUJIN_WEBSTACK_PRIVATE_PASSWORD"); - if (username != nullptr && password != nullptr) { - usernamepassword = std::string(username) + ":" + password; + if (IsHostnameLocal(url.c_str() + start, len)) { + const char *const envunixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); + if (envunixendpoint != nullptr && envunixendpoint[0] != '\0') { + unixendpoint = envunixendpoint; + const char *const username = std::getenv("MUJIN_WEBSTACK_LEGACY_USERNAME"); + const char *const password = std::getenv("MUJIN_WEBSTACK_PRIVATE_PASSWORD"); + if (username != nullptr && password != nullptr) { + usernamepassword = std::string(username) + ":" + password; + } } } break; From fe0c58777825bdd69055a298d328f71793b2e355 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Mon, 15 May 2023 20:42:06 -0400 Subject: [PATCH 427/477] Use ssize_t. --- src/include/mujincontrollercommon/createwebstackclient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index d8965f51..208ac1d3 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -9,7 +9,7 @@ namespace mujincontrollercommon { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length -static bool IsHostnameLocal(const char* hostname, std::ssize_t len = -1) +static bool IsHostnameLocal(const char* hostname, ssize_t len = -1) { if (len == -1) { len = std::strlen(hostname); @@ -52,7 +52,7 @@ static inline mujinclient::ControllerClientPtr CreateWebstackClient( start += sizeof("://") - 1; const std::size_t port = url.find(":", start); // not found is ok const std::size_t slash = url.find("/", start); // not found is ok - std::ssize_t len = -1; + ssize_t len = -1; if (slash == std::string::npos) { if (port == std::string::npos) { From 54bcd5cdf5e99bb7d9a560ab25134d0a6abe1f2b Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 12:10:46 -0400 Subject: [PATCH 428/477] Fix create webstack client. --- src/createwebstackclient.cpp | 80 ++++++++++++++++++ .../createwebstackclient.h | 82 ++----------------- 2 files changed, 89 insertions(+), 73 deletions(-) create mode 100644 src/createwebstackclient.cpp diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp new file mode 100644 index 00000000..3e35a97b --- /dev/null +++ b/src/createwebstackclient.cpp @@ -0,0 +1,80 @@ +#include +#include + +MUJIN_LOGGER("mujin.controllercommon.createwebstackclient"); + +namespace mujincontrollercommon { + +/// \brief determine if hostname is local, if len is not given, then use strlen to determine string length +bool IsHostnameLocal(const char* hostname, ssize_t len) +{ + if (len == -1) { + len = std::strlen(hostname); + } + if (len == sizeof("127.0.0.1") - 1 && strncmp(hostname, "127.0.0.1", len) == 0) { + return true; + } + if (len == sizeof("localhost") - 1 && strncmp(hostname, "localhost", len) == 0) { + return true; + } + char localHostname[HOST_NAME_MAX + 1] = {}; + if (gethostname(localHostname, sizeof(localHostname)) != 0) { + return false; + } + // If the null-terminated hostname is too large to fit, then the name is truncated, and no error is returned (but see NOTES below). + // POSIX.1 says that if such truncation occurs, then it is unspecified whether the returned buffer includes a terminating null byte. + localHostname[HOST_NAME_MAX] = '\0'; + const size_t localHostnameLen = std::strlen(localHostname); + if ((size_t)len == localHostnameLen && strncmp(hostname, localHostname, len) == 0) { + return true; + } + return false; +} + +/// \brief Transparently diverge to private webstack if url is localhost +mujinclient::ControllerClientPtr CreateWebstackClient( + const std::string& usernamepassword, + const std::string& url, + const std::string& proxyserverport, + const std::string& proxyuserpw, + int options, + double timeout, + std::string unixendpoint) +{ + if (unixendpoint.empty()) { + const size_t colonSlashSlash = url.find("://"); + if (colonSlashSlash != std::string::npos) { + const size_t start = colonSlashSlash + sizeof("://") - 1; + const size_t port = url.find(":", start); // not found is ok + const size_t slash = url.find("/", start); // not found is ok + ssize_t len = -1; + if (slash == std::string::npos) { + if (port == std::string::npos) { + // no port, no slash + len = -1; // use the null-terminator + } else { + // has port, no slash + len = port - start - 1; + } + } else { + if (port != std::string::npos && port < slash) { + // has port before slash + len = port - start - 1; + } else { + // no port, but has slash + len = slash - start - 1; + } + } + if (IsHostnameLocal(url.c_str() + start, len)) { + const char *const envunixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); + if (envunixendpoint != nullptr && envunixendpoint[0] != '\0') { + unixendpoint = envunixendpoint; + } + } + } + } + + return mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout, unixendpoint); +} + +} diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 208ac1d3..ad29c13d 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -2,91 +2,27 @@ // Copyright (C) MUJIN Inc. // Do not distribute this file outside of Mujin -#pragma once +#ifndef __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ +#define __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ +#include #include namespace mujincontrollercommon { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length -static bool IsHostnameLocal(const char* hostname, ssize_t len = -1) -{ - if (len == -1) { - len = std::strlen(hostname); - } - if (len == sizeof("127.0.0.1") - 1 && strncmp(hostname, "127.0.0.1", len) == 0) { - return true; - } - if (len == sizeof("localhost") - 1 && strncmp(hostname, "localhost", len) == 0) { - return true; - } - char localHostname[HOST_NAME_MAX + 1] = {}; - if (gethostname(localHostname, sizeof(localHostname)) != 0) { - return false; - } - // If the null-terminated hostname is too large to fit, then the name is truncated, and no error is returned (but see NOTES below). - // POSIX.1 says that if such truncation occurs, then it is unspecified whether the returned buffer includes a terminating null byte. - localHostname[HOST_NAME_MAX] = '\0'; - const std::size_t localHostnameLen = std::strlen(localHostname); - if (len == localHostnameLen && strncmp(hostname, localHostname, len) == 0) { - return true; - } - return false; -} +bool MUJINCONTROLLERCOMMON_API IsHostnameLocal(const char* hostname, ssize_t len = -1); /// \brief Transparently diverge to private webstack if url is localhost -static inline mujinclient::ControllerClientPtr CreateWebstackClient( - std::string usernamepassword, +mujinclient::ControllerClientPtr MUJINCONTROLLERCOMMON_API CreateWebstackClient( + const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport = std::string(), const std::string& proxyuserpw = std::string(), int options = 0, double timeout = 3.0, - std::string unixendpoint = std::string()) -{ - while (unixendpoint.empty()) { - std::size_t start = url.find("://"); - if (start == std::string::npos) { - break; - } - start += sizeof("://") - 1; - const std::size_t port = url.find(":", start); // not found is ok - const std::size_t slash = url.find("/", start); // not found is ok - ssize_t len = -1; + std::string unixendpoint = std::string()); - if (slash == std::string::npos) { - if (port == std::string::npos) { - // no port, no slash - len = -1; // use the null-terminator - } else { - // has port, no slash - len = port - start - 1; - } - } else { - if (port != std::string::npos && port < slash) { - // has port before slash - len = port - start - 1; - } else { - // no port, but has slash - len = slash - start - 1; - } - } +} // namespace mujincontrollercommon - if (IsHostnameLocal(url.c_str() + start, len)) { - const char *const envunixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); - if (envunixendpoint != nullptr && envunixendpoint[0] != '\0') { - unixendpoint = envunixendpoint; - const char *const username = std::getenv("MUJIN_WEBSTACK_LEGACY_USERNAME"); - const char *const password = std::getenv("MUJIN_WEBSTACK_PRIVATE_PASSWORD"); - if (username != nullptr && password != nullptr) { - usernamepassword = std::string(username) + ":" + password; - } - } - } - break; - } - - return mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout, unixendpoint); -} - -} +#endif // __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ From 48af646b0cf28b936dc640ae9ab55cc77ee5181d Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 12:20:38 -0400 Subject: [PATCH 429/477] Add logs. --- src/createwebstackclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 3e35a97b..b30e67cd 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -69,6 +69,7 @@ mujinclient::ControllerClientPtr CreateWebstackClient( const char *const envunixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); if (envunixendpoint != nullptr && envunixendpoint[0] != '\0') { unixendpoint = envunixendpoint; + MUJIN_LOG_DEBUG_FORMAT("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"", unixendpoint%url); } } } From 8ea909f6a7dc0d13562e801cb18fd0cde7e233ac Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 14:43:28 -0400 Subject: [PATCH 430/477] Add test and fix bug. --- src/createwebstackclient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index b30e67cd..5a67aeba 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -54,15 +54,15 @@ mujinclient::ControllerClientPtr CreateWebstackClient( len = -1; // use the null-terminator } else { // has port, no slash - len = port - start - 1; + len = port - start; } } else { if (port != std::string::npos && port < slash) { // has port before slash - len = port - start - 1; + len = port - start; } else { // no port, but has slash - len = slash - start - 1; + len = slash - start; } } if (IsHostnameLocal(url.c_str() + start, len)) { From da4508d62b7c4be544c65a5e592dde24e51afe38 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 19:18:42 -0400 Subject: [PATCH 431/477] Provide GetUnixEndpointForLocalWebstack. --- src/createwebstackclient.cpp | 70 +++++++++++-------- .../createwebstackclient.h | 7 +- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 5a67aeba..e701d0f8 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -31,6 +31,44 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) return false; } +/// \brief determine the unix endpoint if webstack is local +const char* GetUnixEndpointForLocalWebstack(const char* url) +{ + const char* colonSlashSlash = strstr(url, "://"); + if (colonSlashSlash == nullptr) { + return ""; + } + const char* hostname = colonSlashSlash + sizeof("://") - 1; + const char* port = strstr(hostname, ":"); // not found is ok + const char* slash = strstr(hostname, "/"); // not found is ok + ssize_t len = -1; + if (slash == nullptr) { + if (port == nullptr) { + // no port, no slash + len = -1; // use the null-terminator + } else { + // has port, no slash + len = port - hostname; + } + } else { + if (port != nullptr && port < slash) { + // has port before slash + len = port - hostname; + } else { + // no port, but has slash + len = slash - hostname; + } + } + if (IsHostnameLocal(hostname, len)) { + const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); + if (unixendpoint != nullptr && unixendpoint[0] != '\0') { + MUJIN_LOG_DEBUG_FORMAT("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"", unixendpoint%url); + return unixendpoint; + } + } + return ""; +} + /// \brief Transparently diverge to private webstack if url is localhost mujinclient::ControllerClientPtr CreateWebstackClient( const std::string& usernamepassword, @@ -42,37 +80,7 @@ mujinclient::ControllerClientPtr CreateWebstackClient( std::string unixendpoint) { if (unixendpoint.empty()) { - const size_t colonSlashSlash = url.find("://"); - if (colonSlashSlash != std::string::npos) { - const size_t start = colonSlashSlash + sizeof("://") - 1; - const size_t port = url.find(":", start); // not found is ok - const size_t slash = url.find("/", start); // not found is ok - ssize_t len = -1; - if (slash == std::string::npos) { - if (port == std::string::npos) { - // no port, no slash - len = -1; // use the null-terminator - } else { - // has port, no slash - len = port - start; - } - } else { - if (port != std::string::npos && port < slash) { - // has port before slash - len = port - start; - } else { - // no port, but has slash - len = slash - start; - } - } - if (IsHostnameLocal(url.c_str() + start, len)) { - const char *const envunixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); - if (envunixendpoint != nullptr && envunixendpoint[0] != '\0') { - unixendpoint = envunixendpoint; - MUJIN_LOG_DEBUG_FORMAT("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"", unixendpoint%url); - } - } - } + unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); } return mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout, unixendpoint); diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index ad29c13d..7b3e6a18 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -11,10 +11,13 @@ namespace mujincontrollercommon { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length -bool MUJINCONTROLLERCOMMON_API IsHostnameLocal(const char* hostname, ssize_t len = -1); +MUJINCONTROLLERCOMMON_API bool IsHostnameLocal(const char* hostname, ssize_t len = -1); + +/// \brief determine the unix endpoint if webstack is local +MUJINCONTROLLERCOMMON_API const char* GetUnixEndpointForLocalWebstack(const char* url); /// \brief Transparently diverge to private webstack if url is localhost -mujinclient::ControllerClientPtr MUJINCONTROLLERCOMMON_API CreateWebstackClient( +MUJINCONTROLLERCOMMON_API mujinclient::ControllerClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport = std::string(), From db86a332c85c012ce64c4d4c0c92e978862b736e Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 20:23:22 -0400 Subject: [PATCH 432/477] Check that port is 80 if supplied, and handle username password as well. --- src/createwebstackclient.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index e701d0f8..95d360cf 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -39,8 +39,12 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) return ""; } const char* hostname = colonSlashSlash + sizeof("://") - 1; - const char* port = strstr(hostname, ":"); // not found is ok + const char* at = strstr(hostname, "@"); // not found is ok const char* slash = strstr(hostname, "/"); // not found is ok + if (at != nullptr && (slash == nullptr || at < slash)) { + hostname = at + 1; + } + const char* port = strstr(hostname, ":"); // not found is ok ssize_t len = -1; if (slash == nullptr) { if (port == nullptr) { @@ -48,11 +52,17 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) len = -1; // use the null-terminator } else { // has port, no slash + if (strcmp(port, ":80") != 0) { + return ""; + } len = port - hostname; } } else { if (port != nullptr && port < slash) { // has port before slash + if (strncmp(port, ":80", slash - port) != 0) { + return ""; + } len = port - hostname; } else { // no port, but has slash From 3daf535c621aac97a221a59413cc525f7a0e8abb Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 16 May 2023 20:38:11 -0400 Subject: [PATCH 433/477] Expose TestIsWebstackLocal to test if a url is pointing to local webstack. --- src/createwebstackclient.cpp | 18 ++++++++++++------ .../createwebstackclient.h | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 95d360cf..767a1295 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -31,12 +31,12 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) return false; } -/// \brief determine the unix endpoint if webstack is local -const char* GetUnixEndpointForLocalWebstack(const char* url) +/// \brief determine if the url is pointing to local webstack +bool IsWebstackLocal(const char* url) { const char* colonSlashSlash = strstr(url, "://"); if (colonSlashSlash == nullptr) { - return ""; + return false; } const char* hostname = colonSlashSlash + sizeof("://") - 1; const char* at = strstr(hostname, "@"); // not found is ok @@ -53,7 +53,7 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) } else { // has port, no slash if (strcmp(port, ":80") != 0) { - return ""; + return false; } len = port - hostname; } @@ -61,7 +61,7 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) if (port != nullptr && port < slash) { // has port before slash if (strncmp(port, ":80", slash - port) != 0) { - return ""; + return false; } len = port - hostname; } else { @@ -69,7 +69,13 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) len = slash - hostname; } } - if (IsHostnameLocal(hostname, len)) { + return IsHostnameLocal(hostname, len); +} + +/// \brief determine the unix endpoint if webstack is local +const char* GetUnixEndpointForLocalWebstack(const char* url) +{ + if (IsWebstackLocal(url)) { const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); if (unixendpoint != nullptr && unixendpoint[0] != '\0') { MUJIN_LOG_DEBUG_FORMAT("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"", unixendpoint%url); diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 7b3e6a18..201c5eb5 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -13,6 +13,9 @@ namespace mujincontrollercommon { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length MUJINCONTROLLERCOMMON_API bool IsHostnameLocal(const char* hostname, ssize_t len = -1); +/// \brief determine if the url is pointing to local webstack +MUJINCONTROLLERCOMMON_API bool IsWebstackLocal(const char* url); + /// \brief determine the unix endpoint if webstack is local MUJINCONTROLLERCOMMON_API const char* GetUnixEndpointForLocalWebstack(const char* url); From 3564e213a462cfb05f65f39bbfe2236458768784 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Wed, 17 May 2023 11:54:22 -0400 Subject: [PATCH 434/477] Instead of changing constructor signature, add SetUnixEndpoint(). --- src/controllerclientimpl.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index f3e3897c..2628bd48 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -91,7 +91,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } -ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout, const std::string& unixendpoint) +ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); size_t usernameindex = 0; @@ -159,10 +159,6 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, CURL_OPTION_SETTER(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); CURL_OPTION_SETTER(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); - if( !unixendpoint.empty() ) { - CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); - } - // need to set the following? //CURLOPT_USERAGENT //CURLOPT_TCP_KEEPIDLE @@ -274,10 +270,20 @@ void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) { + // mutally exclusive with unix endpoint settings + CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, serverport.c_str()); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); } +void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) +{ + // mutually exclusive with proxy settings + CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); + CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, NULL); + CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); +} + void ControllerClientImpl::SetLanguage(const std::string& language) { boost::mutex::scoped_lock lock(_mutex); From 558013f446a502eab0c7117d1296ad5961178fc8 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Wed, 17 May 2023 11:54:22 -0400 Subject: [PATCH 435/477] Instead of changing constructor signature, add SetUnixEndpoint(). --- include/mujincontrollerclient/mujincontrollerclient.h | 10 +++++++--- src/mujincontrollerclient.cpp | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index 4e5117cb..ca7e890e 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -340,12 +340,17 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the URI used to setup the connection virtual const std::string& GetBaseURI() const = 0; - /// \brief If necessary, changes the proxy to communicate to the controller server + /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. virtual void SetProxy(const std::string& serverport, const std::string& userpw) = 0; + /// \brief If necessary, changes the unix domain socket to be used to communicate to the controller server. Setting unix endpoint disables previously set proxy. + /// + /// \param unixendpoint Specify the file path to the unix domain socket to connect to. + virtual void SetUnixEndpoint(const std::string& unixendpoint) = 0; + /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. /// /// If the server is not responding, call this method to clear the server state and initialize everything. @@ -1206,9 +1211,8 @@ class MUJINCLIENT_API DebugResource : public WebResource \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests - \param unixendpoint if not empty, will use unix socket to connect to the controller */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0, const std::string& unixendpoint=std::string()); +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); /// \brief called at the very end of an application to safely destroy all controller client resources MUJINCLIENT_API void DestroyControllerClient(); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index a3f53c35..c2ad77ff 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1323,9 +1323,9 @@ void DebugResource::Download(std::ostream& outputStream, double timeout) controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); } -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout, const std::string& unixendpoint) +ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout, unixendpoint)); + return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); } void ControllerClientDestroy() From d2fd2287ed9264f87209a5d2ee8b028981d14870 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Wed, 17 May 2023 11:54:42 -0400 Subject: [PATCH 436/477] Update to use SetUnixEndpoint(). --- src/createwebstackclient.cpp | 12 ++++++------ .../mujincontrollercommon/createwebstackclient.h | 3 +-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 767a1295..fa568c40 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -92,14 +92,14 @@ mujinclient::ControllerClientPtr CreateWebstackClient( const std::string& proxyserverport, const std::string& proxyuserpw, int options, - double timeout, - std::string unixendpoint) + double timeout) { - if (unixendpoint.empty()) { - unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); + mujinclient::ControllerClientPtr pClient = mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); + std::string unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); + if (!unixendpoint.empty()) { + pClient->SetUnixEndpoint(unixendpoint); } - - return mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout, unixendpoint); + return pClient; } } diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 201c5eb5..64aab443 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -26,8 +26,7 @@ MUJINCONTROLLERCOMMON_API mujinclient::ControllerClientPtr CreateWebstackClient( const std::string& proxyserverport = std::string(), const std::string& proxyuserpw = std::string(), int options = 0, - double timeout = 3.0, - std::string unixendpoint = std::string()); + double timeout = 3.0); } // namespace mujincontrollercommon From 244ff335dd7541315e6a4bfb58288dffc8d2dfad Mon Sep 17 00:00:00 2001 From: rosen Date: Wed, 21 Jun 2023 15:05:30 +0900 Subject: [PATCH 437/477] add GetURIWithUsernamePassword --- src/controllerclientimpl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2628bd48..7f0ec4e7 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -103,6 +103,15 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _httpheadersjson = NULL; _httpheadersstl = NULL; _httpheadersmultipartformdata = NULL; + + size_t authorityindex = baseuri.find("//"); + if( authorityindex != std::string::npos ) { + _fulluri = baseuri.substr(0,authorityindex+2) + usernamepassword + "@" + baseuri.substr(authorityindex+2); + } + else { + // no idea what to do here.. + _fulluri = std::string("//") + usernamepassword + "@" + baseuri; + } _baseuri = baseuri; // ensure trailing slash if( _baseuri[_baseuri.size()-1] != '/' ) { From ca8fcfc9b8864926c879f3211163465f5509c368 Mon Sep 17 00:00:00 2001 From: rosen Date: Wed, 21 Jun 2023 15:05:30 +0900 Subject: [PATCH 438/477] add GetURIWithUsernamePassword --- include/mujincontrollerclient/mujincontrollerclient.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index ca7e890e..dfaa44f0 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -340,6 +340,9 @@ class MUJINCLIENT_API ControllerClient /// \brief returns the URI used to setup the connection virtual const std::string& GetBaseURI() const = 0; + /// \brief full connection URI with username and password. http://username@password:path + virtual std::string GetURIWithUsernamePassword() const = 0; + /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. From 02c62bfbd1db8b0c6a04d38206f4093d3c67f628 Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 27 Jun 2023 08:43:03 +0900 Subject: [PATCH 439/477] Move ControllerClientInfo to controllerclientcpp. --- src/controllerclientimpl.cpp | 74 ++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 7f0ec4e7..541a2421 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -37,6 +37,63 @@ namespace mujinclient { using namespace mujinjson; +/// \brief given a port string "80", fill ControllerClientInfo httpPort +static void _ParseClientInfoPort(const char* port, size_t length, ControllerClientInfo& clientInfo) +{ + clientInfo.httpPort = 0; + for (; length > 0; ++port, --length) { + clientInfo.httpPort = clientInfo.httpPort * 10 + (*port - '0'); + } +} + +/// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse ControllerClientInfo +static void _ParseClientInfoFromURL(const char* url, ControllerClientInfo& clientInfo) +{ + clientInfo.Reset(); + const char* colonSlashSlash = strstr(url, "://"); + if (colonSlashSlash == nullptr) { + return; + } + const char* hostname = colonSlashSlash + sizeof("://") - 1; + const char* at = strstr(hostname, "@"); // not found is ok + const char* slash = strstr(hostname, "/"); // not found is ok + if (at != nullptr && (slash == nullptr || at < slash)) { + // if the at is before the slash, i.e. for the username:password + const char* usernamePassword = hostname; + hostname = at + sizeof("@") - 1; + const char* colon = strstr(usernamePassword, ":"); // not found is ok + if (colon != nullptr) { + const char* password = colon + sizeof(":") - 1; + clientInfo.username = std::string(usernamePassword, colon - usernamePassword); + clientInfo.password = std::string(password, at - password); + } else { + clientInfo.username = std::string(usernamePassword, at - usernamePassword); + } + } + const char* port = strstr(hostname, ":"); // not found is ok + if (slash == nullptr) { + if (port == nullptr) { + // no port, no slash + clientInfo.host = hostname; + } else { + // has port, no slash + const char* portStart = port + sizeof(":") - 1; + _ParseClientInfoPort(portStart, strlen(portStart), clientInfo); + clientInfo.host = std::string(hostname, port - hostname); + } + } else { + if (port != nullptr && port < slash) { + // has port before slash + const char* portStart = port + sizeof(":") - 1; + _ParseClientInfoPort(portStart, slash - portStart, clientInfo); + clientInfo.host = std::string(hostname, port - hostname); + } else { + // no port, but has slash + clientInfo.host = std::string(hostname, slash - hostname); + } + } +} + template std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) { @@ -94,11 +151,10 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); - size_t usernameindex = 0; - usernameindex = usernamepassword.find_first_of(':'); + const size_t usernameindex = usernamepassword.find_first_of(':'); BOOST_ASSERT(usernameindex != std::string::npos ); - _username = usernamepassword.substr(0,usernameindex); - std::string password = usernamepassword.substr(usernameindex+1); + _username = usernamepassword.substr(0, usernameindex); + const std::string password = usernamepassword.substr(usernameindex + 1); _httpheadersjson = NULL; _httpheadersstl = NULL; @@ -112,6 +168,11 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, // no idea what to do here.. _fulluri = std::string("//") + usernamepassword + "@" + baseuri; } + + _ParseClientInfoFromURL(baseuri.c_str(), _clientInfo); + _clientInfo.username = _username; + _clientInfo.password = password; + _baseuri = baseuri; // ensure trailing slash if( _baseuri[_baseuri.size()-1] != '/' ) { @@ -267,6 +328,11 @@ const std::string& ControllerClientImpl::GetBaseURI() const return _baseuri; } +const ControllerClientInfo& ControllerClientImpl::GetClientInfo() const +{ + return _clientInfo; +} + void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) { boost::mutex::scoped_lock lock(_mutex); From 0699578e3ee6bdc3ab8ced5f39b1d7f54c32bf8f Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 27 Jun 2023 08:43:03 +0900 Subject: [PATCH 440/477] Move ControllerClientInfo to controllerclientcpp. --- .../mujincontrollerclient.h | 30 ++++++++ src/mujincontrollerclient.cpp | 72 +++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index dfaa44f0..e1234591 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -63,6 +63,33 @@ namespace mujinclient { +/// \brief connecting to a controller's webstack +class MUJINCLIENT_API ControllerClientInfo : public mujinjson::JsonSerializable +{ +public: + virtual void Reset(); + + void LoadFromJson(const rapidjson::Value& rClientInfo) override; + void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; + void SaveToJson(rapidjson::Document& rClientInfo) const override; + + bool operator==(const ControllerClientInfo &rhs) const; + bool operator!=(const ControllerClientInfo &rhs) const { + return !operator==(rhs); + } + std::string GetURL(bool bIncludeNamePassword) const; + + inline bool IsEnabled() const { + return !host.empty(); + } + + std::string host; + uint32_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port + std::string username; + std::string password; + bool uploadFilesWithNoModifyDate = false; ///< if true, then any files uploaded will not change the modified date. By default, uploading files changes the modified date. +}; + typedef mujin::Transform Transform; enum TaskResourceOptions @@ -343,6 +370,9 @@ class MUJINCLIENT_API ControllerClient /// \brief full connection URI with username and password. http://username@password:path virtual std::string GetURIWithUsernamePassword() const = 0; + /// \brief returns the client info used to construct this client + virtual const ControllerClientInfo& GetClientInfo() const = 0; + /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index c2ad77ff..d93f3ed4 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -31,6 +31,78 @@ namespace mujinclient { using namespace mujinjson; +void ControllerClientInfo::Reset() +{ + host.clear(); + httpPort = 0; + username.clear(); + password.clear(); + uploadFilesWithNoModifyDate = false; +} + +void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) +{ + mujinjson::LoadJsonValueByKey(rClientInfo, "host", host); + mujinjson::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); + mujinjson::LoadJsonValueByKey(rClientInfo, "username", username); + mujinjson::LoadJsonValueByKey(rClientInfo, "password", password); + mujinjson::LoadJsonValueByKey(rClientInfo, "uploadFilesWithNoModifyDate", uploadFilesWithNoModifyDate); +} + +void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const +{ + rClientInfo.SetObject(); + if( !host.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "host", host, alloc); + } + if( httpPort != 0 ) { + mujinjson::SetJsonValueByKey(rClientInfo, "httpPort", httpPort, alloc); + } + if( !username.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "username", username, alloc); + } + if( !password.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "password", password, alloc); + } + mujinjson::SetJsonValueByKey(rClientInfo, "uploadFilesWithNoModifyDate", uploadFilesWithNoModifyDate, alloc); +} + +void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const +{ + SaveToJson(rClientInfo, rClientInfo.GetAllocator()); +} + +bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const +{ + return host == rhs.host && + httpPort == rhs.httpPort && + username == rhs.username && + password == rhs.password && + uploadFilesWithNoModifyDate == rhs.uploadFilesWithNoModifyDate; +} + +std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const +{ + std::string url; + if( host.empty() ) { + return url; + } + url += "http://"; + if( bIncludeNamePassword ) { + url += username; + url += ":"; + url += password; + url += "@"; + } + + url += host; + if( httpPort != 0 ) { + url += ":"; + url += std::to_string(httpPort); + } + return url; +} + void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) { // FIXME: is this a dict or array? From 3a062cf6ad46450a58eeccffb2403df41ce77cdd Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 27 Jun 2023 14:04:58 +0900 Subject: [PATCH 441/477] Also add additionalHeaders and unixEndpoint in ClientInfo. --- src/controllerclientimpl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 541a2421..0569cc57 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -349,6 +349,7 @@ void ControllerClientImpl::SetProxy(const std::string& serverport, const std::st CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, serverport.c_str()); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); + _clientInfo.unixEndpoint.clear(); } void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) @@ -357,6 +358,7 @@ void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); + _clientInfo.unixEndpoint = unixEndpoint; } void ControllerClientImpl::SetLanguage(const std::string& language) @@ -380,6 +382,7 @@ void ControllerClientImpl::SetAdditionalHeaders(const std::vector& { boost::mutex::scoped_lock lock(_mutex); _additionalHeaders = additionalHeaders; + _clientInfo.additionalHeaders = additionalHeaders; _SetupHTTPHeadersJSON(); _SetupHTTPHeadersSTL(); _SetupHTTPHeadersMultipartFormData(); From 834fd02ef9964200d3b1aa90b2d0f3809f83307c Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 27 Jun 2023 14:04:58 +0900 Subject: [PATCH 442/477] Also add additionalHeaders and unixEndpoint in ClientInfo. --- .../mujincontrollerclient.h | 5 +++-- src/mujincontrollerclient.cpp | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index e1234591..a796938a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -84,10 +84,11 @@ class MUJINCLIENT_API ControllerClientInfo : public mujinjson::JsonSerializable } std::string host; - uint32_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port + uint16_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port std::string username; std::string password; - bool uploadFilesWithNoModifyDate = false; ///< if true, then any files uploaded will not change the modified date. By default, uploading files changes the modified date. + std::vector additionalHeaders; ///< expect each value to be in the format of "Header-Name: header-value" + std::string unixEndpoint; ///< unix socket endpoint for communicating with HTTP server over unix socket }; typedef mujin::Transform Transform; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index d93f3ed4..4be3b564 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -37,7 +37,7 @@ void ControllerClientInfo::Reset() httpPort = 0; username.clear(); password.clear(); - uploadFilesWithNoModifyDate = false; + additionalHeaders.clear(); } void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) @@ -46,7 +46,8 @@ void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) mujinjson::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); mujinjson::LoadJsonValueByKey(rClientInfo, "username", username); mujinjson::LoadJsonValueByKey(rClientInfo, "password", password); - mujinjson::LoadJsonValueByKey(rClientInfo, "uploadFilesWithNoModifyDate", uploadFilesWithNoModifyDate); + mujinjson::LoadJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders); + mujinjson::LoadJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint); } void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const @@ -64,7 +65,12 @@ void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson:: if( !password.empty() ) { mujinjson::SetJsonValueByKey(rClientInfo, "password", password, alloc); } - mujinjson::SetJsonValueByKey(rClientInfo, "uploadFilesWithNoModifyDate", uploadFilesWithNoModifyDate, alloc); + if( !additionalHeaders.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders, alloc); + } + if( !unixEndpoint.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint, alloc); + } } void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const @@ -74,11 +80,12 @@ void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const { - return host == rhs.host && + return host == rhs.host && httpPort == rhs.httpPort && username == rhs.username && password == rhs.password && - uploadFilesWithNoModifyDate == rhs.uploadFilesWithNoModifyDate; + additionalHeaders == rhs.additionalHeaders && + unixEndpoint == rhs.unixEndpoint; } std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const From 1140901208eed6abcd8315ec47d331a7390c58ad Mon Sep 17 00:00:00 2001 From: Ziyan Date: Tue, 27 Jun 2023 14:05:36 +0900 Subject: [PATCH 443/477] Fix typo. --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 0569cc57..2d5213ab 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -358,7 +358,7 @@ void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); - _clientInfo.unixEndpoint = unixEndpoint; + _clientInfo.unixEndpoint = unixendpoint; } void ControllerClientImpl::SetLanguage(const std::string& language) From 794f6562babc311f4d56d499d35caf2961541e8b Mon Sep 17 00:00:00 2001 From: rosen Date: Fri, 30 Jun 2023 10:49:45 +0900 Subject: [PATCH 444/477] update minor ver --- src/mujincontrollerclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 4be3b564..50462edd 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -38,6 +38,7 @@ void ControllerClientInfo::Reset() username.clear(); password.clear(); additionalHeaders.clear(); + unixEndpoint.clear(); } void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) From bfcb8c13cdaa3f565a120300bfb5e3e1ba5270ad Mon Sep 17 00:00:00 2001 From: rosen Date: Fri, 30 Jun 2023 14:05:50 +0900 Subject: [PATCH 445/477] add GetCStringJsonValueByKey that does not allocate anything --- include/mujincontrollerclient/mujinjson.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/mujincontrollerclient/mujinjson.h b/include/mujincontrollerclient/mujinjson.h index 081c4a42..85bed06f 100644 --- a/include/mujincontrollerclient/mujinjson.h +++ b/include/mujincontrollerclient/mujinjson.h @@ -742,6 +742,26 @@ inline std::string GetStringJsonValueByKey(const rapidjson::Value& v, const char return GetJsonValueByKey(v, key, defaultValue); } +/// \brief default value is returned when there is no key or value is null +inline const char* GetCStringJsonValueByKey(const rapidjson::Value& v, const char* key, const char* pDefaultValue=nullptr) { + if (!v.IsObject()) { + throw MujinJSONException("Cannot load value of non-object."); + } + rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); + if (itMember != v.MemberEnd() ) { + const rapidjson::Value& child = itMember->value; + if (!child.IsNull()) { + if( child.IsString() ) { + return child.GetString(); + } + else { + throw MujinJSONException("In GetCStringJsonValueByKey, expecting a String, but got a different object type"); + } + } + } + return pDefaultValue; // not present +} + template inline T GetJsonValueByPath(const rapidjson::Value& v, const char* key) { T r; const rapidjson::Value *child = rapidjson::Pointer(key).Get(v); From 4dd3aebdddd44d9eb6197e03e1f89038f788f942 Mon Sep 17 00:00:00 2001 From: Barkin Simsek Date: Thu, 13 Jul 2023 19:30:36 +0900 Subject: [PATCH 446/477] Add top and bottom radius. --- include/mujincontrollerclient/mujincontrollerclient.h | 2 ++ src/mujincontrollerclient.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h index a796938a..711f7e9a 100644 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ b/include/mujincontrollerclient/mujincontrollerclient.h @@ -765,6 +765,8 @@ class MUJINCLIENT_API ObjectResource : public WebResource Real half_extents[3]; Real height; Real radius; + Real topRadius; + Real bottomRadius; virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 50462edd..09eb3356 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -303,11 +303,13 @@ ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFro /// geomtype /// // mesh // box: half_extents - // cylinder: height, radius + // cylinder: height, topRadius, bottomRadius // sphere: radius LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); LoadJsonValueByKey(*it,"height",geometry->height); LoadJsonValueByKey(*it,"radius",geometry->radius); + LoadJsonValueByKey(*it,"topRadius",geometry->topRadius); + LoadJsonValueByKey(*it,"bottomRadius",geometry->bottomRadius); return geometry; } } @@ -340,6 +342,8 @@ void ObjectResource::LinkResource::GetGeometries(std::vectorhalf_extents); LoadJsonValueByKey(*it,"height",geometry->height); LoadJsonValueByKey(*it,"radius",geometry->radius); + LoadJsonValueByKey(*it,"topRadius",geometry->topRadius); + LoadJsonValueByKey(*it,"bottomRadius",geometry->bottomRadius); geometries.push_back(geometry); } } From c822ed0ffa7c18f74c730b3b408dce6dac60537b Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 18 Jul 2023 09:33:07 -0400 Subject: [PATCH 447/477] set to verbose --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 2d5213ab..4ddc1d05 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -289,7 +289,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _charset = itcodepage->second; } #endif - MUJIN_LOG_INFO("setting character set to " << _charset); + MUJIN_LOG_VERBOSE("setting character set to " << _charset); _SetupHTTPHeadersJSON(); _SetupHTTPHeadersSTL(); _SetupHTTPHeadersMultipartFormData(); From fa881853952af8bb9e3379a2698a5a2ebf45080f Mon Sep 17 00:00:00 2001 From: rosen Date: Tue, 18 Jul 2023 09:34:20 -0400 Subject: [PATCH 448/477] change log level --- src/controllerclientimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 4ddc1d05..9c79f69b 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -748,7 +748,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Doc int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) { - MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); + MUJIN_LOG_DEBUG(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); From 5a7adc3aeafe8aadcfcbfa703d3faea0b7ff8bda Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 20 Jul 2023 15:53:20 +0900 Subject: [PATCH 449/477] Rename files to make the controller client resemble the webstack client --- ...ujinwebstackclient-config-version.cmake.in | 0 ....in => mujinwebstackclient-config.cmake.in | 0 src/binpickingtask.cpp | 2008 ----------------- src/binpickingtaskzmq.cpp | 297 --- src/binpickingtaskzmq.h | 53 - src/controllerclientimpl.h | 293 --- .../mujinwebstackclientcpp/webstackclient.h | 1251 ++++++++++ src/mujincontrollerclient.cpp | 1385 ------------ src/mujindefinitions.cpp | 21 - src/mujinjson.cpp | 113 - src/mujinzmq.cpp | 507 ----- ...ollerclientimpl.cpp => webstackclient.cpp} | 0 12 files changed, 1251 insertions(+), 4677 deletions(-) rename mujincontrollerclient-config-version.cmake.in => mujinwebstackclient-config-version.cmake.in (100%) rename mujincontrollerclient-config.cmake.in => mujinwebstackclient-config.cmake.in (100%) delete mode 100644 src/binpickingtask.cpp delete mode 100644 src/binpickingtaskzmq.cpp delete mode 100644 src/binpickingtaskzmq.h delete mode 100644 src/controllerclientimpl.h create mode 100644 src/include/mujinwebstackclientcpp/webstackclient.h delete mode 100644 src/mujincontrollerclient.cpp delete mode 100644 src/mujindefinitions.cpp delete mode 100644 src/mujinjson.cpp delete mode 100644 src/mujinzmq.cpp rename src/{controllerclientimpl.cpp => webstackclient.cpp} (100%) diff --git a/mujincontrollerclient-config-version.cmake.in b/mujinwebstackclient-config-version.cmake.in similarity index 100% rename from mujincontrollerclient-config-version.cmake.in rename to mujinwebstackclient-config-version.cmake.in diff --git a/mujincontrollerclient-config.cmake.in b/mujinwebstackclient-config.cmake.in similarity index 100% rename from mujincontrollerclient-config.cmake.in rename to mujinwebstackclient-config.cmake.in diff --git a/src/binpickingtask.cpp b/src/binpickingtask.cpp deleted file mode 100644 index cadd052b..00000000 --- a/src/binpickingtask.cpp +++ /dev/null @@ -1,2008 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2016 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "common.h" -#include "controllerclientimpl.h" -#if BOOST_VERSION > 104800 -#include -#endif -#include // for sleep -#include "mujincontrollerclient/binpickingtask.h" - -#ifdef MUJIN_USEZMQ -#include "mujincontrollerclient/zmq.hpp" -#endif - -#ifdef _WIN32 -#include -#define isnan _isnan -#endif - -#include - -#include "logging.h" - -#include -#include -#include -#include "mujincontrollerclient/mujinjson.h" - -MUJIN_LOGGER("mujin.controllerclientcpp.binpickingtask"); - -namespace mujinclient { -using namespace utils; -using namespace mujinjson; - -static void LoadAABBFromJsonValue(const rapidjson::Value& rAABB, mujin::AABB& aabb) -{ - BOOST_ASSERT(rAABB.IsObject()); - BOOST_ASSERT(rAABB.HasMember("pos")); - BOOST_ASSERT(rAABB.HasMember("extents")); - const rapidjson::Value& rPos = rAABB["pos"]; - BOOST_ASSERT(rPos.IsArray()); - mujinjson::LoadJsonValue(rPos[0], aabb.pos[0]); - mujinjson::LoadJsonValue(rPos[1], aabb.pos[1]); - mujinjson::LoadJsonValue(rPos[2], aabb.pos[2]); - const rapidjson::Value& rExtents = rAABB["extents"]; - BOOST_ASSERT(rExtents.IsArray()); - mujinjson::LoadJsonValue(rExtents[0], aabb.extents[0]); - mujinjson::LoadJsonValue(rExtents[1], aabb.extents[1]); - mujinjson::LoadJsonValue(rExtents[2], aabb.extents[2]); -} - -BinPickingResultResource::BinPickingResultResource(ControllerClientPtr controller, const std::string& pk) : PlanningResultResource(controller,"binpickingresult", pk) -{ -} - -BinPickingResultResource::~BinPickingResultResource() -{ -} - -BinPickingTaskResource::BinPickingTaskResource(ControllerClientPtr pcontroller, const std::string& pk, const std::string& scenepk, const std::string& tasktype) : TaskResource(pcontroller,pk), _zmqPort(-1), _heartbeatPort(-1), _tasktype(tasktype), _bIsInitialized(false) -{ - _callerid = str(boost::format("controllerclientcpp%s_web")%MUJINCLIENT_VERSION_STRING); - _scenepk = scenepk; - // get hostname from uri - GETCONTROLLERIMPL(); - const std::string baseuri = controller->GetBaseUri(); - std::string::const_iterator uriend = baseuri.end(); - // query start - std::string::const_iterator querystart = std::find(baseuri.begin(), uriend, '?'); - // protocol - std::string protocol; - std::string::const_iterator protocolstart = baseuri.begin(); - std::string::const_iterator protocolend = std::find(protocolstart, uriend, ':'); - if (protocolend != uriend) { - std::string p = &*(protocolend); - if ((p.length() > 3) & (p.substr(0,3) == "://")) { - protocol = std::string(protocolstart, protocolend); - protocolend +=3; - } else { - protocolend = baseuri.begin(); - } - } else { - protocolend = baseuri.begin(); - } - // host - std::string::const_iterator hoststart = protocolend; - std::string::const_iterator pathstart = std::find(hoststart, uriend, '/'); - std::string::const_iterator hostend = std::find(protocolend, (pathstart != uriend) ? pathstart : querystart, ':'); - _mujinControllerIp = std::string(hoststart, hostend); - - { - /// HACK until can think of proper way to send sceneparams - std::string scenebasename = pcontroller->GetNameFromPrimaryKey_UTF8(scenepk); - - _rSceneParams.SetObject(); - mujinjson::SetJsonValueByKey(_rSceneParams, "scenetype", "mujin"); - mujinjson::SetJsonValueByKey(_rSceneParams, "sceneuri", std::string("mujin:/")+scenebasename); - - // should stop sending scenefilename since it is a hack! - std::string MUJIN_MEDIA_ROOT_DIR = "/var/www/media/u"; - char* pMUJIN_MEDIA_ROOT_DIR = getenv("MUJIN_MEDIA_ROOT_DIR"); - if( !!pMUJIN_MEDIA_ROOT_DIR ) { - MUJIN_MEDIA_ROOT_DIR = pMUJIN_MEDIA_ROOT_DIR; - } - - std::string scenefilename = MUJIN_MEDIA_ROOT_DIR + std::string("/") + pcontroller->GetUserName() + std::string("/") + scenebasename; - mujinjson::SetJsonValueByKey(_rSceneParams, "scenefilename", scenefilename); - _sceneparams_json = mujinjson::DumpJson(_rSceneParams); - } -} - -BinPickingTaskResource::~BinPickingTaskResource() -{ - _bShutdownHeartbeatMonitor = true; - if (!!_pHeartbeatMonitorThread) { - _pHeartbeatMonitorThread->join(); - } -} - -void BinPickingTaskResource::Initialize(const std::string& defaultTaskParameters, const double timeout, const std::string& userinfo, const std::string& slaverequestid) -{ - if( defaultTaskParameters.size() > 0 ) { - _mapTaskParameters.clear(); - rapidjson::Document d; - d.Parse(defaultTaskParameters.c_str()); - for (rapidjson::Value::ConstMemberIterator it = d.MemberBegin(); it != d.MemberEnd(); ++it) { - rapidjson::StringBuffer stringbuffer; - rapidjson::Writer writer(stringbuffer); - it->value.Accept(writer); - _mapTaskParameters[it->name.GetString()] = std::string(stringbuffer.GetString(), stringbuffer.GetSize()); - } - } - - _bIsInitialized = true; - ParseJson(_rUserInfo, userinfo); - _userinfo_json = userinfo; - _slaverequestid = slaverequestid; -} - -void BinPickingTaskResource::SetCallerId(const std::string& callerid) -{ - _callerid = callerid; -} - -const std::string& BinPickingTaskResource::_GetCallerId() const -{ - return _callerid; -} - -#ifdef MUJIN_USEZMQ -void BinPickingTaskResource::Initialize(const std::string& defaultTaskParameters, const int zmqPort, const int heartbeatPort, boost::shared_ptr zmqcontext, const bool initializezmq, const double reinitializetimeout, const double timeout, const std::string& userinfo, const std::string& slaverequestid) -{ - - if( defaultTaskParameters.size() > 0 ) { - _mapTaskParameters.clear(); - rapidjson::Document d; - d.Parse(defaultTaskParameters.c_str()); - for (rapidjson::Value::ConstMemberIterator it = d.MemberBegin(); it != d.MemberEnd(); ++it) { - rapidjson::StringBuffer stringbuffer; - rapidjson::Writer writer(stringbuffer); - it->value.Accept(writer); - _mapTaskParameters[it->name.GetString()] = std::string(stringbuffer.GetString(), stringbuffer.GetSize()); - } - } - - _zmqPort = zmqPort; - _heartbeatPort = heartbeatPort; - _bIsInitialized = true; - _zmqcontext = zmqcontext; - ParseJson(_rUserInfo, userinfo); - _userinfo_json = userinfo; - _slaverequestid = slaverequestid; -} -#endif - -void BinPickingResultResource::GetResultJson(rapidjson::Document& pt) const -{ - GETCONTROLLERIMPL(); - //rapidjson::Document d(rapidjson::kObjectType); - controller->CallGet(boost::str(boost::format("%s/%s/?format=json&limit=1")%GetResourceName()%GetPrimaryKey()), pt); - // in this way we don't copy - rapidjson::Value v; - v.Swap(pt["output"]); - v.Swap(pt); -} - -std::string utils::GetJsonString(const std::string& str) -{ - std::string newstr = str; -#if BOOST_VERSION > 104800 - boost::replace_all(newstr, "\"", "\\\""); -#else - std::vector< std::pair > serachpairs(1); - serachpairs[0].first = "\""; serachpairs[0].second = "\\\""; - SearchAndReplace(newstr, str, serachpairs); -#endif - return "\""+newstr+"\""; -} - -std::string utils::GetJsonString (const std::vector& vec) -{ - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "["; - for (unsigned int i = 0; i < vec.size(); ++i) { - ss << vec[i]; - if (i != vec.size() - 1) { - ss << ", "; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString (const std::vector& vec) -{ - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "["; - for (unsigned int i = 0; i < vec.size(); ++i) { - ss << vec[i]; - if (i != vec.size() - 1) { - ss << ", "; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString (const std::vector& vec) -{ - std::stringstream ss; - ss << "["; - for (unsigned int i = 0; i < vec.size(); ++i) { - ss << vec[i]; - if (i != vec.size() - 1) { - ss << ", "; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString(const std::vector& vec) -{ - std::stringstream ss; - ss << "["; - for (unsigned int i = 0; i < vec.size(); ++i) { - ss << GetJsonString(vec[i]); - if (i != vec.size() - 1) { - ss << ", "; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString(const Transform& transform) -{ - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); - // \"translation\":[%.15f, %.15f, %.15f], \"quaternion\":[%.15f, %.15f, %.15f, %.15f] - ss << GetJsonString("translation") << ": ["; - for (unsigned int i=0; i<3; i++) { - ss << transform.translate[i]; - if (i!=3-1) { - ss << ", "; - } - } - ss << "], "; - ss << GetJsonString("quaternion") << ": ["; - for (unsigned int i=0; i<4; i++) { - ss << transform.quaternion[i]; - if (i!=4-1) { - ss << ", "; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString(const BinPickingTaskResource::DetectedObject& obj) -{ - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); - //"{\"name\": \"obj\",\"translation_\":[100,200,300],\"quat_\":[1,0,0,0],\"confidence\":0.5}" - ss << "{"; - ss << GetJsonString("name") << ": " << GetJsonString(obj.name) << ", "; - ss << GetJsonString("object_uri") << ": " << GetJsonString(obj.object_uri) << ", "; - ss << GetJsonString("translation_") << ": ["; - for (unsigned int i=0; i<3; i++) { - ss << obj.transform.translate[i]; - if (i!=3-1) { - ss << ", "; - } - } - ss << "], "; - ss << GetJsonString("quat_") << ": ["; - for (unsigned int i=0; i<4; i++) { - ss << obj.transform.quaternion[i]; - if (i!=4-1) { - ss << ", "; - } - } - ss << "], "; - ss << GetJsonString("confidence") << ": " << obj.confidence; - ss << ", " << GetJsonString("sensortimestamp") << ": " << obj.timestamp; - ss << ", " << GetJsonString("isPickable") << ": " << obj.isPickable; - if( obj.extra.size() > 0 ) { - ss << ", " << GetJsonString("extra") << ": " << obj.extra; - } - ss << "}"; - return ss.str(); -} - -std::string utils::GetJsonString(const BinPickingTaskResource::PointCloudObstacle& obj) -{ - std::stringstream ss; - ss << std::setprecision(std::numeric_limits::digits10+1); // want to control the size of the JSON file outputted - // "\"name\": __dynamicobstacle__, \"pointsize\": 0.005, \"points\": [] - ss << GetJsonString("pointcloudid") << ": " << GetJsonString(obj.name) << ", "; - ss << GetJsonString("pointsize") << ": " << obj.pointsize <<", "; - - ss << GetJsonString("points") << ": " << "["; - bool bwrite = false; - for (unsigned int i = 0; i < obj.points.size(); i+=3) { - if( !isnan(obj.points[i]) && !isnan(obj.points[i+1]) && !isnan(obj.points[i+2]) ) { // sometimes point clouds can have NaNs, although it's a bug on detectors sending bad point clouds, these points can usually be ignored. - if( bwrite ) { - ss << ","; - } - ss << obj.points[i] << "," << obj.points[i+1] << "," << obj.points[i+2]; - bwrite = true; - } - } - ss << "]"; - return ss.str(); -} - -std::string utils::GetJsonString(const BinPickingTaskResource::SensorOcclusionCheck& check) -{ - std::stringstream ss; - ss << GetJsonString("bodyname") << ": " << GetJsonString(check.bodyname) << ", "; - ss << GetJsonString("cameraname") << ": " << GetJsonString(check.cameraname) << ", "; - ss << GetJsonString("starttime") << ": " << check.starttime <<", "; - ss << GetJsonString("endtime") << ": " << check.endtime; - return ss.str(); -} - -std::string utils::GetJsonString(const std::string& key, const std::string& value) -{ - std::stringstream ss; - ss << GetJsonString(key) << ": " << GetJsonString(value); - return ss.str(); -} - -std::string utils::GetJsonString(const std::string& key, const int value) -{ - std::stringstream ss; - ss << GetJsonString(key) << ": " << value; - return ss.str(); -} - -std::string utils::GetJsonString(const std::string& key, const unsigned long long value) -{ - std::stringstream ss; - ss << GetJsonString(key) << ": " << value; - return ss.str(); -} - -std::string utils::GetJsonString(const std::string& key, const Real value) -{ - std::stringstream ss; - ss << GetJsonString(key) << ": " << value; - return ss.str(); -} - -BinPickingTaskResource::ResultGetJointValues::~ResultGetJointValues() -{ -} - -void BinPickingTaskResource::ResultGetJointValues::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - - LoadJsonValueByKey(v, "robottype", robottype); - LoadJsonValueByKey(v, "jointnames", jointnames); - LoadJsonValueByKey(v, "currentjointvalues", currentjointvalues); - tools.clear(); - if (v.HasMember("tools")) { - const rapidjson::Value &toolsjson = v["tools"]; - for (rapidjson::Document::ConstMemberIterator it = toolsjson.MemberBegin(); it != toolsjson.MemberEnd(); it++) { - Transform transform; - LoadJsonValueByKey(it->value, "translate", transform.translate); - LoadJsonValueByKey(it->value, "quaternion", transform.quaternion); - tools[it->name.GetString()] = transform; - } - } -} - -BinPickingTaskResource::ResultMoveJoints::~ResultMoveJoints() -{ -} - -void BinPickingTaskResource::ResultMoveJoints::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - LoadJsonValueByKey(v, "robottype", robottype); - LoadJsonValueByKey(v, "timedjointvalues", timedjointvalues); - LoadJsonValueByKey(v, "numpoints", numpoints); -} - -BinPickingTaskResource::ResultTransform::~ResultTransform() -{ -} - -void BinPickingTaskResource::ResultTransform::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - - LoadJsonValueByKey(v, "translation", transform.translate); - LoadJsonValueByKey(v, "quaternion", transform.quaternion); -} - -BinPickingTaskResource::ResultInstObjectInfo::~ResultInstObjectInfo() -{ -} - -void BinPickingTaskResource::ResultInstObjectInfo::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& rOutput = pt["output"]; - - LoadJsonValueByKey(rOutput, "translation", instobjecttransform.translate); - LoadJsonValueByKey(rOutput, "quaternion", instobjecttransform.quaternion); - instobjectobb.Parse(rOutput["obb"]); - instobjectinnerobb.Parse(rOutput["innerobb"]); - - if( rOutput.HasMember("geometryInfos") ) { - mujinjson::SaveJsonValue(rGeometryInfos, rOutput["geometryInfos"]); - } - - if( rOutput.HasMember("ikparams") ) { - mujinjson::SaveJsonValue(rIkParams, rOutput["ikparams"]); - } -} - -BinPickingTaskResource::ResultGetInstObjectAndSensorInfo::~ResultGetInstObjectAndSensorInfo() -{ -} - -void BinPickingTaskResource::ResultGetInstObjectAndSensorInfo::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& output = pt["output"]; - - mrGeometryInfos.clear(); - - const rapidjson::Value& instobjects = output["instobjects"]; - for (rapidjson::Document::ConstMemberIterator it = instobjects.MemberBegin(); it != instobjects.MemberEnd(); it++) { - std::string objname = it->name.GetString(); - Transform transform; - ResultOBB resultobb, resultinnerobb; - LoadJsonValueByKey(it->value, "translation", transform.translate); - LoadJsonValueByKey(it->value, "quaternion", transform.quaternion); - resultobb.Parse(it->value["obb"]); - resultinnerobb.Parse(it->value["innerobb"]); - - minstobjecttransform[objname] = transform; - minstobjectobb[objname] = resultobb; - minstobjectinnerobb[objname] = resultinnerobb; - - if( it->value.HasMember("geometryInfos") ) { - boost::shared_ptr pr(new rapidjson::Document());; - mujinjson::SaveJsonValue(*pr, it->value["geometryInfos"]); - mrGeometryInfos[objname] = pr; - } - - LoadJsonValueByKey(it->value, "uri", muri[objname]); - } - - const rapidjson::Value& sensors = output["sensors"]; - for (rapidjson::Document::ConstMemberIterator it = sensors.MemberBegin(); it != sensors.MemberEnd(); it++) { - mujin::SensorSelectionInfo sensorSelectionInfo; - LoadJsonValue(it->name, sensorSelectionInfo.sensorName); - for (rapidjson::Document::ConstMemberIterator itlink = it->value.MemberBegin(); itlink != it->value.MemberEnd(); itlink++) { - LoadJsonValue(itlink->name, sensorSelectionInfo.sensorLinkName); - Transform transform; - RobotResource::AttachedSensorResource::SensorData sensordata; - LoadJsonValueByKey(itlink->value, "translation", transform.translate); - LoadJsonValueByKey(itlink->value, "quaternion", transform.quaternion); - - const rapidjson::Value &sensor = itlink->value["sensordata"]; - LoadJsonValueByKey(sensor, "distortion_coeffs", sensordata.distortion_coeffs); - LoadJsonValueByKey(sensor, "intrinsic", sensordata.intrinsic); - - std::vector imagedimensions; - LoadJsonValueByKey(sensor, "image_dimensions", imagedimensions); - if (imagedimensions.size() == 2) { - imagedimensions.push_back(1); - } - if (imagedimensions.size() != 3) { - throw MujinException("the length of image_dimensions is invalid", MEC_Failed); - } - for (int i = 0; i < 3; i++) { - sensordata.image_dimensions[i] = imagedimensions[i]; - } - - LoadJsonValueByKey(sensor, "extra_parameters", sensordata.extra_parameters); - LoadJsonValueByKey(sensor, "distortion_model", sensordata.distortion_model); - LoadJsonValueByKey(sensor, "focal_length", sensordata.focal_length); - LoadJsonValueByKey(sensor, "measurement_time", sensordata.measurement_time); - - msensortransform[sensorSelectionInfo] = transform; - msensordata[sensorSelectionInfo] = sensordata; - } - } -} - -BinPickingTaskResource::ResultGetBinpickingState::ResultGetBinpickingState() : - statusPickPlace(""), - statusDescPickPlace(""), - statusPhysics(""), - isDynamicEnvironmentStateEmpty(false), - pickAttemptFromSourceId(-1), - timestamp(0), - lastGrabbedTargetTimeStamp(0), - isGrabbingTarget(true), - isGrabbingLastTarget(true), - hasRobotExecutionStarted(false), - orderNumber(-1), - numLeftInOrder(-1), - numLeftInSupply(-1), - placedInDest(-1) -{ -} - -BinPickingTaskResource::ResultGetBinpickingState::~ResultGetBinpickingState() -{ -} - -void BinPickingTaskResource::ResultGetBinpickingState::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - - statusPickPlace = GetJsonValueByKey(v, "statusPickPlace", "unknown"); - statusDescPickPlace = GetJsonValueByKey(v, "statusDescPickPlace", "unknown"); - cycleIndex = GetJsonValueByKey(v, "statusPickPlaceCycleIndex", ""); - statusPhysics = GetJsonValueByKey(v, "statusPhysics", "unknown"); - pickAttemptFromSourceId = GetJsonValueByKey(v, "pickAttemptFromSourceId", -1); - //isContainerEmptyMap.clear(); - //LoadJsonValueByKey(v, "isContainerEmptyMap", isContainerEmptyMap); - //lastInsideSourceTimeStamp = (unsigned long long)(GetJsonValueByKey(v, "lastInsideSourceTimeStamp", 0) * 1000.0); // s -> ms - //lastInsideDestTimeStamp = (unsigned long long)(GetJsonValueByKey(v, "lastInsideDestTimeStamp", 0) * 1000.0); // s -> ms - timestamp = (unsigned long long)(GetJsonValueByKey(v, "timestamp", 0) * 1000.0); // s -> ms - lastGrabbedTargetTimeStamp = (unsigned long long)(GetJsonValueByKey(v, "lastGrabbedTargetTimeStamp", 0) * 1000.0); // s -> ms - - vOcclusionResults.clear(); - const rapidjson::Value::ConstMemberIterator itOcclusionResults = v.FindMember("occlusionResults"); - if( itOcclusionResults != v.MemberEnd() && itOcclusionResults->value.IsArray() ) { - vOcclusionResults.resize(itOcclusionResults->value.Size()); - for(int iocc = 0; iocc < (int)vOcclusionResults.size(); ++iocc) { - const rapidjson::Value& result = itOcclusionResults->value[iocc]; - vOcclusionResults[iocc].sensorSelectionInfo = GetJsonValueByKey(result, "sensorSelectionInfo", mujin::SensorSelectionInfo()); - vOcclusionResults[iocc].bodyname = GetJsonValueByKey(result, "bodyname", std::string()); - vOcclusionResults[iocc].isocclusion = GetJsonValueByKey(result, "isocclusion", -1); - } - } - - isGrabbingTarget = GetJsonValueByKey(v, "isGrabbingTarget", true); - isGrabbingLastTarget = GetJsonValueByKey(v, "isGrabbingLastTarget", true); - hasRobotExecutionStarted = GetJsonValueByKey(v, "hasRobotExecutionStarted", false); - orderNumber = GetJsonValueByPath(v, "/orderstate/orderNumber", -1); - numLeftInOrder = GetJsonValueByPath(v, "/orderstate/numLeftInOrder", -1); - numLeftInSupply = GetJsonValueByPath(v, "/orderstate/numLeftInSupply", -1); - placedInDest = GetJsonValueByPath(v, "/orderstate/placedInDest", -1); - - registerMinViableRegionInfo.locationName = GetJsonValueByPath(v, "/registerMinViableRegionInfo/locationName", std::string()); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/translation_", registerMinViableRegionInfo.translation_); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/quat_", registerMinViableRegionInfo.quat_); - registerMinViableRegionInfo.objectWeight = GetJsonValueByPath(v, "/registerMinViableRegionInfo/objectWeight", 0); - registerMinViableRegionInfo.sensorTimeStampMS = GetJsonValueByPath(v, "/registerMinViableRegionInfo/sensorTimeStampMS", 0); - registerMinViableRegionInfo.robotDepartStopTimestamp = GetJsonValueByPath(v, "/registerMinViableRegionInfo/robotDepartStopTimestamp", 0); - registerMinViableRegionInfo.transferSpeedPostMult = GetJsonValueByPath(v, "/registerMinViableRegionInfo/transferSpeedPostMult", 1.0); - { - registerMinViableRegionInfo.graspModelInfo.SetNull(); - registerMinViableRegionInfo.graspModelInfo.GetAllocator().Clear(); - const rapidjson::Value* graspModelInfoJson = rapidjson::Pointer("/registerMinViableRegionInfo/graspModelInfo").Get(v); - if( !!graspModelInfoJson && graspModelInfoJson->IsObject() ) { - registerMinViableRegionInfo.graspModelInfo.CopyFrom(*graspModelInfoJson, registerMinViableRegionInfo.graspModelInfo.GetAllocator()); - } - } - registerMinViableRegionInfo.minCornerVisibleDist = GetJsonValueByPath(v, "/registerMinViableRegionInfo/minCornerVisibleDist", 30); - registerMinViableRegionInfo.minCornerVisibleInsideDist = GetJsonValueByPath(v, "/registerMinViableRegionInfo/minCornerVisibleInsideDist", 0); - registerMinViableRegionInfo.maxCornerAngleDeviation = GetJsonValueByPath(v, "/registerMinViableRegionInfo/maxCornerAngleDeviation", 0); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/minViableRegion/size2D", registerMinViableRegionInfo.minViableRegion.size2D); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/minViableRegion/maxPossibleSize", registerMinViableRegionInfo.minViableRegion.maxPossibleSize); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/minViableRegion/maxPossibleSizeOriginal", registerMinViableRegionInfo.minViableRegion.maxPossibleSizeOriginal, registerMinViableRegionInfo.minViableRegion.maxPossibleSize); - registerMinViableRegionInfo.minViableRegion.cornerMask = GetJsonValueByPath(v, "/registerMinViableRegionInfo/minViableRegion/cornerMask", 0); - registerMinViableRegionInfo.minViableRegion.cornerMaskOriginal = GetJsonValueByPath(v, "/registerMinViableRegionInfo/minViableRegion/cornerMaskOriginal", 0); - registerMinViableRegionInfo.occlusionFreeCornerMask = GetJsonValueByPath(v, "/registerMinViableRegionInfo/occlusionFreeCornerMask", 0); - const uint8_t registrationMode = GetJsonValueByPath(v, "/registerMinViableRegionInfo/registrationMode", MVRRM_Drag); - if( registrationMode > MVRRM_PerpendicularDrag ) { - throw MujinException(str(boost::format("got unexpected value %d when receiving /registerMinViableRegionInfo/registrationMode. assuming 'drag'")%(int)registrationMode), MEC_InvalidArguments); - } - else { - registerMinViableRegionInfo.registrationMode = static_cast(registrationMode); - } - registerMinViableRegionInfo.maxPossibleSizePadding = GetJsonValueByPath(v, "/registerMinViableRegionInfo/maxPossibleSizePadding", 30); - registerMinViableRegionInfo.skipAppendingToObjectSet = GetJsonValueByPath(v, "/registerMinViableRegionInfo/skipAppendingToObjectSet", false); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/liftedWorldOffset", registerMinViableRegionInfo.liftedWorldOffset); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/minCandidateSize", registerMinViableRegionInfo.minCandidateSize); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/maxCandidateSize", registerMinViableRegionInfo.maxCandidateSize); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/fullDofValues", registerMinViableRegionInfo.fullDofValues); - LoadJsonValueByPath(v, "/registerMinViableRegionInfo/connectedBodyActiveStates", registerMinViableRegionInfo.connectedBodyActiveStates); - - removeObjectFromObjectListInfos.clear(); - if( v.HasMember("removeObjectsFromObjectList") && v["removeObjectsFromObjectList"].IsArray()) { - const rapidjson::Value& rRemoveObjectFromObjectList = v["removeObjectsFromObjectList"]; - removeObjectFromObjectListInfos.resize(rRemoveObjectFromObjectList.Size()); - for(int iitem = 0; iitem < (int)removeObjectFromObjectListInfos.size(); ++iitem) { - const rapidjson::Value& rInfo = rRemoveObjectFromObjectList[iitem]; - removeObjectFromObjectListInfos[iitem].timestamp = GetJsonValueByKey(rInfo, "timestamp", 0); - removeObjectFromObjectListInfos[iitem].objectPk = GetJsonValueByKey(rInfo, "objectPk", std::string()); - } - } - - triggerDetectionCaptureInfo.timestamp = GetJsonValueByPath(v, "/triggerDetectionCaptureInfo/timestamp", 0); - triggerDetectionCaptureInfo.triggerType = GetJsonValueByPath(v, "/triggerDetectionCaptureInfo/triggerType", ""); - triggerDetectionCaptureInfo.locationName = GetJsonValueByPath(v, "/triggerDetectionCaptureInfo/locationName", ""); - triggerDetectionCaptureInfo.targetupdatename = GetJsonValueByPath(v, "/triggerDetectionCaptureInfo/targetupdatename", ""); - - activeLocationTrackingInfos.clear(); - if( v.HasMember("activeLocationTrackingInfos") && v["activeLocationTrackingInfos"].IsArray()) { - const rapidjson::Value& rLocationTrackingInfo = v["activeLocationTrackingInfos"]; - activeLocationTrackingInfos.resize(rLocationTrackingInfo.Size()); - for(int iitem = 0; iitem < (int)rLocationTrackingInfo.Size(); ++iitem) { - const rapidjson::Value& rInfo = rLocationTrackingInfo[iitem]; - activeLocationTrackingInfos[iitem].locationName = GetJsonValueByKey(rInfo, "locationName", std::string()); - activeLocationTrackingInfos[iitem].containerId = GetJsonValueByKey(rInfo, "containerId", std::string()); - activeLocationTrackingInfos[iitem].containerName = GetJsonValueByKey(rInfo, "containerName", std::string()); - activeLocationTrackingInfos[iitem].containerUsage = GetJsonValueByKey(rInfo, "containerUsage", std::string()); - activeLocationTrackingInfos[iitem].cycleIndex = GetJsonValueByKey(rInfo, "cycleIndex", std::string()); - } - } - - locationExecutionInfos.clear(); - if( v.HasMember("locationExecutionInfos") && v["locationExecutionInfos"].IsArray()) { - const rapidjson::Value& rLocationTrackingInfo = v["locationExecutionInfos"]; - locationExecutionInfos.resize(rLocationTrackingInfo.Size()); - for(int iitem = 0; iitem < (int)rLocationTrackingInfo.Size(); ++iitem) { - const rapidjson::Value& rInfo = rLocationTrackingInfo[iitem]; - locationExecutionInfos[iitem].locationName = GetJsonValueByKey(rInfo, "locationName", std::string()); - locationExecutionInfos[iitem].containerId = GetJsonValueByKey(rInfo, "containerId", std::string()); - locationExecutionInfos[iitem].forceRequestStampMS = GetJsonValueByKey(rInfo, "forceRequestStampMS", 0); - locationExecutionInfos[iitem].lastInsideContainerStampMS = GetJsonValueByKey(rInfo, "lastInsideContainerStampMS", 0); - locationExecutionInfos[iitem].needContainerState = GetJsonValueByKey(rInfo, "needContainerState", std::string()); - } - } - - pickPlaceHistoryItems.clear(); - if( v.HasMember("pickPlaceHistoryItems") && v["pickPlaceHistoryItems"].IsArray() ) { - pickPlaceHistoryItems.resize(v["pickPlaceHistoryItems"].Size()); - for(int iitem = 0; iitem < (int)pickPlaceHistoryItems.size(); ++iitem) { - const rapidjson::Value& rItem = v["pickPlaceHistoryItems"][iitem]; - pickPlaceHistoryItems[iitem].pickPlaceType = GetJsonValueByKey(rItem, "pickPlaceType", std::string()); - pickPlaceHistoryItems[iitem].locationName = GetJsonValueByKey(rItem, "locationName", std::string()); - pickPlaceHistoryItems[iitem].eventTimeStampUS = GetJsonValueByKey(rItem, "eventTimeStampUS", 0); - pickPlaceHistoryItems[iitem].object_uri = GetJsonValueByKey(rItem, "object_uri", std::string()); - - pickPlaceHistoryItems[iitem].objectpose = Transform(); - const rapidjson::Value::ConstMemberIterator itPose = rItem.FindMember("objectpose"); - if( itPose != rItem.MemberEnd() ) { - const rapidjson::Value& rObjectPose = itPose->value;; - if( rObjectPose.IsArray() && rObjectPose.Size() == 7 ) { - LoadJsonValue(rObjectPose[0], pickPlaceHistoryItems[iitem].objectpose.quaternion[0]); - LoadJsonValue(rObjectPose[1], pickPlaceHistoryItems[iitem].objectpose.quaternion[1]); - LoadJsonValue(rObjectPose[2], pickPlaceHistoryItems[iitem].objectpose.quaternion[2]); - LoadJsonValue(rObjectPose[3], pickPlaceHistoryItems[iitem].objectpose.quaternion[3]); - LoadJsonValue(rObjectPose[4], pickPlaceHistoryItems[iitem].objectpose.translate[0]); - LoadJsonValue(rObjectPose[5], pickPlaceHistoryItems[iitem].objectpose.translate[1]); - LoadJsonValue(rObjectPose[6], pickPlaceHistoryItems[iitem].objectpose.translate[2]); - } - } - - pickPlaceHistoryItems[iitem].localaabb = mujin::AABB(); - const rapidjson::Value::ConstMemberIterator itLocalAABB = rItem.FindMember("localaabb"); - if( itLocalAABB != rItem.MemberEnd() ) { - const rapidjson::Value& rLocalAABB = itLocalAABB->value; - LoadAABBFromJsonValue(rLocalAABB, pickPlaceHistoryItems[iitem].localaabb); - } - - pickPlaceHistoryItems[iitem].sensorTimeStampUS = GetJsonValueByKey(rItem, "sensorTimeStampUS", 0); - } - } -} - -BinPickingTaskResource::ResultGetBinpickingState::RegisterMinViableRegionInfo::RegisterMinViableRegionInfo() : - objectWeight(0.0), - sensorTimeStampMS(0), - robotDepartStopTimestamp(0), - transferSpeedPostMult(1.0), - minCornerVisibleDist(30), - minCornerVisibleInsideDist(0), - occlusionFreeCornerMask(0), - skipAppendingToObjectSet(false), - maxPossibleSizePadding(30) -{ - translation_.fill(0); - quat_.fill(0); - liftedWorldOffset.fill(0); - maxCandidateSize.fill(0); - minCandidateSize.fill(0); -} - -BinPickingTaskResource::ResultGetBinpickingState::RegisterMinViableRegionInfo::MinViableRegionInfo::MinViableRegionInfo() : - cornerMask(0) -{ - size2D.fill(0); - maxPossibleSize.fill(0); - maxPossibleSizeOriginal.fill(0); -} - -BinPickingTaskResource::ResultGetBinpickingState::RemoveObjectFromObjectListInfo::RemoveObjectFromObjectListInfo() : - timestamp(0) -{ -} - -BinPickingTaskResource::ResultGetBinpickingState::TriggerDetectionCaptureInfo::TriggerDetectionCaptureInfo() : - timestamp(0) -{ -} - -BinPickingTaskResource::ResultIsRobotOccludingBody::~ResultIsRobotOccludingBody() -{ -} - -void BinPickingTaskResource::ResultIsRobotOccludingBody::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - if (!v.IsObject() || !v.HasMember("occluded")) { - throw MujinException("Output does not have \"occluded\" attribute!", MEC_Failed); - } - result = GetJsonValueByKey(v, "occluded", 1) == 1; -} - -void BinPickingTaskResource::ResultGetPickedPositions::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - for (rapidjson::Document::ConstMemberIterator value = v.MemberBegin(); value != v.MemberEnd(); ++value) { - if (std::string(value->name.GetString()) == "positions" && value->value.IsArray()) { - for (rapidjson::Document::ConstValueIterator it = value->value.Begin(); it != value->value.End(); ++it) { - if (it->IsArray() && it->Size() >= 8) { - Transform transform; - for (int i = 0; i < 4; i++) { - transform.quaternion[i] = (*it)[i].GetDouble(); - } - for (int i = 0; i < 3; i++) { - transform.translate[i] = (*it)[i + 4].GetDouble(); - } - transforms.push_back(transform); - timestamps.push_back((*it)[7].GetInt64()); - } - } - } - } -} - -void BinPickingTaskResource::ResultAABB::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - LoadJsonValueByKey(v, "pos", pos); - LoadJsonValueByKey(v, "extents", extents); - if (pos.size() != 3) { - throw MujinException("The length of pos is invalid.", MEC_Failed); - } - if (extents.size() != 3) { - throw MujinException("The length of extents is invalid.", MEC_Failed); - } -} - -void BinPickingTaskResource::ResultOBB::Parse(const rapidjson::Value& pt) -{ - const rapidjson::Value& v = (pt.IsObject()&&pt.HasMember("output") ? pt["output"] : pt); - - LoadJsonValueByKey(v, "translation", translation); - LoadJsonValueByKey(v, "extents", extents); - std::vector > rotationmatrix2d; - LoadJsonValueByKey(v, "rotationmat", rotationmatrix2d); - if (translation.size() != 3) { - throw MujinException("The length of translation is invalid.", MEC_Failed); - } - if (extents.size() != 3) { - throw MujinException("The length of extents is invalid.", MEC_Failed); - } - if (rotationmatrix2d.size() != 3 || rotationmatrix2d[0].size() != 3 || rotationmatrix2d[1].size() != 3 || rotationmatrix2d[2].size() != 3) { - throw MujinException("The row number of rotationmat is invalid.", MEC_Failed); - } - - rotationmat.resize(9); - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - rotationmat[i*3+j] = rotationmatrix2d[i][j]; - } - } - - LoadJsonValueByKey(v, "quaternion", quaternion); -} - -void BinPickingTaskResource::ResultComputeIkParamPosition::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v = pt["output"]; - LoadJsonValueByKey(v, "translation", translation); - LoadJsonValueByKey(v, "quaternion", quaternion); - LoadJsonValueByKey(v, "direction", direction); - LoadJsonValueByKey(v, "angleXZ", angleXZ); - LoadJsonValueByKey(v, "angleYX", angleYX); - LoadJsonValueByKey(v, "angleZY", angleZY); - LoadJsonValueByKey(v, "angleX", angleX); - LoadJsonValueByKey(v, "angleY", angleY); - LoadJsonValueByKey(v, "angleZ", angleZ); - - if (translation.size() != 3) { - throw MujinException("The length of translation is invalid.", MEC_Failed); - } - if (quaternion.size() != 4) { - throw MujinException("The length of quaternion is invalid.", MEC_Failed); - } - if (direction.size() != 3) { - throw MujinException("The length of direction is invalid.", MEC_Failed); - } -} - -void BinPickingTaskResource::ResultComputeIKFromParameters::Parse(const rapidjson::Value& pt) -{ - BOOST_ASSERT(pt.IsObject() && pt.HasMember("output")); - const rapidjson::Value& v_ = pt["output"]; - BOOST_ASSERT(v_.IsObject() && v_.HasMember("solutions")); - const rapidjson::Value& v = v_["solutions"]; - for (rapidjson::Document::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { - std::vector dofvalues_; - std::string extra_; - LoadJsonValueByKey(*it, "dofvalues", dofvalues_); - extra_ = DumpJson((*it)["extra"]); - dofvalues.push_back(dofvalues_); - extra.push_back(extra_); - } -} - -BinPickingTaskResource::ResultHeartBeat::~ResultHeartBeat() -{ -} - -void BinPickingTaskResource::ResultHeartBeat::Parse(const rapidjson::Value& pt) -{ - status = ""; - msg = ""; - timestamp = 0; - LoadJsonValueByKey(pt, "status", status); - LoadJsonValueByKey(pt, "message",msg); - LoadJsonValueByKey(pt, "timestamp", timestamp); - if (pt.HasMember("slavestates") && _slaverequestid.size() > 0) { - rapidjson::Document d(rapidjson::kObjectType), taskstatejson; - std::string key = "slaverequestid-" + _slaverequestid; - //try { - if (pt["slavestates"].HasMember(key.c_str()) && pt["slavestates"][key.c_str()].HasMember("taskstate")) { - mujinjson::SaveJsonValue(taskstatejson, pt["slavestates"][key.c_str()]["taskstate"]); - SetJsonValueByKey(d, "output", taskstatejson); - taskstate.Parse(d); - } -// } -// catch (const std::exception& ex){ -// MUJIN_LOG_WARN("parsing heartbeat at " << timestamp ": " << ex.what()); -// } - } -} - -namespace { -void SetMapTaskParameters(std::stringstream &ss, const std::map ¶ms) -{ - ss << std::setprecision(std::numeric_limits::digits10+1); - ss.str(""); - ss.clear(); - ss << "{"; - FOREACHC(it, params) { - ss << "\"" << it->first << "\":" << it->second << ", "; - } -} - -void SerializeGetStateCommand(std::stringstream &ss, const std::map ¶ms, - const std::string &functionname, const std::string &tasktype, - const std::string &robotname, const std::string &unit, const double timeout) { - SetMapTaskParameters(ss, params); - - ss << GetJsonString("command", functionname) << ", "; - ss << GetJsonString("tasktype", tasktype) << ", "; - if (!robotname.empty()) { - ss << GetJsonString("robotname", robotname) << ", "; - } - ss << GetJsonString("unit", unit); - ss << "}"; -} - -void -GenerateMoveToolCommand(const std::string &movetype, const std::string &goaltype, const std::vector &goals, - const std::string &robotname, const std::string &toolname, const double robotspeed, - Real envclearance, std::stringstream &ss, - const std::map ¶ms) { - SetMapTaskParameters(ss, params); - ss << GetJsonString("command", movetype) << ", "; - ss << GetJsonString("goaltype", goaltype) << ", "; - if (!robotname.empty()) { - ss << GetJsonString("robotname", robotname) << ", "; - } - if (!toolname.empty()) { - ss << GetJsonString("toolname", toolname) << ", "; - } - if (robotspeed >= 0) { - ss << GetJsonString("robotspeed") << ": " << robotspeed << ", "; - } - if (envclearance >= 0) { - ss << GetJsonString("envclearance") << ": " << envclearance << ", "; - } - ss << GetJsonString("goals") << ": " << GetJsonString(goals); - ss << "}"; - -} - -void -GenerateMoveToolByIkParamCommand(const std::string &movetype, const std::string &instobjectname, const std::string &ikparamname, - const std::string &robotname, const std::string &toolname, const double robotspeed, - Real envclearance, std::stringstream &ss, - const std::map ¶ms) { - SetMapTaskParameters(ss, params); - ss << GetJsonString("command", movetype) << ", "; - ss << "\"goaltype\": null,"; - ss << GetJsonString("instobjectname", instobjectname) << ", "; - if (!robotname.empty()) { - ss << GetJsonString("robotname", robotname) << ", "; - } - if (!toolname.empty()) { - ss << GetJsonString("toolname", toolname) << ", "; - } - if (robotspeed >= 0) { - ss << GetJsonString("robotspeed") << ": " << robotspeed << ", "; - } - if (envclearance >= 0) { - ss << GetJsonString("envclearance") << ": " << envclearance << ", "; - } - ss << GetJsonString("ikparamname", ikparamname); - ss << "}"; - -} - -void SetTrajectory(const rapidjson::Value &pt, - std::string *pTraj) { - if (!(pt.IsObject() && pt.HasMember("output") && pt["output"].HasMember("trajectory"))) { - throw MujinException("trajectory is not available in output", MEC_Failed); - } - *pTraj = GetJsonValueByPath(pt, "/output/trajectory"); -} -} - -void BinPickingTaskResource::GetJointValues(ResultGetJointValues& result, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetJointValues"; - std::string robottype = "densowave"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("robottype", robottype) << ", "; - _ss << GetJsonString("unit", unit) << ", "; - _ss << GetJsonString("tasktype", _tasktype); - _ss << "}"; - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::SetInstantaneousJointValues(const std::vector& jointvalues, const std::string& unit, const double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - { - for(std::map::iterator it=_mapTaskParameters.begin(); it!=_mapTaskParameters.end(); ++it) { - rapidjson::Document t; - ParseJson(t,it->second); - SetJsonValueByKey(pt,it->first,t); - } - } - SetJsonValueByKey(pt,"command","SetInstantaneousJointValues"); - SetJsonValueByKey(pt,"tasktype",_tasktype); - SetJsonValueByKey(pt,"jointvalues",jointvalues); - SetJsonValueByKey(pt,"unit",unit); - rapidjson::Document d; - ExecuteCommand(DumpJson(pt), d, timeout); // need to check return code -} - -void BinPickingTaskResource::ComputeIkParamPosition(ResultComputeIkParamPosition& result, const std::string& name, const std::string& unit, const double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - { - for(std::map::iterator it=_mapTaskParameters.begin(); it!=_mapTaskParameters.end(); ++it) { - rapidjson::Document t; - ParseJson(t,it->second); - SetJsonValueByKey(pt,it->first,t); - } - } - SetJsonValueByKey(pt,"command","ComputeIkParamPosition"); - SetJsonValueByKey(pt,"tasktype",_tasktype); - SetJsonValueByKey(pt,"name",name); - SetJsonValueByKey(pt,"unit",unit); - rapidjson::Document d; - ExecuteCommand(DumpJson(pt), d, timeout); - result.Parse(d); -} - -void BinPickingTaskResource::ComputeIKFromParameters(ResultComputeIKFromParameters& result, const std::string& targetname, const std::vector& ikparamnames, const int filteroptions, const int limit, const double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - { - for(std::map::iterator it=_mapTaskParameters.begin(); it!=_mapTaskParameters.end(); ++it) { - rapidjson::Document t; - ParseJson(t,it->second); - SetJsonValueByKey(pt,it->first,t); - } - } - SetJsonValueByKey(pt,"command","ComputeIKFromParameters"); - SetJsonValueByKey(pt,"tasktype",_tasktype); - SetJsonValueByKey(pt,"targetname",targetname); - SetJsonValueByKey(pt,"ikparamnames",ikparamnames); - SetJsonValueByKey(pt,"filteroptions",filteroptions); // 0 - SetJsonValueByKey(pt,"limit",limit); // 0 - rapidjson::Document d; - ExecuteCommand(DumpJson(pt), d, timeout); - result.Parse(d); -} - -void BinPickingTaskResource::MoveJoints(const std::vector& goaljoints, const std::vector& jointindices, const Real envclearance, const Real speed, ResultMoveJoints& result, const double timeout, std::string* pTraj) -{ - _mapTaskParameters["execute"] = !!pTraj ? "0" : "1"; - SetMapTaskParameters(_ss, _mapTaskParameters); - - std::string command = "MoveJoints"; - std::string robottype = "densowave"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("robottype", robottype) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("goaljoints") << ": " << GetJsonString(goaljoints) << ", "; - _ss << GetJsonString("jointindices") << ": " << GetJsonString(jointindices) << ", "; - _ss << GetJsonString("envclearance",envclearance ) << ", "; - _ss << GetJsonString("speed", speed); - _ss << "}"; - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); - if (!!pTraj) { - SetTrajectory(pt, pTraj); - } -} - -void BinPickingTaskResource::GetTransform(const std::string& targetname, Transform& transform, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetTransform"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - ResultTransform result; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); - transform = result.transform; -} - -void BinPickingTaskResource::SendMVRRegistrationResult( - const rapidjson::Document &mvrResultInfo, - double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "SendMVRRegistrationResult") << ", "; - _ss << GetJsonString("mvrResultInfo", DumpJson(mvrResultInfo)) << ", "; - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - -} - -void BinPickingTaskResource::SendRemoveObjectsFromObjectListResult( - const std::vector& removeObjectFromObjectListInfos, - const bool success, - const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "SendRemoveObjectsFromObjectListResult") << ", "; - _ss << GetJsonString("objectPks") << ": ["; - for (size_t iInfo = 0; iInfo < removeObjectFromObjectListInfos.size(); ++iInfo) { - _ss << GetJsonString(removeObjectFromObjectListInfos[iInfo].objectPk); - if (iInfo != removeObjectFromObjectListInfos.size() - 1) { - _ss << ", "; - } - } - _ss << "], "; - _ss << GetJsonString("success", success) << ", "; - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); -} - - -void BinPickingTaskResource::SendTriggerDetectionCaptureResult(const std::string& triggerType, const std::string& returnCode, double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "SendTriggerDetectionCaptureResult") << ", "; - _ss << GetJsonString("triggerType", triggerType) << ", "; - _ss << GetJsonString("returnCode", returnCode) << ", "; - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); -} - -void BinPickingTaskResource::SetTransform(const std::string& targetname, const Transform &transform, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "SetTransform"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString(transform) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); // need to check return code -} - -void BinPickingTaskResource::GetManipTransformToRobot(Transform& transform, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetManipTransformToRobot"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - ResultTransform result; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); - transform = result.transform; -} - -void BinPickingTaskResource::GetManipTransform(Transform& transform, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetManipTransform"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - ResultTransform result; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); - transform = result.transform; -} - -void BinPickingTaskResource::GetAABB(const std::string& targetname, ResultAABB& result, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetAABB"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::GetInnerEmptyRegionOBB(ResultOBB& result, const std::string& targetname, const std::string& linkname, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetInnerEmptyRegionOBB"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - if (linkname != "") { - _ss << GetJsonString("linkname", linkname) << ", "; - } - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::GetOBB(ResultOBB& result, const std::string& targetname, const std::string& linkname, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetOBB"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - if (linkname != "") { - _ss << GetJsonString("linkname", linkname) << ", "; - } - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::InitializeZMQ(const double reinitializetimeout, const double timeout) -{ -#ifdef MUJIN_USEZMQ - if (!_pHeartbeatMonitorThread) { - _bShutdownHeartbeatMonitor = false; - if ( reinitializetimeout > 0) { - _pHeartbeatMonitorThread.reset(new boost::thread(boost::bind(&BinPickingTaskResource::_HeartbeatMonitorThread, this, reinitializetimeout, timeout))); - } - } -#endif -} - -void BinPickingTaskResource::UpdateObjects(const std::string& objectname, const std::vector& detectedobjects, const std::string& resultstate, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - static const std::string command = "UpdateObjects"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("objectname", objectname) << ", "; - _ss << GetJsonString("envstate") << ": ["; - for (unsigned int i=0; i&vpoints, const Real pointsize, const std::string& name, const unsigned long long starttimestamp, const unsigned long long endtimestamp, const bool executionverification, const std::string& unit, int isoccluded, const std::string& locationName, const double timeout, bool clampToContainer, CropContainerMarginsXYZXYZPtr pCropContainerMargins, AddPointOffsetInfoPtr pAddPointOffsetInfo) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "AddPointCloudObstacle"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("isoccluded", isoccluded) << ", "; - _ss << GetJsonString("locationName", locationName) << ", "; - _ss << GetJsonString("clampToContainer", clampToContainer) << ", "; - if( !!pCropContainerMargins ) { - _ss << "\"cropContainerMarginsXYZXYZ\":[" << pCropContainerMargins->minMargins[0] << ", " << pCropContainerMargins->minMargins[1] << ", " << pCropContainerMargins->minMargins[2] << ", " << pCropContainerMargins->maxMargins[0] << ", " << pCropContainerMargins->maxMargins[1] << ", " << pCropContainerMargins->maxMargins[2] << "], "; - } - if( !!pAddPointOffsetInfo ) { - _ss << "\"addPointOffsetInfo\":{"; - _ss << "\"zOffsetAtBottom\": " << pAddPointOffsetInfo->zOffsetAtBottom << ", "; - _ss << "\"zOffsetAtTop\": " << pAddPointOffsetInfo->zOffsetAtTop << ", "; - _ss << "\"use\": true"; - _ss << "}, "; - } - PointCloudObstacle pointcloudobstacle; - pointcloudobstacle.name = name; - pointcloudobstacle.pointsize = pointsize; - pointcloudobstacle.points = vpoints; - _ss << GetJsonString(pointcloudobstacle); - - // send timestamp regardless of the pointcloud definition - _ss << ", \"starttimestamp\": " << starttimestamp; - _ss << ", \"endtimestamp\": " << endtimestamp; - _ss << ", \"executionverification\": " << (int) executionverification; - - _ss << ", " << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document rResult; - ExecuteCommand(_ss.str(), rResult, timeout); // need to check return code -} - -void BinPickingTaskResource::UpdateEnvironmentState(const std::string& objectname, const std::vector& detectedobjects, const std::vector& vpoints, const std::string& state, const Real pointsize, const std::string& pointcloudobstaclename, const std::string& unit, const double timeout, const std::string& locationName, const std::vector& cameranames, CropContainerMarginsXYZXYZPtr pCropContainerMargins) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "UpdateEnvironmentState"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("objectname", objectname) << ", "; - _ss << GetJsonString("locationName", locationName) << ", "; - _ss << "\"cameranames\":" << GetJsonString(cameranames) << ", "; - _ss << GetJsonString("envstate") << ": ["; - for (unsigned int i=0; iminMargins[0] << ", " << pCropContainerMargins->minMargins[1] << ", " << pCropContainerMargins->minMargins[2] << ", " << pCropContainerMargins->maxMargins[0] << ", " << pCropContainerMargins->maxMargins[1] << ", " << pCropContainerMargins->maxMargins[2] << "], "; - } - PointCloudObstacle pointcloudobstacle; - pointcloudobstacle.name = pointcloudobstaclename; - pointcloudobstacle.pointsize = pointsize; - pointcloudobstacle.points = vpoints; - _ss << GetJsonString(pointcloudobstacle); - - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(),d, timeout); // need to check return code -} - -void BinPickingTaskResource::RemoveObjectsWithPrefix(const std::string& prefix, double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "RemoveObjectsWithPrefix"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("prefix", prefix); - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(),d, timeout); - -} -void BinPickingTaskResource::VisualizePointCloud(const std::vector >&pointslist, const Real pointsize, const std::vector&names, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "VisualizePointCloud"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("pointslist") << ": ["; - for (unsigned int i=0; i< pointslist.size(); i++) { - _ss << GetJsonString(pointslist[i]); - if (iCallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk,errormessage")%GetPrimaryKey()), pt); - BinPickingResultResourcePtr result; - if(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { - rapidjson::Value& objects = pt["objects"]; - std::string pk = GetJsonValueByKey(objects[0], "pk", pk); - result.reset(new BinPickingResultResource(controller, pk)); - std::string erroptional = GetJsonValueByKey(objects[0], "errormessage"); - if (erroptional.size() > 0 && erroptional != "succeed") { - throw MujinException(erroptional, MEC_BinPickingError); - } - } - return result; -} - -void BinPickingTaskResource::GetInstObjectAndSensorInfo(const std::vector& instobjectnames, const std::vector& sensorSelectionInfos, ResultGetInstObjectAndSensorInfo& result, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetInstObjectAndSensorInfo"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("tasktype", _tasktype) << ", "; - _ss << GetJsonString("instobjectnames") << ": " << GetJsonString(instobjectnames) << ", "; - _ss << GetJsonString("sensorSelectionInfos") << ": " << GetJsonString(sensorSelectionInfos) << ", "; - _ss << GetJsonString("unit", unit); - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - try { - result.Parse(pt); - } - catch(const std::exception& ex) { - MUJIN_LOG_ERROR(str(boost::format("got error when parsing result. exception: %s result: %s")%ex.what()%DumpJson(pt))); - throw; - } -} - -void BinPickingTaskResource::GetInstObjectInfoFromURI(const std::string& objecturi, const Transform& instobjecttransform, ResultInstObjectInfo& result, const std::string& unit, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - std::string command = "GetInstObjectInfoFromURI"; - _ss << GetJsonString("command", command) << ", "; - _ss << GetJsonString("unit", unit) << ", "; - _ss << "\"objecturi\":" << GetJsonString(objecturi) << ", "; - _ss << "\"instobjectpose\":["; - _ss << instobjecttransform.quaternion[0] << ", " << instobjecttransform.quaternion[1] << ", " << instobjecttransform.quaternion[2] << ", " << instobjecttransform.quaternion[3] << ", "; - _ss << instobjecttransform.translate[0] << ", " << instobjecttransform.translate[1] << ", " << instobjecttransform.translate[2]; - _ss << "]"; - _ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - try { - result.Parse(pt); - } - catch(const std::exception& ex) { - MUJIN_LOG_ERROR(str(boost::format("got error when parsing result: %s result: %s")%ex.what()%DumpJson(pt))); - throw; - } -} - -void BinPickingTaskResource::GetPublishedTaskState(ResultGetBinpickingState& result, const std::string& robotname, const std::string& unit, const double timeout) -{ - ResultGetBinpickingState taskstate; - { - boost::mutex::scoped_lock lock(_mutexTaskState); - taskstate =_taskstate; - } - - if (taskstate.timestamp == 0) { - if (_tasktype == "binpicking") { - MUJIN_LOG_INFO("Have not received published message yet, getting published state from GetBinpickingState()"); - GetBinpickingState(result, robotname, unit, timeout); - } - else { - MUJIN_LOG_INFO("Have not received published message yet, getting published state from GetITLState()"); - GetITLState(result, robotname, unit, timeout); - } - { - boost::mutex::scoped_lock lock(_mutexTaskState); - _taskstate = result; - } - } else { - result = taskstate; - } -} - -void BinPickingTaskResource::GetBinpickingState(ResultGetBinpickingState& result, const std::string& robotname, const std::string& unit, const double timeout) -{ - SerializeGetStateCommand(_ss, _mapTaskParameters, "GetState", _tasktype, robotname, unit, timeout); - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::GetITLState(ResultGetBinpickingState& result, const std::string& robotname, const std::string& unit, const double timeout) -{ - SerializeGetStateCommand(_ss, _mapTaskParameters, "GetState", _tasktype, robotname, unit, timeout); - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - result.Parse(pt); -} - -void BinPickingTaskResource::SetJogModeVelocities(const std::string& jogtype, const std::vector& movejointsigns, const std::string& robotname, const std::string& toolname, const double robotspeed, const double robotaccelmult, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", std::string("SetJogModeVelocities")) << ", "; - _ss << GetJsonString("jogtype", jogtype) << ", "; - - if (!robotname.empty()) { - _ss << GetJsonString("robotname", robotname) << ", "; - } - if (!toolname.empty()) { - _ss << GetJsonString("toolname", toolname) << ", "; - } - if (robotspeed >= 0) { - _ss << GetJsonString("robotspeed") << ": " << robotspeed << ", "; - } - if (robotaccelmult >= 0) { - _ss << GetJsonString("robotaccelmult") << ": " << robotaccelmult << ", "; - } - _ss << GetJsonString("movejointsigns") << ": " << GetJsonString(movejointsigns); - _ss << "}"; - //std::cout << "Sending\n" << _ss.str() << " from " << __func__ << std::endl; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); -} - -void BinPickingTaskResource::MoveToolLinear(const std::string& goaltype, const std::vector& goals, const std::string& robotname, const std::string& toolname, const double workspeedlin, const double workspeedrot, bool checkEndeffectorCollision, const double timeout, std::string* pTraj) -{ - _mapTaskParameters["execute"] = !!pTraj ? "0" : "1"; - - const std::string ignorethresh = checkEndeffectorCollision ? "0.0" : "1000.0"; // zero to not ignore collision at any time, large number (1000) to ignore collision of end effector for first and last part of trajectory as well as ignore collision of robot at initial part of trajectory - _mapTaskParameters["workignorefirstcollisionee"] = ignorethresh; - _mapTaskParameters["workignorelastcollisionee"] = ignorethresh; - _mapTaskParameters["workignorefirstcollision"] = ignorethresh; - if (workspeedlin > 0 && workspeedrot > 0) { - std::stringstream ss; - ss << "[" << workspeedrot << ", " << workspeedlin << "]"; - _mapTaskParameters["workspeed"] = ss.str(); - } - GenerateMoveToolCommand("MoveToolLinear", goaltype, goals, robotname, toolname, -1, -1, _ss, _mapTaskParameters); - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - if (!!pTraj) { - SetTrajectory(pt, pTraj); - } -} - -void BinPickingTaskResource::MoveToolLinear(const std::string& instobjectname, const std::string& ikparamname, const std::string& robotname, const std::string& toolname, const double workspeedlin, const double workspeedrot, bool checkEndeffectorCollision, const double timeout, std::string* pTraj) -{ - _mapTaskParameters["execute"] = !!pTraj ? "0" : "1"; - - const std::string ignorethresh = checkEndeffectorCollision ? "0.0" : "1000.0"; // zero to not ignore collision at any time, large number (1000) to ignore collision of end effector for first and last part of trajectory as well as ignore collision of robot at initial part of trajectory - _mapTaskParameters["workignorefirstcollisionee"] = ignorethresh; - _mapTaskParameters["workignorelastcollisionee"] = ignorethresh; - _mapTaskParameters["workignorefirstcollision"] = ignorethresh; - if (workspeedlin > 0 && workspeedrot > 0) { - std::stringstream ss; - ss << "[" << workspeedrot << ", " << workspeedlin << "]"; - _mapTaskParameters["workspeed"] = ss.str(); - } - GenerateMoveToolByIkParamCommand("MoveToolLinear", instobjectname, ikparamname, robotname, toolname, -1, -1, _ss, _mapTaskParameters); - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - if (!!pTraj) { - SetTrajectory(pt, pTraj); - } -} - -void BinPickingTaskResource::MoveToHandPosition(const std::string& goaltype, const std::vector& goals, const std::string& robotname, const std::string& toolname, const double robotspeed, const double timeout, Real envclearance, std::string* pTraj) -{ - _mapTaskParameters["execute"] = !!pTraj ? "0" : "1"; - - GenerateMoveToolCommand("MoveToHandPosition", goaltype, goals, robotname, toolname, robotspeed, envclearance, _ss, _mapTaskParameters); - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - if (!!pTraj) { - SetTrajectory(pt, pTraj); - } -} - -void BinPickingTaskResource::MoveToHandPosition(const std::string& instobjectname, const std::string& ikparamname, const std::string& robotname, const std::string& toolname, const double robotspeed, const double timeout, Real envclearance, std::string* pTraj) -{ - _mapTaskParameters["execute"] = !!pTraj ? "0" : "1"; - - GenerateMoveToolByIkParamCommand("MoveToHandPosition", instobjectname, ikparamname, robotname, toolname, robotspeed, envclearance, _ss, _mapTaskParameters); - - rapidjson::Document pt(rapidjson::kObjectType); - ExecuteCommand(_ss.str(), pt, timeout); - if (!!pTraj) { - SetTrajectory(pt, pTraj); - } -} - -void BinPickingTaskResource::GetGrabbed(std::vector& grabbed, const std::string& robotname, const double timeout) -{ - grabbed.clear(); - rapidjson::Document pt(rapidjson::kObjectType); - { - for(std::map::iterator it=_mapTaskParameters.begin(); it!=_mapTaskParameters.end(); ++it) { - rapidjson::Document t; - ParseJson(t,it->second); - SetJsonValueByKey(pt,it->first,t); - } - } - SetJsonValueByKey(pt,"command","GetGrabbed"); - SetJsonValueByKey(pt,"tasktype",_tasktype); - if (!robotname.empty()) { - SetJsonValueByKey(pt, "robotname", robotname); - } - rapidjson::Document d; - ExecuteCommand(DumpJson(pt), d, timeout); // need to check return code - BOOST_ASSERT(d.IsObject() && d.HasMember("output")); - const rapidjson::Value& v = d["output"]; - if(v.HasMember("names") && !v["names"].IsNull()) { - LoadJsonValueByKey(v, "names", grabbed); - } -} - -void BinPickingTaskResource::ExecuteSingleXMLTrajectory(const std::string& trajectory, bool filterTraj, const double timeout) -{ - _ss.str(""); _ss.clear(); - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "ExecuteSingleXMLTrajectory") << ", " - << GetJsonString("filtertraj", filterTraj ? 1 : 0) << ", " - << GetJsonString("trajectory", trajectory) << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); -} - -void BinPickingTaskResource::Grab(const std::string& targetname, const std::string& robotname, const std::string& toolname, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "Grab") << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - if (!robotname.empty()) { - _ss << GetJsonString("robotname", robotname) << ", "; - } - if (!toolname.empty()) { - _ss << GetJsonString("toolname", toolname) << ", "; - } - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); -} - -void BinPickingTaskResource::Release(const std::string& targetname, const std::string& robotname, const std::string& toolname, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "Release") << ", "; - _ss << GetJsonString("targetname", targetname) << ", "; - if (!robotname.empty()) { - _ss << GetJsonString("robotname", robotname) << ", "; - } - if (!toolname.empty()) { - _ss << GetJsonString("toolname", toolname) << ", "; - } - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); -} - -void BinPickingTaskResource::GetRobotBridgeIOVariableString(const std::vector& ionames, std::vector& iovalues, const double timeout) -{ - SetMapTaskParameters(_ss, _mapTaskParameters); - _ss << GetJsonString("command", "GetRobotBridgeIOVariableString") << ", "; - _ss << "\"ionames\":" << GetJsonString(ionames); - _ss << "}"; - rapidjson::Document d; - ExecuteCommand(_ss.str(), d, timeout); - BOOST_ASSERT(d.IsObject() && d.HasMember("output")); - const rapidjson::Value& rIOOutputs = d["output"]; - - // process - iovalues.resize(ionames.size()); - for(size_t index = 0; index < ionames.size(); ++index) { - if( rIOOutputs.HasMember(ionames[index].c_str()) ) { - iovalues[index] = mujinjson::GetStringJsonValueByKey(rIOOutputs, ionames[index].c_str(), std::string()); - } - else { - MUJIN_LOG_DEBUG(str(boost::format("could not read ioname %s")%ionames[index])); - } - } -} - -const std::string& BinPickingTaskResource::GetSlaveRequestId() const -{ - return _slaverequestid; -} - -void BinPickingTaskResource::ExecuteCommand(const std::string& taskparameters, rapidjson::Document& rResult, const double timeout, const bool getresult) -{ - if (!_bIsInitialized) { - throw MujinException("BinPicking task is not initialized, please call Initialzie() first.", MEC_Failed); - } - - GETCONTROLLERIMPL(); - - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "{\"tasktype\": \"" << _tasktype << "\", \"taskparameters\": " << taskparameters << ", "; - ss << "\"sceneparams\": " << _sceneparams_json << ", "; - ss << "\"userinfo\": " << _userinfo_json << ", "; - if (_slaverequestid != "") { - ss << GetJsonString("slaverequestid", _slaverequestid) << ", "; - } - ss << "\"stamp\": " << (GetMilliTime()*1e-3) << ", "; - ss << "\"callerid\": \"" << _GetCallerId() << "\""; - ss << "}"; - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPutJSON(str(boost::format("task/%s/?format=json")%GetPrimaryKey()), ss.str(), pt); - Execute(); - - double secondspassed = 0; - while (1) { - BinPickingResultResourcePtr resultresource; - resultresource = boost::dynamic_pointer_cast(GetResult()); - if( !!resultresource ) { - if (getresult) { - resultresource->GetResultJson(rResult); - } - return; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - secondspassed+=0.1; - if( timeout != 0 && secondspassed > timeout ) { - controller->CancelAllJobs(); - std::stringstream sss; sss << std::setprecision(std::numeric_limits::digits10+1); - sss << secondspassed; - throw MujinException("operation timed out after " +sss.str() + " seconds, cancelling all jobs and quitting", MEC_Timeout); - } - } -} - -void BinPickingTaskResource::ExecuteCommand(rapidjson::Value& rTaskParameters, rapidjson::Document& rOutput, const double timeout) -{ - BOOST_ASSERT(0); // not supported -} - -void utils::GetAttachedSensors(SceneResource& scene, const std::string& bodyname, std::vector& attachedsensors) -{ - SceneResource::InstObjectPtr sensorinstobject; - if (!scene.FindInstObject(bodyname, sensorinstobject)) { - throw MujinException("Could not find instobject with name: " + bodyname+".", MEC_Failed); - } - - RobotResourcePtr sensorrobot; - sensorrobot.reset(new RobotResource(scene.GetController(),sensorinstobject->object_pk)); - sensorrobot->GetAttachedSensors(attachedsensors); - if (attachedsensors.size() == 0) { - throw MujinException("Could not find attached sensor. Is calibration done for sensor: " + bodyname + "?", MEC_Failed); - } -} - -void utils::GetSensorData(SceneResource& scene, const std::string& bodyname, const std::string& sensorname, RobotResource::AttachedSensorResource::SensorData& result) -{ - std::vector attachedsensors; - utils::GetAttachedSensors(scene, bodyname, attachedsensors); - for (size_t i=0; iname == sensorname) { - result = attachedsensors.at(i)->sensordata; - return; - } - } - throw MujinException("Could not find attached sensor " + sensorname + " on " + bodyname + ".", MEC_Failed); -} - -void utils::GetSensorTransform(SceneResource& scene, const std::string& bodyname, const std::string& sensorname, Transform& result, const std::string& unit) -{ - std::vector attachedsensors; - utils::GetAttachedSensors(scene, bodyname, attachedsensors); - for (size_t i=0; iname == sensorname) { - Transform transform; - std::copy(attachedsensors.at(i)->quaternion, attachedsensors.at(i)->quaternion+4, transform.quaternion); - std::copy(attachedsensors.at(i)->translate, attachedsensors.at(i)->translate+3, transform.translate); - if (unit == "m") { //?! - transform.translate[0] *= 0.001; - transform.translate[1] *= 0.001; - transform.translate[2] *= 0.001; - } - - result = transform; - return; - } - } - throw MujinException("Could not find attached sensor " + sensorname + " on " + bodyname + ".", MEC_Failed); -} - -void utils::DeleteObject(SceneResource& scene, const std::string& name) -{ - //TODO needs to robot.Release(name) - std::vector instobjects; - scene.GetInstObjects(instobjects); - - for(unsigned int i = 0; i < instobjects.size(); ++i) { - const std::size_t found_at = instobjects[i]->name.find(name); - if (found_at != std::string::npos) { - instobjects[i]->Delete(); - break; - } - } -} - -void BinPickingTaskResource::_HeartbeatMonitorThread(const double reinitializetimeout, const double commandtimeout) -{ -#ifdef MUJIN_USEZMQ - boost::shared_ptr socket; - - while (!_bShutdownHeartbeatMonitor) { - if (!!socket) { - socket->close(); - socket.reset(); - } - socket.reset(new zmq::socket_t((*_zmqcontext.get()),ZMQ_SUB)); - socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << _heartbeatPort; - socket->connect(("tcp://"+ _mujinControllerIp+":"+ss.str()).c_str()); - socket->setsockopt(ZMQ_SUBSCRIBE, "", 0); - - zmq::pollitem_t pollitem; - memset(&pollitem, 0, sizeof(zmq::pollitem_t)); - pollitem.socket = socket->operator void*(); - pollitem.events = ZMQ_POLLIN; - - unsigned long long lastheartbeat = GetMilliTime(); - while (!_bShutdownHeartbeatMonitor && (GetMilliTime() - lastheartbeat) / 1000.0f < reinitializetimeout) { - zmq::poll(&pollitem,1, 50); // wait 50 ms for message - if (pollitem.revents & ZMQ_POLLIN) { - zmq::message_t reply; - socket->recv(&reply); - std::string replystring((char *)reply.data (), (size_t)reply.size()); - //if ((size_t)reply.size() == 1 && ((char *)reply.data())[0]==255) { - if (replystring == "255") { - lastheartbeat = GetMilliTime(); - } - } - } - if (!_bShutdownHeartbeatMonitor) { - std::stringstream sss; sss << std::setprecision(std::numeric_limits::digits10+1); - sss << (double)((GetMilliTime() - lastheartbeat)/1000.0f) << " seconds passed since last heartbeat signal, re-intializing ZMQ server."; - MUJIN_LOG_INFO(sss.str()); - } - } -#else - MUJIN_LOG_ERROR("cannot create heartbeat monitor since not compiled with libzmq"); -#endif -} - -#ifdef MUJIN_USEZMQ -std::string utils::GetHeartbeat(const std::string& endpoint) { - zmq::context_t zmqcontext(1); - zmq::socket_t socket(zmqcontext, ZMQ_SUB); - socket.connect(endpoint.c_str()); - socket.setsockopt(ZMQ_SUBSCRIBE, "", 0); - - zmq::pollitem_t pollitem; - memset(&pollitem, 0, sizeof(zmq::pollitem_t)); - pollitem.socket = socket; - pollitem.events = ZMQ_POLLIN; - - zmq::poll(&pollitem,1, 50); // wait 50 ms for message - if (!(pollitem.revents & ZMQ_POLLIN)) { - return ""; - } - - zmq::message_t reply; - socket.recv(&reply); - const std::string received((char *)reply.data (), (size_t)reply.size()); -#ifndef _WIN32 - return received; -#else - // sometimes buffer can container \n or \\, which windows does not like - std::string newbuffer; - std::vector< std::pair > serachpairs(2); - serachpairs[0].first = "\n"; serachpairs[0].second = ""; - serachpairs[1].first = "\\"; serachpairs[1].second = ""; - SearchAndReplace(newbuffer, received, serachpairs); - return newbuffer; -#endif -} - - -namespace { -std::string FindSmallestSlaveRequestId(const rapidjson::Value& pt) { - // get all slave request ids - std::vector slavereqids; - if (pt.IsObject() && pt.HasMember("slavestates")) { - const rapidjson::Value& slavestates = pt["slavestates"]; - for (rapidjson::Document::ConstMemberIterator it = slavestates.MemberBegin(); it != slavestates.MemberEnd(); ++it) { - static const std::string prefix("slaverequestid-"); - if (std::string(it->name.GetString()).substr(0,prefix.length()) == prefix) { - // GetValueForSmallestSlaveRequestId uses slavereqid directly, so cannot substr here - slavereqids.push_back(it->name.GetString()); - } - } - } - - // find numerically smallest suffix (find one with smallest ### in slave request id of form hostname_slave###) - int smallest_suffix_index = -1; - int smallest_suffix = INT_MAX; - static const char searchstr('_'); - for (std::vector::const_iterator it = slavereqids.begin(); - it != slavereqids.end(); ++it) { - const size_t foundindex = it->rfind(searchstr); - if (foundindex == std::string::npos) { - continue; - } - - if ((*it)[it->length()-1] < '0' || '9' < (*it)[it->length()-1]) { - continue; - } - int suffix = 0; - int po = 1; - for (int i = it->length()-1; i >= 0 && '0' <= (*it)[i] && (*it)[i] <= '9'; i--, po *= 10) { - suffix = suffix + ((*it)[i] - '0')*po; - } - - if (smallest_suffix > suffix) { - smallest_suffix = suffix; - smallest_suffix_index = std::distance::const_iterator>(slavereqids.begin(), it); - } - } - - if (smallest_suffix_index == -1) { - throw MujinException("Failed to find slave request id like hostname_slave### where ### is a number"); - } - return slavereqids[smallest_suffix_index]; -} - -std::string GetValueForSmallestSlaveRequestId(const std::string& heartbeat, - const std::string& key) -{ - - rapidjson::Document pt(rapidjson::kObjectType); - std::stringstream ss(heartbeat); - ParseJson(pt, ss.str()); - try { - const std::string slavereqid = FindSmallestSlaveRequestId(pt); - std::string result; - LoadJsonValue(pt["slavestates"][slavereqid.c_str()][key.c_str()], result); - return result; - } - catch (const MujinException& ex) { - throw MujinException(boost::str(boost::format("%s from heartbeat:\n%s")%ex.what()%heartbeat)); - } - -} -} - - -std::string mujinclient::utils::GetScenePkFromHeartbeat(const std::string& heartbeat) { - static const std::string prefix("mujin:/"); - return GetValueForSmallestSlaveRequestId(heartbeat, "currentsceneuri").substr(prefix.length()); -} - -std::string utils::GetSlaveRequestIdFromHeartbeat(const std::string& heartbeat) { - rapidjson::Document pt; - std::stringstream ss(heartbeat); - ParseJson(pt, ss.str()); - try { - static const std::string prefix("slaverequestid-"); - return FindSmallestSlaveRequestId(pt).substr(prefix.length()); - } - catch (const MujinException& ex) { - throw MujinException(boost::str(boost::format("%s from heartbeat:\n%s")%ex.what()%heartbeat)); - } -} -#endif - -} // end namespace mujinclient diff --git a/src/binpickingtaskzmq.cpp b/src/binpickingtaskzmq.cpp deleted file mode 100644 index a62aa88e..00000000 --- a/src/binpickingtaskzmq.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2014 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "common.h" -#include "controllerclientimpl.h" -#include "binpickingtaskzmq.h" -#include "mujincontrollerclient/mujinzmq.h" - -#include // find - -#include "logging.h" -#include "mujincontrollerclient/mujinjson.h" - -MUJIN_LOGGER("mujin.controllerclientcpp.binpickingtask.zmq"); - -using namespace mujinzmq; - -namespace mujinclient { -using namespace utils; -using namespace mujinjson; - -class ZmqMujinControllerClient : public mujinzmq::ZmqClient -{ - -public: - ZmqMujinControllerClient(boost::shared_ptr context, const std::string& host, const int port); - - virtual ~ZmqMujinControllerClient(); - -}; - -ZmqMujinControllerClient::ZmqMujinControllerClient(boost::shared_ptr context, const std::string& host, const int port) : ZmqClient(host, port) -{ - _InitializeSocket(context); -} - -ZmqMujinControllerClient::~ZmqMujinControllerClient() -{ - // _DestroySocket() is called in ~ZmqClient() -} - -BinPickingTaskZmqResource::BinPickingTaskZmqResource(ControllerClientPtr c, const std::string& pk, const std::string& scenepk, const std::string& tasktype) : BinPickingTaskResource(c, pk, scenepk, tasktype) -{ - _callerid = str(boost::format("controllerclientcpp%s_zmq")%MUJINCLIENT_VERSION_STRING); -} - -BinPickingTaskZmqResource::~BinPickingTaskZmqResource() -{ -} - -void BinPickingTaskZmqResource::Initialize(const std::string& defaultTaskParameters, const int zmqPort, const int heartbeatPort, boost::shared_ptr zmqcontext, const bool initializezmq, const double reinitializetimeout, const double timeout, const std::string& userinfo, const std::string& slaverequestid) -{ - BinPickingTaskResource::Initialize(defaultTaskParameters, zmqPort, heartbeatPort, zmqcontext, initializezmq, reinitializetimeout, timeout, userinfo, slaverequestid); - - if (initializezmq) { - InitializeZMQ(reinitializetimeout, timeout); - } - - _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); - if (!_zmqmujincontrollerclient) { - throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); - } - if (!_pHeartbeatMonitorThread) { - _bShutdownHeartbeatMonitor = false; - if (reinitializetimeout > 0 ) { - _pHeartbeatMonitorThread.reset(new boost::thread(boost::bind(&BinPickingTaskZmqResource::_HeartbeatMonitorThread, this, reinitializetimeout, timeout))); - } - } -} - -void _LogTaskParametersAndThrow(const std::string& taskparameters) { - std::string errstr; - if (taskparameters.size()>1000) { - errstr = taskparameters.substr(0, 1000); - } else { - errstr = taskparameters; - } - throw MujinException(boost::str(boost::format("Timed out receiving response of command with taskparameters=%s...")%errstr)); -} - -void BinPickingTaskZmqResource::ExecuteCommand(const std::string& taskparameters, rapidjson::Document &pt, const double timeout /* [sec] */, const bool getresult) -{ - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << "{\"fnname\": \""; - ss << (_tasktype == "binpicking" ? "binpicking.RunCommand\", " : "RunCommand\", "); - - ss << "\"stamp\": " << (GetMilliTime()*1e-3) << ", "; - ss << "\"callerid\": \"" << _GetCallerId() << "\", "; - ss << "\"taskparams\": {\"tasktype\": \"" << _tasktype << "\", "; - - ss << "\"taskparameters\": " << taskparameters << ", "; - ss << "\"sceneparams\": " << _sceneparams_json << "}, "; - ss << "\"userinfo\": " << _userinfo_json; - if (_slaverequestid != "") { - ss << ", " << GetJsonString("slaverequestid", _slaverequestid); - } - ss << "}"; - std::string result_ss; - - try{ - _ExecuteCommandZMQ(ss.str(), pt, timeout, getresult); - } - catch (const MujinException& e) { - MUJIN_LOG_ERROR(e.what()); - if (e.GetCode() == MEC_Timeout) { - _LogTaskParametersAndThrow(taskparameters); - } - else { - throw; - } - } -} - -void BinPickingTaskZmqResource::ExecuteCommand(rapidjson::Value& rTaskParameters, rapidjson::Document& rOutput, const double timeout) -{ - rapidjson::Document rCommand; rCommand.SetObject(); - mujinjson::SetJsonValueByKey(rCommand, "fnname", _tasktype == "binpicking" ? "binpicking.RunCommand" : "RunCommand"); - mujinjson::SetJsonValueByKey(rCommand, "stamp", GetMilliTime()*1e-3); - mujinjson::SetJsonValueByKey(rCommand, "callerid", _GetCallerId()); - - { - rapidjson::Value rTaskParams; rTaskParams.SetObject(); - mujinjson::SetJsonValueByKey(rTaskParams, "tasktype", _tasktype, rCommand.GetAllocator()); - rTaskParams.AddMember(rapidjson::Document::StringRefType("taskparameters"), rTaskParameters, rCommand.GetAllocator()); - - { - rapidjson::Value rSceneParams; - rSceneParams.CopyFrom(_rSceneParams, rCommand.GetAllocator()); - rTaskParams.AddMember(rapidjson::Document::StringRefType("sceneparams"), rSceneParams, rCommand.GetAllocator()); - } - rCommand.AddMember(rapidjson::Document::StringRefType("taskparams"), rTaskParams, rCommand.GetAllocator()); - } - - { - rapidjson::Value rUserInfo; - rUserInfo.CopyFrom(_rUserInfo, rCommand.GetAllocator()); - rCommand.AddMember(rapidjson::Document::StringRefType("userinfo"), rUserInfo, rCommand.GetAllocator()); - } - - if (!_slaverequestid.empty()) { - mujinjson::SetJsonValueByKey(rCommand, "slaverequestid", _slaverequestid); - } - - try { - _ExecuteCommandZMQ(mujinjson::DumpJson(rCommand), rOutput, timeout); - } - catch (const MujinException& e) { - MUJIN_LOG_ERROR(e.what()); - if (e.GetCode() == MEC_Timeout) { - _LogTaskParametersAndThrow(mujinjson::DumpJson(rCommand["taskparams"])); - } - else { - throw; - } - } -} - -void BinPickingTaskZmqResource::_ExecuteCommandZMQ(const std::string& command, rapidjson::Document& rOutput, const double timeout, const bool getresult) -{ - if (!_bIsInitialized) { - throw MujinException("BinPicking task is not initialized, please call Initialzie() first.", MEC_Failed); - } - - if (!_zmqmujincontrollerclient) { - MUJIN_LOG_ERROR("zmqcontrollerclient is not initialized! initialize"); - _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); - } - - std::string result_ss; - try { - result_ss = _zmqmujincontrollerclient->Call(command, timeout); - } - catch (const MujinException& e) { - MUJIN_LOG_ERROR(e.what()); - if (e.GetCode() == MEC_ZMQNoResponse) { - MUJIN_LOG_INFO("reinitializing zmq connection with the slave"); - _zmqmujincontrollerclient.reset(new ZmqMujinControllerClient(_zmqcontext, _mujinControllerIp, _zmqPort)); - if (!_zmqmujincontrollerclient) { - throw MujinException(boost::str(boost::format("Failed to establish ZMQ connection to mujin controller at %s:%d")%_mujinControllerIp%_zmqPort), MEC_Failed); - } - } else if (e.GetCode() == MEC_Timeout) { - throw MujinException(""); // Filled by `ExecuteCommand` callers who can access taskparameters more easily - } - else { - throw; - } - } - - try { - ParseJson(rOutput, result_ss); - } - catch(const std::exception& ex) { - MUJIN_LOG_ERROR(str(boost::format("Could not parse result %s")%result_ss)); - throw; - } - if( rOutput.IsObject() && rOutput.HasMember("error")) { - std::string error = GetJsonValueByKey(rOutput["error"], "errorcode"); - std::string description = GetJsonValueByKey(rOutput["error"], "description"); - if ( error.size() > 0 ) { - std::string serror; - if ( description.size() > 0 ) { - serror = description; - } - else { - serror = error; - } - if( serror.size() > 1000 ) { - MUJIN_LOG_ERROR(str(boost::format("truncated original error message from %d")%serror.size())); - serror = serror.substr(0,1000); - } - throw MujinException(str(boost::format("Error when calling binpicking.RunCommand: %s")%serror), MEC_BinPickingError); - } - } -} - -void BinPickingTaskZmqResource::InitializeZMQ(const double reinitializetimeout, const double timeout) -{ -} - -void BinPickingTaskZmqResource::_HeartbeatMonitorThread(const double reinitializetimeout, const double commandtimeout) -{ - MUJIN_LOG_DEBUG(str(boost::format("starting controller %s monitoring thread on port %d for slaverequestid=%s.")%_mujinControllerIp%_heartbeatPort%_slaverequestid)); - boost::shared_ptr socket; - BinPickingTaskResource::ResultHeartBeat heartbeat; - heartbeat._slaverequestid = _slaverequestid; - while (!_bShutdownHeartbeatMonitor) { - if (!!socket) { - socket->close(); - socket.reset(); - } - socket.reset(new zmq::socket_t((*_zmqcontext.get()),ZMQ_SUB)); - socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - std::stringstream ss; ss << std::setprecision(std::numeric_limits::digits10+1); - ss << _heartbeatPort; - socket->connect (("tcp://"+ _mujinControllerIp+":"+ss.str()).c_str()); - socket->setsockopt(ZMQ_SUBSCRIBE, "", 0); - - zmq::pollitem_t pollitem; - memset(&pollitem, 0, sizeof(zmq::pollitem_t)); - pollitem.socket = socket->operator void*(); - pollitem.events = ZMQ_POLLIN; - unsigned long long lastheartbeat = GetMilliTime(); - while (!_bShutdownHeartbeatMonitor && (GetMilliTime() - lastheartbeat) / 1000.0f < reinitializetimeout) { - zmq::poll(&pollitem,1, 50); // wait 50 ms for message - if (pollitem.revents & ZMQ_POLLIN) { - zmq::message_t reply; - socket->recv(&reply); - std::string replystring((char *)reply.data (), (size_t)reply.size()); - rapidjson::Document pt(rapidjson::kObjectType); - try{ - std::stringstream replystring_ss(replystring); - ParseJson(pt, replystring_ss.str()); - heartbeat.Parse(pt); - { - boost::mutex::scoped_lock lock(_mutexTaskState); - _taskstate = heartbeat.taskstate; - } - //BINPICKING_LOG_ERROR(replystring); - - if (heartbeat.status != std::string("lost") && heartbeat.status.size() > 1) { - lastheartbeat = GetMilliTime(); - } - } - catch (std::exception const &e) { - MUJIN_LOG_ERROR("HeartBeat reply is not JSON"); - MUJIN_LOG_ERROR(replystring); - MUJIN_LOG_ERROR(e.what()); - continue; - } - } - } - if (!_bShutdownHeartbeatMonitor) { - std::stringstream sss; sss << std::setprecision(std::numeric_limits::digits10+1); - sss << (double)((GetMilliTime() - lastheartbeat)/1000.0f) << " seconds passed since last heartbeat signal, re-intializing ZMQ server."; - MUJIN_LOG_INFO(sss.str()); - } - } - MUJIN_LOG_DEBUG(str(boost::format("Stopped controller %s monitoring thread on port %d for slaverequestid=%s.")%_mujinControllerIp%_heartbeatPort%_slaverequestid)); -} - - - -} // end namespace mujinclient diff --git a/src/binpickingtaskzmq.h b/src/binpickingtaskzmq.h deleted file mode 100644 index 4a22ff90..00000000 --- a/src/binpickingtaskzmq.h +++ /dev/null @@ -1,53 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2014 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** \file mujincontrollerclient.h - \brief Defines the public headers of the MUJIN Controller Client - */ -#ifndef MUJIN_CONTROLLERCLIENT_BINPICKINGTASK_ZMQ_H -#define MUJIN_CONTROLLERCLIENT_BINPICKINGTASK_ZMQ_H - -#include "mujincontrollerclient/binpickingtask.h" -#include "mujincontrollerclient/mujinzmq.h" - -namespace mujinclient { - -/** \brief client to mujin controller via zmq socket connection - */ -class ZmqMujinControllerClient; -typedef boost::shared_ptr ZmqMujinControllerClientPtr; -typedef boost::weak_ptr ZmqMujinControllerClientWeakPtr; - -class MUJINCLIENT_API BinPickingTaskZmqResource : public BinPickingTaskResource -{ -public: - BinPickingTaskZmqResource(ControllerClientPtr controller, const std::string& pk, const std::string& scenepk, const std::string& tasktype = "binpicking"); - - ~BinPickingTaskZmqResource(); - - void ExecuteCommand(const std::string& taskparameters, rapidjson::Document &pt, const double timeout /* [sec] */=0.0, const bool getresult=true) override; - - virtual void ExecuteCommand(rapidjson::Value& rTaskParameters, rapidjson::Document& rOutput, const double timeout /* second */=5.0) override; - void _ExecuteCommandZMQ(const std::string& command, rapidjson::Document& rOutput, const double timeout /* second */=5.0, const bool getresult=true); - - void Initialize(const std::string& defaultTaskParameters, const int zmqPort, const int heartbeatPort, boost::shared_ptr zmqcontext, const bool initializezmq=false, const double reinitializetimeout=10, const double timeout=0, const std::string& userinfo="{}", const std::string& slaverequestid="") override; - - void InitializeZMQ(const double reinitializetimeout = 5, const double timeout /* second */=0); - void _HeartbeatMonitorThread(const double reinitializetimeout, const double commandtimeout); - -private: - ZmqMujinControllerClientPtr _zmqmujincontrollerclient; -}; - -} // namespace mujinclient -#endif diff --git a/src/controllerclientimpl.h b/src/controllerclientimpl.h deleted file mode 100644 index 963f0187..00000000 --- a/src/controllerclientimpl.h +++ /dev/null @@ -1,293 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2013 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** \file controllerclientimpl.h - \brief Private header file implementing the ControllerClient interface - */ -#ifndef MUJIN_CONTROLLERCLIENT_IMPL_H -#define MUJIN_CONTROLLERCLIENT_IMPL_H - -#include - -#include - -namespace mujinclient { - -class ControllerClientImpl : public ControllerClient, public boost::enable_shared_from_this -{ -public: - ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout); - virtual ~ControllerClientImpl(); - - virtual const std::string& GetUserName() const; - virtual const std::string& GetBaseURI() const; - - virtual std::string GetVersion(); - virtual void SetCharacterEncoding(const std::string& newencoding); - virtual void SetProxy(const std::string& serverport, const std::string& userpw); - virtual void SetUnixEndpoint(const std::string& unixendpoint) override; - virtual void SetLanguage(const std::string& language); - virtual void SetUserAgent(const std::string& userAgent); - virtual void SetAdditionalHeaders(const std::vector& additionalHeaders); - virtual void RestartServer(double timeout); - virtual void _ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse); - virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout); - virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout); - virtual void CancelAllJobs(); - virtual void GetRunTimeStatuses(std::vector& statuses, int options); - virtual void GetScenePrimaryKeys(std::vector& scenekeys); - virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype); - virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype); - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite=false); - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri, bool overwrite=false); - - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype); - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype); - - virtual void UploadFileToController_UTF8(const std::string& filename, const std::string& desturi); - virtual void UploadFileToController_UTF16(const std::wstring& filename, const std::wstring& desturi); - virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi); - virtual void UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi); - virtual void UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi); - virtual void UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi); - virtual void DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata); - virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata); - virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout); - virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout); - virtual long GetModifiedTime(const std::string& uri, double timeout); - virtual void DeleteFileOnController_UTF8(const std::string& desturi); - virtual void DeleteFileOnController_UTF16(const std::wstring& desturi); - virtual void DeleteDirectoryOnController_UTF8(const std::string& desturi); - virtual void DeleteDirectoryOnController_UTF16(const std::wstring& desturi); - virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout); - - virtual void SaveBackup(std::ostream& outputStream, bool config, bool media, const std::string& backupscenepks, double timeout); - virtual void RestoreBackup(std::istream& inputStream, bool config, bool media, double timeout); - virtual void Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout); - virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout); - virtual void CancelUpgrade(double timeout); - virtual void Reboot(double timeout); - virtual void DeleteAllScenes(double timeout); - virtual void DeleteAllITLPrograms(double timeout); - - virtual void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0); - virtual void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0); - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode=200, double timeout = 5.0); - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode=200, double timeout = 5.0); - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode=200, double timeout = 5.0); - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - int CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode=200, double timeout = 5.0); - - /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception - /// - /// \param relativeuri URL-encoded UTF-8 encoded - /// \param data encoded depending on the character encoding set on the system - int CallPost(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - - /// \param data utf-8 encoded - int CallPost_UTF8(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - /// \param data utf-16 encoded - int CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - - /// \brief puts json string - /// \param relativeuri relative uri to put at - /// \param data json string to put - /// \param pt reply is stored - /// \param expectedhttpcode expected http code - /// \param timeout timeout of puts - /// \return http code returned - int CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=202, double timeout = 5.0); - - /// \brief puts stl data - /// \param relativeuri relative uri to put at - /// \param data stl raw data - /// \param pt reply is stored - /// \param expectedhttpcode expected http code - /// \param timeout timeout of puts - /// \return http code returned - int CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode=202, double timeout = 5.0); - - - void CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout = 5.0); - - std::stringstream& GetBuffer(); - - virtual void SetDefaultSceneType(const std::string& scenetype); - virtual const std::string& GetDefaultSceneType(); - virtual void SetDefaultTaskType(const std::string& tasktype); - virtual const std::string& GetDefaultTaskType(); - - std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); - std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); - std::string GetPrimaryKeyFromName_UTF8(const std::string& name); - std::string GetPrimaryKeyFromName_UTF16(const std::wstring& name); - std::string GetNameFromPrimaryKey_UTF8(const std::string& pk); - std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk); - - /// \brief create geometry for a link of an object - /// \param objectPk primary key for the object - /// \param geometryName name of the geometry - /// \param linkPk primary key for the link - /// \param timeout timeout of creating object geometry - /// \return primary key for the geometry created - std::string CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout = 5); - - std::string CreateIkParam(const std::string& objectPk, const std::string& name, const std::string& iktype, double timeout = 5); - std::string CreateLink(const std::string& objectPk, const std::string& parentlinkPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout = 5); - - /// \brief set geometry for an object - /// \param objectPk primary key for the object - /// \param scenePk primary key for the scene - /// \param meshData mesh data to be set to the object - /// \param timeout timeout of creating object geometry - /// \return primary key for the geometry created - std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& scenePk, const std::vector& meshData, const std::string& unit = "mm", double timeout = 5); - - void GetDebugInfos(std::vector& debuginfos, double timeout = 5); - - inline std::string GetBaseUri() const - { - return _baseuri; - } - - /// \brief URL-encode raw string - inline std::string EscapeString(const std::string& raw) const - { - boost::shared_ptr pstr(curl_easy_escape(_curl, raw.c_str(), raw.size()), curl_free); - return std::string(pstr.get()); - } - - /// \brief decode URL-encoded raw string - inline std::string UnescapeString(const std::string& raw) const - { - int outlength = 0; - boost::shared_ptr pstr(curl_easy_unescape(_curl, raw.c_str(), raw.size(), &outlength), curl_free); - return std::string(pstr.get(), outlength); - } - - -protected: - - int _CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, rapidjson::Document& pt, curl_slist* headers, int expectedhttpcode=202, double timeout = 5.0); - - static int _WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData); - static int _WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData); - static int _WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData); - static int _ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *writerData); - - /// \brief sets up http header for doing http operation with json data - void _SetupHTTPHeadersJSON(); - - /// \brief sets up http header for doing http operation with stl data - void _SetupHTTPHeadersSTL(); - - /// \brief sets up http header for doing http operation with multipart/form-data data - void _SetupHTTPHeadersMultipartFormData(); - - /// \brief given a raw uri with "mujin:/", return the real network uri - /// - /// mutex should be locked - /// \param bEnsurePath if true, will make sure the directories on the server side are created - /// \param bEnsureSlash if true, will ensure returned uri ends with slash / - std::string _PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath=true, bool bEnsureSlash=false, bool bIsDirectory=false); - std::string _PrepareDestinationURI_UTF16(const std::wstring& rawuri, bool bEnsurePath=true, bool bEnsureSlash=false, bool bIsDirectory=false); - - // encode a URL without the / separator - std::string _EncodeWithoutSeparator(const std::string& raw); - - /// \param relativeuri utf-8 encoded directory inside the user webdav folder. has a trailing slash. relative to real uri - void _EnsureWebDAVDirectories(const std::string& relativeuri, double timeout = 3.0); - - /// For all webdav internal functions: mutex is already locked, desturi directories are already created - //@{ - - /// \param desturi expects the fully resolved URI to pass to curl - int _CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode=200, double timeout = 5.0); - int _CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode=200, double timeout = 5.0); - int _CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode=200, double timeout = 5.0); - int _CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode=200, double timeout = 5.0); - int _CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _UploadFileToController_UTF8(const std::string& filename, const std::string& desturi); - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _UploadFileToController_UTF16(const std::wstring& filename, const std::string& desturi); - - /// \brief uploads a single file, to dest location specified by filename - /// - /// overwrites the file if it already exists. - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size (ifstream subclass is applicable to files). - virtual void _UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout = 0); - - /// \brief uploads a single file, to dest location specified by filename - /// - /// overwrites the file if it already exists. - /// \param data the buffer represententing the file - /// \param size the length of the buffer represententing the file - virtual void _UploadDataToControllerViaForm(const void* data, size_t size, const std::string& filename, const std::string& endpoint, double timeout = 0); - - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi); - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _UploadDirectoryToController_UTF16(const std::wstring& wcopydir, const std::string& desturi); - - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _DeleteFileOnController(const std::string& desturi); - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _DeleteDirectoryOnController(const std::string& desturi); - - /// \brief desturi is URL-encoded. Also assume _mutex is locked. - virtual void _DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5); - - //@} - - /// \brief read upload function for win32. - /// MUST also provide this read callback using CURLOPT_READFUNCTION. Failing to do so will give you a crash since a DLL may not use the variable's memory when passed in to it from an app like this. */ - static size_t _ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream); - - /// \param stream is std::pair::const_iterator, size_t>*, which gets incremented everytime this function is called. - static size_t _ReadInMemoryUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream); - - int _lastmode; - CURL *_curl; - boost::mutex _mutex; - std::stringstream _buffer; - std::string _baseuri, _baseapiuri, _basewebdavuri, _uri, _username; - - curl_slist *_httpheadersjson; - curl_slist *_httpheadersstl; - curl_slist *_httpheadersmultipartformdata; - std::string _charset, _language; - std::string _csrfmiddlewaretoken; - std::vector _additionalHeaders; ///< list of "Header-Name: header-value" additional http headers - - rapidjson::Document _profile; ///< user profile and versioning - std::string _errormessage; ///< set when an error occurs in libcurl - - std::string _defaultscenetype, _defaulttasktype; - - rapidjson::StringBuffer _rRequestStringBufferCache; ///< cache for request string, protected by _mutex -}; - -typedef boost::shared_ptr ControllerClientImplPtr; - -} // end namespace mujinclient - -#endif diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h new file mode 100644 index 00000000..ca7e890e --- /dev/null +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -0,0 +1,1251 @@ +// -*- coding: utf-8 -*- +// +// Copyright (C) 2012-2013 MUJIN Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** \file mujincontrollerclient.h + \brief Defines the public headers of the MUJIN Controller Client + */ +#ifndef MUJIN_CONTROLLERCLIENT_H +#define MUJIN_CONTROLLERCLIENT_H + +#ifdef _MSC_VER + +#pragma warning(disable:4251)// needs to have dll-interface to be used by clients of class +#pragma warning(disable:4190)// C-linkage specified, but returns UDT 'boost::shared_ptr' which is incompatible with C +#pragma warning(disable:4819)//The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss using native typeof + +#ifndef __PRETTY_FUNCTION__ +#define __PRETTY_FUNCTION__ __FUNCDNAME__ +#endif + +#else +#endif + +#if defined(__GNUC__) +#define MUJINCLIENT_DEPRECATED __attribute__((deprecated)) +#else +#define MUJINCLIENT_DEPRECATED +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace mujinclient { + +typedef mujin::Transform Transform; + +enum TaskResourceOptions +{ + TRO_EnableZMQ=1, ///< create a task resource with zeromq client +}; + +class ControllerClient; +class ObjectResource; +class RobotResource; +class SceneResource; +class TaskResource; +class BinPickingTaskResource; +class OptimizationResource; +class PlanningResultResource; +class BinPickingResultResource; +class DebugResource; + +/// \brief (scene) file entry in mujin controller +struct FileEntry +{ + std::string filename; + double modified; // in epoch seconds + size_t size; // file size in bytes +}; + +typedef boost::shared_ptr ControllerClientPtr; +typedef boost::weak_ptr ControllerClientWeakPtr; +typedef boost::shared_ptr ObjectResourcePtr; +typedef boost::weak_ptr ObjectResourceWeakPtr; +typedef boost::shared_ptr RobotResourcePtr; +typedef boost::weak_ptr RobotResourceWeakPtr; +typedef boost::shared_ptr SceneResourcePtr; +typedef boost::weak_ptr SceneResourceWeakPtr; +typedef boost::shared_ptr TaskResourcePtr; +typedef boost::weak_ptr TaskResourceWeakPtr; +typedef boost::shared_ptr BinPickingTaskResourcePtr; +typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; +typedef boost::shared_ptr OptimizationResourcePtr; +typedef boost::weak_ptr OptimizationResourceWeakPtr; +typedef boost::shared_ptr PlanningResultResourcePtr; +typedef boost::weak_ptr PlanningResultResourceWeakPtr; +typedef boost::shared_ptr BinPickingResultResourcePtr; +typedef boost::weak_ptr BinPickingResultResourceWeakPtr; +typedef boost::shared_ptr DebugResourcePtr; +typedef boost::weak_ptr DebugResourceWeakPtr; +typedef double Real; + +/// \brief status code for a job +/// +/// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html +enum JobStatusCode { + JSC_Pending = 0, ///< The goal has yet to be processed + JSC_Active = 1, ///< The goal is currently being processed + JSC_Preempted = 2, ///< The goal received a cancel request after it started executing and has since completed its execution. + JSC_Succeeded = 3, ///< The goal was achieved successfully. + JSC_Aborted = 4, ///< The goal was aborted during execution due to some failure + JSC_Rejected = 5, ///< The goal was rejected without being processed, because the goal was unattainable or invalid. + JSC_Preempting = 6, ///< The goal received a cancel request after it started executing and has not yet completed execution + JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. + JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled + JSC_Lost = 9, ///< An error happened and the job stopped being tracked. + JSC_Unknown = 0xffffffff, ///< the job is unknown +}; + + +/// \brief get status code from string representation +/// +/// \param str string representation of status +/// \return JobStatusCode equivalent +JobStatusCode GetStatusCode(const std::string& str); + +struct JobStatus +{ + JobStatus() : code(JSC_Unknown) { + } + JobStatusCode code; ///< status code on whether the job is active + std::string type; ///< the type of job running + std::string message; ///< current message of the job + double elapsedtime; ///< how long the job has been running for in seconds + std::string pk; ///< the primary key to differentiate this job +}; + +struct InstanceObjectState +{ + Transform transform; ///< the transform of this instance object + std::vector dofvalues; ///< the joint values +}; + +typedef std::map EnvironmentState; + +struct SceneInformation +{ + std::string pk; ///< primary key + std::string uri; ///< uri of the file pointed to + std::string datemodified; ///< late date modified + std::string name; +}; + +/// \brief holds information about the itlplanning task parameters +class ITLPlanningTaskParameters +{ +public: + ITLPlanningTaskParameters() { + SetDefaults(); + } + virtual void SetDefaults() { + startfromcurrent = 0; + returnmode = "start"; + vrcruns = 1; + ignorefigure = 1; + unit = "mm"; + optimizationvalue = 1; + program.clear(); + } + + int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. + + /// specifies the final movement of the robot. There's 3 different modes: + /// - \b "" - (empty string) meaning robot doesn't return to anything + /// - \b "start" - robot returns to wherever it started + /// - \b "final" - robot returns to the final_envstate + std::string returnmode; + + int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. + int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) + std::string program; ///< itl program + std::string parameters; ///< parameters (json) + + EnvironmentState initial_envstate; ///< initial environment state to set the ITL task to. + EnvironmentState final_envstate; ///< final environment state that describes where the robot should end at. If returnmode is set to final, then use this state. +}; + +/// program is wincaps rc8 pac script +class DensoWaveWincapsTaskParameters : public ITLPlanningTaskParameters +{ +public: + DensoWaveWincapsTaskParameters() : ITLPlanningTaskParameters() { + SetDefaults(); + } + void SetDefaults() { + ITLPlanningTaskParameters::SetDefaults(); + preservespeedparameters = 0; + } + int preservespeedparameters; ///< if 1, preserves all SPEED/ACCEL commands as best as possible. +}; + +/// \brief placement optimization for a robot or another target. +struct RobotPlacementOptimizationParameters +{ + RobotPlacementOptimizationParameters() { + SetDefaults(); + } + inline void SetDefaults() { + unit = "mm"; + topstorecandidates = 20; + targetname.clear(); + framename.clear(); + minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; + maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; + stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; + ignorebasecollision = 0; + } + std::string targetname; ///< the name of the target object to optimize for. Cannot be blank. Has to start with "0 instobject " is targetting an environment instance object. For Example "0 instobject myrobot". + std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" + Real maxrange[4]; ///< X, Y, Z, Angle (deg) + Real minrange[4]; ///< X, Y, Z, Angle (deg) + Real stepsize[4]; ///< X, Y, Z, Angle (deg) + int ignorebasecollision; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. + + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. +}; + +struct PlacementsOptimizationParameters +{ + PlacementsOptimizationParameters() { + SetDefaults(); + } + inline void SetDefaults() { + unit = "mm"; + topstorecandidates = 20; + for(size_t itarget = 0; itarget < targetnames.size(); ++itarget) { + targetnames[itarget].clear(); + framenames[itarget].clear(); + ignorebasecollisions[itarget] = 0; + } + minranges[0][0] = -400; minranges[0][1] = -400; minranges[0][2] = 0; minranges[0][3] = -180; + maxranges[0][0] = 400; maxranges[0][1] = 400; maxranges[0][2] = 400; maxranges[0][3] = 90; + stepsizes[0][0] = 100; stepsizes[0][1] = 100; stepsizes[0][2] = 100; stepsizes[0][3] = 90; + minranges[1][0] = -100; minranges[1][1] = -100; minranges[1][2] = 0; minranges[1][3] = 0; + maxranges[1][0] = 100; maxranges[1][1] = 100; maxranges[1][2] = 100; maxranges[1][3] = 0; + stepsizes[1][0] = 100; stepsizes[1][1] = 100; stepsizes[1][2] = 100; stepsizes[1][3] = 90; + } + + // for every target, there's one setting: + boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. + boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. + boost::array maxranges; ///< X, Y, Z, Angle (deg) + boost::array minranges; ///< X, Y, Z, Angle (deg) + boost::array stepsizes; ///< X, Y, Z, Angle (deg) + boost::array ignorebasecollisions; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. + + // shared settings + std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc + int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. +}; + +/// \brief program data for an individual robot +class RobotProgramData +{ +public: + RobotProgramData() { + } + RobotProgramData(const std::string& programdata_, const std::string& type_) : programdata(programdata_), type(type_) { + } + std::string programdata; ///< the program data + std::string type; ///< the type of program +}; + +/// \brief program data for all robots. +class RobotControllerPrograms +{ +public: + std::map programs; ///< the keys are the robot instance primary keys of the scene +}; + +/// \brief Creates on MUJIN Controller instance. +/// +/// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. +class MUJINCLIENT_API ControllerClient +{ +public: + virtual ~ControllerClient() { + } + +// \brief Returns a list of filenames in the user system of a particular type +// +// \param scenetype the type of scene possible values are: +// - mujincollada +// - wincaps +// - rttoolbox +// - cecrobodiaxml +// - stl +// - x +// - vrml +// - stl +// +// virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; + + /// \brief sets the character encoding for all strings that are being input and output from the resources + /// + /// The default character encoding is \b utf-8, can also set it to \b Shift_JIS for windows japanese unicode, \b iso-2022-jp + /// List of possible sets: http://www.iana.org/assignments/character-sets/character-sets.xml + virtual void SetCharacterEncoding(const std::string& newencoding) = 0; + + /// \brief sets the language code for all output + /// + /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + virtual void SetLanguage(const std::string& language) = 0; + + /// \brief sets the user agent to be sent with each http request + virtual void SetUserAgent(const std::string& userAgent) = 0; + + /// \brief sets additional http headers to be included on all requests + /// + /// \param additionalHeaders expect each value to be in the format of "Header-Name: header-value" + virtual void SetAdditionalHeaders(const std::vector& additionalHeaders) = 0; + + /// \brief returns the username logged into this controller + virtual const std::string& GetUserName() const = 0; + + /// \brief returns the URI used to setup the connection + virtual const std::string& GetBaseURI() const = 0; + + /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. + /// + /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + virtual void SetProxy(const std::string& serverport, const std::string& userpw) = 0; + + /// \brief If necessary, changes the unix domain socket to be used to communicate to the controller server. Setting unix endpoint disables previously set proxy. + /// + /// \param unixendpoint Specify the file path to the unix domain socket to connect to. + virtual void SetUnixEndpoint(const std::string& unixendpoint) = 0; + + /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. + /// + /// If the server is not responding, call this method to clear the server state and initialize everything. + /// The method is blocking, when it returns the MUJIN Controller would have been restarted. + virtual void RestartServer(double timeout = 5.0) = 0; + + /// \brief Execute GraphQL query or mutation against Mujin Controller. + /// + /// Throws an exception if there are any errors + /// \param rResultData The "data" field of the result if the query returns without problems + virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResultData, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + + /// \brief Execute the GraphQL query or mutation against Mujin Controller and return any output as-is without doing any error processing + /// + /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". + virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + + /// \brief returns the mujin controller version + virtual std::string GetVersion() = 0; + + /// \brief sends the cancel message to all jobs. + /// + /// The method is non-blocking + virtual void CancelAllJobs() = 0; + + /// \brief get all the run-time statuses + /// + /// \param options if options is 1, also get the message + virtual void GetRunTimeStatuses(std::vector& statuses, int options=0) = 0; + + /// \brief gets a list of all the scene primary keys currently available to the user + virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; + + /** \brief Register a scene to be used by the MUJIN Controller + + \param uri utf-8 encoded URI of the file on the MUJIN Controller to import. Usually starts with \b mujin:/ + \param scenetype The format of the source file. Can be: + - **mujincollada** + - **wincaps** (DensoWave WINCAPS III) + - **rttoolbox** (Mitsubishi RT ToolBox) + - **x** (DirectX) + - **vrml** + - **stl** + - **cecrobodiaxml** (CEC RoboDiA XML environments) + */ + virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) = 0; + + /// \brief registers scene with default scene type + virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri) + { + return RegisterScene_UTF8(uri,GetDefaultSceneType()); + } + + /// \see RegisterScene_UTF8 + /// + /// \param uri utf-16 encoded URI + virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) = 0; + + /// \brief registers scene with default scene type + virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri) + { + return RegisterScene_UTF16(uri,GetDefaultSceneType()); + } + + /** \brief import a scene into COLLADA format using from scene identified by a URI + + \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext + \param sourcescenetype The format of the source file. Can be: + - **mujincollada** + - **wincaps** (DensoWave WINCAPS III) + - **rttoolbox** (Mitsubishi RT ToolBox) + - **x** (DirectX) + - **vrml** + - **stl** + - **cecrobodiaxml** (CEC RoboDiA XML environments) + \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae + \param overwrite if true, will overwrite any existing scenes at newuri with the new scene. + */ + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri, bool overwrite=false) = 0; + + /// \see ImportSceneToCOLLADA_UTF8 + /// + /// \param sourceuri utf-16 encoded + /// \param newuri utf-16 encoded + virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; + + /** \brief Recommended way of uploading a scene's files into the network filesystem. + + Depending on the scenetype, can upload entire directory trees. + \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. + \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default prefix with "mujin:/". Use the / separator for different paths. + \param scenetype UTF-8 encoded type of scene uploading. + \throw mujin_exception if the upload fails, will throw an exception + */ + virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; + + /// \see SyncUpload_UTF8 + virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir) + { + SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); + } + + /// \see SyncUpload_UTF8 + /// + /// \param sourcefilename UTF-16 encoded. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. + /// \param destinationdir UTF-16 encoded + /// \param scenetype UTF-16 encoded + virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir, const std::string& scenetype) = 0; + + /// \see SyncUpload + virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir) + { + SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); + } + + /// \brief Uploads a single file to the controller network filesystem. + /// + /// Overwrites the file if it already exists + /// \param filename utf-8 encoded path of the file on the system + /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. + virtual void UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) = 0; + + /// \brief \see UploadFileToController_UTF8 + /// + /// \param filename utf-16 encoded + /// \param desturi UTF-16 encoded + virtual void UploadFileToController_UTF16(const std::wstring& filename, const std::wstring& desturi) = 0; + + /// \brief Uploads binary data to a single file on the controller network filesystem. + /// + /// Overwrites the destination uri if it already exists + /// \param data binary data to upload to the uri + /// \param size binary data size in bytes + /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. + virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) = 0; + + /// \brief \see UploadDataToController_UTF8 + /// + /// \param data binary data to upload to the uri + /// \param size binary data size in bytes + /// \param desturi UTF-16 encoded + virtual void UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) = 0; + + /// \brief Build a backup of config/media and download it. + /// + /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. + /// \param config whether to backup config. By default true. + /// \param media whether to include media files in the backup. By default true + /// \param backupscenepks comma separated list of scenes to backup. By default empty. + virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, const std::string& backupscenepks = "", double timeout = 60.0) = 0; + + /// \brief Restore backup archive into controller. Restaring might be required after restoration. + /// + /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). + /// \param config whether to restore config. By default true (if the backup file has config). + /// \param media whether to restore media. By default true (if the backup file has media). + virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; + + /// \brief Upgrade controller's software. + /// + /// \param inputStream the stream represententing the software file provided by MUJIN. + /// It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). + /// Pass stream with size 0 to use previously uploaded file. + /// \param autorestart whether to restart automatically after upgrading. if false, Reboot() can be called later. + /// \param uploadonly whether to upload only (so that upgrade can be continued later without uploading). + virtual void Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; + + /// \brief Get upgrade status. + /// + /// \param status upgrade status + /// \param progress progress 0 to 1 + /// \return true if the status was received (false means upgrade was not started yet). + virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout = 5.0) = 0; + + /// \brief Cancel the current upgrade process. + virtual void CancelUpgrade(double timeout = 5.0) = 0; + + /// \brief (Request to) reboot controller. + virtual void Reboot(double timeout = 5.0) = 0; + + /// \brief Delete all scenes. + virtual void DeleteAllScenes(double timeout = 5.0) = 0; + + /// \brief Delete all itl programs. + virtual void DeleteAllITLPrograms(double timeout = 5.0) = 0; + + /** \brief Recursively uploads a directory to the controller network filesystem. + + Creates directories along the way if they don't exist. + By default, overwrites all the files + \param copydir is utf-8 encoded. Cannot have trailing slashes '/', '\' + \param desturi UTF-8 encoded destination file in the network filesystem. If it has a trailing slash, then copydir is inside that URL. If there is no trailing slash, the copydir directory is renamed to the URI. By default prefix with "mujin:/". Use the / separator for different paths. + */ + virtual void UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) = 0; + + /// \brief \see UploadDirectoryToController_UTF8 + /// + /// \param copydir is utf-16 encoded + /// \param desturi UTF-16 encoded + virtual void UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) = 0; + + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) = 0; + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) = 0; + + /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header + /// \param remotetimeval will output the modified date in response + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; + + /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header + /// \param remotetimeval will output the modified date in response + /// \param vdata filled with the contents of the file on the controller filesystem + virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; + + /// \brief returns seconds since epoch, last modified time from server header + virtual long GetModifiedTime(const std::string& uri, double timeout = 5.0) = 0; + + /// \brief Deletes a file on the controller network filesystem. + /// + /// \param uri UTF-8 encoded file in the network filesystem to delete. + virtual void DeleteFileOnController_UTF8(const std::string& uri) = 0; + + /// \brief \see DeleteFileOnController_UTF8 + /// + /// \param uri UTF-16 encoded file in the network filesystem to delete. + virtual void DeleteFileOnController_UTF16(const std::wstring& uri) = 0; + + /// \brief Recursively deletes a directory on the controller network filesystem. + /// + /// \param uri UTF-8 encoded file in the network filesystem to delete. + virtual void DeleteDirectoryOnController_UTF8(const std::string& uri) = 0; + + /// \brief Get file list in specified directory. + /// + /// \param dirname UTF-8 encoded dirname to query. + virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; + + /// \brief \see DeleteDirectoryOnController_UTF8 + /// + /// \param uri UTF-16 encoded + virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; + + virtual void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; + + virtual void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; + + virtual void SetDefaultSceneType(const std::string& scenetype) = 0; + + virtual const std::string& GetDefaultSceneType() = 0; + + virtual void SetDefaultTaskType(const std::string& tasktype) = 0; + + virtual const std::string& GetDefaultTaskType() = 0; + + /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) + + For example, the URI + + mujin:/検証動作_121122.mujin.dae + + is represented as: + + "mujin:/\xe6\xa4\x9c\xe8\xa8\xbc\xe5\x8b\x95\xe4\xbd\x9c_121122.mujin.dae" + + Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" + \param uri utf-8 encoded URI + */ + virtual std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) = 0; + + /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) + + If input URL is L"mujin:/\u691c\u8a3c\u52d5\u4f5c_121122.mujin.dae" + Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" + + \param uri utf-16 encoded URI + */ + virtual std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) = 0; + + /// \brief returns the primary key of a name + /// + /// \param name utf-8 encoded + virtual std::string GetPrimaryKeyFromName_UTF8(const std::string& name) = 0; + + /// \brief returns the primary key of a name + /// + /// \param name utf-16 encoded + virtual std::string GetPrimaryKeyFromName_UTF16(const std::wstring& name) = 0; + + /// \brief returns the uncoded name from a primary key + /// + /// \return utf-8 encoded name + virtual std::string GetNameFromPrimaryKey_UTF8(const std::string& pk) = 0; + + /// \brief returns the uncoded name from a primary key + /// + /// \return utf-16 encoded name + virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; + + virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout = 5) = 0; + + /// \brief set geometry mesh to an object + /// \param objectPk primary key for the object to set mesh data to + /// \param geometryPk primary key for the geometry + /// \param data stl format binary mesh data + /// \param unit length unit of mesh + /// \param timeout timeout of uploading mesh + /// + virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; + + /// \brief get debug infos + virtual void GetDebugInfos(std::vector& debuginfos, double timeout = 5) = 0; +}; + +class MUJINCLIENT_API WebResource +{ +public: + WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk); + virtual ~WebResource() { + } + + inline ControllerClientPtr GetController() const { + return __controller; + } + inline const std::string& GetResourceName() const { + return __resourcename; + } + inline const std::string& GetPrimaryKey() const { + return __pk; + } + + /// \brief gets an attribute of this web resource + template + inline T Get(const std::string& field, double timeout = 5.0) { + rapidjson::Document pt(rapidjson::kObjectType); + GetWrap(pt, field, timeout); + return mujinjson::GetJsonValueByKey(pt, field.c_str()); + } + + /// \brief sets an attribute of this web resource + virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); + + /// \brief sets an attribute of this web resource + virtual void SetJSON(const std::string& json, double timeout = 5.0); + + /// \brief delete the resource and all its child resources + virtual void Delete(double timeout = 5.0); + + /// \brief copy the resource and all its child resources to a new name + virtual void Copy(const std::string& newname, int options, double timeout = 5.0); + +private: + virtual void GetWrap(rapidjson::Document& pt, const std::string& field, double timeout = 5.0); + + ControllerClientPtr __controller; + std::string __resourcename, __pk; +}; + +class MUJINCLIENT_API ObjectResource : public WebResource +{ +public: + class MUJINCLIENT_API GeometryResource : public WebResource { +public: + GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~GeometryResource() { + } + std::string name; + std::string pk; + std::string objectpk; + std::string linkpk; + std::string geomtype; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + bool visible; + Real diffusecolor[4]; + Real transparency; + Real half_extents[3]; + Real height; + Real radius; + + virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); + virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); + virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on + virtual int GetVisible(); + }; + typedef boost::shared_ptr GeometryResourcePtr; + + class MUJINCLIENT_API IkParamResource : public WebResource { +public: + IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~IkParamResource() { + } + std::string name; + std::string pk; + std::string iktype; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translation[3]; + Real direction[3]; + Real angle; + }; + typedef boost::shared_ptr IkParamResourcePtr; + + class MUJINCLIENT_API LinkResource : public WebResource { +public: + LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); + virtual ~LinkResource() { + } + + virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout = 5.0); + virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout = 5.0); + + virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); + + virtual void GetGeometries(std::vector& links); + + virtual boost::shared_ptr AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]); + + virtual void SetCollision(bool collision); + /// 0 -> off, 1 -> on + virtual int GetCollision(); + virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on, 2 -> partial + virtual int GetVisible(); + + std::vector attachmentpks; + std::string name; + std::string pk; + std::string objectpk; + std::string parentlinkpk; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + bool collision; + }; + typedef boost::shared_ptr LinkResourcePtr; + + + ObjectResource(ControllerClientPtr controller, const std::string& pk); + virtual ~ObjectResource() { + } + virtual void GetLinks(std::vector& links); + + virtual void GetIkParams(std::vector& ikparams); + + virtual LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]); + virtual IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype); + + virtual void SetCollision(bool collision); + /// 0 -> off, 1 -> on, 2 -> partial + virtual int GetCollision(); + virtual void SetVisible(bool visible); + /// 0 -> off, 1 -> on, 2 -> partial + virtual int GetVisible(); + + std::string name; + int nundof; + std::string datemodified; + std::string geometry; + bool isrobot; + std::string pk; + std::string resource_uri; + std::string scenepk; + std::string unit; + std::string uri; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + +protected: + ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); + +}; + +class MUJINCLIENT_API RobotResource : public ObjectResource +{ +public: + class MUJINCLIENT_API ToolResource : public WebResource { +public: + ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~ToolResource() { + } + + std::string name; + std::string frame_origin; + std::string frame_tip; + std::string pk; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + typedef boost::shared_ptr ToolResourcePtr; + + class MUJINCLIENT_API AttachedSensorResource : public WebResource { +public: + AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); + virtual ~AttachedSensorResource() { + } + + std::string name; + std::string frame_origin; + std::string pk; + //Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + std::string sensortype; + + struct SensorData { +public: + bool operator!=(const SensorData& other) const { + return std::memcmp(distortion_coeffs, other.distortion_coeffs, 5 * sizeof(Real)) != 0 || + distortion_model != other.distortion_model || + focal_length != other.focal_length || + std::memcmp(image_dimensions, other.image_dimensions, 3 * sizeof(int)) != 0 || + std::memcmp(intrinsic, other.intrinsic, 6 * sizeof(Real)) != 0 || + measurement_time != other.measurement_time || + extra_parameters != other.extra_parameters; + } + bool operator==(const SensorData& other) const { + return !operator!=(other); + } + Real distortion_coeffs[5]; + std::string distortion_model; + Real focal_length; + int image_dimensions[3]; + Real intrinsic[6]; + Real measurement_time; + std::vector extra_parameters; + }; + SensorData sensordata; + }; + + typedef boost::shared_ptr AttachedSensorResourcePtr; + + RobotResource(ControllerClientPtr controller, const std::string& pk); + virtual ~RobotResource() { + } + + virtual void GetTools(std::vector& tools); + virtual void GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies = true); + + // attachments + // ikparams + // images + int numdof; + std::string simulation_file; +}; + +class MUJINCLIENT_API SceneResource : public WebResource +{ +public: + class InstObject; + typedef boost::shared_ptr InstObjectPtr; + /// \brief nested resource in the scene describe an object in the scene + class MUJINCLIENT_API InstObject : public WebResource + { +public: + InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk); + virtual ~InstObject() { + } + + class MUJINCLIENT_API Link { +public: + std::string name; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Tool { +public: + std::string name; + Real direction[3]; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + class MUJINCLIENT_API Grab { +public: + std::string instobjectpk; ///< grabed_instobject_pk + std::string grabbed_linkpk; + std::string grabbing_linkpk; + + std::string Serialize() { + return boost::str(boost::format("{\"instobjectpk\": \"%s\", \"grabbed_linkpk\": \"%s\", \"grabbing_linkpk\": \"%s\"}")%instobjectpk%grabbed_linkpk%grabbing_linkpk); + } + + bool operator==(const Grab grab) { + if (this->instobjectpk == grab.instobjectpk + && this->grabbed_linkpk == grab.grabbed_linkpk + && this->grabbing_linkpk == grab.grabbing_linkpk) { + return true; + } + return false; + } + }; + + class MUJINCLIENT_API AttachedSensor { +public: + std::string name; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + }; + + void SetTransform(const Transform& t); + void SetDOFValues(); + virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + virtual void ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); + + + std::vector dofvalues; + std::string name; + std::string pk; + std::string object_pk; + std::string reference_object_pk; + std::string reference_uri; + Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] + Real translate[3]; + std::vector grabs; + std::vector links; + std::vector tools; + std::vector attachedsensors; + }; + + SceneResource(ControllerClientPtr controller, const std::string& pk); + virtual ~SceneResource() { + } + + virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); + + /** \brief Gets or creates the a task part of the scene + + If task exists already, validates it with tasktype. + \param taskname utf-8 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown + \param tasktype The type of task to create. Supported types are: + - itlplanning + */ + + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); + + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) + { + return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType(), options); + } + + virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname, int options=0); + + /** \brief Gets or creates the a task part of the scene + + If task exists already, validates it with tasktype. + \param taskname utf-16 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown + \param tasktype The type of task to create. Supported types are: + - itlplanning + */ + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options=0); + + virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, int options=0) + { + return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType(), options); + } + + virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); + + + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype="binpicking", int options=0); + virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype="binpicking", int options=0); + + + /// \brief gets a list of all the scene primary keys currently available to the user + virtual void GetTaskPrimaryKeys(std::vector& taskkeys); + + virtual void GetTaskNames(std::vector& names); + + /// \brief gets a list of all the instance objects of the scene + virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); + virtual void GetInstObjects(std::vector& instobjects); + virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); + + /// \brief creates an inst object in scene + /// \param name name of the object to create + /// \param referenceUri uri to reference. Leave empty to reference nothing. + /// \param quaternion quaternion of the object + /// \param translate translation of the object + /// \return pointer to inst object created + virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout = 300); + + /// \brief deletes an inst object in scene + /// \param pk primary key of the object to delete + virtual void DeleteInstObject(const std::string& pk); + + virtual SceneResourcePtr Copy(const std::string& name); +}; + +class MUJINCLIENT_API TaskResource : public WebResource +{ +public: + TaskResource(ControllerClientPtr controller, const std::string& pk); + virtual ~TaskResource() { + } + + /// \brief execute the task. + /// + /// This operation is non-blocking and will return immediately after the execution is started. In order to check if the task is running or is complete, use \ref GetRunTimeStatus() and \ref GetResult() + /// \return true if task was executed fine + virtual bool Execute(); + + /// \brief if the task is currently executing, send a cancel request + virtual void Cancel(); + + /// \brief get the run-time status of the executed task. + /// + /// This will only work if the task has been previously Executed with execute + /// If the task is not currently running, will set status.code to JSC_Unknown + /// \param options if options is 1, also get the message + virtual void GetRunTimeStatus(JobStatus& status, int options = 1); + + /// \brief Gets or creates the a optimization part of the scene + /// + /// \param optimizationname the name of the optimization to search for or create + /// \param optimizaitontype The type of optimization, can be "robotplacement" or "placements" + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); + + /// \brief \see GetOrCreateOptimizationFromName_UTF8 + virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); + + /// \brief gets a list of all the scene primary keys currently available to the user + virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); + + /// \brief Get the task info for tasks of type itlplanning + virtual void GetTaskParameters(ITLPlanningTaskParameters& taskparameters); + + /// \brief Set new task info for tasks of type itlplanning + virtual void SetTaskParameters(const ITLPlanningTaskParameters& taskparameters); + + /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. + virtual PlanningResultResourcePtr GetResult(); + +protected: + std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called +}; + +class MUJINCLIENT_API OptimizationResource : public WebResource +{ +public: + OptimizationResource(ControllerClientPtr controller, const std::string& pk); + virtual ~OptimizationResource() { + } + + /// \brief execute the optimization + /// + /// \param bClearOldResults if true, will clear the old optimiation results. If false, will keep the old optimization results and only compute those that need to be computed. + virtual void Execute(bool bClearOldResults=true); + + /// \brief if the optimization is currently executing, send a cancel request + virtual void Cancel(); + + /// \brief Set new task info for tasks of type robotplanning + void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); + + /// \brief Set new task info for tasks of type placements + void SetOptimizationParameters(const PlacementsOptimizationParameters& optparams); + + /// \brief get the run-time status of the executed optimization. + /// + /// This will only work if the optimization has been previously Executed with execute + /// If the task is not currently running, will set status.code to JSC_Unknown + /// \param options if options is 1, also get the message + virtual void GetRunTimeStatus(JobStatus& status, int options = 1); + + /// \brief Gets the results of the optimization execution ordered by task_time. + /// + /// \param startoffset The offset to retrieve the results from. Ordered + /// \param num The number of results to get starting at startoffset. If 0, will return ALL results. + virtual void GetResults(std::vector& results, int startoffset=0, int num=0); + +protected: + std::string _jobpk; ///< the job primary key used to track the status of the running optimization after \ref Execute is called +}; + +class MUJINCLIENT_API PlanningResultResource : public WebResource +{ +public: + PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk); + PlanningResultResource(ControllerClientPtr controller, const std::string& pk); + virtual ~PlanningResultResource() { + } + + /// \brief Get all the transforms the results are storing. Depending on the optimization, can be more than just the robot + virtual void GetEnvironmentState(EnvironmentState& envstate); + + /** \brief Gets the raw program information + + \param[in] programtype The type of program to return. Possible values are: + - auto - special type that returns the most suited programs + - mujinxml - \b xml + - melfabasicv - \b json with Mitsubishi-specific programs + - densowaverc8pac - \b json with DensoWave-specific programs + - cecrobodiasim - zip file + + If \b auto is set, then the robot-maker specific program is returned if possible. If not possible, then mujin xml is returned. All the programs for all robots planned are returned. + + \param[out] outputdata The raw program data + */ + virtual void GetAllRawProgramData(std::string& outputdata, const std::string& programtype="auto"); + + /** \brief Gets the raw program information of a specific robot, if supported. + + \param[in] robotpk The primary key of the robot instance in the scene. + \param[out] outputdata The raw program data + \param[in] programtype The type of program to return. + \throw mujin_exception If robot program is not supported, will throw an exception + */ + virtual void GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype="auto"); + + /// \brief Gets parsed program information + /// + /// If the robot doesn't have a recognizable controller, then no programs might be returned. + /// \param[out] programs The programs for each robot. The best suited program for each robot is determined from its controller. + /// \param[in] programtype The type of program to return. + virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); +}; + +class MUJINCLIENT_API DebugResource : public WebResource +{ +public: + DebugResource(ControllerClientPtr controller, const std::string& pk); + virtual ~DebugResource() { + } + + /// \brief download the encrypted debug log to outputStream + virtual void Download(std::ostream &outputStream, double timeout = 60.0); + + //std::string datemodified; + std::string description; + //std::string downloadUri; + std::string name; + std::string pk; + std::string resource_uri; + size_t size; + +protected: + DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); +}; + +/** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests + */ +MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); + +/// \brief called at the very end of an application to safely destroy all controller client resources +MUJINCLIENT_API void DestroyControllerClient(); + +/// \deprecated 14/03/14 +MUJINCLIENT_API void ControllerClientDestroy() MUJINCLIENT_DEPRECATED; + +/// \brief Compute a 3x4 matrix from a Transform +MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); + +/** \brief Compute Euler angles in ZXY order (T = Z*X*Y) from a 3x4 matrix + + Rx = Matrix(3,3,[1,0,0,0,cos(x),-sin(x),0,sin(x),cos(x)]) + Ry = Matrix(3,3,[cos(y),0,sin(y),0,1,0,-sin(y),0,cos(y)]) + Rz = Matrix(3,3,[cos(z),-sin(z),0,sin(z),cos(z),0,0,0,1]) + Rz*Rx*Ry + + [-sin(x)*sin(y)*sin(z) + cos(y)*cos(z), -sin(z)*cos(x), sin(x)*sin(z)*cos(y) + sin(y)*cos(z)] + [ sin(x)*sin(y)*cos(z) + sin(z)*cos(y), cos(x)*cos(z), -sin(x)*cos(y)*cos(z) + sin(y)*sin(z)] + [ -sin(y)*cos(x), sin(x), cos(x)*cos(y)] + + */ +MUJINCLIENT_API void ComputeZXYFromMatrix(Real ZXY[3], const Real matrix[12]); + +MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &transform); + +MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); + + +} // namespace mujinclient + +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MAJOR>=0&&MUJINCLIENT_VERSION_MAJOR<=255); +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MINOR>=0&&MUJINCLIENT_VERSION_MINOR<=255); +BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_PATCH>=0&&MUJINCLIENT_VERSION_PATCH<=255); + +#endif diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp deleted file mode 100644 index c2ad77ff..00000000 --- a/src/mujincontrollerclient.cpp +++ /dev/null @@ -1,1385 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2013 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "common.h" -#include "controllerclientimpl.h" -#include // for sleep -#include - -#include - -#ifdef MUJIN_USEZMQ -#include "binpickingtaskzmq.h" -#endif - -#include "logging.h" -#include "mujincontrollerclient/mujinjson.h" - -MUJIN_LOGGER("mujin.controllerclientcpp"); - -namespace mujinclient { - -using namespace mujinjson; - -void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) -{ - // FIXME: is this a dict or array? - envstate.clear(); - for (rapidjson::Document::ConstValueIterator it = envstatejson.Begin(); it != envstatejson.End(); ++it) { - InstanceObjectState objstate; - std::string name = GetJsonValueByKey(*it, "name"); - std::vector quat = GetJsonValueByKey >(*it, "quat_"); - BOOST_ASSERT(quat.size() == 4); - Real dist2 = 0; - for (int i = 0; i < 4; i++ ) { - Real f = quat[i] * quat[i]; - dist2 += f; - objstate.transform.quaternion[i] = f; - } - // normalize the quaternion - if( dist2 > 0 ) { - Real fnorm =1/std::sqrt(dist2); - objstate.transform.quaternion[0] *= fnorm; - objstate.transform.quaternion[1] *= fnorm; - objstate.transform.quaternion[2] *= fnorm; - objstate.transform.quaternion[3] *= fnorm; - } - LoadJsonValueByKey(*it, "translation_", objstate.transform.translate); - LoadJsonValueByKey(*it, "dofvalues", objstate.dofvalues); - envstate[name] = objstate; - } -} - -void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os) -{ - os << "["; - bool bhaswritten = false; - FOREACHC(itstate, envstate) { - if( itstate->first.size() > 0 ) { - if( bhaswritten ) { - os << ","; - } - os << "{ \"name\":\"" << itstate->first << "\", \"translation_\":["; - for(int i = 0; i < 3; ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.transform.translate[i]; - } - os << "], \"quat_\":["; - for(int i = 0; i < 4; ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.transform.quaternion[i]; - } - os << "], \"dofvalues\":["; - for(size_t i = 0; i < itstate->second.dofvalues.size(); ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.dofvalues.at(i); - } - os << "] }"; - bhaswritten = true; - } - } - os << "]"; -} - -WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) -{ - BOOST_ASSERT(__pk.size()>0); -} - -void WebResource::GetWrap(rapidjson::Document& pt, const std::string& field, double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, 200, timeout); -} - -void WebResource::Set(const std::string& field, const std::string& newvalue, double timeout) -{ - throw MujinException("not implemented"); -} - -void WebResource::SetJSON(const std::string& json, double timeout) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), json, pt, 202, timeout); -} - -void WebResource::Delete(double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey()), 204, timeout); -} - -void WebResource::Copy(const std::string& newname, int options, double timeout) -{ - throw MujinException("not implemented yet"); -} - -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "object", pk_), pk(pk_) -{ -} - -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) -{ -} - -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/link")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) -{ -} - -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) -{ -} - -ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk_), pk_), pk(pk_) -{ -} - -void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("%s/%s/?format=json&limit=0&mesh=true")%GetResourceName()%GetPrimaryKey())); - controller->CallGet(relativeuri, pt); - rapidjson::Value& objects = pt["mesh"]; - LoadJsonValueByKey(objects,"primitive",primitive); - LoadJsonValueByKey(objects,"indices",indices); - LoadJsonValueByKey(objects,"vertices",vertices); -} - -void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout) -{ - GETCONTROLLERIMPL(); - if (this->geomtype != "mesh") { - throw MUJIN_EXCEPTION_FORMAT("geomtype is not mesh: %s", this->geomtype, MEC_InvalidArguments); - } - controller->SetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& geomname, const std::string& unit, double timeout) -{ - GETCONTROLLERIMPL(); - const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, "mesh", timeout); - - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = geomname; - geometry->geomtype = "mesh"; - geometry->linkpk = linkpk; - geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); - return geometry; -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGeometry(const std::string& geomname, const std::string& geomtype, double timeout) -{ - GETCONTROLLERIMPL(); - const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, geomtype, timeout); - - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = geomname; - geometry->geomtype = geomtype; - geometry->linkpk = linkpk; - return geometry; -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); - controller->CallGet(relativeuri, pt); - if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { - rapidjson::Value& objects = pt["geometries"]; - for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string geomname = it->HasMember("name") ? GetJsonValueByKey(*it, "name") : GetJsonValueByKey(*it, "pk"); - if (geomname == geometryName && (*it)["linkpk"].GetString() == this->pk) { - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = geomname; - LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); - LoadJsonValueByKey(*it,"visible",geometry->visible); - LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); - LoadJsonValueByKey(*it,"transparency",geometry->transparency); - LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); - LoadJsonValueByKey(*it,"translate",geometry->translate); - LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); - - /// geomtype /// - // mesh - // box: half_extents - // cylinder: height, radius - // sphere: radius - LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); - LoadJsonValueByKey(*it,"height",geometry->height); - LoadJsonValueByKey(*it,"radius",geometry->radius); - return geometry; - } - } - } - throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); -} - -void ObjectResource::LinkResource::GetGeometries(std::vector& geometries) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); - controller->CallGet(relativeuri, pt); - if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { - rapidjson::Value& objects = pt["geometries"]; - geometries.clear(); - for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string linkpk = GetJsonValueByKey(*it, "linkpk"); - if (linkpk == this->pk) { - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->linkpk = linkpk; - LoadJsonValueByKey(*it,"name",geometry->name,geometry->pk); - LoadJsonValueByKey(*it,"visible",geometry->visible); - LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); - LoadJsonValueByKey(*it,"transparency",geometry->transparency); - LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); - LoadJsonValueByKey(*it,"translate",geometry->translate); - LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); - - LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); - LoadJsonValueByKey(*it,"height",geometry->height); - LoadJsonValueByKey(*it,"radius",geometry->radius); - geometries.push_back(geometry); - } - } - } -} - -void ObjectResource::LinkResource::SetCollision(bool hasCollision) -{ - this->SetJSON(mujinjson::GetJsonStringByKey("collision", hasCollision)); - this->collision = hasCollision; -} -void ObjectResource::SetCollision(bool collision) -{ - std::vector links; - this->GetLinks(links); - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - link->SetCollision(collision); - } -} -int ObjectResource::LinkResource::GetCollision() -{ - return this->collision; -} -int ObjectResource::GetCollision() -{ - std::vector links; - this->GetLinks(links); - int ret=0; - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - ret|=link->GetCollision()+1; - } - return ret-1; -} - -void ObjectResource::GeometryResource::SetVisible(bool isVisible) -{ - this->SetJSON(mujinjson::GetJsonStringByKey("visible",isVisible)); - this->visible = isVisible; -} -void ObjectResource::LinkResource::SetVisible(bool visible) -{ - std::vector geometries; - this->GetGeometries(geometries); - BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ - geometry->SetVisible(visible); - } -} -void ObjectResource::SetVisible(bool visible) -{ - std::vector links; - this->GetLinks(links); - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - link->SetVisible(visible); - } -} -int ObjectResource::GeometryResource::GetVisible() -{ - return this->visible; -} -int ObjectResource::LinkResource::GetVisible() -{ - std::vector geometries; - this->GetGeometries(geometries); - int ret=0; - BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ - ret|=geometry->GetVisible()+1; - } - return ret-1; -} -int ObjectResource::GetVisible() -{ - std::vector links; - this->GetLinks(links); - int ret=0; - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - ret|=link->GetVisible()+1; - } - return ret-1; -} - -void ObjectResource::GetLinks(std::vector& links) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("object/%s/link/?format=json&limit=0&fields=links")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["links"]; - links.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - LoadJsonValueByKey(*it,"parentlinkpk",link->parentlinkpk); - LoadJsonValueByKey(*it,"name",link->name); - LoadJsonValueByKey(*it,"collision",link->collision); - LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); - LoadJsonValueByKey(*it,"quaternion",link->quaternion); - LoadJsonValueByKey(*it,"translate",link->translate); - links[i++] = link; - } -} - -ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) -{ - GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->pk, "", objname, quaternion_, translate_); - - ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->pk, linkPk)); - link->name = objname; - link->parentlinkpk = ""; - return link; -} - -ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) -{ - GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, objname, quaternion_, translate_); - - ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->objectpk, linkPk)); - link->name = objname; - link->parentlinkpk = this->pk; - return link; -} - -ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& objname, const std::string& iktype) -{ - GETCONTROLLERIMPL(); - const std::string ikparamPk = controller->CreateIkParam(this->pk, objname, iktype); - - return ObjectResource::IkParamResourcePtr(new IkParamResource(controller, this->pk, ikparamPk)); -} - -void ObjectResource::GetIkParams(std::vector& ikparams) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("object/%s/ikparam/?format=json&limit=0&fields=ikparams")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["ikparams"]; - ikparams.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - IkParamResourcePtr ikparam(new IkParamResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - LoadJsonValueByKey(*it,"name",ikparam->name); - LoadJsonValueByKey(*it,"iktype",ikparam->iktype); - LoadJsonValueByKey(*it,"quaternion",ikparam->quaternion); - LoadJsonValueByKey(*it,"direction",ikparam->direction); - LoadJsonValueByKey(*it,"translation",ikparam->translation); - LoadJsonValueByKey(*it,"angle",ikparam->angle); - ikparams[i++] = ikparam; - } -} - -RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk_) : ObjectResource(controller, "robot", pk_) -{ -} - -RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk_), pk(pk_) -{ -} - -void RobotResource::GetTools(std::vector& tools) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/tool/?format=json&limit=0&fields=tools")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["tools"]; - tools.resize(objects.Size()); - size_t i = 0; -// FOREACH(v, objects) { - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - - LoadJsonValueByKey(*it, "name", tool->name); - LoadJsonValueByKey(*it, "frame_orgin", tool->frame_origin); - LoadJsonValueByKey(*it, "frame_tip", tool->frame_tip); - LoadJsonValueByKey(*it, "direction", tool->direction); - LoadJsonValueByKey(*it, "quaternion", tool->quaternion); - LoadJsonValueByKey(*it, "translate", tool->translate); - - tools[i++] = tool; - } -} - -RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk_), pk(pk_) -{ -} - -void RobotResource::GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); - - rapidjson::Value& rAttachedSensors = pt["attachedsensors"]; - attachedsensors.resize(rAttachedSensors.Size()); - size_t attachedSensorIdx = 0; - for (rapidjson::Document::ValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*itAttachedSensor, "pk"))); - - LoadJsonValueByKey(*itAttachedSensor, "name", attachedsensor->name); - LoadJsonValueByKey(*itAttachedSensor, "frame_origin", attachedsensor->frame_origin); - LoadJsonValueByKey(*itAttachedSensor, "sensortype", attachedsensor->sensortype); - LoadJsonValueByKey(*itAttachedSensor, "quaternion", attachedsensor->quaternion); - LoadJsonValueByKey(*itAttachedSensor, "translate", attachedsensor->translate); - std::vector distortionCoeffs = GetJsonValueByPath > (*itAttachedSensor, "/sensordata/distortion_coeffs"); - - BOOST_ASSERT(distortionCoeffs.size() <= 5); - for (size_t i = 0; i < distortionCoeffs.size(); i++) { - attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; - } - attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*itAttachedSensor, "/sensordata/distortion_model"); - attachedsensor->sensordata.focal_length = GetJsonValueByPath(*itAttachedSensor, "/sensordata/focal_length"); - attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*itAttachedSensor, "/sensordata/measurement_time"); - std::vector intrinsics = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/intrinsic"); - BOOST_ASSERT(intrinsics.size() <= 6); - for (size_t i = 0; i < intrinsics.size(); i++) { - attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; - } - std::vector imgdim = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/image_dimensions"); - BOOST_ASSERT(imgdim.size() <= 3); - for (size_t i = 0; i < imgdim.size(); i++) { - attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; - } - - if (rapidjson::Pointer("/sensordata/extra_parameters").Get(*itAttachedSensor)) { - std::string parameters_string = GetJsonValueByPath(*itAttachedSensor, "/sensordata/extra_parameters"); - //std::cout << "extra param " << parameters_string << std::endl; - std::list results; - boost::split(results, parameters_string, boost::is_any_of(" ")); - results.remove(""); - attachedsensor->sensordata.extra_parameters.resize(results.size()); - size_t iparam = 0; - BOOST_FOREACH(std::string p, results) { - //std::cout << "'"<< p << "'"<< std::endl; - try { - attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); - } catch (...) { - //lexical_cast fails... - } - } - } else { - //std::cout << "no asus param" << std::endl; - } - - attachedsensors[attachedSensorIdx++] = attachedsensor; - } - - rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%GetPrimaryKey()), rRobotConnectedBodies); - rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; - if (useConnectedBodies && rConnectedBodies.IsArray() && rConnectedBodies.Size() > 0) { - for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { - std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); - std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); - rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { - if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { - continue; - } - std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - RobotResourcePtr connectedbodyrobot(new RobotResource(controller,connectedBodyObjectPk)); - std::vector connectedbodyattachedsensors; - - connectedbodyrobot->GetAttachedSensors(connectedbodyattachedsensors, false); - - for (size_t i = 0; i < connectedbodyattachedsensors.size(); i++) { - std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%connectedbodyattachedsensors[i]->name); - connectedbodyattachedsensors[i]->name = resolvedSensorName; - } - - attachedsensors.reserve(attachedsensors.size() + connectedbodyattachedsensors.size()); - attachedsensors.insert(attachedsensors.end(), connectedbodyattachedsensors.begin(), connectedbodyattachedsensors.end()); - } - } - } -} - -SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk_) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk_), pk(pk_) -{ -} - -void SceneResource::InstObject::SetTransform(const Transform& t) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt; - std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); -} - -void SceneResource::InstObject::SetDOFValues() -{ - GETCONTROLLERIMPL(); - std::stringstream ss; - ss << "{\"dofvalues\":"; - ss << "["; - if( this->dofvalues.size() > 0 ) { - for (unsigned int i = 0; i < this->dofvalues.size(); i++) { - ss << this->dofvalues[i]; - if( i != this->dofvalues.size()-1) { - ss << ", "; - } - } - } - ss << "]}"; - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); -} - - -void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) -{ - SceneResource::InstObject::Grab grab; - grab.instobjectpk = grabbedobject->pk; - grab.grabbed_linkpk = grabbedobjectlinkpk; - grab.grabbing_linkpk = grabbinglinkpk; - //TODO do not use this->grabs. this is the cached information - for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { - if (this->grabs[igrab] == grab) { - std::stringstream ss; - ss << grabbedobject->name << "is already grabbed"; - MUJIN_LOG_ERROR(ss.str()); - return; - } - } - std::stringstream ss; - ss << "{\"grabs\":"; - ss << "["; - if( this->grabs.size() > 0 ) { - for (unsigned int i = 0; i < this->grabs.size(); i++) { - ss << this->grabs[i].Serialize() << ", "; - } - } - ss << grab.Serialize(); - ss << "]}"; - GETCONTROLLERIMPL(); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); -} - -void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) -{ - SceneResource::InstObject::Grab grab; - grab.instobjectpk = grabbedobject->pk; - grab.grabbed_linkpk = grabbedobjectlinkpk; - grab.grabbing_linkpk = grabbinglinkpk; - for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { - if (this->grabs[igrab] == grab) { - this->grabs.erase(std::remove(this->grabs.begin(), this->grabs.end(), this->grabs[igrab]), this->grabs.end()); - std::stringstream ss; - ss << "{\"grabs\":"; - ss << "["; - if( this->grabs.size() > 0 ) { - for (unsigned int i = 0; i < this->grabs.size(); i++) { - ss << this->grabs[i].Serialize() << ", "; - } - if( igrab != this->grabs.size()-1) { - ss << ", "; - } - } - ss << "]}"; - GETCONTROLLERIMPL(); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); - } - } - std::stringstream ss; - ss << grabbedobject->name << "is not grabbed"; - MUJIN_LOG_ERROR(ss.str()); - -} - -SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) -{ - // get something from the scene? - //this->Get(""); -} - -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); - // task exists - std::string pk; - - std::string tasktype_internal = tasktype; - if( tasktype == "realtimeitlplanning" ) { - tasktype_internal = "realtimeitlplanning3"; - } - - if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { - rapidjson::Value& objects = pt["objects"]; - pk = GetJsonValueByKey(objects[0], "pk"); - std::string currenttasktype = GetJsonValueByKey(objects[0], "tasktype"); - if( currenttasktype != tasktype_internal && (currenttasktype != "realtimeitlplanning" || tasktype_internal != "realtimeitlplanning3")) { - throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype_internal, MEC_InvalidState); - } - } - else { - pt.SetObject(); - controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype_internal%GetPrimaryKey()), pt); - LoadJsonValueByKey(pt, "pk", pk); - } - - if( pk.size() == 0 ) { - return TaskResourcePtr(); - } - - if( tasktype_internal == "binpicking" || tasktype_internal == "realtimeitlplanning3") { - BinPickingTaskResourcePtr task; - if( options & 1 ) { -#ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey(), tasktype_internal)); -#else - throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); -#endif - } - else { - task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); - } - return task; - } - else if( tasktype_internal == "cablepicking" ) { // TODO create CablePickingTaskResource - BinPickingTaskResourcePtr task; - if( options & 1 ) { -#ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); -#else - throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); -#endif - } - else { - task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); - } - return task; - } - else { - TaskResourcePtr task(new TaskResource(GetController(), pk)); - return task; - } -} - -void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) -{ - GETCONTROLLERIMPL(); - if (instobjects.size() != states.size()) { - throw MUJIN_EXCEPTION_FORMAT("the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); - } - boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); - std::string datastring, sdofvalues; - for(size_t i = 0; i < instobjects.size(); ++i) { - const Transform& transform = states[i].transform; - if( states[i].dofvalues.size() > 0 ) { - sdofvalues = str(boost::format(", \"dofvalues\":[%.15f")%states[i].dofvalues.at(0)); - for(size_t j = 1; j < states[i].dofvalues.size(); ++j) { - sdofvalues += str(boost::format(", %.15f")%states[i].dofvalues.at(j)); - } - sdofvalues += "]"; - } - else { - sdofvalues = ""; - } - datastring += str(transformtemplate%instobjects[i]->pk%transform.quaternion[0]%transform.quaternion[1]%transform.quaternion[2]%transform.quaternion[3]%transform.translate[0]%transform.translate[1]%transform.translate[2]%sdofvalues); - if ( i != instobjects.size()-1) { - datastring += ","; - } - } - std::string data = str(boost::format("{\"objects\": [%s]}")%datastring); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); -} - -TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname, int options) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); - // task exists - - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { - throw MUJIN_EXCEPTION_FORMAT("could not find task with name %s", taskname, MEC_InvalidState); - } - - std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); - TaskResourcePtr task(new TaskResource(GetController(), pk)); - return task; -} - -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) -{ - std::string taskname_utf8; - utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetOrCreateTaskFromName_UTF8(taskname_utf8, tasktype, options); -} - -TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& taskname, int options) -{ - std::string taskname_utf8; - utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetTaskFromName_UTF8(taskname_utf8, options); -} - -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) -{ - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, tasktype, options)); -} - -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) -{ - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, tasktype, options)); -} - -void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - taskkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - taskkeys[i++] = GetJsonValueByKey(*it, "pk"); - } -} - -void SceneResource::GetTaskNames(std::vector& taskkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=name")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - taskkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - taskkeys[i++] = GetJsonValueByKey(*it, "name"); - } -} - -void SceneResource::GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos) -{ - GETCONTROLLERIMPL(); - allSensorSelectionInfos.clear(); - rapidjson::Document rInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,connectedBodies,object_pk,name")%GetPrimaryKey()), rInstObjects); - for (rapidjson::Document::ConstValueIterator itInstObject = rInstObjects["objects"].Begin(); itInstObject != rInstObjects["objects"].End(); ++itInstObject) { - const std::string sensorName = GetJsonValueByKey(*itInstObject, "name"); - const std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); - if ( itInstObject->HasMember("attachedsensors") && (*itInstObject)["attachedsensors"].IsArray() && (*itInstObject)["attachedsensors"].Size() > 0) { - rapidjson::Document rRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%objectPk), rRobotAttachedSensors); - const rapidjson::Value& rAttachedSensors = rRobotAttachedSensors["attachedsensors"]; - for (rapidjson::Document::ConstValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - const std::string sensorLinkName = GetJsonValueByKey(*itAttachedSensor, "linkName"); - allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); - } - } - if ( itInstObject->HasMember("connectedBodies") && (*itInstObject)["connectedBodies"].IsArray() && (*itInstObject)["connectedBodies"].Size() > 0 ) { - rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%objectPk), rRobotConnectedBodies); - rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; - for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { - const std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); - const std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); - rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { - if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { - continue; - } - std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); - rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; - for (rapidjson::Document::ConstValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { - const std::string sensorLinkName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "linkName"); - allSensorSelectionInfos.emplace_back(sensorName, connectedBodyName+"_"+sensorLinkName); - } - } - } - } - } -} - -void SceneResource::GetInstObjects(std::vector& instobjects) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - - instobjects.resize(objects.Size()); - size_t iobj = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - - LoadJsonValueByKey(*it, "name", instobject->name); - LoadJsonValueByKey(*it, "object_pk", instobject->object_pk); - LoadJsonValueByKey(*it, "reference_object_pk", instobject->reference_object_pk, std::string()); - LoadJsonValueByKey(*it, "reference_uri", instobject->reference_uri); - LoadJsonValueByKey(*it, "dofvalues", instobject->dofvalues); - LoadJsonValueByKey(*it, "quaternion", instobject->quaternion); - LoadJsonValueByKey(*it, "translate", instobject->translate); - - if (it->HasMember("links")) { - rapidjson::Value& jsonlinks = (*it)["links"]; - instobject->links.resize(jsonlinks.Size()); - size_t ilink = 0; - for (rapidjson::Document::ValueIterator itlink = jsonlinks.Begin(); itlink != jsonlinks.End(); ++itlink) { - InstObject::Link& link = instobject->links[ilink]; - LoadJsonValueByKey(*itlink, "name", link.name); - LoadJsonValueByKey(*itlink, "quaternion", link.quaternion); - LoadJsonValueByKey(*itlink, "translate", link.translate); - ilink++; - } - } - - if (it->HasMember("tools")) { - rapidjson::Value& jsontools = (*it)["tools"]; - instobject->tools.resize(jsontools.Size()); - size_t itool = 0; - for (rapidjson::Document::ValueIterator ittool = jsontools.Begin(); ittool != jsontools.End(); ++ittool) { - InstObject::Tool &tool = instobject->tools[itool]; - LoadJsonValueByKey(*ittool, "name", tool.name); - LoadJsonValueByKey(*ittool, "quaternion", tool.quaternion); - LoadJsonValueByKey(*ittool, "translate", tool.translate); - LoadJsonValueByKey(*ittool, "direction", tool.direction); - itool++; - } - } - - if (it->HasMember("grabs")) { - rapidjson::Value& jsongrabs = (*it)["grabs"]; - instobject->grabs.resize(jsongrabs.Size()); - size_t igrab = 0; - for (rapidjson::Document::ValueIterator itgrab = jsongrabs.Begin(); itgrab != jsongrabs.End(); ++itgrab) { - InstObject::Grab &grab = instobject->grabs[igrab]; - LoadJsonValueByKey(*itgrab, "instobjectpk", grab.instobjectpk); - LoadJsonValueByKey(*itgrab, "grabbed_linkpk", grab.grabbed_linkpk); - LoadJsonValueByKey(*itgrab, "grabbing_linkpk", grab.grabbing_linkpk); - igrab++; - } - } - - if (it->HasMember("attachedsensors")) { - rapidjson::Value& jsonattachedsensors = (*it)["attachedsensors"]; - instobject->attachedsensors.resize(jsonattachedsensors.Size()); - size_t iattchedsensor = 0; - for (rapidjson::Document::ValueIterator itsensor = jsonattachedsensors.Begin(); - itsensor != jsonattachedsensors.End(); ++itsensor) { - InstObject::AttachedSensor& sensor = instobject->attachedsensors[iattchedsensor]; - LoadJsonValueByKey(*itsensor, "name", sensor.name); - LoadJsonValueByKey(*itsensor, "quaternion", sensor.quaternion); - LoadJsonValueByKey(*itsensor, "translate", sensor.translate); - iattchedsensor++; - } - } - instobjects.at(iobj++) = instobject; - } -} - -bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstObjectPtr& instobject) -{ - - std::vector instobjects; - this->GetInstObjects(instobjects); - for(size_t i = 0; i < instobjects.size(); ++i) { - if (instobjects[i]->name == name) { - instobject = instobjects[i]; - return true; - } - } - return false; -} - -SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) -{ - GETCONTROLLERIMPL(); - const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk,object_pk,reference_object_pk,reference_uri,dofvalues,quaternion,translate")%GetPrimaryKey())); - std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); - if (!referenceUri.empty()) { - data += ", \"reference_uri\": \"" + referenceUri + "\""; - } - data += "}"; - - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost(uri, data, pt, 201, timeout); - std::string inst_pk = GetJsonValueByKey(pt, "pk"); - SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); - LoadJsonValueByKey(pt, "object_pk", instobject->object_pk); - LoadJsonValueByKey(pt, "reference_object_pk", instobject->reference_object_pk, std::string()); - LoadJsonValueByKey(pt, "reference_uri", instobject->reference_uri); - LoadJsonValueByKey(pt, "dofvalues", instobject->dofvalues); - LoadJsonValueByKey(pt, "quaternion", instobject->quaternion); - LoadJsonValueByKey(pt, "translate", instobject->translate); - return instobject; -} - -void SceneResource::DeleteInstObject(const std::string& pk) -{ - GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("scene/%s/instobject/%s/")%GetPrimaryKey()%pk), 204); -} - -SceneResourcePtr SceneResource::Copy(const std::string& name) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost("scene/?format=json", str(boost::format("{\"name\":\"%s\", \"reference_pk\":\"%s\", \"overwrite\": \"1\"}")%name%GetPrimaryKey()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(GetController(), pk)); - return scene; -} - -TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) -{ -} - -bool TaskResource::Execute() -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost("job/", str(boost::format("{\"resource_type\":\"task\", \"target_pk\":%s}")%GetPrimaryKey()), pt, 200); - _jobpk = GetJsonValueByKey(pt, "jobpk"); - return true; -} - -void TaskResource::Cancel() -{ - // have to look through all jobs for the task - BOOST_ASSERT(0); -} - -JobStatusCode GetStatusCode(const std::string& str) -{ - MUJIN_LOG_INFO(str); - if (str == "pending") return JSC_Pending; - if (str == "active") return JSC_Active; - if (str == "preempted") return JSC_Preempted; - if (str == "succeeded") return JSC_Succeeded; - if (str == "aborted") return JSC_Aborted; - if (str == "rejected") return JSC_Rejected; - if (str == "preempting") return JSC_Preempting; - if (str == "recalling") return JSC_Recalling; - if (str == "recalled") return JSC_Recalled; - if (str == "lost") return JSC_Lost; - if (str == "unknown") return JSC_Unknown; - throw MUJIN_EXCEPTION_FORMAT("unknown staus %s", str, MEC_InvalidArguments); -} - -void TaskResource::GetRunTimeStatus(JobStatus& status, int options) -{ - status.code = JSC_Unknown; - if( _jobpk.size() > 0 ) { - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); - if( options & 1 ) { - url += std::string(",status_text"); - } - controller->CallGet(url, pt); - //pt.get("error_message") - LoadJsonValueByKey(pt, "pk", status.pk); - //LoadJsonValueByKey(pt, "status", status.code); - status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); - LoadJsonValueByKey(pt, "elapsedtime", status.elapsedtime); - LoadJsonValueByKey(pt, "fname", status.type); - if( options & 1 ) { - LoadJsonValueByKey(pt, "status_text", status.message); - } - } -} - -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%controller->EscapeString(optimizationname)), pt); - // optimization exists - if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { - rapidjson::Value& object = pt["objects"][0]; - std::string pk = GetJsonValueByKey(object, "pk"); - std::string currentoptimizationtype = GetJsonValueByKey(object, "optimizationtype"); - if( currentoptimizationtype != optimizationtype ) { - throw MUJIN_EXCEPTION_FORMAT("optimization pk %s exists and has type %s, expected is %s", pk%currentoptimizationtype%optimizationtype, MEC_InvalidState); - } - OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); - return optimization; - } - - pt.SetObject(); - controller->CallPost(str(boost::format("task/%s/optimization/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"optimizationtype\":\"%s\", \"taskpk\":\"%s\"}")%optimizationname%optimizationtype%GetPrimaryKey()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); - return optimization; -} - -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype) -{ - std::string optimizationname_utf8; - utf8::utf16to8(optimizationname.begin(), optimizationname.end(), std::back_inserter(optimizationname_utf8)); - return GetOrCreateOptimizationFromName_UTF8(optimizationname_utf8, optimizationtype); -} - -void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - - optimizationkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - LoadJsonValueByKey(*it, "pk", optimizationkeys[i++]); - } -} - -void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskparameters,tasktype")%GetPrimaryKey()), pt); - std::string tasktype = GetJsonValueByKey(pt, "tasktype"); - if( tasktype != "itlplanning" ) { - throw MUJIN_EXCEPTION_FORMAT("task %s is type %s, expected itlplanning", GetPrimaryKey()%tasktype, MEC_InvalidArguments); - } - rapidjson::Value& taskparametersjson = pt["taskparameters"]; - taskparameters.SetDefaults(); - bool bhasreturnmode = false, bhasreturntostart = false, breturntostart = false; - for (rapidjson::Document::MemberIterator v = taskparametersjson.MemberBegin(); v != taskparametersjson.MemberEnd(); ++v) { - if( std::string(v->name.GetString()) == "startfromcurrent" ) { - taskparameters.startfromcurrent = std::string("True") == v->value.GetString(); - } - else if(std::string(v->name.GetString()) == "returntostart" ) { - bhasreturntostart = true; - breturntostart = std::string("True") == v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "returnmode" ) { - taskparameters.returnmode = v->value.GetString(); - bhasreturnmode = true; - } - else if( std::string(v->name.GetString()) == "ignorefigure" ) { - taskparameters.ignorefigure = std::string("True") == v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "vrcruns" ) { - //taskparameters.vrcruns = boost::lexical_cast(v->value); - LoadJsonValueByKey(taskparametersjson, "vrcruns", taskparameters.vrcruns); - } - else if( std::string(v->name.GetString()) == "unit" ) { - taskparameters.unit = v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "optimizationvalue" ) { - LoadJsonValueByKey(taskparametersjson, "optimizationvalue", taskparameters.optimizationvalue); - //taskparameters.optimizationvalue = boost::lexical_cast(v->second.data()); - } - else if( std::string(v->name.GetString()) == "program" ) { - taskparameters.program = v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "parameters" ) { - taskparameters.parameters = DumpJson(v->value,2); - } - else if( std::string(v->name.GetString()) == "initial_envstate" ) { - ExtractEnvironmentStateFromPTree(v->value, taskparameters.initial_envstate); - } - else if( std::string(v->name.GetString()) == "final_envstate" ) { - ExtractEnvironmentStateFromPTree(v->value, taskparameters.final_envstate); - } - else { - std::stringstream ss; - ss << "unsupported ITL task parameter " << v->name.GetString(); - MUJIN_LOG_ERROR(ss.str()); - } - } - // for back compat - if( !bhasreturnmode && bhasreturntostart ) { - taskparameters.returnmode = breturntostart ? "start" : ""; - } -} - -void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - std::string startfromcurrent = taskparameters.startfromcurrent ? "True" : "False"; - std::string ignorefigure = taskparameters.ignorefigure ? "True" : "False"; - std::string vrcruns = boost::lexical_cast(taskparameters.vrcruns); - - std::stringstream ssinitial_envstate; - if( taskparameters.initial_envstate.size() > 0 ) { - ssinitial_envstate << std::setprecision(std::numeric_limits::digits10+1); - ssinitial_envstate << ", \"initial_envstate\":"; - SerializeEnvironmentStateToJSON(taskparameters.initial_envstate, ssinitial_envstate); - } - std::stringstream ssfinal_envstate; - if( taskparameters.final_envstate.size() > 0 ) { - ssfinal_envstate << std::setprecision(std::numeric_limits::digits10+1); - ssfinal_envstate << ", \"final_envstate\":"; - SerializeEnvironmentStateToJSON(taskparameters.final_envstate, ssfinal_envstate); - } - - // because program will inside string, encode newlines - std::string program; - std::vector< std::pair > serachpairs(3); - serachpairs[0].first = "\""; serachpairs[0].second = "\\\""; - serachpairs[1].first = "\n"; serachpairs[1].second = "\\n"; - serachpairs[2].first = "\r\n"; serachpairs[2].second = "\\n"; - SearchAndReplace(program, taskparameters.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"parameters\":%s, \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.parameters%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); -} - -PlanningResultResourcePtr TaskResource::GetResult() -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) ) { - return PlanningResultResourcePtr(); - } - std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); - PlanningResultResourcePtr result(new PlanningResultResource(GetController(), pk)); - return result; -} - -OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) -{ -} - -void OptimizationResource::Execute(bool bClearOldResults) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), str(boost::format("{\"clear\":%d}")%bClearOldResults), pt, 200); - _jobpk = GetJsonValueByKey(pt, "jobpk"); -} - -void OptimizationResource::Cancel() -{ - BOOST_ASSERT(0); -} - -void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) -{ - status.code = JSC_Unknown; - if( _jobpk.size() > 0 ) { - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); - if( options & 1 ) { - url += std::string(",status_text"); - } - controller->CallGet(url, pt); - //pt.get("error_message") - LoadJsonValueByKey(pt, "pk", status.pk); - // LoadJsonValueByKey(pt, "status", status.code); - status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); - LoadJsonValueByKey(pt, "fname", status.type); - LoadJsonValueByKey(pt, "elpasedtime", status.elapsedtime); - if( options & 1 ) { - LoadJsonValueByKey(pt, "status-text", status.message); - } - } -} - -void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams) -{ - GETCONTROLLERIMPL(); - std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationtype\":\"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); -} - -void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizationParameters& optparams) -{ - GETCONTROLLERIMPL(); - std::stringstream optimizationgoalput; - optimizationgoalput << str(boost::format("{\"optimizationtype\":\"placements\", \"optimizationparameters\":{ \"unit\":\"%s\", \"topstorecandidates\":%d")%optparams.unit%optparams.topstorecandidates); - for(size_t itarget = 0; itarget < optparams.targetnames.size(); ++itarget) { - std::string ignorebasecollision = optparams.ignorebasecollisions[itarget] ? "True" : "False"; - std::string suffix; - if( itarget > 0 ) { - suffix = boost::lexical_cast(itarget+1); - } - optimizationgoalput << str(boost::format(", \"targetname%s\":\"%s\", \"frame%s\":\"%s\", \"ignorebasecollision%s\":\"%s\", , \"maxrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize%s_\":[ %.15f, %.15f, %.15f, %.15f]")%suffix%optparams.targetnames[itarget]%suffix%optparams.framenames[itarget]%suffix%ignorebasecollision%suffix%optparams.maxranges[itarget][0]%optparams.maxranges[itarget][1]%optparams.maxranges[itarget][2]%optparams.maxranges[itarget][3]%suffix%optparams.minranges[itarget][0]%optparams.minranges[itarget][1]%optparams.minranges[itarget][2]%optparams.minranges[itarget][3]%suffix%optparams.stepsizes[itarget][0]%optparams.stepsizes[itarget][1]%optparams.stepsizes[itarget][2]%optparams.stepsizes[itarget][3]); - } - optimizationgoalput << "} }"; - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); -} - -void OptimizationResource::GetResults(std::vector& results, int startoffset, int num) -{ - GETCONTROLLERIMPL(); - std::string querystring = str(boost::format("optimization/%s/result/?format=json&fields=pk&order_by=task_time&offset=%d&limit=%d")%GetPrimaryKey()%startoffset%num); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(querystring, pt); - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { - return; - } - rapidjson::Value& objects = pt["objects"]; - results.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - results[i++].reset(new PlanningResultResource(controller, GetJsonValueByKey(*it, "pk"))); - } -} - -PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk) : WebResource(controller,resulttype,pk) -{ -} - -PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) -{ -} - -void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); - ExtractEnvironmentStateFromPTree(pt["envstate"], envstate); -} - -void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/?type=%s")%GetResourceName()%GetPrimaryKey()%programtype), outputdata); -} - -void PlanningResultResource::GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/%s/?type=%s")%GetResourceName()%GetPrimaryKey()%robotpk%programtype), outputdata); -} - -void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - programs.programs.clear(); - controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), pt); - for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { - std::string robotpk = it->name.GetString(); - std::string program = GetJsonValueByKey(it->value, "program"); - std::string currenttype = GetJsonValueByKey(it->value, "type"); - programs.programs[robotpk] = RobotProgramData(program, currenttype); - } -} - -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "debug", pk_), pk(pk_) -{ -} - -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) -{ -} - -void DebugResource::Download(std::ostream& outputStream, double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); -} - -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) -{ - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); -} - -void ControllerClientDestroy() -{ - DestroyControllerClient(); -} - -void DestroyControllerClient() -{ -} - -void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) -{ - throw MujinException("not implemented yet"); -// length2 = numpy.sum(quat**2) -// ilength2 = 2.0/length2 -// qq1 = ilength2*quat[1]*quat[1] -// qq2 = ilength2*quat[2]*quat[2] -// qq3 = ilength2*quat[3]*quat[3] -// T = numpy.eye(4) -// T[0,0] = 1 - qq2 - qq3 -// T[0,1] = ilength2*(quat[1]*quat[2] - quat[0]*quat[3]) -// T[0,2] = ilength2*(quat[1]*quat[3] + quat[0]*quat[2]) -// T[1,0] = ilength2*(quat[1]*quat[2] + quat[0]*quat[3]) -// T[1,1] = 1 - qq1 - qq3 -// T[1,2] = ilength2*(quat[2]*quat[3] - quat[0]*quat[1]) -// T[2,0] = ilength2*(quat[1]*quat[3] - quat[0]*quat[2]) -// T[2,1] = ilength2*(quat[2]*quat[3] + quat[0]*quat[1]) -// T[2,2] = 1 - qq1 - qq2 -} - -void ComputeZXYFromMatrix(Real ZXY[3], Real matrix[12]) -{ - throw MujinException("not implemented yet"); -// if abs(T[2][0]) < 1e-10 and abs(T[2][2]) < 1e-10: -// sinx = T[2][1] -// x = numpy.pi/2 if sinx > 0 else -numpy.pi/2 -// z = 0.0 -// y = numpy.arctan2(sinx*T[1][0],T[0][0]) -// else: -// y = numpy.arctan2(-T[2][0],T[2][2]) -// siny = numpy.sin(y) -// cosy = numpy.cos(y) -// Ryinv = numpy.array([[cosy,0,-siny],[0,1,0],[siny,0,cosy]]) -// Rzx = numpy.dot(T[0:3,0:3],Ryinv) -// x = numpy.arctan2(Rzx[2][1],Rzx[2][2]) -// z = numpy.arctan2(Rzx[1][0],Rzx[0][0]) -// return numpy.array([x,y,z]) -} - -void ComputeZXYFromTransform(Real ZXY[3], const Transform& transform) -{ - throw MujinException("not implemented yet"); - //zxyFromMatrix(matrixFromTransform()) -} - -} diff --git a/src/mujindefinitions.cpp b/src/mujindefinitions.cpp deleted file mode 100644 index 27256694..00000000 --- a/src/mujindefinitions.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2023 MUJIN Inc. -#include - -namespace mujin { - - -void SensorSelectionInfo::LoadFromJson(const rapidjson::Value& rSensorSelectionInfo) -{ - mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName); - mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName); -} - -void SensorSelectionInfo::SaveToJson(rapidjson::Value& rSensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) const -{ - rSensorSelectionInfo.SetObject(); - mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName, alloc); - mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName, alloc); -} - -} // end namespace mujin diff --git a/src/mujinjson.cpp b/src/mujinjson.cpp deleted file mode 100644 index 2654a946..00000000 --- a/src/mujinjson.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2022 MUJIN Inc. -#include - -#include -#include -#include - -namespace mujinjson { - -template -void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer) -{ - static_assert(sizeof(typename Container::value_type) == sizeof(char), "buffer must contain byte-sized elements"); - - const int fd = ::open(filename, O_RDONLY); - if (fd < 0) { - throw MujinJSONException(boost::str(boost::format("Could not open Json file %s") % filename)); - } - - struct stat fs; - if (::fstat(fd, &fs) != 0) { - ::close(fd); - throw MujinJSONException(boost::str(boost::format("Could not get file stats of Json file %s") % filename)); - } - - if( fs.st_size == 0 ) { - // webstack files can report size 0 even though there is content in there, so have to have a growing buffer to compensate for this - size_t nChunkSize = 4096; - size_t nBufferSize = nChunkSize; - char* pbuffer = (char*)::malloc(nBufferSize); - if( !pbuffer ) { - throw MujinJSONException("Could not allocate memory"); - } - size_t nFileSize = 0; - - while(1) { - size_t nTotalToRead = nBufferSize - nFileSize; - if( nTotalToRead < nChunkSize ) { - nBufferSize += nChunkSize; - pbuffer = (char*)::realloc(pbuffer, nBufferSize); - if( !pbuffer ) { - throw MujinJSONException("Could not allocate memory"); - } - nTotalToRead = nBufferSize - nFileSize; - } - ssize_t count = ::read(fd, pbuffer + nFileSize, nBufferSize - nFileSize); - if (count < 0) { - if (errno == EINTR) { - continue; // retry if interrupted - } - ::close(fd); - ::free(pbuffer); - throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); - } - if( count == 0 ) { - break; // EOF - } - nFileSize += count; - } - - ::close(fd); - - if( nFileSize == 0 ) { - ::free(pbuffer); - throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); - } - - try { - ParseJson(d, pbuffer, nFileSize); - } - catch(const std::exception& ex) { - ::free(pbuffer); - throw; - } - - ::free(pbuffer); - return; - } - - buffer.resize(fs.st_size); - ssize_t offset = 0; - do { - ssize_t count = ::read(fd, buffer.data() + offset, fs.st_size - offset); - if (count < 0) { - if (errno == EINTR) { - continue; // retry if interrupted - } - ::close(fd); - throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); - } - if( count == 0 ) { - break; // EOF - } - offset += count; - } while (offset < fs.st_size); - - ::close(fd); - if( offset == 0 ) { - throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); - } - - ParseJson(d, reinterpret_cast(buffer.data()), offset); -} - -// used for declaration of the specialization -void __InternalParseJsonFile(rapidjson::Document& d, const char* filename) -{ - std::vector buffer; - return ParseJsonFile(d, filename, buffer); -} - -} // end namespace mujinjson diff --git a/src/mujinzmq.cpp b/src/mujinzmq.cpp deleted file mode 100644 index fcfb814e..00000000 --- a/src/mujinzmq.cpp +++ /dev/null @@ -1,507 +0,0 @@ -#include "mujincontrollerclient/mujinzmq.h" - -#include -#if BOOST_VERSION > 104800 -#include -#endif -#include -#include - -#include "common.h" -#include "logging.h" - -MUJIN_LOGGER("mujin.controllerclientcpp.mujinzmq"); - - -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#endif - - -#ifndef MUJIN_TIME -#define MUJIN_TIME -#include - -#ifndef _WIN32 -#if !(defined(CLOCK_GETTIME_FOUND) && (POSIX_TIMERS > 0 || _POSIX_TIMERS > 0)) -#include -#endif -#else -#define WIN32_LEAN_AND_MEAN -#include -#include // ftime(), struct timeb -inline void usleep(unsigned long microseconds) { - Sleep((microseconds+999)/1000); -} -#endif - -#ifdef _WIN32 -inline uint64_t GetMilliTime() -{ - LARGE_INTEGER count, freq; - QueryPerformanceCounter(&count); - QueryPerformanceFrequency(&freq); - return (uint64_t)((count.QuadPart * 1000) / freq.QuadPart); -} - -inline uint64_t GetMicroTime() -{ - LARGE_INTEGER count, freq; - QueryPerformanceCounter(&count); - QueryPerformanceFrequency(&freq); - return (count.QuadPart * 1000000) / freq.QuadPart; -} - -inline uint64_t GetNanoTime() -{ - LARGE_INTEGER count, freq; - QueryPerformanceCounter(&count); - QueryPerformanceFrequency(&freq); - return (count.QuadPart * 1000000000) / freq.QuadPart; -} - -inline static uint64_t GetNanoPerformanceTime() { - return GetNanoTime(); -} - -#else - -inline void GetWallTime(uint32_t& sec, uint32_t& nsec) -{ -#if defined(CLOCK_GETTIME_FOUND) && (POSIX_TIMERS > 0 || _POSIX_TIMERS > 0) - struct timespec start; - clock_gettime(CLOCK_REALTIME, &start); - sec = start.tv_sec; - nsec = start.tv_nsec; -#else - struct timeval timeofday; - gettimeofday(&timeofday,NULL); - sec = timeofday.tv_sec; - nsec = timeofday.tv_usec * 1000; -#endif -} - -inline uint64_t GetMilliTimeOfDay() -{ - struct timeval timeofday; - gettimeofday(&timeofday,NULL); - return (uint64_t)timeofday.tv_sec*1000+(uint64_t)timeofday.tv_usec/1000; -} - -inline uint64_t GetNanoTime() -{ - uint32_t sec,nsec; - GetWallTime(sec,nsec); - return (uint64_t)sec*1000000000 + (uint64_t)nsec; -} - -inline uint64_t GetMicroTime() -{ - uint32_t sec,nsec; - GetWallTime(sec,nsec); - return (uint64_t)sec*1000000 + (uint64_t)nsec/1000; -} - -inline uint64_t GetMilliTime() -{ - uint32_t sec,nsec; - GetWallTime(sec,nsec); - return (uint64_t)sec*1000 + (uint64_t)nsec/1000000; -} - -inline static uint64_t GetNanoPerformanceTime() -{ -#if defined(CLOCK_GETTIME_FOUND) && (POSIX_TIMERS > 0 || _POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) - struct timespec start; - uint32_t sec, nsec; - clock_gettime(CLOCK_MONOTONIC, &start); - sec = start.tv_sec; - nsec = start.tv_nsec; - return (uint64_t)sec*1000000000 + (uint64_t)nsec; -#else - return GetNanoTime(); -#endif -} -#endif -#endif - - -using namespace mujinzmq; -using namespace mujinclient; - -ZmqSubscriber::ZmqSubscriber(const std::string& host, const unsigned int port) -{ - _host = host; - _port = port; -} - -ZmqSubscriber::~ZmqSubscriber() -{ - _DestroySocket(); -} - -void ZmqSubscriber::_InitializeSocket(boost::shared_ptr context) -{ - if (!!context) { - _context = context; - _sharedcontext = true; - } else { - _context.reset(new zmq::context_t(1)); - _sharedcontext = false; - } - _socket.reset(new zmq::socket_t ((*_context.get()), ZMQ_SUB)); - _socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - _socket->setsockopt(ZMQ_SNDHWM, 2); - _socket->setsockopt(ZMQ_LINGER, 100); // ms - std::ostringstream port_stream; - port_stream << _port; - _socket->connect (("tcp://" + _host + ":" + port_stream.str()).c_str()); - _socket->setsockopt(ZMQ_SUBSCRIBE, "", 0); -} - -void ZmqSubscriber::_DestroySocket() -{ - if (!!_socket) { - _socket->close(); - _socket.reset(); - } - if (!!_context && !_sharedcontext) { - _context->close(); - _context.reset(); - } -} - -ZmqPublisher::ZmqPublisher(const unsigned int port) -{ - _port = port; -} - -ZmqPublisher::~ZmqPublisher() -{ - _DestroySocket(); -} - -bool ZmqPublisher::Publish(const std::string& messagestr) -{ - zmq::message_t message(messagestr.size()); - memcpy(message.data(), messagestr.data(), messagestr.size()); - return _socket->send(message); -} - -void ZmqPublisher::_InitializeSocket(boost::shared_ptr context) -{ - if (!!context) { - _context = context; - _sharedcontext = true; - } - else { - _context.reset(new zmq::context_t(1)); - _sharedcontext = false; - } - _socket.reset(new zmq::socket_t ((*(zmq::context_t*)_context.get()), ZMQ_PUB)); - _socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - _socket->setsockopt(ZMQ_SNDHWM, 2); - _socket->setsockopt(ZMQ_LINGER, 100); // ms - std::ostringstream port_stream; - port_stream << _port; - _socket->bind (("tcp://*:" + port_stream.str()).c_str()); -} - -void ZmqPublisher::_DestroySocket() -{ - if (!!_socket) { - _socket->close(); - _socket.reset(); - } - if (!!_context && !_sharedcontext) { - _context->close(); - _context.reset(); - } -} - - -ZmqClient::ZmqClient(const std::string& host, const unsigned int port, const CheckPreemptFn& preemptfn) -{ - _host = host; - _port = port; - _preemptfn = preemptfn; -} - -ZmqClient::~ZmqClient() -{ - _DestroySocket(); -} - -std::string ZmqClient::Call(const std::string& msg, const double timeout, const unsigned int checkpreemptbits) -{ - //send - zmq::message_t request (msg.size()); - // std::cout << msg.size() << std::endl; - // std::cout << msg << std::endl; - memcpy ((void *) request.data (), msg.c_str(), msg.size()); - - uint64_t starttime = GetMilliTime(); - bool recreatedonce = false; - while (GetMilliTime() - starttime < timeout*1000.0) { - try { - _socket->send(request); - break; - } catch (const zmq::error_t& e) { - if (e.num() == EAGAIN) { - MUJIN_LOG_ERROR("failed to send request, try again"); - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - continue; - } else { - std::stringstream errss; - errss << "failed to send msg: "; - if (msg.length() > 1000) { - errss << msg.substr(0, 1000) << "..."; - } else { - errss << msg; - } - MUJIN_LOG_ERROR(errss.str()); - } - if (!recreatedonce) { - MUJIN_LOG_INFO("re-creating zmq socket and trying again"); - if (!!_socket) { - _socket->close(); - _socket.reset(); - } - _InitializeSocket(_context); - recreatedonce = true; - } else{ - std::stringstream ss; - ss << "Failed to send request after re-creating socket."; - MUJIN_LOG_ERROR(ss.str()); - throw MujinException(ss.str(), MEC_Failed); - } - } - if( !!_preemptfn ) { - _preemptfn(checkpreemptbits); - } - - } - if (GetMilliTime() - starttime > timeout*1000.0) { - std::stringstream ss; - ss << "Timed out trying to send request."; - MUJIN_LOG_ERROR(ss.str()); - if (msg.length() > 1000) { - MUJIN_LOG_INFO(msg.substr(0,1000) << "..."); - } else { - MUJIN_LOG_INFO(msg); - } - throw MujinException(ss.str(), MEC_Timeout); - } - //recv - recreatedonce = false; - zmq::message_t reply; - bool receivedonce = false; // receive at least once - while (!receivedonce || (GetMilliTime() - starttime < timeout * 1000.0)) { - if( !!_preemptfn ) { - _preemptfn(checkpreemptbits); - } - - try { - - zmq::pollitem_t pollitem; - memset(&pollitem, 0, sizeof(zmq::pollitem_t)); - pollitem.socket = _socket->operator void*(); - pollitem.events = ZMQ_POLLIN; - - // if timeout param is 0, caller means infinite - long timeoutms = -1; - if (timeout > 0) { - timeoutms = timeout * 1000.0; - } - - zmq::poll(&pollitem, 1, timeoutms); - receivedonce = true; - if (pollitem.revents & ZMQ_POLLIN) { - _socket->recv(&reply); - std::string replystring((char *) reply.data (), (size_t) reply.size()); - return replystring; - } else{ - std::stringstream ss; - if (msg.length() > 1000) { - ss << "Timed out receiving response of command " << msg.substr(0, 1000) << "... after " << timeout << " seconds"; - } else { - ss << "Timed out receiving response of command " << msg << " after " << timeout << " seconds"; - } - MUJIN_LOG_ERROR(ss.str()); -#if BOOST_VERSION > 104800 - std::string errstr = ss.str(); - boost::replace_all(errstr, "\"", ""); // need to remove " in the message so that json parser works - boost::replace_all(errstr, "\\", ""); // need to remove \ in the message so that json parser works -#else - std::vector< std::pair > serachpairs(2); - serachpairs[0].first = "\""; serachpairs[0].second = ""; - serachpairs[1].first = "\\"; serachpairs[1].second = ""; - std::string errstr; - mujinclient::SearchAndReplace(errstr, ss.str(), serachpairs); -#endif - throw MujinException(errstr, MEC_Timeout); - } - - } catch (const zmq::error_t& e) { - if (e.num() == EAGAIN) { - MUJIN_LOG_ERROR("failed to receive reply, zmq::EAGAIN"); - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - continue; - } else { - MUJIN_LOG_INFO("failed to send"); - if (msg.length() > 1000) { - MUJIN_LOG_INFO(msg.substr(0,1000) << "..."); - } else { - MUJIN_LOG_INFO(msg); - } - } - if (!recreatedonce) { - MUJIN_LOG_INFO("re-creating zmq socket and trying again"); - if (!!_socket) { - _socket->close(); - _socket.reset(); - } - _InitializeSocket(_context); - recreatedonce = true; - } else{ - std::string errstr = "Failed to receive response after re-creating socket."; - MUJIN_LOG_ERROR(errstr); - throw MujinException(errstr, MEC_Failed); - } - } - } - if (GetMilliTime() - starttime > timeout*1000.0) { - std::stringstream ss; - ss << "timed out trying to receive request"; - MUJIN_LOG_ERROR(ss.str()); - if (msg.length() > 1000) { - MUJIN_LOG_INFO(msg.substr(0,1000) << "..."); - } else { - MUJIN_LOG_INFO(msg); - } - throw MujinException(ss.str(), MEC_Failed); - } - - return ""; -} - -void ZmqClient::_InitializeSocket(boost::shared_ptr context) -{ - if (!!context) { - _context = context; - _sharedcontext = true; - } else { - _context.reset(new zmq::context_t(1)); - _sharedcontext = false; - } - _socket.reset(new zmq::socket_t ((*(zmq::context_t*)_context.get()), ZMQ_REQ)); - _socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - std::ostringstream port_stream; - port_stream << _port; - std::stringstream ss; - ss << "connecting to socket at " << _host << ":" << _port; - MUJIN_LOG_INFO(ss.str()); - _socket->connect (("tcp://" + _host + ":" + port_stream.str()).c_str()); -} - -void ZmqClient::_DestroySocket() -{ - if (!!_socket) { - _socket->setsockopt(ZMQ_LINGER, 0); - _socket->close(); - _socket.reset(); - } - if (!!_context && !_sharedcontext) { - _context->close(); - _context.reset(); - } -} - -ZmqServer::ZmqServer(const unsigned int port) : _sharedcontext(false), _port(port) { -} - -ZmqServer::~ZmqServer() { - _DestroySocket(); -} - -unsigned int ZmqServer::Recv(std::string& data, long timeout) -{ - // wait timeout in millisecond for message - if (timeout > 0) { - zmq::poll(&_pollitem, 1, timeout); - if ((_pollitem.revents & ZMQ_POLLIN) == 0) - { - // did not receive anything - return 0; - } - } - - const bool ret = _socket->recv(&_reply, ZMQ_NOBLOCK); - if (ret && _reply.size() > 0) { - data.resize(_reply.size()); - std::copy((uint8_t*)_reply.data(), (uint8_t*)_reply.data() + _reply.size(), data.begin()); - return _reply.size(); - } else { - return 0; - } -} - -void ZmqServer::Send(const std::string& message) -{ - zmq::message_t request(message.size()); - memcpy((void *)request.data(), message.c_str(), message.size()); - _socket->send(request); -} - -void ZmqServer::_InitializeSocket(boost::shared_ptr context) -{ - if (!!context) { - _context = context; - _sharedcontext = true; - } else { - _context.reset(new zmq::context_t(1)); - _sharedcontext = false; - } - - _socket.reset(new zmq::socket_t((*(zmq::context_t*)_context.get()), ZMQ_REP)); - _socket->setsockopt(ZMQ_TCP_KEEPALIVE, 1); // turn on tcp keepalive, do these configuration before connect - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, 2); // the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, 2); // the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime - _socket->setsockopt(ZMQ_TCP_KEEPALIVE_CNT, 2); // the number of unacknowledged probes to send before considering the connection dead and notifying the application layer - - // setup the pollitem - memset(&_pollitem, 0, sizeof(_pollitem)); - _pollitem.socket = _socket->operator void*(); - _pollitem.events = ZMQ_POLLIN; - - std::ostringstream endpoint; - endpoint << "tcp://*:" << _port; - _socket->bind(endpoint.str().c_str()); - std::stringstream ss; - ss << "binded to " << endpoint.str(); - MUJIN_LOG_INFO(ss.str()); -} - -void ZmqServer::_DestroySocket() -{ - if (!!_socket) { - _socket->setsockopt(ZMQ_LINGER, 0); - _socket->close(); - _socket.reset(); - } - if (!!_context && !_sharedcontext) { - _context->close(); - _context.reset(); - } - memset(&_pollitem, 0, sizeof(_pollitem)); -} diff --git a/src/controllerclientimpl.cpp b/src/webstackclient.cpp similarity index 100% rename from src/controllerclientimpl.cpp rename to src/webstackclient.cpp From af29e8905fa39a7e75ec42d2c27eccd60bcca284 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 20 Jul 2023 16:10:14 +0900 Subject: [PATCH 450/477] Create a minimal viable webstack client --- CMakeLists.txt | 94 +- mujinwebstackclient-config.cmake.in | 64 +- src/CMakeLists.txt | 66 +- src/common.h | 11 +- .../mujinwebstackclientcpp/webstackclient.h | 1125 ++----------- src/webstackclient.cpp | 1454 +++-------------- 6 files changed, 490 insertions(+), 2324 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ab57140..b05050bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,21 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. cmake_minimum_required (VERSION 2.8.0) -project(mujincontrollerclient) +project(mujinwebstackclient) set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE ) # Define here the needed parameters # make sure to change the version in docs/Makefile -set (MUJINCLIENT_VERSION_MAJOR 0) -set (MUJINCLIENT_VERSION_MINOR 65) -set (MUJINCLIENT_VERSION_PATCH 0) -set (MUJINCLIENT_VERSION ${MUJINCLIENT_VERSION_MAJOR}.${MUJINCLIENT_VERSION_MINOR}.${MUJINCLIENT_VERSION_PATCH}) -set (MUJINCLIENT_SOVERSION ${MUJINCLIENT_VERSION_MAJOR}.${MUJINCLIENT_VERSION_MINOR}) -set (CLIENT_SOVERSION ${MUJINCLIENT_VERSION_MAJOR}.${MUJINCLIENT_VERSION_MINOR}) -message(STATUS "Compiling MUJIN Controller Client C++ Version ${MUJINCLIENT_VERSION}, soversion=${CLIENT_SOVERSION}") +set (MUJINWEBSTACKCLIENT_VERSION_MAJOR 0) +set (MUJINWEBSTACKCLIENT_VERSION_MINOR 65) +set (MUJINWEBSTACKCLIENT_VERSION_PATCH 0) +set (MUJINWEBSTACKCLIENT_VERSION ${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR}.${MUJINWEBSTACKCLIENT_VERSION_PATCH}) +set (MUJINWEBSTACKCLIENT_SOVERSION ${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR}) +set (CLIENT_SOVERSION ${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR}) +message(STATUS "Compiling MUJIN Controller Client C++ Version ${MUJINWEBSTACKCLIENT_VERSION}, soversion=${CLIENT_SOVERSION}") -set(MUJINCLIENT_CMAKE_INSTALL_DIR "mujincontrollerclient-${MUJINCLIENT_VERSION_MAJOR}.${MUJINCLIENT_VERSION_MINOR}" CACHE STRING "Directory to install the cmake config files.") -set(MUJINCLIENT_TARGET_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE STRING "The target processor architecture to build for, this is combined with the generator toolchain") +set(MUJINWEBSTACKCLIENT_CMAKE_INSTALL_DIR "mujinwebstackclient-${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR}" CACHE STRING "Directory to install the cmake config files.") +set(MUJINWEBSTACKCLIENT_TARGET_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE STRING "The target processor architecture to build for, this is combined with the generator toolchain") message(STATUS "Using cmake version ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" ) # http://www.cmake.org/cmake/help/cmake-2.6.html#policy:CMP0002 @@ -66,9 +66,9 @@ include(CheckCXXCompilerFlag) add_definitions("-DBOOST_SPIRIT_THREADSAFE") # for json parsing # have to include before boost since the boost headers can be located in a previous installed version of this library -set(MUJINCLIENT_INCLUDE_LOCAL_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(MUJINWEBSTACKCLIENT_INCLUDE_LOCAL_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/include) include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) -include_directories(${MUJINCLIENT_INCLUDE_LOCAL_DIRS}) +include_directories(${MUJINWEBSTACKCLIENT_INCLUDE_LOCAL_DIRS}) if( MSVC ) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE) @@ -102,7 +102,7 @@ if( MSVC ) check_include_file(stdint.h HAVE_STDINT_H) if( NOT HAVE_STDINT_H ) - #install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/msvc_include/stdint.h DESTINATION include/mujinclient-${MUJINCLIENT_VERSION_MAJOR}.${MUJINCLIENT_VERSION_MINOR} COMPONENT ${COMPONENT_PREFIX}dev) + #install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/msvc_include/stdint.h DESTINATION include/mujinclient-${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR} COMPONENT ${COMPONENT_PREFIX}dev) #include_directories(${CMAKE_CURRENT_SOURCE_DIR}/msvc_include) endif() @@ -120,10 +120,10 @@ if( MSVC ) set(MSVC_PREFIX "vc100") set(MSVC_PREFIX2 "v100") endif() - set(MUJINCLIENT_LIBRARY_SUFFIX "${MUJINCLIENT_SOVERSION}-${MSVC_PREFIX}-mt" CACHE STRING "Suffix to append to library names") + set(MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX "${MUJINWEBSTACKCLIENT_SOVERSION}-${MSVC_PREFIX}-mt" CACHE STRING "Suffix to append to library names") # install all DLLs - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/bin/" DESTINATION bin FILES_MATCHING PATTERN "*.dll") + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/bin/" DESTINATION bin FILES_MATCHING PATTERN "*.dll") # force multi-threaded DLL boost set(Boost_USE_MULTITHREAD ON) @@ -131,27 +131,29 @@ if( MSVC ) set(Boost_USE_STATIC_RUNTIME OFF) set(Boost_CFLAGS "-DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB") else() - set(MUJINCLIENT_LIBRARY_SUFFIX "${MUJINCLIENT_SOVERSION}" CACHE STRING "Suffix to append to library names") + set(MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX "${MUJINWEBSTACKCLIENT_SOVERSION}" CACHE STRING "Suffix to append to library names") endif() -set(MUJINCLIENT_LINK_DIRS) +set(MUJINWEBSTACKCLIENT_LINK_DIRS) find_package(PkgConfig) -set(MUJINCLIENT_LOG4CXX 0) +# TODO(document/team#86): Remove this when (if?) client utilities are moved to controller common. +find_package(MujinControllerClient 0.64.0 REQUIRED) +set(MUJINWEBSTACKCLIENT_LOG4CXX 0) if (OPT_LOG4CXX) pkg_check_modules(LOG4CXX liblog4cxx) if (LOG4CXX_FOUND) if( MSVC ) - set(MUJINCLIENT_LOG4CXX_INCLUDE_DIRS "/I\"${LOG4CXX_INCLUDEDIR}\"") - set(MUJINCLIENT_LOG4CXX_LIB_DIRS "/LIBPATH:\"${LOG4CXX_LIBDIR}\"") + set(MUJINWEBSTACKCLIENT_LOG4CXX_INCLUDE_DIRS "/I\"${LOG4CXX_INCLUDEDIR}\"") + set(MUJINWEBSTACKCLIENT_LOG4CXX_LIB_DIRS "/LIBPATH:\"${LOG4CXX_LIBDIR}\"") else() - set(MUJINCLIENT_LOG4CXX_INCLUDE_DIRS "-I${LOG4CXX_INCLUDEDIR}") - set(MUJINCLIENT_LOG4CXX_LIB_DIRS "-L${LOG4CXX_LIBDIR}") + set(MUJINWEBSTACKCLIENT_LOG4CXX_INCLUDE_DIRS "-I${LOG4CXX_INCLUDEDIR}") + set(MUJINWEBSTACKCLIENT_LOG4CXX_LIB_DIRS "-L${LOG4CXX_LIBDIR}") endif() - set(MUJINCLIENT_LOG4CXX_LIBRARY "-l${LOG4CXX_LIBRARIES}") + set(MUJINWEBSTACKCLIENT_LOG4CXX_LIBRARY "-l${LOG4CXX_LIBRARIES}") - set(MUJINCLIENT_LINK_DIRS ${MUJINCLIENT_LINK_DIRS} ${LOG4CXX_LIBDIR}) - set(MUJINCLIENT_LOG4CXX 1) + set(MUJINWEBSTACKCLIENT_LINK_DIRS ${MUJINWEBSTACKCLIENT_LINK_DIRS} ${LOG4CXX_LIBDIR}) + set(MUJINWEBSTACKCLIENT_LOG4CXX 1) endif() endif() @@ -182,11 +184,11 @@ endif() if( Boost_FOUND ) include_directories(${Boost_INCLUDE_DIRS}) - set(MUJINCLIENT_LINK_DIRS ${MUJINCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) + set(MUJINWEBSTACKCLIENT_LINK_DIRS ${MUJINWEBSTACKCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) set(EXTRA_MSVC_DEPEND) # reset extra depend elseif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") include_directories(${Boost_INCLUDE_DIRS}) - set(MUJINCLIENT_LINK_DIRS ${MUJINCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) + set(MUJINWEBSTACKCLIENT_LINK_DIRS ${MUJINWEBSTACKCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) set(EXTRA_MSVC_DEPEND msvc_boost) # reset extra depend elseif( MSVC ) # to facilitate compilation, visual studio libraries are included locally @@ -195,7 +197,7 @@ elseif( MSVC ) set(Boost_FOUND 1) set(Boost_INCLUDE_DIRS "${BOOST_ROOT}") set(Boost_INCLUDE_DIR "${BOOST_ROOT}") - set(Boost_LIBRARY_DIRS "${BOOST_ROOT}/${MUJINCLIENT_TARGET_PROCESSOR}/lib") + set(Boost_LIBRARY_DIRS "${BOOST_ROOT}/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/lib") set(Boost_REGEX_FOUND 0) set(Boost_FILESYSTEM_FOUND 1) set(Boost_IOSTREAMS_FOUND 1) @@ -227,7 +229,7 @@ elseif( MSVC ) install(FILES ${Boost_DATE_TIME_LIBRARY_DLL} ${Boost_THREAD_LIBRARY_DLL} ${Boost_SYSTEM_LIBRARY_DLL} ${Boost_FILESYSTEM_LIBRARY_DLL} ${Boost_PROGRAM_OPTIONS_LIBRARY_DLL} DESTINATION bin COMPONENT ${COMPONENT_PREFIX}dev) install(DIRECTORY "${Boost_INCLUDE_DIR}/boost" DESTINATION include COMPONENT ${COMPONENT_PREFIX}dev) include_directories(${Boost_INCLUDE_DIRS}) - set(MUJINCLIENT_LINK_DIRS ${MUJINCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) + set(MUJINWEBSTACKCLIENT_LINK_DIRS ${MUJINWEBSTACKCLIENT_LINK_DIRS} ${Boost_LIBRARY_DIRS}) else() message(FATAL_ERROR "Could not find boost libraries!") endif() @@ -256,14 +258,14 @@ if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) add_definitions("-fno-strict-aliasing -Wall -Werror=shadow") endif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/mujincontrollerclient/config.h IMMEDIATE @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/mujinwebstackclientcpp/config.h IMMEDIATE @ONLY) find_package(CURL) if( NOT CURL_FOUND ) if( MSVC ) - message(STATUS "setting local curl library from msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}") - set(CURL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/include") - set(CURL_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/lib/libcurl-${MSVC_PREFIX}-mt_imp.lib") + message(STATUS "setting local curl library from msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}") + set(CURL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/include") + set(CURL_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/lib/libcurl-${MSVC_PREFIX}-mt_imp.lib") else() message(FATAL_ERROR "could not find CURL library") endif() @@ -297,10 +299,10 @@ else() endif() if (NOT libzmq_FOUND) if( MSVC ) - set(libzmq_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/include") - set(libzmq_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/lib/libzmq-${MSVC_PREFIX2}-mt-4_0_4.lib") + set(libzmq_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/include") + set(libzmq_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}/lib/libzmq-${MSVC_PREFIX2}-mt-4_0_4.lib") if(EXISTS ${libzmq_LIBRARIES} ) - message(STATUS "setting local zmq library from msvc_binaries/${MUJINCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}") + message(STATUS "setting local zmq library from msvc_binaries/${MUJINWEBSTACKCLIENT_TARGET_PROCESSOR}/${MSVC_PREFIX}") set(libzmq_FOUND 1) else() message(STATUS "could not find msvc zmq library ${libzmq_LIBRARIES}") @@ -311,21 +313,21 @@ endif() if (libzmq_FOUND) include_directories(${libzmq_INCLUDE_DIRS}) - set(MUJINCLIENT_LINK_DIRS ${MUJINCLIENT_LINK_DIRS} ${libzmq_LIBRARY_DIRS}) + set(MUJINWEBSTACKCLIENT_LINK_DIRS ${MUJINWEBSTACKCLIENT_LINK_DIRS} ${libzmq_LIBRARY_DIRS}) else() message(WARNING "compiling without libzmq library") endif() -file(GLOB mujin_header_files ${CMAKE_CURRENT_SOURCE_DIR}/include/mujincontrollerclient/*.h ${CMAKE_CURRENT_SOURCE_DIR}/include/mujincontrollerclient/*.hpp) -install(FILES ${mujin_header_files} ${CMAKE_CURRENT_BINARY_DIR}/include/mujincontrollerclient/config.h DESTINATION include/mujincontrollerclient) +file(GLOB mujin_header_files ${CMAKE_CURRENT_SOURCE_DIR}/include/mujinwebstackclientcpp/*.h ${CMAKE_CURRENT_SOURCE_DIR}/include/mujinwebstackclientcpp/*.hpp) +install(FILES ${mujin_header_files} ${CMAKE_CURRENT_BINARY_DIR}/include/mujinwebstackclientcpp/config.h DESTINATION include/mujinwebstackclientcpp) macro(build_sample name) include_directories(${LOG4CXX_INCLUDEDIR} ${libzmq_INCLUDE_DIRS}) link_directories(${LOG4CXX_LIBDIR}) add_executable(${name} ${name}.cpp) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${Boost_CFLAGS}" LINK_FLAGS "") - add_dependencies(${name} libmujincontrollerclient) - target_link_libraries (${name} libmujincontrollerclient ${Boost_THREAD_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${EXTRA_LIBRARIES} ${LOG4CXX_LIBRARIES}) + add_dependencies(${name} libmujinwebstackclient) + target_link_libraries (${name} libmujinwebstackclient ${Boost_THREAD_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${EXTRA_LIBRARIES} ${LOG4CXX_LIBRARIES}) install(TARGETS ${name} DESTINATION bin) endmacro(build_sample) @@ -337,15 +339,13 @@ if( OPT_BUILD_TESTS ) add_subdirectory(test) endif() -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/mujincontrollerclient DESTINATION share) - # add make uninstall capability configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") -set(MujinControllerClient_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mujincontrollerclient-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/mujincontrollerclient-config.cmake" IMMEDIATE @ONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mujincontrollerclient-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/mujincontrollerclient-config-version.cmake" IMMEDIATE @ONLY) +set(Mujinwebstackclient_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mujinwebstackclient-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/mujinwebstackclient-config.cmake" IMMEDIATE @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mujinwebstackclient-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/mujinwebstackclient-config-version.cmake" IMMEDIATE @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mujincontrollerclient-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/mujincontrollerclient-config-version.cmake" DESTINATION "lib${LIB_SUFFIX}/cmake/${MUJINCLIENT_CMAKE_INSTALL_DIR}") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mujinwebstackclient-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/mujinwebstackclient-config-version.cmake" DESTINATION "lib${LIB_SUFFIX}/cmake/${MUJINWEBSTACKCLIENT_CMAKE_INSTALL_DIR}") diff --git a/mujinwebstackclient-config.cmake.in b/mujinwebstackclient-config.cmake.in index 46a0bfc1..b0318ec8 100644 --- a/mujinwebstackclient-config.cmake.in +++ b/mujinwebstackclient-config.cmake.in @@ -1,15 +1,15 @@ # - Find Mujin Controller Client C++ Library # # Users can set the following variables before calling the module: -# MujinControllerClient_DIR - The preferred installation prefix for searching for MujinControllerClient. Set by the user. +# MujinWebstackClient_DIR - The preferred installation prefix for searching for MujinWebstackClient. Set by the user. # -# MujinControllerClient_ROOT_DIR - the root directory where the installation can be found -# MujinControllerClient_CXX_FLAGS - extra flags for compilation -# MujinControllerClient_LINK_FLAGS - extra flags for linking -# MujinControllerClient_INCLUDE_DIRS - include directories -# MujinControllerClient_LIBRARY_DIRS - link directories -# MujinControllerClient_LIBRARIES - libraries to link plugins with -# MujinControllerClient_Boost_VERSION - the boost version was compiled with +# MujinWebstackClient_ROOT_DIR - the root directory where the installation can be found +# MujinWebstackClient_CXX_FLAGS - extra flags for compilation +# MujinWebstackClient_LINK_FLAGS - extra flags for linking +# MujinWebstackClient_INCLUDE_DIRS - include directories +# MujinWebstackClient_LIBRARY_DIRS - link directories +# MujinWebstackClient_LIBRARIES - libraries to link plugins with +# MujinWebstackClient_Boost_VERSION - the boost version was compiled with #================================================================================== # Copyright (C) 2009-2011 Rosen Diankov @@ -25,14 +25,14 @@ # License text for the above reference.) #================================================================================== if( MSVC ) -get_filename_component(MujinControllerClient_ROOT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -set( MujinControllerClient_INCLUDE_DIRS "@MujinControllerClient_INCLUDE_DIR@;${MujinControllerClient_ROOT_DIR}/include") +get_filename_component(MujinWebstackClient_ROOT_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set( MujinWebstackClient_INCLUDE_DIRS "@MujinWebstackClient_INCLUDE_DIR@;${MujinWebstackClient_ROOT_DIR}/include") else() get_filename_component(_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_PREFIX "${_PREFIX}" PATH) get_filename_component(_PREFIX "${_PREFIX}" PATH) -get_filename_component(MujinControllerClient_ROOT_DIR "${_PREFIX}" PATH) -set( MujinControllerClient_INCLUDE_DIRS "${MujinControllerClient_ROOT_DIR}/include") +get_filename_component(MujinWebstackClient_ROOT_DIR "${_PREFIX}" PATH) +set( MujinWebstackClient_INCLUDE_DIRS "${MujinWebstackClient_ROOT_DIR}/include") endif() if( MSVC ) @@ -46,44 +46,44 @@ if( MSVC ) else() set(MSVC_PREFIX "vc100") endif() - set(MujinControllerClient_LIBRARY_SUFFIX "@MUJINCLIENT_VERSION_MAJOR@.@MUJINCLIENT_VERSION_MINOR@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the mujin client libraries" FORCE) + set(MujinWebstackClient_LIBRARY_SUFFIX "@MUJINWEBSTACKCLIENT_VERSION_MAJOR@.@MUJINWEBSTACKCLIENT_VERSION_MINOR@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the mujin client libraries" FORCE) else() - set(MujinControllerClient_LIBRARY_SUFFIX "@MUJINCLIENT_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the mujin client libraries" FORCE) + set(MujinWebstackClient_LIBRARY_SUFFIX "@MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the mujin client libraries" FORCE) endif() -set( MujinControllerClient_CXX_FLAGS "-DMUJINCLIENT_DLL @MUJINCLIENT_EXPORT_CXXFLAGS@ @MUJINCLIENT_LOG4CXX_INCLUDE_DIRS@" ) +set( MujinWebstackClient_CXX_FLAGS "-DMUJINWEBSTACKCLIENT_DLL @MUJINWEBSTACKCLIENT_EXPORT_CXXFLAGS@ @MUJINWEBSTACKCLIENT_LOG4CXX_INCLUDE_DIRS@" ) if( WIN32 ) - set( MujinControllerClient_CXX_FLAGS "${MujinControllerClient_CXX_FLAGS} -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB") + set( MujinWebstackClient_CXX_FLAGS "${MujinWebstackClient_CXX_FLAGS} -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB") endif() if( MSVC ) - set( MujinControllerClient_CXX_FLAGS "${MujinControllerClient_CXX_FLAGS} /EHc-") + set( MujinWebstackClient_CXX_FLAGS "${MujinWebstackClient_CXX_FLAGS} /EHc-") endif() -set( MujinControllerClient_LINK_FLAGS "@MUJINCLIENT_LOG4CXX_LIB_DIRS@" ) -set( MujinControllerClient_LIBRARY_DIRS "${MujinControllerClient_ROOT_DIR}/lib@LIB_SUFFIX@") -set( MujinControllerClient_LIBRARIES mujincontrollerclient${MujinControllerClient_LIBRARY_SUFFIX} @LOG4CXX_LIBRARIES@) +set( MujinWebstackClient_LINK_FLAGS "@MUJINWEBSTACKCLIENT_LOG4CXX_LIB_DIRS@" ) +set( MujinWebstackClient_LIBRARY_DIRS "${MujinWebstackClient_ROOT_DIR}/lib@LIB_SUFFIX@") +set( MujinWebstackClient_LIBRARIES mujincontrollerclient${MujinWebstackClient_LIBRARY_SUFFIX} @LOG4CXX_LIBRARIES@) -set( MujinControllerClient_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@") +set( MujinWebstackClient_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@") if( WIN32 ) # search for the boost version was compiled with set(Boost_USE_MULTITHREAD ON) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_RUNTIME OFF) - find_package(Boost ${MujinControllerClient_Boost_VERSION} EXACT COMPONENTS thread date_time) + find_package(Boost ${MujinWebstackClient_Boost_VERSION} EXACT COMPONENTS thread date_time) if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") - set( MujinControllerClient_INCLUDE_DIRS "${MujinControllerClient_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS}) - set( MujinControllerClient_LIBRARY_DIRS "${MujinControllerClient_LIBRARY_DIRS}" ${Boost_LIBRARY_DIRS}) + set( MujinWebstackClient_INCLUDE_DIRS "${MujinWebstackClient_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS}) + set( MujinWebstackClient_LIBRARY_DIRS "${MujinWebstackClient_LIBRARY_DIRS}" ${Boost_LIBRARY_DIRS}) else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") - message(WARNING "Failed to find Boost ${MujinControllerClient_Boost_VERSION} necessary MujinControllerClient") + message(WARNING "Failed to find Boost ${MujinWebstackClient_Boost_VERSION} necessary MujinWebstackClient") endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") endif( WIN32 ) mark_as_advanced( - MujinControllerClient_ROOT_DIR - MujinControllerClient_CXX_FLAGS - MujinControllerClient_LINK_FLAGS - MujinControllerClient_INCLUDE_DIRS - MujinControllerClient_LIBRARY_DIRS - MujinControllerClient_LIBRARIES - MujinControllerClient_Boost_VERSION + MujinWebstackClient_ROOT_DIR + MujinWebstackClient_CXX_FLAGS + MujinWebstackClient_LINK_FLAGS + MujinWebstackClient_INCLUDE_DIRS + MujinWebstackClient_LIBRARY_DIRS + MujinWebstackClient_LIBRARIES + MujinWebstackClient_Boost_VERSION ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d975da3f..3738fc90 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,65 +12,57 @@ # See the License for the specific language governing permissions and # limitations under the License. -include_directories(${CURL_INCLUDE_DIRS} ${LOG4CXX_INCLUDEDIR}) -if (libzmq_FOUND) - include_directories(${libzmq_INCLUDE_DIRS}) -endif() - -link_directories(${MUJINCLIENT_LINK_DIRS}) +include_directories(${CURL_INCLUDE_DIRS} ${LOG4CXX_INCLUDEDIR} ${MujinControllerClient_INCLUDE_DIRS}) +link_directories(${MUJINWEBSTACKCLIENT_LINK_DIRS}) set(SOURCE_FILES boost_assertion_failed.cpp - binpickingtask.cpp - common.cpp + utf8.h common.h - controllerclientimpl.cpp - controllerclientimpl.h - mujincontrollerclient.cpp - mujindefinitions.cpp - mujinjson.cpp - utf8.h ) - -if (libzmq_FOUND) - set(SOURCE_FILES ${SOURCE_FILES} binpickingtaskzmq.h binpickingtaskzmq.cpp mujinzmq.cpp) -endif() + common.cpp + logging.h + webstackclient.cpp ) -add_library(libmujincontrollerclient SHARED ${SOURCE_FILES}) +add_library(libmujinwebstackclient SHARED ${SOURCE_FILES}) if( EXTRA_MSVC_DEPEND ) message(STATUS "adding msvc_boost dependency") - add_dependencies(libmujincontrollerclient ${EXTRA_MSVC_DEPEND}) + add_dependencies(libmujinwebstackclient ${EXTRA_MSVC_DEPEND}) endif() -set_target_properties(libmujincontrollerclient PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} ${Boost_CFLAGS} -DMUJINCLIENT_DLL_EXPORTS -DMUJINCLIENT_DLL" LINK_FLAGS "" - OUTPUT_NAME mujincontrollerclient${MUJINCLIENT_LIBRARY_SUFFIX} + +set_target_properties(libmujinwebstackclient PROPERTIES + COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} ${Boost_CFLAGS} -DMUJINWEBSTACKCLIENT_DLL_EXPORTS -DMUJINWEBSTACKCLIENT_DLL" + LINK_FLAGS "" + OUTPUT_NAME mujinwebstackclient${MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX} SOVERSION 0 # always have it 0 since we're including the soversion as part of the library name - VERSION ${MUJINCLIENT_VERSION} + VERSION ${MUJINWEBSTACKCLIENT_VERSION} CLEAN_DIRECT_OUTPUT 1 ) -target_link_libraries(libmujincontrollerclient ${CURL_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${EXTRA_LIBRARIES} ${libzmq_LIBRARIES} ${LOG4CXX_LIBRARIES}) +target_link_libraries(libmujinwebstackclient ${CURL_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${EXTRA_LIBRARIES} ${libzmq_LIBRARIES} ${LOG4CXX_LIBRARIES}) if( MSVC ) - install(TARGETS libmujincontrollerclient RUNTIME DESTINATION bin LIBRARY DESTINATION bin ARCHIVE DESTINATION lib${LIB_SUFFIX}) + install(TARGETS libmujinwebstackclient RUNTIME DESTINATION bin LIBRARY DESTINATION bin ARCHIVE DESTINATION lib${LIB_SUFFIX}) else() - install(TARGETS libmujincontrollerclient DESTINATION lib${LIB_SUFFIX}) + install(TARGETS libmujinwebstackclient DESTINATION lib${LIB_SUFFIX}) endif() if( OPT_BUILD_STATIC ) # visual studio needs static lib built if( MSVC ) # static version needs to have different name - set(LIBMUJINCONTROLLERCLIENT_NAME libmujincontrollerclient${MUJINCLIENT_LIBRARY_SUFFIX}) + set(LIBMUJINWEBSTACKCLIENT_NAME libmujinwebstackclient${MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX}) else() - set(LIBMUJINCONTROLLERCLIENT_NAME mujincontrollerclient${MUJINCLIENT_LIBRARY_SUFFIX}) + set(LIBMUJINWEBSTACKCLIENT_NAME mujinwebstackclient${MUJINWEBSTACKCLIENT_LIBRARY_SUFFIX}) endif() - add_library(libmujincontrollerclient_static STATIC ${SOURCE_FILES}) - set_target_properties(libmujincontrollerclient_static PROPERTIES OUTPUT_NAME ${LIBMUJINCONTROLLERCLIENT_NAME} - SOVERSION 0 # always have it 0 since we're including the soversion as part of the library name - VERSION ${MUJINCLIENT_VERSION} - CLEAN_DIRECT_OUTPUT 1 - COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} ${Boost_CFLAGS} -DMUJINCLIENT_DLL_EXPORTS -DMUJINCLIENT_DLL" - LINK_FLAGS "") + add_library(libmujinwebstackclient_static STATIC ${SOURCE_FILES}) + set_target_properties(libmujinwebstackclient_static PROPERTIES + OUTPUT_NAME ${LIBMUJINWEBSTACKCLIENT_NAME} + SOVERSION 0 # always have it 0 since we're including the soversion as part of the library name + VERSION ${MUJINWEBSTACKCLIENT_VERSION} + CLEAN_DIRECT_OUTPUT 1 + COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} ${Boost_CFLAGS} -DMUJINWEBSTACKCLIENT_DLL_EXPORTS -DMUJINWEBSTACKCLIENT_DLL" + LINK_FLAGS "") - target_link_libraries(libmujincontrollerclient_static ${CURL_LIBRARIES} ${EXTRA_LIBRARIES} ${libzmq_LIBRARIES} ${libzmq_LIBRARIES} ${LOG4CXX_LIBRARIES}) - install(TARGETS libmujincontrollerclient_static DESTINATION lib${LIB_SUFFIX}) + target_link_libraries(libmujinwebstackclient_static ${CURL_LIBRARIES} ${EXTRA_LIBRARIES} ${libzmq_LIBRARIES} ${libzmq_LIBRARIES} ${LOG4CXX_LIBRARIES}) + install(TARGETS libmujinwebstackclient_static DESTINATION lib${LIB_SUFFIX}) endif() diff --git a/src/common.h b/src/common.h index df48a950..b6235f9f 100644 --- a/src/common.h +++ b/src/common.h @@ -18,7 +18,10 @@ #define MUJIN_CONTROLLERCLIENT_COMMON_H #define WIN32_LEAN_AND_MEAN -#include + +#include +#include +#include #include #include @@ -28,12 +31,10 @@ #include #include #include - -#include -#include -#include #include +#include + #if defined(_WIN32) || defined(_WIN64) #include #undef GetUserName // classes with ControllerClient::GetUserName diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index ca7e890e..1994d5ba 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -55,6 +55,9 @@ #include #include #include +#include +#include + #include #include #include @@ -70,17 +73,6 @@ enum TaskResourceOptions TRO_EnableZMQ=1, ///< create a task resource with zeromq client }; -class ControllerClient; -class ObjectResource; -class RobotResource; -class SceneResource; -class TaskResource; -class BinPickingTaskResource; -class OptimizationResource; -class PlanningResultResource; -class BinPickingResultResource; -class DebugResource; - /// \brief (scene) file entry in mujin controller struct FileEntry { @@ -89,523 +81,93 @@ struct FileEntry size_t size; // file size in bytes }; -typedef boost::shared_ptr ControllerClientPtr; -typedef boost::weak_ptr ControllerClientWeakPtr; -typedef boost::shared_ptr ObjectResourcePtr; -typedef boost::weak_ptr ObjectResourceWeakPtr; -typedef boost::shared_ptr RobotResourcePtr; -typedef boost::weak_ptr RobotResourceWeakPtr; -typedef boost::shared_ptr SceneResourcePtr; -typedef boost::weak_ptr SceneResourceWeakPtr; -typedef boost::shared_ptr TaskResourcePtr; -typedef boost::weak_ptr TaskResourceWeakPtr; -typedef boost::shared_ptr BinPickingTaskResourcePtr; -typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; -typedef boost::shared_ptr OptimizationResourcePtr; -typedef boost::weak_ptr OptimizationResourceWeakPtr; -typedef boost::shared_ptr PlanningResultResourcePtr; -typedef boost::weak_ptr PlanningResultResourceWeakPtr; -typedef boost::shared_ptr BinPickingResultResourcePtr; -typedef boost::weak_ptr BinPickingResultResourceWeakPtr; -typedef boost::shared_ptr DebugResourcePtr; -typedef boost::weak_ptr DebugResourceWeakPtr; typedef double Real; -/// \brief status code for a job -/// -/// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html -enum JobStatusCode { - JSC_Pending = 0, ///< The goal has yet to be processed - JSC_Active = 1, ///< The goal is currently being processed - JSC_Preempted = 2, ///< The goal received a cancel request after it started executing and has since completed its execution. - JSC_Succeeded = 3, ///< The goal was achieved successfully. - JSC_Aborted = 4, ///< The goal was aborted during execution due to some failure - JSC_Rejected = 5, ///< The goal was rejected without being processed, because the goal was unattainable or invalid. - JSC_Preempting = 6, ///< The goal received a cancel request after it started executing and has not yet completed execution - JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. - JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled - JSC_Lost = 9, ///< An error happened and the job stopped being tracked. - JSC_Unknown = 0xffffffff, ///< the job is unknown -}; - - -/// \brief get status code from string representation -/// -/// \param str string representation of status -/// \return JobStatusCode equivalent -JobStatusCode GetStatusCode(const std::string& str); - -struct JobStatus -{ - JobStatus() : code(JSC_Unknown) { - } - JobStatusCode code; ///< status code on whether the job is active - std::string type; ///< the type of job running - std::string message; ///< current message of the job - double elapsedtime; ///< how long the job has been running for in seconds - std::string pk; ///< the primary key to differentiate this job -}; - -struct InstanceObjectState -{ - Transform transform; ///< the transform of this instance object - std::vector dofvalues; ///< the joint values -}; - -typedef std::map EnvironmentState; - -struct SceneInformation -{ - std::string pk; ///< primary key - std::string uri; ///< uri of the file pointed to - std::string datemodified; ///< late date modified - std::string name; -}; - -/// \brief holds information about the itlplanning task parameters -class ITLPlanningTaskParameters -{ -public: - ITLPlanningTaskParameters() { - SetDefaults(); - } - virtual void SetDefaults() { - startfromcurrent = 0; - returnmode = "start"; - vrcruns = 1; - ignorefigure = 1; - unit = "mm"; - optimizationvalue = 1; - program.clear(); - } - - int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. - - /// specifies the final movement of the robot. There's 3 different modes: - /// - \b "" - (empty string) meaning robot doesn't return to anything - /// - \b "start" - robot returns to wherever it started - /// - \b "final" - robot returns to the final_envstate - std::string returnmode; - - int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. - int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) - std::string program; ///< itl program - std::string parameters; ///< parameters (json) - - EnvironmentState initial_envstate; ///< initial environment state to set the ITL task to. - EnvironmentState final_envstate; ///< final environment state that describes where the robot should end at. If returnmode is set to final, then use this state. -}; - -/// program is wincaps rc8 pac script -class DensoWaveWincapsTaskParameters : public ITLPlanningTaskParameters -{ -public: - DensoWaveWincapsTaskParameters() : ITLPlanningTaskParameters() { - SetDefaults(); - } - void SetDefaults() { - ITLPlanningTaskParameters::SetDefaults(); - preservespeedparameters = 0; - } - int preservespeedparameters; ///< if 1, preserves all SPEED/ACCEL commands as best as possible. -}; - -/// \brief placement optimization for a robot or another target. -struct RobotPlacementOptimizationParameters -{ - RobotPlacementOptimizationParameters() { - SetDefaults(); - } - inline void SetDefaults() { - unit = "mm"; - topstorecandidates = 20; - targetname.clear(); - framename.clear(); - minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; - maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; - stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; - ignorebasecollision = 0; - } - std::string targetname; ///< the name of the target object to optimize for. Cannot be blank. Has to start with "0 instobject " is targetting an environment instance object. For Example "0 instobject myrobot". - std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" - Real maxrange[4]; ///< X, Y, Z, Angle (deg) - Real minrange[4]; ///< X, Y, Z, Angle (deg) - Real stepsize[4]; ///< X, Y, Z, Angle (deg) - int ignorebasecollision; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. - - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. -}; - -struct PlacementsOptimizationParameters -{ - PlacementsOptimizationParameters() { - SetDefaults(); - } - inline void SetDefaults() { - unit = "mm"; - topstorecandidates = 20; - for(size_t itarget = 0; itarget < targetnames.size(); ++itarget) { - targetnames[itarget].clear(); - framenames[itarget].clear(); - ignorebasecollisions[itarget] = 0; - } - minranges[0][0] = -400; minranges[0][1] = -400; minranges[0][2] = 0; minranges[0][3] = -180; - maxranges[0][0] = 400; maxranges[0][1] = 400; maxranges[0][2] = 400; maxranges[0][3] = 90; - stepsizes[0][0] = 100; stepsizes[0][1] = 100; stepsizes[0][2] = 100; stepsizes[0][3] = 90; - minranges[1][0] = -100; minranges[1][1] = -100; minranges[1][2] = 0; minranges[1][3] = 0; - maxranges[1][0] = 100; maxranges[1][1] = 100; maxranges[1][2] = 100; maxranges[1][3] = 0; - stepsizes[1][0] = 100; stepsizes[1][1] = 100; stepsizes[1][2] = 100; stepsizes[1][3] = 90; - } - - // for every target, there's one setting: - boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. - boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. - boost::array maxranges; ///< X, Y, Z, Angle (deg) - boost::array minranges; ///< X, Y, Z, Angle (deg) - boost::array stepsizes; ///< X, Y, Z, Angle (deg) - boost::array ignorebasecollisions; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. - - // shared settings - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. -}; - -/// \brief program data for an individual robot -class RobotProgramData -{ -public: - RobotProgramData() { - } - RobotProgramData(const std::string& programdata_, const std::string& type_) : programdata(programdata_), type(type_) { - } - std::string programdata; ///< the program data - std::string type; ///< the type of program -}; - -/// \brief program data for all robots. -class RobotControllerPrograms -{ -public: - std::map programs; ///< the keys are the robot instance primary keys of the scene -}; - /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. -class MUJINCLIENT_API ControllerClient +class MUJINCLIENT_API WebstackClient { public: - virtual ~ControllerClient() { - } - -// \brief Returns a list of filenames in the user system of a particular type -// -// \param scenetype the type of scene possible values are: -// - mujincollada -// - wincaps -// - rttoolbox -// - cecrobodiaxml -// - stl -// - x -// - vrml -// - stl -// -// virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; + WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout); + virtual ~WebstackClient(); /// \brief sets the character encoding for all strings that are being input and output from the resources /// /// The default character encoding is \b utf-8, can also set it to \b Shift_JIS for windows japanese unicode, \b iso-2022-jp /// List of possible sets: http://www.iana.org/assignments/character-sets/character-sets.xml - virtual void SetCharacterEncoding(const std::string& newencoding) = 0; + void SetCharacterEncoding(const std::string& newencoding); /// \brief sets the language code for all output /// /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes - virtual void SetLanguage(const std::string& language) = 0; + void SetLanguage(const std::string& language); /// \brief sets the user agent to be sent with each http request - virtual void SetUserAgent(const std::string& userAgent) = 0; + void SetUserAgent(const std::string& userAgent); /// \brief sets additional http headers to be included on all requests /// /// \param additionalHeaders expect each value to be in the format of "Header-Name: header-value" - virtual void SetAdditionalHeaders(const std::vector& additionalHeaders) = 0; + void SetAdditionalHeaders(const std::vector& additionalHeaders); /// \brief returns the username logged into this controller - virtual const std::string& GetUserName() const = 0; + const std::string& GetUserName() const; /// \brief returns the URI used to setup the connection - virtual const std::string& GetBaseURI() const = 0; + const std::string& GetBaseURI() const; /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - virtual void SetProxy(const std::string& serverport, const std::string& userpw) = 0; + void SetProxy(const std::string& serverport, const std::string& userpw); /// \brief If necessary, changes the unix domain socket to be used to communicate to the controller server. Setting unix endpoint disables previously set proxy. /// /// \param unixendpoint Specify the file path to the unix domain socket to connect to. - virtual void SetUnixEndpoint(const std::string& unixendpoint) = 0; + void SetUnixEndpoint(const std::string& unixendpoint); /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. /// /// If the server is not responding, call this method to clear the server state and initialize everything. /// The method is blocking, when it returns the MUJIN Controller would have been restarted. - virtual void RestartServer(double timeout = 5.0) = 0; + void RestartServer(double timeout = 5.0); /// \brief Execute GraphQL query or mutation against Mujin Controller. /// /// Throws an exception if there are any errors /// \param rResultData The "data" field of the result if the query returns without problems - virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResultData, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResultData, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0); /// \brief Execute the GraphQL query or mutation against Mujin Controller and return any output as-is without doing any error processing /// /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". - virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; + void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0); /// \brief returns the mujin controller version - virtual std::string GetVersion() = 0; + std::string GetVersion(); /// \brief sends the cancel message to all jobs. /// /// The method is non-blocking - virtual void CancelAllJobs() = 0; - - /// \brief get all the run-time statuses - /// - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatuses(std::vector& statuses, int options=0) = 0; - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; - - /** \brief Register a scene to be used by the MUJIN Controller - - \param uri utf-8 encoded URI of the file on the MUJIN Controller to import. Usually starts with \b mujin:/ - \param scenetype The format of the source file. Can be: - - **mujincollada** - - **wincaps** (DensoWave WINCAPS III) - - **rttoolbox** (Mitsubishi RT ToolBox) - - **x** (DirectX) - - **vrml** - - **stl** - - **cecrobodiaxml** (CEC RoboDiA XML environments) - */ - virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) = 0; - - /// \brief registers scene with default scene type - virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri) - { - return RegisterScene_UTF8(uri,GetDefaultSceneType()); - } - - /// \see RegisterScene_UTF8 - /// - /// \param uri utf-16 encoded URI - virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) = 0; - - /// \brief registers scene with default scene type - virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri) - { - return RegisterScene_UTF16(uri,GetDefaultSceneType()); - } - - /** \brief import a scene into COLLADA format using from scene identified by a URI - - \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext - \param sourcescenetype The format of the source file. Can be: - - **mujincollada** - - **wincaps** (DensoWave WINCAPS III) - - **rttoolbox** (Mitsubishi RT ToolBox) - - **x** (DirectX) - - **vrml** - - **stl** - - **cecrobodiaxml** (CEC RoboDiA XML environments) - \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae - \param overwrite if true, will overwrite any existing scenes at newuri with the new scene. - */ - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri, bool overwrite=false) = 0; - - /// \see ImportSceneToCOLLADA_UTF8 - /// - /// \param sourceuri utf-16 encoded - /// \param newuri utf-16 encoded - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; - - /** \brief Recommended way of uploading a scene's files into the network filesystem. - - Depending on the scenetype, can upload entire directory trees. - \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. - \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default prefix with "mujin:/". Use the / separator for different paths. - \param scenetype UTF-8 encoded type of scene uploading. - \throw mujin_exception if the upload fails, will throw an exception - */ - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; - - /// \see SyncUpload_UTF8 - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir) - { - SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); - } - - /// \see SyncUpload_UTF8 - /// - /// \param sourcefilename UTF-16 encoded. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. - /// \param destinationdir UTF-16 encoded - /// \param scenetype UTF-16 encoded - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir, const std::string& scenetype) = 0; - - /// \see SyncUpload - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir) - { - SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); - } - - /// \brief Uploads a single file to the controller network filesystem. - /// - /// Overwrites the file if it already exists - /// \param filename utf-8 encoded path of the file on the system - /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. - virtual void UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) = 0; - - /// \brief \see UploadFileToController_UTF8 - /// - /// \param filename utf-16 encoded - /// \param desturi UTF-16 encoded - virtual void UploadFileToController_UTF16(const std::wstring& filename, const std::wstring& desturi) = 0; - - /// \brief Uploads binary data to a single file on the controller network filesystem. - /// - /// Overwrites the destination uri if it already exists - /// \param data binary data to upload to the uri - /// \param size binary data size in bytes - /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. - virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) = 0; - - /// \brief \see UploadDataToController_UTF8 - /// - /// \param data binary data to upload to the uri - /// \param size binary data size in bytes - /// \param desturi UTF-16 encoded - virtual void UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) = 0; - - /// \brief Build a backup of config/media and download it. - /// - /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. - /// \param config whether to backup config. By default true. - /// \param media whether to include media files in the backup. By default true - /// \param backupscenepks comma separated list of scenes to backup. By default empty. - virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, const std::string& backupscenepks = "", double timeout = 60.0) = 0; - - /// \brief Restore backup archive into controller. Restaring might be required after restoration. - /// - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). - /// \param config whether to restore config. By default true (if the backup file has config). - /// \param media whether to restore media. By default true (if the backup file has media). - virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; - - /// \brief Upgrade controller's software. - /// - /// \param inputStream the stream represententing the software file provided by MUJIN. - /// It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). - /// Pass stream with size 0 to use previously uploaded file. - /// \param autorestart whether to restart automatically after upgrading. if false, Reboot() can be called later. - /// \param uploadonly whether to upload only (so that upgrade can be continued later without uploading). - virtual void Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; - - /// \brief Get upgrade status. - /// - /// \param status upgrade status - /// \param progress progress 0 to 1 - /// \return true if the status was received (false means upgrade was not started yet). - virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout = 5.0) = 0; - - /// \brief Cancel the current upgrade process. - virtual void CancelUpgrade(double timeout = 5.0) = 0; - - /// \brief (Request to) reboot controller. - virtual void Reboot(double timeout = 5.0) = 0; - - /// \brief Delete all scenes. - virtual void DeleteAllScenes(double timeout = 5.0) = 0; - - /// \brief Delete all itl programs. - virtual void DeleteAllITLPrograms(double timeout = 5.0) = 0; - - /** \brief Recursively uploads a directory to the controller network filesystem. - - Creates directories along the way if they don't exist. - By default, overwrites all the files - \param copydir is utf-8 encoded. Cannot have trailing slashes '/', '\' - \param desturi UTF-8 encoded destination file in the network filesystem. If it has a trailing slash, then copydir is inside that URL. If there is no trailing slash, the copydir directory is renamed to the URI. By default prefix with "mujin:/". Use the / separator for different paths. - */ - virtual void UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) = 0; - - /// \brief \see UploadDirectoryToController_UTF8 - /// - /// \param copydir is utf-16 encoded - /// \param desturi UTF-16 encoded - virtual void UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) = 0; - - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) = 0; - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) = 0; + void CancelAllJobs(); /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header /// \param remotetimeval will output the modified date in response /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; + void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0); /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header /// \param remotetimeval will output the modified date in response /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; - - /// \brief returns seconds since epoch, last modified time from server header - virtual long GetModifiedTime(const std::string& uri, double timeout = 5.0) = 0; - - /// \brief Deletes a file on the controller network filesystem. - /// - /// \param uri UTF-8 encoded file in the network filesystem to delete. - virtual void DeleteFileOnController_UTF8(const std::string& uri) = 0; - - /// \brief \see DeleteFileOnController_UTF8 - /// - /// \param uri UTF-16 encoded file in the network filesystem to delete. - virtual void DeleteFileOnController_UTF16(const std::wstring& uri) = 0; - - /// \brief Recursively deletes a directory on the controller network filesystem. - /// - /// \param uri UTF-8 encoded file in the network filesystem to delete. - virtual void DeleteDirectoryOnController_UTF8(const std::string& uri) = 0; - - /// \brief Get file list in specified directory. - /// - /// \param dirname UTF-8 encoded dirname to query. - virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; - - /// \brief \see DeleteDirectoryOnController_UTF8 - /// - /// \param uri UTF-16 encoded - virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; + void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0); - virtual void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; + void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0); - virtual void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; + void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0); - virtual void SetDefaultSceneType(const std::string& scenetype) = 0; - - virtual const std::string& GetDefaultSceneType() = 0; - - virtual void SetDefaultTaskType(const std::string& tasktype) = 0; - - virtual const std::string& GetDefaultTaskType() = 0; + const std::string& GetDefaultTaskType(); /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) @@ -620,7 +182,7 @@ class MUJINCLIENT_API ControllerClient Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" \param uri utf-8 encoded URI */ - virtual std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) = 0; + std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri); /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) @@ -629,29 +191,19 @@ class MUJINCLIENT_API ControllerClient \param uri utf-16 encoded URI */ - virtual std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) = 0; - - /// \brief returns the primary key of a name - /// - /// \param name utf-8 encoded - virtual std::string GetPrimaryKeyFromName_UTF8(const std::string& name) = 0; - - /// \brief returns the primary key of a name - /// - /// \param name utf-16 encoded - virtual std::string GetPrimaryKeyFromName_UTF16(const std::wstring& name) = 0; + std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri); /// \brief returns the uncoded name from a primary key /// /// \return utf-8 encoded name - virtual std::string GetNameFromPrimaryKey_UTF8(const std::string& pk) = 0; + std::string GetNameFromPrimaryKey_UTF8(const std::string& pk); /// \brief returns the uncoded name from a primary key /// /// \return utf-16 encoded name - virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; + std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk); - virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout = 5) = 0; + std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout = 5); /// \brief set geometry mesh to an object /// \param objectPk primary key for the object to set mesh data to @@ -660,538 +212,141 @@ class MUJINCLIENT_API ControllerClient /// \param unit length unit of mesh /// \param timeout timeout of uploading mesh /// - virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; - - /// \brief get debug infos - virtual void GetDebugInfos(std::vector& debuginfos, double timeout = 5) = 0; -}; - -class MUJINCLIENT_API WebResource -{ -public: - WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk); - virtual ~WebResource() { - } - - inline ControllerClientPtr GetController() const { - return __controller; - } - inline const std::string& GetResourceName() const { - return __resourcename; - } - inline const std::string& GetPrimaryKey() const { - return __pk; - } - - /// \brief gets an attribute of this web resource - template - inline T Get(const std::string& field, double timeout = 5.0) { - rapidjson::Document pt(rapidjson::kObjectType); - GetWrap(pt, field, timeout); - return mujinjson::GetJsonValueByKey(pt, field.c_str()); - } - - /// \brief sets an attribute of this web resource - virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); - - /// \brief sets an attribute of this web resource - virtual void SetJSON(const std::string& json, double timeout = 5.0); - - /// \brief delete the resource and all its child resources - virtual void Delete(double timeout = 5.0); - - /// \brief copy the resource and all its child resources to a new name - virtual void Copy(const std::string& newname, int options, double timeout = 5.0); - -private: - virtual void GetWrap(rapidjson::Document& pt, const std::string& field, double timeout = 5.0); - - ControllerClientPtr __controller; - std::string __resourcename, __pk; -}; - -class MUJINCLIENT_API ObjectResource : public WebResource -{ -public: - class MUJINCLIENT_API GeometryResource : public WebResource { -public: - GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~GeometryResource() { - } - std::string name; - std::string pk; - std::string objectpk; - std::string linkpk; - std::string geomtype; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - bool visible; - Real diffusecolor[4]; - Real transparency; - Real half_extents[3]; - Real height; - Real radius; - - virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); - virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on - virtual int GetVisible(); - }; - typedef boost::shared_ptr GeometryResourcePtr; - - class MUJINCLIENT_API IkParamResource : public WebResource { -public: - IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~IkParamResource() { - } - std::string name; - std::string pk; - std::string iktype; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translation[3]; - Real direction[3]; - Real angle; - }; - typedef boost::shared_ptr IkParamResourcePtr; - - class MUJINCLIENT_API LinkResource : public WebResource { -public: - LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~LinkResource() { - } - - virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout = 5.0); - virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout = 5.0); - - virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); - - virtual void GetGeometries(std::vector& links); - - virtual boost::shared_ptr AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]); - - virtual void SetCollision(bool collision); - /// 0 -> off, 1 -> on - virtual int GetCollision(); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetVisible(); - - std::vector attachmentpks; - std::string name; - std::string pk; - std::string objectpk; - std::string parentlinkpk; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - bool collision; - }; - typedef boost::shared_ptr LinkResourcePtr; + std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5); + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode=200, double timeout = 5.0); - ObjectResource(ControllerClientPtr controller, const std::string& pk); - virtual ~ObjectResource() { - } - virtual void GetLinks(std::vector& links); - - virtual void GetIkParams(std::vector& ikparams); - - virtual LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]); - virtual IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype); - - virtual void SetCollision(bool collision); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetCollision(); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetVisible(); - - std::string name; - int nundof; - std::string datemodified; - std::string geometry; - bool isrobot; - std::string pk; - std::string resource_uri; - std::string scenepk; - std::string unit; - std::string uri; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - -protected: - ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode=200, double timeout = 5.0); -}; + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode=200, double timeout = 5.0); -class MUJINCLIENT_API RobotResource : public ObjectResource -{ -public: - class MUJINCLIENT_API ToolResource : public WebResource { -public: - ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); - virtual ~ToolResource() { - } - - std::string name; - std::string frame_origin; - std::string frame_tip; - std::string pk; - Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - typedef boost::shared_ptr ToolResourcePtr; - - class MUJINCLIENT_API AttachedSensorResource : public WebResource { -public: - AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); - virtual ~AttachedSensorResource() { - } - - std::string name; - std::string frame_origin; - std::string pk; - //Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - std::string sensortype; - - struct SensorData { -public: - bool operator!=(const SensorData& other) const { - return std::memcmp(distortion_coeffs, other.distortion_coeffs, 5 * sizeof(Real)) != 0 || - distortion_model != other.distortion_model || - focal_length != other.focal_length || - std::memcmp(image_dimensions, other.image_dimensions, 3 * sizeof(int)) != 0 || - std::memcmp(intrinsic, other.intrinsic, 6 * sizeof(Real)) != 0 || - measurement_time != other.measurement_time || - extra_parameters != other.extra_parameters; - } - bool operator==(const SensorData& other) const { - return !operator!=(other); - } - Real distortion_coeffs[5]; - std::string distortion_model; - Real focal_length; - int image_dimensions[3]; - Real intrinsic[6]; - Real measurement_time; - std::vector extra_parameters; - }; - SensorData sensordata; - }; - - typedef boost::shared_ptr AttachedSensorResourcePtr; - - RobotResource(ControllerClientPtr controller, const std::string& pk); - virtual ~RobotResource() { - } + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + int CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode=200, double timeout = 5.0); - virtual void GetTools(std::vector& tools); - virtual void GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies = true); - - // attachments - // ikparams - // images - int numdof; - std::string simulation_file; -}; - -class MUJINCLIENT_API SceneResource : public WebResource -{ -public: - class InstObject; - typedef boost::shared_ptr InstObjectPtr; - /// \brief nested resource in the scene describe an object in the scene - class MUJINCLIENT_API InstObject : public WebResource - { -public: - InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk); - virtual ~InstObject() { - } - - class MUJINCLIENT_API Link { -public: - std::string name; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; + /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception + /// + /// \param relativeuri URL-encoded UTF-8 encoded + /// \param data encoded depending on the character encoding set on the system + int CallPost(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - class MUJINCLIENT_API Tool { -public: - std::string name; - Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; + /// \param data utf-8 encoded + int CallPost_UTF8(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); + /// \param data utf-16 encoded + int CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - class MUJINCLIENT_API Grab { -public: - std::string instobjectpk; ///< grabed_instobject_pk - std::string grabbed_linkpk; - std::string grabbing_linkpk; - - std::string Serialize() { - return boost::str(boost::format("{\"instobjectpk\": \"%s\", \"grabbed_linkpk\": \"%s\", \"grabbing_linkpk\": \"%s\"}")%instobjectpk%grabbed_linkpk%grabbing_linkpk); - } - - bool operator==(const Grab grab) { - if (this->instobjectpk == grab.instobjectpk - && this->grabbed_linkpk == grab.grabbed_linkpk - && this->grabbing_linkpk == grab.grabbing_linkpk) { - return true; - } - return false; - } - }; - - class MUJINCLIENT_API AttachedSensor { -public: - std::string name; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - - void SetTransform(const Transform& t); - void SetDOFValues(); - virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); - virtual void ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); - - - std::vector dofvalues; - std::string name; - std::string pk; - std::string object_pk; - std::string reference_object_pk; - std::string reference_uri; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - std::vector grabs; - std::vector links; - std::vector tools; - std::vector attachedsensors; - }; - - SceneResource(ControllerClientPtr controller, const std::string& pk); - virtual ~SceneResource() { - } + /// \brief puts json string + /// \param relativeuri relative uri to put at + /// \param data json string to put + /// \param pt reply is stored + /// \param expectedhttpcode expected http code + /// \param timeout timeout of puts + /// \return http code returned + int CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=202, double timeout = 5.0); - virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); + /// \brief puts stl data + /// \param relativeuri relative uri to put at + /// \param data stl raw data + /// \param pt reply is stored + /// \param expectedhttpcode expected http code + /// \param timeout timeout of puts + /// \return http code returned + int CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode=202, double timeout = 5.0); - /** \brief Gets or creates the a task part of the scene - If task exists already, validates it with tasktype. - \param taskname utf-8 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown - \param tasktype The type of task to create. Supported types are: - - itlplanning - */ + void CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout = 5.0); - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); + std::stringstream& GetBuffer(); - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) + /// \brief URL-encode raw string + inline std::string EscapeString(const std::string& raw) const { - return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType(), options); + boost::shared_ptr pstr(curl_easy_escape(_curl, raw.c_str(), raw.size()), curl_free); + return std::string(pstr.get()); } - virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname, int options=0); - - /** \brief Gets or creates the a task part of the scene - - If task exists already, validates it with tasktype. - \param taskname utf-16 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown - \param tasktype The type of task to create. Supported types are: - - itlplanning - */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options=0); - - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, int options=0) + /// \brief decode URL-encoded raw string + inline std::string UnescapeString(const std::string& raw) const { - return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType(), options); + int outlength = 0; + boost::shared_ptr pstr(curl_easy_unescape(_curl, raw.c_str(), raw.size(), &outlength), curl_free); + return std::string(pstr.get(), outlength); } - virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); - - - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype="binpicking", int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype="binpicking", int options=0); - - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetTaskPrimaryKeys(std::vector& taskkeys); - - virtual void GetTaskNames(std::vector& names); - - /// \brief gets a list of all the instance objects of the scene - virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); - virtual void GetInstObjects(std::vector& instobjects); - virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); - - /// \brief creates an inst object in scene - /// \param name name of the object to create - /// \param referenceUri uri to reference. Leave empty to reference nothing. - /// \param quaternion quaternion of the object - /// \param translate translation of the object - /// \return pointer to inst object created - virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout = 300); - - /// \brief deletes an inst object in scene - /// \param pk primary key of the object to delete - virtual void DeleteInstObject(const std::string& pk); - - virtual SceneResourcePtr Copy(const std::string& name); -}; - -class MUJINCLIENT_API TaskResource : public WebResource -{ -public: - TaskResource(ControllerClientPtr controller, const std::string& pk); - virtual ~TaskResource() { - } - - /// \brief execute the task. - /// - /// This operation is non-blocking and will return immediately after the execution is started. In order to check if the task is running or is complete, use \ref GetRunTimeStatus() and \ref GetResult() - /// \return true if task was executed fine - virtual bool Execute(); - - /// \brief if the task is currently executing, send a cancel request - virtual void Cancel(); - - /// \brief get the run-time status of the executed task. - /// - /// This will only work if the task has been previously Executed with execute - /// If the task is not currently running, will set status.code to JSC_Unknown - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatus(JobStatus& status, int options = 1); - - /// \brief Gets or creates the a optimization part of the scene - /// - /// \param optimizationname the name of the optimization to search for or create - /// \param optimizaitontype The type of optimization, can be "robotplacement" or "placements" - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); - - /// \brief \see GetOrCreateOptimizationFromName_UTF8 - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); - - /// \brief Get the task info for tasks of type itlplanning - virtual void GetTaskParameters(ITLPlanningTaskParameters& taskparameters); - - /// \brief Set new task info for tasks of type itlplanning - virtual void SetTaskParameters(const ITLPlanningTaskParameters& taskparameters); +private: + int _CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, rapidjson::Document& pt, curl_slist* headers, int expectedhttpcode=202, double timeout = 5.0); - /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. - virtual PlanningResultResourcePtr GetResult(); + /// For all webdav internal functions: mutex is already locked, desturi directories are already created + //@{ -protected: - std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called -}; + /// \param desturi expects the fully resolved URI to pass to curl + int _CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode=200, double timeout = 5.0); + int _CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode=200, double timeout = 5.0); + int _CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode=200, double timeout = 5.0); + int _CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode=200, double timeout = 5.0); -class MUJINCLIENT_API OptimizationResource : public WebResource -{ -public: - OptimizationResource(ControllerClientPtr controller, const std::string& pk); - virtual ~OptimizationResource() { - } + int _CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); - /// \brief execute the optimization - /// - /// \param bClearOldResults if true, will clear the old optimiation results. If false, will keep the old optimization results and only compute those that need to be computed. - virtual void Execute(bool bClearOldResults=true); + static int _WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData); + static int _WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData); + static int _WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData); + static int _ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *writerData); - /// \brief if the optimization is currently executing, send a cancel request - virtual void Cancel(); + /// \brief sets up http header for doing http operation with json data + void _SetupHTTPHeadersJSON(); - /// \brief Set new task info for tasks of type robotplanning - void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); + /// \brief sets up http header for doing http operation with stl data + void _SetupHTTPHeadersSTL(); - /// \brief Set new task info for tasks of type placements - void SetOptimizationParameters(const PlacementsOptimizationParameters& optparams); + /// \brief sets up http header for doing http operation with multipart/form-data data + void _SetupHTTPHeadersMultipartFormData(); - /// \brief get the run-time status of the executed optimization. - /// - /// This will only work if the optimization has been previously Executed with execute - /// If the task is not currently running, will set status.code to JSC_Unknown - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatus(JobStatus& status, int options = 1); + void _DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5); - /// \brief Gets the results of the optimization execution ordered by task_time. + /// \brief given a raw uri with "mujin:/", return the real network uri /// - /// \param startoffset The offset to retrieve the results from. Ordered - /// \param num The number of results to get starting at startoffset. If 0, will return ALL results. - virtual void GetResults(std::vector& results, int startoffset=0, int num=0); + /// mutex should be locked + /// \param bEnsurePath if true, will make sure the directories on the server side are created + /// \param bEnsureSlash if true, will ensure returned uri ends with slash / + std::string _PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath=true, bool bEnsureSlash=false, bool bIsDirectory=false); + std::string _PrepareDestinationURI_UTF16(const std::wstring& rawuri, bool bEnsurePath=true, bool bEnsureSlash=false, bool bIsDirectory=false); -protected: - std::string _jobpk; ///< the job primary key used to track the status of the running optimization after \ref Execute is called -}; + // encode a URL without the / separator + std::string _EncodeWithoutSeparator(const std::string& raw); -class MUJINCLIENT_API PlanningResultResource : public WebResource -{ -public: - PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk); - PlanningResultResource(ControllerClientPtr controller, const std::string& pk); - virtual ~PlanningResultResource() { - } + /// \param relativeuri utf-8 encoded directory inside the user webdav folder. has a trailing slash. relative to real uri + void _EnsureWebDAVDirectories(const std::string& relativeuri, double timeout = 3.0); - /// \brief Get all the transforms the results are storing. Depending on the optimization, can be more than just the robot - virtual void GetEnvironmentState(EnvironmentState& envstate); - /** \brief Gets the raw program information + void _ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse); - \param[in] programtype The type of program to return. Possible values are: - - auto - special type that returns the most suited programs - - mujinxml - \b xml - - melfabasicv - \b json with Mitsubishi-specific programs - - densowaverc8pac - \b json with DensoWave-specific programs - - cecrobodiasim - zip file + // INSTANCE FIELDS + int _lastmode; + CURL *_curl; + boost::mutex _mutex; + std::stringstream _buffer; + std::string _baseuri, _baseapiuri, _basewebdavuri, _uri, _username; - If \b auto is set, then the robot-maker specific program is returned if possible. If not possible, then mujin xml is returned. All the programs for all robots planned are returned. + curl_slist *_httpheadersjson; + curl_slist *_httpheadersstl; + curl_slist *_httpheadersmultipartformdata; + std::string _charset, _language; + std::string _csrfmiddlewaretoken; + std::vector _additionalHeaders; ///< list of "Header-Name: header-value" additional http headers - \param[out] outputdata The raw program data - */ - virtual void GetAllRawProgramData(std::string& outputdata, const std::string& programtype="auto"); + rapidjson::Document _profile; ///< user profile and versioning + std::string _errormessage; ///< set when an error occurs in libcurl - /** \brief Gets the raw program information of a specific robot, if supported. + std::string _defaultscenetype, _defaulttasktype; - \param[in] robotpk The primary key of the robot instance in the scene. - \param[out] outputdata The raw program data - \param[in] programtype The type of program to return. - \throw mujin_exception If robot program is not supported, will throw an exception - */ - virtual void GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype="auto"); + rapidjson::StringBuffer _rRequestStringBufferCache; ///< cache for request string, protected by _mutex - /// \brief Gets parsed program information - /// - /// If the robot doesn't have a recognizable controller, then no programs might be returned. - /// \param[out] programs The programs for each robot. The best suited program for each robot is determined from its controller. - /// \param[in] programtype The type of program to return. - virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); -}; +}; // End class WebstackClient -class MUJINCLIENT_API DebugResource : public WebResource -{ -public: - DebugResource(ControllerClientPtr controller, const std::string& pk); - virtual ~DebugResource() { - } - - /// \brief download the encrypted debug log to outputStream - virtual void Download(std::ostream &outputStream, double timeout = 60.0); - - //std::string datemodified; - std::string description; - //std::string downloadUri; - std::string name; - std::string pk; - std::string resource_uri; - size_t size; - -protected: - DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); -}; +typedef boost::shared_ptr WebstackClientPtr; +typedef boost::weak_ptr WebstackClientWeakPtr; /** \en \brief creates the controller with an account. This function is not thread safe. @@ -1212,35 +367,7 @@ class MUJINCLIENT_API DebugResource : public WebResource \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); - -/// \brief called at the very end of an application to safely destroy all controller client resources -MUJINCLIENT_API void DestroyControllerClient(); - -/// \deprecated 14/03/14 -MUJINCLIENT_API void ControllerClientDestroy() MUJINCLIENT_DEPRECATED; - -/// \brief Compute a 3x4 matrix from a Transform -MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); - -/** \brief Compute Euler angles in ZXY order (T = Z*X*Y) from a 3x4 matrix - - Rx = Matrix(3,3,[1,0,0,0,cos(x),-sin(x),0,sin(x),cos(x)]) - Ry = Matrix(3,3,[cos(y),0,sin(y),0,1,0,-sin(y),0,cos(y)]) - Rz = Matrix(3,3,[cos(z),-sin(z),0,sin(z),cos(z),0,0,0,1]) - Rz*Rx*Ry - - [-sin(x)*sin(y)*sin(z) + cos(y)*cos(z), -sin(z)*cos(x), sin(x)*sin(z)*cos(y) + sin(y)*cos(z)] - [ sin(x)*sin(y)*cos(z) + sin(z)*cos(y), cos(x)*cos(z), -sin(x)*cos(y)*cos(z) + sin(y)*sin(z)] - [ -sin(y)*cos(x), sin(x), cos(x)*cos(y)] - - */ -MUJINCLIENT_API void ComputeZXYFromMatrix(Real ZXY[3], const Real matrix[12]); - -MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &transform); - -MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); - +MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); } // namespace mujinclient diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 2628bd48..b345ce2b 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -11,20 +11,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#include "common.h" -#include "controllerclientimpl.h" + +#include #include #include #include #include +#include "common.h" +#include "logging.h" + #define SKIP_PEER_VERIFICATION // temporary //#define SKIP_HOSTNAME_VERIFICATION -#include "logging.h" - -MUJIN_LOGGER("mujin.controllerclientcpp"); +MUJIN_LOGGER("mujin.webstackcpp"); #define CURL_OPTION_SAVER(curl, curlopt, curvalue) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)) #define CURL_OPTION_SETTER(curl, curlopt, newvalue) CHECKCURLCODE(curl_easy_setopt(curl, curlopt, newvalue), "curl_easy_setopt " # curlopt) @@ -91,7 +92,7 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } -ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +WebstackClient::WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); size_t usernameindex = 0; @@ -225,7 +226,7 @@ ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, _SetupHTTPHeadersMultipartFormData(); } -ControllerClientImpl::~ControllerClientImpl() +WebstackClient::~WebstackClient() { if( !!_httpheadersjson ) { curl_slist_free_all(_httpheadersjson); @@ -239,36 +240,53 @@ ControllerClientImpl::~ControllerClientImpl() curl_easy_cleanup(_curl); } -std::string ControllerClientImpl::GetVersion() +void WebstackClient::SetCharacterEncoding(const std::string& newencoding) { - if (!_profile.IsObject()) { - _profile.SetObject(); - CallGet("profile/", _profile); - } - return GetJsonValueByKey(_profile, "version"); + boost::mutex::scoped_lock lock(_mutex); + _charset = newencoding; + _SetupHTTPHeadersJSON(); + // the following two format does not need charset + // _SetupHTTPHeadersSTL(); + // _SetupHTTPHeadersMultipartFormData(); } -const std::string& ControllerClientImpl::GetUserName() const +void WebstackClient::SetLanguage(const std::string& language) { - return _username; + boost::mutex::scoped_lock lock(_mutex); + if (language!= "") { + _language = language; + } + _SetupHTTPHeadersJSON(); + // the following two format does not need language + // _SetupHTTPHeadersSTL(); + // _SetupHTTPHeadersMultipartFormData(); } -const std::string& ControllerClientImpl::GetBaseURI() const +void WebstackClient::SetUserAgent(const std::string& userAgent) { - return _baseuri; + CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, userAgent.c_str()); } -void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) +void WebstackClient::SetAdditionalHeaders(const std::vector& additionalHeaders) { boost::mutex::scoped_lock lock(_mutex); - _charset = newencoding; + _additionalHeaders = additionalHeaders; _SetupHTTPHeadersJSON(); - // the following two format does not need charset - // _SetupHTTPHeadersSTL(); - // _SetupHTTPHeadersMultipartFormData(); + _SetupHTTPHeadersSTL(); + _SetupHTTPHeadersMultipartFormData(); +} + +const std::string& WebstackClient::GetUserName() const +{ + return _username; } -void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) +const std::string& WebstackClient::GetBaseURI() const +{ + return _baseuri; +} + +void WebstackClient::SetProxy(const std::string& serverport, const std::string& userpw) { // mutally exclusive with unix endpoint settings CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, NULL); @@ -276,7 +294,7 @@ void ControllerClientImpl::SetProxy(const std::string& serverport, const std::st CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); } -void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) +void WebstackClient::SetUnixEndpoint(const std::string& unixendpoint) { // mutually exclusive with proxy settings CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); @@ -284,33 +302,37 @@ void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); } -void ControllerClientImpl::SetLanguage(const std::string& language) +void WebstackClient::RestartServer(double timeout) { boost::mutex::scoped_lock lock(_mutex); - if (language!= "") { - _language = language; + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + _uri = _baseuri + std::string("restartserver/"); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); + _buffer.clear(); + _buffer.str(""); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_PERFORM(_curl); + long http_code = 0; + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + if( http_code != 200 ) { + throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); } - _SetupHTTPHeadersJSON(); - // the following two format does not need language - // _SetupHTTPHeadersSTL(); - // _SetupHTTPHeadersMultipartFormData(); } -void ControllerClientImpl::SetUserAgent(const std::string& userAgent) +void WebstackClient::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, userAgent.c_str()); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); } -void ControllerClientImpl::SetAdditionalHeaders(const std::vector& additionalHeaders) +void WebstackClient::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) { - boost::mutex::scoped_lock lock(_mutex); - _additionalHeaders = additionalHeaders; - _SetupHTTPHeadersJSON(); - _SetupHTTPHeadersSTL(); - _SetupHTTPHeadersMultipartFormData(); + _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); } -void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) +void WebstackClient::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) { rResult.SetNull(); // zero output @@ -379,288 +401,135 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c } } -void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +std::string WebstackClient::GetVersion() { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); + if (!_profile.IsObject()) { + _profile.SetObject(); + CallGet("profile/", _profile); + } + return GetJsonValueByKey(_profile, "version"); } -void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) +void WebstackClient::CancelAllJobs() { - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); + CallDelete("job/?format=json", 204); } -void ControllerClientImpl::RestartServer(double timeout) +void WebstackClient::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) { boost::mutex::scoped_lock lock(_mutex); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - _uri = _baseuri + std::string("restartserver/"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); - } + _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata, timeout); } -void ControllerClientImpl::CancelAllJobs() +void WebstackClient::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) { - CallDelete("job/?format=json", 204); + boost::mutex::scoped_lock lock(_mutex); + _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata, timeout); } -void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, int options) +void WebstackClient::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) { - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; - if( options & 1 ) { - url += std::string(",status_text"); - } - CallGet(url, pt); - rapidjson::Value& objects = pt["objects"]; - size_t i = 0; - statuses.resize(objects.Size()); - for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { - - statuses[i].pk = GetJsonValueByKey(*it, "pk"); - statuses[i].code = GetStatusCode(GetJsonValueByKey(*it, "status")); - statuses[i].type = GetJsonValueByKey(*it, "fnname"); - statuses[i].elapsedtime = GetJsonValueByKey(*it, "elapsedtime"); - if( options & 1 ) { - statuses[i].message = GetJsonValueByKey(*it, "status_text"); + remotetimeval = 0; + + // ask for remote file time + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); + + // use if modified since if local file time is provided + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, localtimeval > 0 ? CURL_TIMECOND_IFMODSINCE : CURL_TIMECOND_NONE); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEVALUE, 0L, localtimeval > 0 ? localtimeval : 0L); + + // do the get call + long http_code = _CallGet(desturi, outputdata, 0, timeout); + if ((http_code != 200 && http_code != 304)) { + if (outputdata.size() > 0) { + std::stringstream ss; + ss.write((const char*)&outputdata[0], outputdata.size()); + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%ss.str(), MEC_HTTPServer); } - i++; + throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); } -} -void ControllerClientImpl::GetScenePrimaryKeys(std::vector& scenekeys) -{ - rapidjson::Document pt(rapidjson::kObjectType); - CallGet("scene/?format=json&limit=0&fields=pk", pt); - rapidjson::Value& objects = pt["objects"]; - scenekeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { - scenekeys[i++] = GetJsonValueByKey(*it, "pk"); + // retrieve remote file time + if (http_code != 304) { + // got the entire file so fill in the timestamp of that file + CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &remotetimeval); } } -SceneResourcePtr ControllerClientImpl::RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) +void WebstackClient::ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) { - BOOST_ASSERT(scenetype.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} + rapidjson::Document pt, pt2; + rapidjson::Value value; -SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) -{ - BOOST_ASSERT(scenetype.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype.c_str()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} + pt.SetObject(); -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) -{ - BOOST_ASSERT(importformat.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF8(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} + value.SetString(scenepk.c_str(), pt.GetAllocator()); + pt.AddMember("scenepk", value, pt.GetAllocator()); -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri, bool overwrite) -{ - BOOST_ASSERT(importformat.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF16(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} + value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); + pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); -void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, const std::string& destinationdir, const std::string& scenetype) -{ - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - baseuploaduri += _EncodeWithoutSeparator(destinationdir.substr(7)); - _EnsureWebDAVDirectories(destinationdir.substr(7)); - } - else { - baseuploaduri = destinationdir; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } + _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, 200, timeout); +} - std::string sourcefilename = _sourcefilename; -#if defined(_WIN32) || defined(_WIN64) - // check if / is used anywhere and send a warning if it is - if( sourcefilename.find_first_of('/') != std::string::npos ) { - std::stringstream ss; - ss << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\"; - MUJIN_LOG_INFO(ss.str()); - for(size_t i = 0; i < sourcefilename.size(); ++i) { - if( sourcefilename[i] == '/' ) { - sourcefilename[i] = '\\'; - } - } - } -#endif +void WebstackClient::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) +{ + rapidjson::Document pt, pt2; + rapidjson::Value value; - size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } + pt.SetObject(); - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename, encoding::ConvertUTF8ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNPath; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNPath)); - std::string strWCNURI = strWCNPath; - size_t lastindex = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - strWCNPath[i] = s_filesep; - lastindex = i; - } - } - std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); - _UploadDirectoryToController_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); - } - } - else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - if( nBaseFilenameStartIndex > 0 ) { - // sourcefilename[nBaseFilenameStartIndex] should be == s_filesep - _UploadDirectoryToController_UTF8(sourcefilename.substr(0,nBaseFilenameStartIndex), baseuploaduri); - } - return; - } + value.SetString(scenepk.c_str(), pt.GetAllocator()); + pt.AddMember("scenepk", value, pt.GetAllocator()); - // sourcefilenamebase is utf-8 - std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilename.substr(nBaseFilenameStartIndex)); - _UploadFileToController_UTF8(sourcefilename, uploadfileuri); + value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); + pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); - /* webdav operations - const char *postdata = - "" - "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" - " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " - "WHERE \"DAV:isfolder\" = True\r\n"; - */ + boost::mutex::scoped_lock lock(_mutex); + _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, 200, timeout); } -void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) +const std::string& WebstackClient::GetDefaultTaskType() { - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? - boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - std::string destinationdir_utf8; - utf8::utf16to8(destinationdir_utf16.begin(), destinationdir_utf16.end(), std::back_inserter(destinationdir_utf8)); + return _defaulttasktype; +} - if( destinationdir_utf8.size() >= 7 && destinationdir_utf8.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - std::string s = destinationdir_utf8.substr(7); - baseuploaduri += _EncodeWithoutSeparator(s); - _EnsureWebDAVDirectories(s); - } - else { - baseuploaduri = destinationdir_utf8; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); +std::string WebstackClient::GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) +{ + size_t index = uri.find(":/"); + if (index == std::string::npos) { + throw MUJIN_EXCEPTION_FORMAT("bad URI: %s", uri, MEC_InvalidArguments); } + return EscapeString(uri.substr(index+2)); +} - std::wstring sourcefilename_utf16 = _sourcefilename_utf16; -#if defined(_WIN32) || defined(_WIN64) - // check if / is used anywhere and send a warning if it is - if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { - std::stringstream ss; - ss << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\"; - MUJIN_LOG_INFO(ss.str()); - for(size_t i = 0; i < sourcefilename_utf16.size(); ++i) { - if( sourcefilename_utf16[i] == L'/' ) { - sourcefilename_utf16[i] = L'\\'; - } - } - - boost::replace_all(sourcefilename_utf16, L"/", L"\\"); - } -#endif +std::string WebstackClient::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) +{ + std::string utf8line; + utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); + return GetScenePrimaryKeyFromURI_UTF8(utf8line); +} - size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } +std::string WebstackClient::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout) +{ + rapidjson::Document pt(rapidjson::kObjectType); + const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"" + geomtype + "\"}"); + const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename_utf16, encoding::ConvertUTF16ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNURI; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNURI)); - size_t lastindex_utf8 = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - lastindex_utf8 = i; - } - } - size_t lastindex_utf16 = 0; - for(size_t i = 0; i < strWCNPath_utf16.size(); ++i) { - if( strWCNPath_utf16[i] == '\\' ) { - strWCNPath_utf16[i] = s_wfilesep; - lastindex_utf16 = i; - } - } - std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); - _UploadDirectoryToController_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); - } - } - else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - if( nBaseFilenameStartIndex > 0 ) { - // sourcefilename_utf16[nBaseFilenameStartIndex] should be == s_filesep - _UploadDirectoryToController_UTF16(sourcefilename_utf16.substr(0,nBaseFilenameStartIndex), baseuploaduri); - } - return; - } + CallPost(uri, geometryData, pt, 201, timeout); + return GetJsonValueByKey(pt, "pk"); +} - // sourcefilenamebase is utf-8 - std::string sourcefilenamedir_utf8; - utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); - std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilenamedir_utf8); - _UploadFileToController_UTF16(sourcefilename_utf16, uploadfileuri); +std::string WebstackClient::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) +{ + rapidjson::Document pt(rapidjson::kObjectType); + const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); + CallPutSTL(uri, meshData, pt, 202, timeout); + return GetJsonValueByKey(pt, "pk"); } -/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int WebstackClient::CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -668,7 +537,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Doc return _CallGet(_uri, pt, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int WebstackClient::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) { MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -693,7 +562,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Docume return http_code; } -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode, double timeout) +int WebstackClient::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -701,7 +570,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& o return _CallGet(_uri, outputdata, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) +int WebstackClient::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -729,7 +598,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outp return http_code; } -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode, double timeout) +int WebstackClient::CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -737,7 +606,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::ostream& return _CallGet(_uri, outputStream, expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode, double timeout) +int WebstackClient::_CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -756,7 +625,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::ostream& out return http_code; } -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) +int WebstackClient::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) { boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; @@ -764,7 +633,7 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) +int WebstackClient::_CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -794,8 +663,7 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); +} + +int WebstackClient::CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) +{ + return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, timeout); +} + +int WebstackClient::_CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, rapidjson::Document& pt, curl_slist* headers, int expectedhttpcode, double timeout) { MUJIN_LOG_DEBUG(str(boost::format("PUT %s%s")%_baseapiuri%relativeuri)); boost::mutex::scoped_lock lock(_mutex); @@ -876,17 +754,7 @@ int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* p return http_code; } -int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, timeout); -} - -int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return _CallPut(relativeuri, static_cast(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); -} - -void ControllerClientImpl::CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout) +void WebstackClient::CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout) { MUJIN_LOG_DEBUG(str(boost::format("DELETE %s%s")%_baseapiuri%relativeuri)); boost::mutex::scoped_lock lock(_mutex); @@ -912,124 +780,21 @@ void ControllerClientImpl::CallDelete(const std::string& relativeuri, int expect } } -std::stringstream& ControllerClientImpl::GetBuffer() +std::stringstream& WebstackClient::GetBuffer() { return _buffer; } -void ControllerClientImpl::SetDefaultSceneType(const std::string& scenetype) +int WebstackClient::_WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData) { - _defaultscenetype = scenetype; -} - -const std::string& ControllerClientImpl::GetDefaultSceneType() -{ - return _defaultscenetype; + if (writerData == NULL) { + return 0; + } + writerData->write(data, size*nmemb); + return size * nmemb; } -void ControllerClientImpl::SetDefaultTaskType(const std::string& tasktype) -{ - _defaulttasktype = tasktype; -} - -const std::string& ControllerClientImpl::GetDefaultTaskType() -{ - return _defaulttasktype; -} - -std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) -{ - size_t index = uri.find(":/"); - if (index == std::string::npos) { - throw MUJIN_EXCEPTION_FORMAT("bad URI: %s", uri, MEC_InvalidArguments); - } - return EscapeString(uri.substr(index+2)); -} - -std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) -{ - std::string utf8line; - utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); - return GetScenePrimaryKeyFromURI_UTF8(utf8line); -} - -std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF8(const std::string& name) -{ - return EscapeString(name); -} - -std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring& name) -{ - std::string name_utf8; - utf8::utf16to8(name.begin(), name.end(), std::back_inserter(name_utf8)); - return GetPrimaryKeyFromName_UTF8(name_utf8); -} - -std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) -{ - return UnescapeString(pk); -} - -std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) -{ - std::string utf8 = GetNameFromPrimaryKey_UTF8(pk); - std::wstring utf16; - utf8::utf8to16(utf8.begin(), utf8.end(), std::back_inserter(utf16)); - return utf16; -} - -std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"" + geomtype + "\"}"); - const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); - - CallPost(uri, geometryData, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, const std::string& name, const std::string& iktype, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string ikparamData("{\"name\":\"" + name + "\", \"iktype\":\"" + iktype + "\"}"); - const std::string uri(str(boost::format("object/%s/ikparam/") % objectPk)); - - CallPost(uri, ikparamData, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const std::string& parentlinkPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); - if (!parentlinkPk.empty()) { - data += ", \"parentlinkpk\": \"" + parentlinkPk + "\""; - } - data += "}"; - const std::string uri(str(boost::format("object/%s/link/") % objectPk)); - - CallPost(uri, data, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); - CallPutSTL(uri, meshData, pt, 202, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -int ControllerClientImpl::_WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData) -{ - if (writerData == NULL) { - return 0; - } - writerData->write(data, size*nmemb); - return size * nmemb; -} - -int ControllerClientImpl::_WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData) +int WebstackClient::_WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData) { if (writerData == NULL) { return 0; @@ -1038,7 +803,7 @@ int ControllerClientImpl::_WriteOStreamCallback(char *data, size_t size, size_t return size * nmemb; } -int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData) +int WebstackClient::_WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData) { if (writerData == NULL) { return 0; @@ -1047,7 +812,7 @@ int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t n return size * nmemb; } -int ControllerClientImpl::_ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *readerData) +int WebstackClient::_ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *readerData) { if (readerData == NULL) { return 0; @@ -1055,7 +820,7 @@ int ControllerClientImpl::_ReadIStreamCallback(char *data, size_t size, size_t n return readerData->read(data, size*nmemb).gcount(); } -void ControllerClientImpl::_SetupHTTPHeadersJSON() +void WebstackClient::_SetupHTTPHeadersJSON() { // set the header to only send json std::string s = std::string("Content-Type: application/json; charset=") + _charset; @@ -1079,7 +844,7 @@ void ControllerClientImpl::_SetupHTTPHeadersJSON() } } -void ControllerClientImpl::_SetupHTTPHeadersSTL() +void WebstackClient::_SetupHTTPHeadersSTL() { // set the header to only send stl std::string s = std::string("Content-Type: application/sla"); @@ -1099,7 +864,7 @@ void ControllerClientImpl::_SetupHTTPHeadersSTL() } } -void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() +void WebstackClient::_SetupHTTPHeadersMultipartFormData() { // set the header to only send stl std::string s = std::string("Content-Type: multipart/form-data"); @@ -1119,90 +884,7 @@ void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() } } -std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw) -{ - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < raw.size(); ++i) { - if( raw[i] == '/' ) { - if( startindex != i ) { - output += EscapeString(raw.substr(startindex, i-startindex)); - startindex = i+1; - } - output += '/'; - } - } - if( startindex != raw.size() ) { - output += EscapeString(raw.substr(startindex)); - } - return output; -} - -void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeuri, double timeout) -{ - if (relativeuri.empty()) { - return; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - std::list listCreateDirs; - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < relativeuri.size(); ++i) { - if( relativeuri[i] == '/' ) { - if( startindex != i ) { - listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex, i-startindex))); - startindex = i+1; - } - } - } - if( startindex != relativeuri.size() ) { - listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex))); - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - - std::string totaluri = ""; - for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { - // first have to create the directory structure up to destinationdir - if( totaluri.size() > 0 ) { - totaluri += '/'; - } - totaluri += *itdir; - _uri = _basewebdavuri + totaluri; - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - /* creating directories - - Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. - - 201 (Created) - The collection or structured resource was created in its entirety. - - 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. - - 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. - - 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. - - 415 (Unsupported Media Type)- The server does not support the request type of the body. - - 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. - - */ - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); - } - } -} - -std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) +std::string WebstackClient::_PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) { std::string baseuploaduri; if( rawuri.size() >= 7 && rawuri.substr(0,7) == "mujin:/" ) { @@ -1236,7 +918,7 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& return baseuploaduri; } -std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstring& rawuri_utf16, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) +std::string WebstackClient::_PrepareDestinationURI_UTF16(const std::wstring& rawuri_utf16, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) { std::string baseuploaduri; std::string desturi_utf8; @@ -1273,723 +955,87 @@ std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstrin return baseuploaduri; } -void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF8(filename, _PrepareDestinationURI_UTF8(desturi, false)); -} - -void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& filename_utf16, const std::wstring& desturi_utf16) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16, false)); -} - -void ControllerClientImpl::UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - const std::string filename = _PrepareDestinationURI_UTF8(desturi, false).substr(_basewebdavuri.size()); - _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); -} - -void ControllerClientImpl::UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - const std::string filename = _PrepareDestinationURI_UTF16(desturi, false).substr(_basewebdavuri.size()); - _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); -} - -void ControllerClientImpl::UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) +std::string WebstackClient::_EncodeWithoutSeparator(const std::string& raw) { - boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF8(copydir, _PrepareDestinationURI_UTF8(desturi, false, false, true)); + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < raw.size(); ++i) { + if( raw[i] == '/' ) { + if( startindex != i ) { + output += EscapeString(raw.substr(startindex, i-startindex)); + startindex = i+1; + } + output += '/'; + } + } + if( startindex != raw.size() ) { + output += EscapeString(raw.substr(startindex)); + } + return output; } -void ControllerClientImpl::UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) +void WebstackClient::_EnsureWebDAVDirectories(const std::string& relativeuri, double timeout) { - boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF16(copydir, _PrepareDestinationURI_UTF16(desturi, false, false, true)); -} + if (relativeuri.empty()) { + return; + } -void ControllerClientImpl::DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) -{ - boost::mutex::scoped_lock lock(_mutex); - _CallGet(_PrepareDestinationURI_UTF8(desturi, false), vdata); -} + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); + std::list listCreateDirs; + std::string output; + size_t startindex = 0; + for(size_t i = 0; i < relativeuri.size(); ++i) { + if( relativeuri[i] == '/' ) { + if( startindex != i ) { + listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex, i-startindex))); + startindex = i+1; + } + } + } + if( startindex != relativeuri.size() ) { + listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex))); + } -void ControllerClientImpl::DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) -{ - boost::mutex::scoped_lock lock(_mutex); - _CallGet(_PrepareDestinationURI_UTF16(desturi, false), vdata); -} + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata, timeout); -} + std::string totaluri = ""; + for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { + // first have to create the directory structure up to destinationdir + if( totaluri.size() > 0 ) { + totaluri += '/'; + } + totaluri += *itdir; + _uri = _basewebdavuri + totaluri; + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); + _buffer.clear(); + _buffer.str(""); + CURL_PERFORM(_curl); + long http_code = 0; + CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + /* creating directories -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata, timeout); -} + Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. -long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); + 201 (Created) - The collection or structured resource was created in its entirety. - // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); + 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. - // in order to resolve cache correctly, need to go thorugh file/download endpoint - std::string apiendpoint = _baseuri + "file/download/?filename="; - if( uri.size() >= 7 && uri.substr(0,7) == "mujin:/" ) { - apiendpoint += _EncodeWithoutSeparator(uri.substr(7)); - } + 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, apiendpoint.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_NOBODY, 0L, 1L); - CURL_PERFORM(_curl); + 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("Cannot get modified date of %s for HTTP HEAD call: return is %s", uri%http_code, MEC_HTTPServer); - } + 415 (Unsupported Media Type)- The server does not support the request type of the body. - long filetime=-1; - CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &filetime); - return filetime; -} + 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. -void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) -{ - remotetimeval = 0; - - // ask for remote file time - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); - - // use if modified since if local file time is provided - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, localtimeval > 0 ? CURL_TIMECOND_IFMODSINCE : CURL_TIMECOND_NONE); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEVALUE, 0L, localtimeval > 0 ? localtimeval : 0L); - - // do the get call - long http_code = _CallGet(desturi, outputdata, 0, timeout); - if ((http_code != 200 && http_code != 304)) { - if (outputdata.size() > 0) { - std::stringstream ss; - ss.write((const char*)&outputdata[0], outputdata.size()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%ss.str(), MEC_HTTPServer); - } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); - } - - // retrieve remote file time - if (http_code != 304) { - // got the entire file so fill in the timestamp of that file - CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &remotetimeval); - } -} - -void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, bool media, const std::string& backupscenepks, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false")+"&backupscenepks="+backupscenepks; - _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); -} - -void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm(inputStream, "", _baseuri+"backup/"+query, timeout); -} - -void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?autorestart=")+(autorestart ? "1" : "0")+("&uploadonly=")+(uploadonly ? "1" : "0"); - - std::streampos originalPos = inputStream.tellg(); - inputStream.seekg(0, std::ios::end); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); - } - std::streampos contentLength = inputStream.tellg() - originalPos; - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); - } - inputStream.seekg(originalPos, std::ios::beg); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); - } - - if(contentLength) { - _UploadFileToControllerViaForm(inputStream, "", _baseuri+"upgrade/"+query, timeout); - } else { - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"upgrade/"+query, "", pt, 200, timeout); - } -} - -bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progress, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"upgrade/", pt, 200, timeout); - if(pt.IsNull()) { - return false; - } - status = GetJsonValueByKey(pt, "status"); - progress = GetJsonValueByKey(pt, "progress"); - return true; -} - -void ControllerClientImpl::CancelUpgrade(double timeout) -{ - CallDelete(_baseuri+"upgrade/", 200, timeout); -} - -void ControllerClientImpl::Reboot(double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"reboot/", "", pt, 200, timeout); -} - -void ControllerClientImpl::DeleteAllScenes(double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - CallDelete("scene/", 204, timeout); -} - -void ControllerClientImpl::DeleteAllITLPrograms(double timeout) -{ - CallDelete("itl/", 204, timeout); -} - -void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteFileOnController(_PrepareDestinationURI_UTF8(desturi, false)); -} - -void ControllerClientImpl::DeleteFileOnController_UTF16(const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteFileOnController(_PrepareDestinationURI_UTF16(desturi, false)); -} - -void ControllerClientImpl::DeleteDirectoryOnController_UTF8(const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteDirectoryOnController(_PrepareDestinationURI_UTF8(desturi, false, false, true)); -} - -void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); -} - -void ControllerClientImpl::ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) -{ - rapidjson::Document pt, pt2; - rapidjson::Value value; - - pt.SetObject(); - - value.SetString(scenepk.c_str(), pt.GetAllocator()); - pt.AddMember("scenepk", value, pt.GetAllocator()); - - value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); - pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); - - boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, 200, timeout); -} - -void ControllerClientImpl::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) -{ - rapidjson::Document pt, pt2; - rapidjson::Value value; - - pt.SetObject(); - - value.SetString(scenepk.c_str(), pt.GetAllocator()); - pt.AddMember("scenepk", value, pt.GetAllocator()); - - value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); - pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); - - boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, 200, timeout); -} - -void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) -{ - BOOST_ASSERT(rawuri.size()>0 && copydir_utf8.size()>0); - - // if there's a trailing slash, have to get rid of it - std::string uri; - if( rawuri.at(rawuri.size()-1) == '/' ) { - if( copydir_utf8.at(copydir_utf8.size()-1) != s_filesep ) { - // append the copydir_utf8 name to rawuri - size_t nBaseFilenameStartIndex = copydir_utf8.find_last_of(s_filesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - uri = rawuri + EscapeString(copydir_utf8.substr(nBaseFilenameStartIndex)); - } - else { - // copydir also ends in a fileseparator, so remove the file separator from rawuri - uri = rawuri.substr(0, rawuri.size()-1); - } - } - else { - if (copydir_utf8.at(copydir_utf8.size()-1) == s_filesep) { - throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", copydir_utf8%s_filesep, MEC_InvalidArguments); - } - uri = rawuri; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - - { - // make sure the directory is created - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir_utf8); - // remove the fileseparator if it exists - std::stringstream ss; - ss << "uploading " << sCopyDir_FS << " -> " << uri; - MUJIN_LOG_INFO(ss.str()); - -#if defined(_WIN32) || defined(_WIN64) - bool bhasseparator = false; - if( sCopyDir_FS.size() > 0 && sCopyDir_FS.at(sCopyDir_FS.size()-1) == s_filesep ) { - sCopyDir_FS.resize(sCopyDir_FS.size()-1); - bhasseparator = true; - } - - WIN32_FIND_DATAA ffd; - std::string searchstr = sCopyDir_FS + std::string("\\*"); - HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); - } - - do { - std::string filename = std::string(ffd.cFileName); - if( filename != "." && filename != ".." ) { - std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir_utf8; - if( bhasseparator ) { - newcopydir_utf8 = copydir_utf8 + filename_utf8; - } - else { - newcopydir_utf8 = str(boost::format("%s%c%s")%copydir_utf8%s_filesep%filename_utf8); - } - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToController_UTF8(newcopydir_utf8, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToController_UTF8(newcopydir_utf8, newuri); - } - } - } while(FindNextFileA(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); - } - -#else - boost::filesystem::path bfpcopydir(copydir_utf8); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); -#else - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); -#endif - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF8(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF8(itdir->path().string(), newuri); - } - } -#endif // defined(_WIN32) || defined(_WIN64) -} - -void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring& copydir_utf16, const std::string& rawuri) -{ - BOOST_ASSERT(rawuri.size()>0 && copydir_utf16.size()>0); - - // if there's a trailing slash, have to get rid of it - std::string uri; - if( rawuri.at(rawuri.size()-1) == '/' ) { - if( copydir_utf16.at(copydir_utf16.size()-1) != s_wfilesep ) { - // append the copydir_utf16 name to rawuri - size_t nBaseFilenameStartIndex = copydir_utf16.find_last_of(s_wfilesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - std::string name_utf8; - utf8::utf16to8(copydir_utf16.begin()+nBaseFilenameStartIndex, copydir_utf16.end(), std::back_inserter(name_utf8)); - uri = rawuri + EscapeString(name_utf8); - } - else { - // copydir also ends in a fileseparator, so remove the file separator from rawuri - uri = rawuri.substr(0, rawuri.size()-1); - } - } - else { - if (copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep) { - throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); - } - uri = rawuri; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - - { - // make sure the directory is created - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); + */ if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::wstring sCopyDir_FS; - // remove the fileseparator if it exists - if( copydir_utf16.size() > 0 && copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep ) { - sCopyDir_FS = copydir_utf16.substr(0,copydir_utf16.size()-1); - } - else { - sCopyDir_FS = copydir_utf16; - } - std::stringstream ss; - ss << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri; - MUJIN_LOG_INFO(ss.str()); - -#if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATAW ffd; - std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); - HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_Assert); - } - - do { - std::wstring filename = std::wstring(ffd.cFileName); - if( filename != L"." && filename != L".." ) { - std::string filename_utf8; - utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); - std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir_utf16%filename); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToController_UTF16(newcopydir, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToController_UTF16(newcopydir, newuri); - } - } - } while(FindNextFileW(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_HTTPServer); - } - -#elif defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - boost::filesystem::path bfpcopydir(copydir_utf16); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { - std::wstring dirfilename_utf16 = itdir->path().filename().wstring(); - std::string dirfilename; - utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF16(itdir->path().wstring(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF16(itdir->path().wstring(), newuri); - } - } -#else - // boost filesystem v2 - boost::filesystem::wpath bfpcopydir(copydir_utf16); - for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { - std::wstring dirfilename_utf16 = itdir->path().filename(); - std::string dirfilename; - utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF16(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF16(itdir->path().string(), newuri); + throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); } } -#endif // defined(_WIN32) || defined(_WIN64) -} - -void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filename, const std::string& uri) -{ - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); - } - std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); - - std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); - if(!fin.good()) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); - } - - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); -} - -void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) -{ - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); - } - std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); - - std::string sFilename_FS = encoding::ConvertUTF16ToFileSystemEncoding(filename); - std::vectorcontent; - std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); - if(!fin.good()) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); - } - - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); -} - -void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - //timeout is default to 0 (never) - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - - std::streampos originalPos = inputStream.tellg(); - inputStream.seekg(0, std::ios::end); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); - } - std::streampos contentLength = inputStream.tellg() - originalPos; - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); - } - inputStream.seekg(originalPos, std::ios::beg); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadIStreamCallback); - // prepare form - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - CURL_FORM_RELEASER(formpost); - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "files[]", - CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), - CURLFORM_STREAM, &inputStream, -#if !CURL_AT_LEAST_VERSION(7,46,0) - // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. - // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. - // streampos can be directly converted to streamoff, but it does not correspond on 32bit machines. - CURLFORM_CONTENTSLENGTH, (long)contentLength, -#else - // Actually we should use CURLFORM_CONTENTLEN, whose argument type is curl_off_t, which is 64bit. - // However, it was added in curl 7.46 and cannot be used in official Windows build. - CURLFORM_CONTENTLEN, (curl_off_t)contentLength, -#endif - CURLFORM_END); - if(!filename.empty()) { - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "filename", - CURLFORM_COPYCONTENTS, filename.c_str(), - CURLFORM_END); - } - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); - CURL_PERFORM(_curl); - // get http status - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // 204 is when it overwrites the file? - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); - } -} - -void ControllerClientImpl::_UploadDataToControllerViaForm(const void* data, size_t size, const std::string& filename, const std::string& endpoint, double timeout) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - //timeout is default to 0 (never) - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - - // prepare form - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - CURL_FORM_RELEASER(formpost); - curl_formadd(&formpost, &lastptr, - CURLFORM_PTRNAME, "files[]", - CURLFORM_BUFFER, filename.empty() ? "unused" : filename.c_str(), - CURLFORM_BUFFERPTR, data, - CURLFORM_END); - if(!filename.empty()) { - curl_formadd(&formpost, &lastptr, - CURLFORM_PTRNAME, "filename", - CURLFORM_PTRCONTENTS, filename.c_str(), - CURLFORM_END); - } - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); - CURL_PERFORM(_curl); - // get http status - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // 204 is when it overwrites the file? - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); - } -} - -void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) -{ - MUJIN_LOG_DEBUG(str(boost::format("delete %s")%desturi)) - - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( desturi.size() < _basewebdavuri.size() || desturi.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", desturi, MEC_HTTPServer); - } - std::string filename = desturi.substr(_basewebdavuri.size()); - - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"file/delete/?filename="+filename, "", pt, 200, 5.0); -} - -void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "DELETE"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - MUJIN_LOG_INFO("response code: " << http_code); -} - -size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) -{ - // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally - size_t nread = fread(ptr, size, nmemb, (FILE*)stream); - //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); - return nread; -} - -size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) -{ - std::pair::const_iterator, size_t>* pstreamdata = static_cast::const_iterator, size_t>*>(stream); - size_t nBytesToRead = size*nmemb; - if( nBytesToRead > pstreamdata->second ) { - nBytesToRead = pstreamdata->second; - } - if( nBytesToRead > 0 ) { - std::copy(pstreamdata->first, pstreamdata->first+nBytesToRead, static_cast(ptr)); - pstreamdata->first += nBytesToRead; - pstreamdata->second -= nBytesToRead; - } - return nBytesToRead; -} - -void ControllerClientImpl::GetDebugInfos(std::vector& debuginfos, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - CallGet(str(boost::format("debug/?format=json&limit=0")), pt, 200, timeout); - rapidjson::Value& objects = pt["objects"]; - - debuginfos.resize(objects.Size()); - size_t iobj = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - DebugResourcePtr debuginfo(new DebugResource(shared_from_this(), GetJsonValueByKey(*it, "pk"))); - - //LoadJsonValueByKey(*it, "datemodified", debuginfo->datemodified); - LoadJsonValueByKey(*it, "description", debuginfo->description); - //LoadJsonValueByKey(*it, "downloadUri", debuginfo->downloadUri); - LoadJsonValueByKey(*it, "name", debuginfo->name); - //LoadJsonValueByKey(*it, "resource_uri", debuginfo->resource_uri); - LoadJsonValueByKey(*it, "size", debuginfo->size); - - debuginfos.at(iobj++) = debuginfo; - } -} - -void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, 200, timeout); - fileentries.resize(pt.MemberCount()); - size_t iobj = 0; - for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { - FileEntry &fileentry = fileentries.at(iobj); - - fileentry.filename = it->name.GetString(); - LoadJsonValueByKey(it->value, "modified", fileentry.modified); - LoadJsonValueByKey(it->value, "size", fileentry.size); - - iobj++; - } } } // end namespace mujinclient From 22b84b0e698a68ca23044588188b7500b6896c9e Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 20 Jul 2023 16:55:58 +0900 Subject: [PATCH 451/477] Implement CreateWebStackClientPtr --- src/webstackclient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index b345ce2b..b0c05578 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "common.h" @@ -38,6 +39,8 @@ namespace mujinclient { using namespace mujinjson; +namespace { + template std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) { @@ -92,6 +95,8 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } +} // end namespace + WebstackClient::WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); @@ -1038,4 +1043,8 @@ void WebstackClient::_EnsureWebDAVDirectories(const std::string& relativeuri, do } } +MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0) { + return boost::make_shared(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); +} + } // end namespace mujinclient From 5b5aa5dadaf64d944d37dad81025ac29b2d2240d Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 20 Jul 2023 17:08:40 +0900 Subject: [PATCH 452/477] Fix build issue --- README.md | 11 +++++++++++ src/webstackclient.cpp | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..c9e8d774 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Mujin Webstack Client Cpp + +This is the client for webstack, in C++. + +We also have a [python version](https://github.com/mujin/mujinwebstackclientpy). + +## Building? + +You can try to `cmake`, but as of this commit, it's probably difficult since there's some dependencies that aren't on github. + +We'll get there. \ No newline at end of file diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index b0c05578..7cde3be0 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -1043,7 +1043,8 @@ void WebstackClient::_EnsureWebDAVDirectories(const std::string& relativeuri, do } } -MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0) { +MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +{ return boost::make_shared(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); } From 389b56a0bdb318eb4bbf3f5e93915f10b00033e9 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Fri, 21 Jul 2023 10:05:01 +0900 Subject: [PATCH 453/477] Reorganize tree to resemble webstack client's tree --- .../include/mujinwebstackclientcpp}/mujindefinitions.h | 0 .../include/mujinwebstackclientcpp}/mujinexceptions.h | 0 .../include/mujinwebstackclientcpp}/mujinjson.h | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {include/mujincontrollerclient => src/include/mujinwebstackclientcpp}/mujindefinitions.h (100%) rename {include/mujincontrollerclient => src/include/mujinwebstackclientcpp}/mujinexceptions.h (100%) rename {include/mujincontrollerclient => src/include/mujinwebstackclientcpp}/mujinjson.h (100%) diff --git a/include/mujincontrollerclient/mujindefinitions.h b/src/include/mujinwebstackclientcpp/mujindefinitions.h similarity index 100% rename from include/mujincontrollerclient/mujindefinitions.h rename to src/include/mujinwebstackclientcpp/mujindefinitions.h diff --git a/include/mujincontrollerclient/mujinexceptions.h b/src/include/mujinwebstackclientcpp/mujinexceptions.h similarity index 100% rename from include/mujincontrollerclient/mujinexceptions.h rename to src/include/mujinwebstackclientcpp/mujinexceptions.h diff --git a/include/mujincontrollerclient/mujinjson.h b/src/include/mujinwebstackclientcpp/mujinjson.h similarity index 100% rename from include/mujincontrollerclient/mujinjson.h rename to src/include/mujinwebstackclientcpp/mujinjson.h From a6259b862d3fedbc0f5288333cc23be2cc8534ef Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Fri, 21 Jul 2023 10:24:38 +0900 Subject: [PATCH 454/477] Build webstack client independently of Mujin. --- CMakeLists.txt | 6 +- README.md | 4 +- cmake_uninstall.cmake.in | 31 -------- config.h.in | 74 +++++++++---------- include/mujinwebstackclientcpp/config.h | 56 ++++++++++++++ mujinwebstackclient-config-version.cmake.in | 6 +- mujinwebstackclient-config.cmake.in | 2 +- src/CMakeLists.txt | 4 +- src/boost_assertion_failed.cpp | 6 +- src/common.cpp | 39 +--------- src/common.h | 22 ++---- .../mujinwebstackclientcpp/mujindefinitions.h | 8 +- .../mujinwebstackclientcpp/mujinexceptions.h | 12 +-- .../mujinwebstackclientcpp/mujinjson.h | 4 +- .../mujinwebstackclientcpp/webstackclient.h | 37 ++++------ src/logging.h | 2 +- src/mujindefinitions.cpp | 2 +- src/mujinjson.cpp | 2 +- src/webstackclient.cpp | 10 +-- 19 files changed, 154 insertions(+), 173 deletions(-) delete mode 100644 cmake_uninstall.cmake.in create mode 100644 include/mujinwebstackclientcpp/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b05050bd..e5d8fd8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ cmake_policy(SET CMP0002 NEW) # http://www.cmake.org/cmake/help/cmake-2.6.html#policy:CMP0003 cmake_policy(SET CMP0003 NEW) -option(OPT_SAMPLES "Build the samples" ON) +option(OPT_SAMPLES "Build the samples" OFF) option(OPT_BUILD_TESTS "Build the tests" OFF) option(OPT_BUILD_STATIC "Build static libraries for the client" ON) option(OPT_LOG4CXX "Use log4cxx for logging" ON) @@ -102,7 +102,7 @@ if( MSVC ) check_include_file(stdint.h HAVE_STDINT_H) if( NOT HAVE_STDINT_H ) - #install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/msvc_include/stdint.h DESTINATION include/mujinclient-${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR} COMPONENT ${COMPONENT_PREFIX}dev) + #install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/msvc_include/stdint.h DESTINATION include/mujinwebstackclient-${MUJINWEBSTACKCLIENT_VERSION_MAJOR}.${MUJINWEBSTACKCLIENT_VERSION_MINOR} COMPONENT ${COMPONENT_PREFIX}dev) #include_directories(${CMAKE_CURRENT_SOURCE_DIR}/msvc_include) endif() @@ -137,8 +137,6 @@ endif() set(MUJINWEBSTACKCLIENT_LINK_DIRS) find_package(PkgConfig) -# TODO(document/team#86): Remove this when (if?) client utilities are moved to controller common. -find_package(MujinControllerClient 0.64.0 REQUIRED) set(MUJINWEBSTACKCLIENT_LOG4CXX 0) if (OPT_LOG4CXX) pkg_check_modules(LOG4CXX liblog4cxx) diff --git a/README.md b/README.md index c9e8d774..749cb93c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,4 @@ We also have a [python version](https://github.com/mujin/mujinwebstackclientpy). ## Building? -You can try to `cmake`, but as of this commit, it's probably difficult since there's some dependencies that aren't on github. - -We'll get there. \ No newline at end of file +Assuming you have rapid json and curl, you can simply `cmake . && make` in this directory. \ No newline at end of file diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in deleted file mode 100644 index 29409d12..00000000 --- a/cmake_uninstall.cmake.in +++ /dev/null @@ -1,31 +0,0 @@ -IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -ENDIF() - -FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -STRING(REGEX REPLACE "\n" ";" files "${files}") - -FOREACH(file ${files}) - MESSAGE(STATUS "Uninstalling \"${file}\"") - IF(EXISTS "${file}") - EXECUTE_PROCESS( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - IF(NOT "${rm_retval}" STREQUAL 0) - MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") - ENDIF() - ELSEIF(IS_SYMLINK "${file}") - EXEC_PROGRAM( - "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" - OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval - ) - IF(NOT "${rm_retval}" STREQUAL 0) - MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") - ENDIF() - ELSE() - MESSAGE(STATUS "File \"${file}\" does not exist.") - ENDIF() -ENDFOREACH() diff --git a/config.h.in b/config.h.in index d6da334a..c2504f2b 100644 --- a/config.h.in +++ b/config.h.in @@ -1,56 +1,56 @@ /** \file config.h \brief Defines MUJIN Controller Client installation-specific information. */ -#ifndef MUJINCLIENT_DEFINITIONS_H -#define MUJINCLIENT_DEFINITIONS_H +#ifndef MUJINWEBSTACKCLIENT_DEFINITIONS_H +#define MUJINWEBSTACKCLIENT_DEFINITIONS_H #if defined(_WIN32) || defined(__CYGWIN__) || defined(_MSC_VER) - #define MUJINCLIENT_HELPER_DLL_IMPORT __declspec(dllimport) - #define MUJINCLIENT_HELPER_DLL_EXPORT __declspec(dllexport) - #define MUJINCLIENT_HELPER_DLL_LOCAL + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __declspec(dllimport) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __declspec(dllexport) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL #else #if __GNUC__ >= 4 - #define MUJINCLIENT_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) - #define MUJINCLIENT_HELPER_DLL_EXPORT __attribute__ ((visibility("default"))) - #define MUJINCLIENT_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden"))) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __attribute__ ((visibility("default"))) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden"))) #else - #define MUJINCLIENT_HELPER_DLL_IMPORT - #define MUJINCLIENT_HELPER_DLL_EXPORT - #define MUJINCLIENT_HELPER_DLL_LOCAL + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL #endif #endif -// Now we use the generic helper definitions above to define MUJINCLIENT_API and MUJINCLIENT_LOCAL. -// MUJINCLIENT_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) -// MUJINCLIENT_LOCAL is used for non-api symbols. -#if defined(MUJINCLIENT_DLL) || defined(MUJINCLIENT_CORE_DLL) // defined if OpenRAVE is compiled as a DLL - #ifdef MUJINCLIENT_DLL_EXPORTS // defined if we are building the OpenRAVE DLL (instead of using it) - #define MUJINCLIENT_API MUJINCLIENT_HELPER_DLL_EXPORT +// Now we use the generic helper definitions above to define MUJINWEBSTACKCLIENT_API and MUJINWEBSTACKCLIENT_LOCAL. +// MUJINWEBSTACKCLIENT_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) +// MUJINWEBSTACKCLIENT_LOCAL is used for non-api symbols. +#if defined(MUJINWEBSTACKCLIENT_DLL) || defined(MUJINWEBSTACKCLIENT_CORE_DLL) // defined if OpenRAVE is compiled as a DLL + #ifdef MUJINWEBSTACKCLIENT_DLL_EXPORTS // defined if we are building the OpenRAVE DLL (instead of using it) + #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT #else - #define MUJINCLIENT_API MUJINCLIENT_HELPER_DLL_IMPORT - #endif // MUJINCLIENT_DLL_EXPORTS - #define MUJINCLIENT_LOCAL MUJINCLIENT_HELPER_DLL_LOCAL -#else // MUJINCLIENT_DLL is not defined: this means OpenRAVE is a static lib. - #define MUJINCLIENT_API - #define MUJINCLIENT_LOCAL -#endif // MUJINCLIENT_DLL + #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT + #endif // MUJINWEBSTACKCLIENT_DLL_EXPORTS + #define MUJINWEBSTACKCLIENT_LOCAL MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL +#else // MUJINWEBSTACKCLIENT_DLL is not defined: this means OpenRAVE is a static lib. + #define MUJINWEBSTACKCLIENT_API + #define MUJINWEBSTACKCLIENT_LOCAL +#endif // MUJINWEBSTACKCLIENT_DLL -#define MUJINCLIENT_VERSION_MAJOR @MUJINCLIENT_VERSION_MAJOR@ -#define MUJINCLIENT_VERSION_MINOR @MUJINCLIENT_VERSION_MINOR@ -#define MUJINCLIENT_VERSION_PATCH @MUJINCLIENT_VERSION_PATCH@ -#define MUJINCLIENT_VERSION_COMBINED(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) -#define MUJINCLIENT_VERSION MUJINCLIENT_VERSION_COMBINED(MUJINCLIENT_VERSION_MAJOR, MUJINCLIENT_VERSION_MINOR, MUJINCLIENT_VERSION_PATCH) -#define MUJINCLIENT_VERSION_EXTRACT_MAJOR(version) (((version)>>16)&0xff) -#define MUJINCLIENT_VERSION_EXTRACT_MINOR(version) (((version)>>8)&0xff) -#define MUJINCLIENT_VERSION_EXTRACT_PATCH(version) (((version))&0xff) -#define MUJINCLIENT_VERSION_STRING "@MUJINCLIENT_VERSION_MAJOR@.@MUJINCLIENT_VERSION_MINOR@.@MUJINCLIENT_VERSION_PATCH@" -#define MUJINCLIENT_VERSION_STRING_FORMAT(version) boost::str(boost::format("%s.%s.%s")%(MUJINCLIENT_VERSION_EXTRACT_MAJOR(version))%(MUJINCLIENT_VERSION_EXTRACT_MINOR(version))%(MUJINCLIENT_VERSION_EXTRACT_PATCH(version))) +#define MUJINWEBSTACKCLIENT_VERSION_MAJOR @MUJINWEBSTACKCLIENT_VERSION_MAJOR@ +#define MUJINWEBSTACKCLIENT_VERSION_MINOR @MUJINWEBSTACKCLIENT_VERSION_MINOR@ +#define MUJINWEBSTACKCLIENT_VERSION_PATCH @MUJINWEBSTACKCLIENT_VERSION_PATCH@ +#define MUJINWEBSTACKCLIENT_VERSION_COMBINED(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) +#define MUJINWEBSTACKCLIENT_VERSION MUJINWEBSTACKCLIENT_VERSION_COMBINED(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version) (((version)>>16)&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version) (((version)>>8)&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version) (((version))&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_STRING "@MUJINWEBSTACKCLIENT_VERSION_MAJOR@.@MUJINWEBSTACKCLIENT_VERSION_MINOR@.@MUJINWEBSTACKCLIENT_VERSION_PATCH@" +#define MUJINWEBSTACKCLIENT_VERSION_STRING_FORMAT(version) boost::str(boost::format("%s.%s.%s")%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version))) -#define MUJINCLIENT_VERSION_GE(major1, minor1, patch1, major2, minor2, patch2) (MUJINCLIENT_VERSION_COMBINED(major1, minor1, patch1) >= MUJINCLIENT_VERSION_COMBINED(major2, minor2, patch2)) -#define MUJINCLIENT_VERSION_MINIMUM(major, minor, patch) MUJINCLIENT_VERSION_GE(MUJINCLIENT_VERSION_MAJOR, MUJINCLIENT_VERSION_MINOR, MUJINCLIENT_VERSION_PATCH, major, minor, patch) +#define MUJINWEBSTACKCLIENT_VERSION_GE(major1, minor1, patch1, major2, minor2, patch2) (MUJINWEBSTACKCLIENT_VERSION_COMBINED(major1, minor1, patch1) >= MUJINWEBSTACKCLIENT_VERSION_COMBINED(major2, minor2, patch2)) +#define MUJINWEBSTACKCLIENT_VERSION_MINIMUM(major, minor, patch) MUJINWEBSTACKCLIENT_VERSION_GE(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH, major, minor, patch) // whether log4cxx is to be used -#define MUJINCLIENT_LOG4CXX @MUJINCLIENT_LOG4CXX@ +#define MUJINWEBSTACKCLIENT_LOG4CXX @MUJINWEBSTACKCLIENT_LOG4CXX@ #define MUJIN_USEZMQ @MUJIN_USEZMQ@ #endif diff --git a/include/mujinwebstackclientcpp/config.h b/include/mujinwebstackclientcpp/config.h new file mode 100644 index 00000000..5cd29b8f --- /dev/null +++ b/include/mujinwebstackclientcpp/config.h @@ -0,0 +1,56 @@ +/** \file config.h + \brief Defines MUJIN Controller Client installation-specific information. +*/ +#ifndef MUJINWEBSTACKCLIENT_DEFINITIONS_H +#define MUJINWEBSTACKCLIENT_DEFINITIONS_H + +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_MSC_VER) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __declspec(dllimport) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __declspec(dllexport) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL +#else + #if __GNUC__ >= 4 + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __attribute__ ((visibility("default"))) + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden"))) + #else + #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT + #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT + #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL + #endif +#endif + +// Now we use the generic helper definitions above to define MUJINWEBSTACKCLIENT_API and MUJINWEBSTACKCLIENT_LOCAL. +// MUJINWEBSTACKCLIENT_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) +// MUJINWEBSTACKCLIENT_LOCAL is used for non-api symbols. +#if defined(MUJINWEBSTACKCLIENT_DLL) || defined(MUJINWEBSTACKCLIENT_CORE_DLL) // defined if OpenRAVE is compiled as a DLL + #ifdef MUJINWEBSTACKCLIENT_DLL_EXPORTS // defined if we are building the OpenRAVE DLL (instead of using it) + #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT + #else + #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT + #endif // MUJINWEBSTACKCLIENT_DLL_EXPORTS + #define MUJINWEBSTACKCLIENT_LOCAL MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL +#else // MUJINWEBSTACKCLIENT_DLL is not defined: this means OpenRAVE is a static lib. + #define MUJINWEBSTACKCLIENT_API + #define MUJINWEBSTACKCLIENT_LOCAL +#endif // MUJINWEBSTACKCLIENT_DLL + +#define MUJINWEBSTACKCLIENT_VERSION_MAJOR 0 +#define MUJINWEBSTACKCLIENT_VERSION_MINOR 65 +#define MUJINWEBSTACKCLIENT_VERSION_PATCH 0 +#define MUJINWEBSTACKCLIENT_VERSION_COMBINED(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) +#define MUJINWEBSTACKCLIENT_VERSION MUJINWEBSTACKCLIENT_VERSION_COMBINED(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version) (((version)>>16)&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version) (((version)>>8)&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version) (((version))&0xff) +#define MUJINWEBSTACKCLIENT_VERSION_STRING "0.65.0" +#define MUJINWEBSTACKCLIENT_VERSION_STRING_FORMAT(version) boost::str(boost::format("%s.%s.%s")%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version))) + +#define MUJINWEBSTACKCLIENT_VERSION_GE(major1, minor1, patch1, major2, minor2, patch2) (MUJINWEBSTACKCLIENT_VERSION_COMBINED(major1, minor1, patch1) >= MUJINWEBSTACKCLIENT_VERSION_COMBINED(major2, minor2, patch2)) +#define MUJINWEBSTACKCLIENT_VERSION_MINIMUM(major, minor, patch) MUJINWEBSTACKCLIENT_VERSION_GE(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH, major, minor, patch) + +// whether log4cxx is to be used +#define MUJINWEBSTACKCLIENT_LOG4CXX 1 +#define MUJIN_USEZMQ + +#endif diff --git a/mujinwebstackclient-config-version.cmake.in b/mujinwebstackclient-config-version.cmake.in index cfd29d6a..d47b1791 100644 --- a/mujinwebstackclient-config-version.cmake.in +++ b/mujinwebstackclient-config-version.cmake.in @@ -1,9 +1,9 @@ -set( PACKAGE_VERSION "@MUJINCLIENT_VERSION@" ) -if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@MUJINCLIENT_VERSION@") +set( PACKAGE_VERSION "@MUJINWEBSTACKCLIENT_VERSION@" ) +if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@MUJINWEBSTACKCLIENT_VERSION@") set(PACKAGE_VERSION_EXACT 1) set(PACKAGE_VERSION_COMPATIBLE 1) endif() -if( "${PACKAGE_FIND_VERSION}" VERSION_LESS "@MUJINCLIENT_VERSION@") +if( "${PACKAGE_FIND_VERSION}" VERSION_LESS "@MUJINWEBSTACKCLIENT_VERSION@") set(PACKAGE_VERSION_COMPATIBLE 1) endif() diff --git a/mujinwebstackclient-config.cmake.in b/mujinwebstackclient-config.cmake.in index b0318ec8..01e4a352 100644 --- a/mujinwebstackclient-config.cmake.in +++ b/mujinwebstackclient-config.cmake.in @@ -60,7 +60,7 @@ if( MSVC ) endif() set( MujinWebstackClient_LINK_FLAGS "@MUJINWEBSTACKCLIENT_LOG4CXX_LIB_DIRS@" ) set( MujinWebstackClient_LIBRARY_DIRS "${MujinWebstackClient_ROOT_DIR}/lib@LIB_SUFFIX@") -set( MujinWebstackClient_LIBRARIES mujincontrollerclient${MujinWebstackClient_LIBRARY_SUFFIX} @LOG4CXX_LIBRARIES@) +set( MujinWebstackClient_LIBRARIES mujinwebstackclient${MujinWebstackClient_LIBRARY_SUFFIX} @LOG4CXX_LIBRARIES@) set( MujinWebstackClient_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3738fc90..aeb598ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -include_directories(${CURL_INCLUDE_DIRS} ${LOG4CXX_INCLUDEDIR} ${MujinControllerClient_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS} ${LOG4CXX_INCLUDEDIR}) link_directories(${MUJINWEBSTACKCLIENT_LINK_DIRS}) set(SOURCE_FILES boost_assertion_failed.cpp + mujinjson.cpp + mujindefinitions.cpp utf8.h common.h common.cpp diff --git a/src/boost_assertion_failed.cpp b/src/boost_assertion_failed.cpp index 573e77cb..ea93d857 100644 --- a/src/boost_assertion_failed.cpp +++ b/src/boost_assertion_failed.cpp @@ -1,7 +1,7 @@ #ifdef BOOST_ENABLE_ASSERT_HANDLER #include -#include +#include // Derived from https://gcc.gnu.org/wiki/Visibility #if !(defined _WIN32 || defined __CYGWIN__) && __GNUC__ >= 4 @@ -15,13 +15,13 @@ namespace boost { HIDDEN void assertion_failed(char const * expr, char const * function, char const * file, long line) { - throw mujinclient::MujinException((boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr).str(),mujinclient::MEC_Assert); + throw mujinwebstackclient::MujinException((boost::format("[%s:%d] -> %s, expr: %s")%file%line%function%expr).str(),mujinwebstackclient::MEC_Assert); } #if BOOST_VERSION>104600 HIDDEN void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) { - throw mujinclient::MujinException((boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg).str(),mujinclient::MEC_Assert); + throw mujinwebstackclient::MujinException((boost::format("[%s:%d] -> %s, expr: %s, msg: %s")%file%line%function%expr%msg).str(),mujinwebstackclient::MEC_Assert); } #endif } // namespace boost diff --git a/src/common.cpp b/src/common.cpp index 8e8daef7..113d9510 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -13,44 +13,13 @@ // limitations under the License. #include "common.h" -namespace mujinclient { +namespace mujinwebstackclient { bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1) { return p0.first.size() > p1.first.size(); } -std::string& SearchAndReplace(std::string& out, const std::string& in, const std::vector< std::pair >&_pairs) -{ - BOOST_ASSERT(&out != &in); - std::vector< std::pair >::const_iterator itp, itbestp; - for(itp = _pairs.begin(); itp != _pairs.end(); ++itp) { - BOOST_ASSERT(itp->first.size()>0); - } - std::vector< std::pair > pairs = _pairs; - stable_sort(pairs.begin(),pairs.end(),PairStringLengthCompare); - out.resize(0); - size_t startindex = 0; - while(startindex < in.size()) { - size_t nextindex=std::string::npos; - for(itp = pairs.begin(); itp != pairs.end(); ++itp) { - size_t index = in.find(itp->first,startindex); - if((nextindex == std::string::npos)|| ((index != std::string::npos)&&(index < nextindex)) ) { - nextindex = index; - itbestp = itp; - } - } - if( nextindex == std::string::npos ) { - out += in.substr(startindex); - break; - } - out += in.substr(startindex,nextindex-startindex); - out += itbestp->second; - startindex = nextindex+itbestp->first.size(); - } - return out; -} - namespace encoding { #if defined(_WIN32) || defined(_WIN64) @@ -113,11 +82,11 @@ void ConvertTimestampToFloat(const std::string& in, const std::size_t closingCurly = in.substr(timestampbegin, len).find("}"); if (comma == std::string::npos && closingCurly == std::string::npos) { - throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed); + throw mujinwebstackclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinwebstackclient::MEC_Failed); } const std::size_t timestampend = timestampbegin + (comma < closingCurly ? comma : closingCurly); if (timestampend == std::string::npos) { - throw mujinclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinclient::MEC_Failed); + throw mujinwebstackclient::MujinException(boost::str(boost::format("error while converting timestamp value format for %s")%in), mujinwebstackclient::MEC_Failed); } const std::size_t period = in.substr(timestampbegin, len).find("."); @@ -133,4 +102,4 @@ void ConvertTimestampToFloat(const std::string& in, } } -} // namespace mujinclient +} // namespace mujinwebstackclient diff --git a/src/common.h b/src/common.h index b6235f9f..59467ba6 100644 --- a/src/common.h +++ b/src/common.h @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. /** \file common.h - \brief Private common definitions for mujin controller client. + \brief Private common definitions for mujin webstack client. */ -#ifndef MUJIN_CONTROLLERCLIENT_COMMON_H -#define MUJIN_CONTROLLERCLIENT_COMMON_H +#ifndef MUJIN_WEBSTACKCLIENT_COMMON_H +#define MUJIN_WEBSTACKCLIENT_COMMON_H #define WIN32_LEAN_AND_MEAN @@ -33,7 +33,7 @@ #include #include -#include +#include #if defined(_WIN32) || defined(_WIN64) #include @@ -187,7 +187,6 @@ inline static unsigned long long GetNanoPerformanceTime() #endif #endif -#define GETCONTROLLERIMPL() ControllerClientImplPtr controller = boost::dynamic_pointer_cast(GetController()); #define CHECKCURLCODE(code, msg) if (code != CURLE_OK) { \ throw MujinException(boost::str(boost::format("[%s:%d] curl function %s with error '%s': %s")%(__PRETTY_FUNCTION__)%(__LINE__)%(msg)%curl_easy_strerror(code)%_errormessage), MEC_HTTPClient); \ } @@ -201,18 +200,14 @@ inline static unsigned long long GetNanoPerformanceTime() } #endif -#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) +#define MUJIN_EXCEPTION_FORMAT0(s, errorcode) mujinwebstackclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)),errorcode) /// adds the function name and line number to an exception -#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) +#define MUJIN_EXCEPTION_FORMAT(s, args,errorcode) mujinwebstackclient::MujinException(boost::str(boost::format("[%s:%d] " s)%(__PRETTY_FUNCTION__)%(__LINE__)%args),errorcode) BOOST_STATIC_ASSERT(sizeof(unsigned short) == 2); // need this for utf-16 reading -namespace mujinclient { - -class BinPickingTaskZmqResource; -typedef boost::shared_ptr BinPickingTaskZmqResourcePtr; -typedef boost::weak_ptr BinPickingTaskZmqResourceWeakPtr; +namespace mujinwebstackclient { class FileHandler { @@ -234,7 +229,6 @@ class FileHandler }; bool PairStringLengthCompare(const std::pair&p0, const std::pair&p1); -std::string& SearchAndReplace(std::string& out, const std::string& in, const std::vector< std::pair >&_pairs); namespace encoding { @@ -362,6 +356,6 @@ const char s_filesep = '/'; const wchar_t s_wfilesep = L'/'; #endif -} // end namespace mujinclient +} // end namespace mujinwebstackclient #endif diff --git a/src/include/mujinwebstackclientcpp/mujindefinitions.h b/src/include/mujinwebstackclientcpp/mujindefinitions.h index 0dafedfd..c585d9fb 100644 --- a/src/include/mujinwebstackclientcpp/mujindefinitions.h +++ b/src/include/mujinwebstackclientcpp/mujindefinitions.h @@ -18,8 +18,8 @@ #ifndef MUJIN_CONTROLLERCLIENT_DEFINITIONS_H #define MUJIN_CONTROLLERCLIENT_DEFINITIONS_H -#include -#include +#include +#include #include @@ -85,7 +85,7 @@ struct AABB Real extents[3]; ///< half extents of AABB }; -struct MUJINCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable +struct MUJINWEBSTACKCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable { SensorSelectionInfo() = default; SensorSelectionInfo(const std::string& sensorNameIn, const std::string& sensorLinkNameIn) : sensorName(sensorNameIn), sensorLinkName(sensorLinkNameIn) { @@ -112,7 +112,7 @@ struct MUJINCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable /// \brief the picking history being published from the slave. Anytime the robot goes inside of the source container, its pick history will be udpated. -struct MUJINCLIENT_API PickPlaceHistoryItem +struct MUJINWEBSTACKCLIENT_API PickPlaceHistoryItem { std::string pickPlaceType; ///< the type of action that ocurred can be: "picked", "placed", "touched" std::string locationName; ///< the name of the region where picking occurred for "picked", where placing occurred when "placed", and where touching occurred for "touched" diff --git a/src/include/mujinwebstackclientcpp/mujinexceptions.h b/src/include/mujinwebstackclientcpp/mujinexceptions.h index d38e52da..e45c48a2 100644 --- a/src/include/mujinwebstackclientcpp/mujinexceptions.h +++ b/src/include/mujinwebstackclientcpp/mujinexceptions.h @@ -17,12 +17,12 @@ #ifndef MUJIN_EXCEPTIONS_H #define MUJIN_EXCEPTIONS_H -namespace mujinclient { +namespace mujinwebstackclient { -#include +#include /// \brief exception throw when user interrupts the function -class MUJINCLIENT_API UserInterruptException : public std::exception +class MUJINWEBSTACKCLIENT_API UserInterruptException : public std::exception { public: UserInterruptException() : std::exception() { @@ -83,7 +83,7 @@ inline const char* GetErrorCodeString(MujinErrorCode error) } /// \brief Exception that all Mujin internal methods throw; the error codes are held in \ref MujinErrorCode. -class MUJINCLIENT_API MujinException : public std::exception +class MUJINWEBSTACKCLIENT_API MujinException : public std::exception { public: MujinException() : std::exception(), _s("unknown exception"), _error(MEC_Failed) { @@ -112,7 +112,7 @@ class MUJINCLIENT_API MujinException : public std::exception }; /// \brief Error that can be thrown by ExecuteGraphQuery API, use GetGraphQueryErrorCode to get detailed error code -class MUJINCLIENT_API MujinGraphQueryError : public MujinException +class MUJINWEBSTACKCLIENT_API MujinGraphQueryError : public MujinException { public: MujinGraphQueryError(const std::string& s, const std::string& graphQueryErrorCode) : MujinGraphQueryError(s, graphQueryErrorCode.c_str()) {} @@ -129,5 +129,5 @@ class MUJINCLIENT_API MujinGraphQueryError : public MujinException std::string _graphQueryErrorCode; }; -} // namespace mujinclient +} // namespace mujinwebstackclient #endif diff --git a/src/include/mujinwebstackclientcpp/mujinjson.h b/src/include/mujinwebstackclientcpp/mujinjson.h index 85bed06f..a5a40cc7 100644 --- a/src/include/mujinwebstackclientcpp/mujinjson.h +++ b/src/include/mujinwebstackclientcpp/mujinjson.h @@ -37,7 +37,7 @@ #include #include -#include +#include #ifndef MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY #define MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY(rValue, key, param) \ @@ -193,7 +193,7 @@ inline void ParseJson(rapidjson::Document& d, std::istream& is) { } template -MUJINCLIENT_API void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer); +MUJINWEBSTACKCLIENT_API void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer); inline void ParseJsonFile(rapidjson::Document& d, const char* filename) { diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 1994d5ba..71a0f859 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -12,11 +12,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -/** \file mujincontrollerclient.h +/** \file mujinwebstackclient.h \brief Defines the public headers of the MUJIN Controller Client */ -#ifndef MUJIN_CONTROLLERCLIENT_H -#define MUJIN_CONTROLLERCLIENT_H +#ifndef MUJIN_WEBSTACKCLIENT_H +#define MUJIN_WEBSTACKCLIENT_H #ifdef _MSC_VER @@ -32,9 +32,9 @@ #endif #if defined(__GNUC__) -#define MUJINCLIENT_DEPRECATED __attribute__((deprecated)) +#define MUJINWEBSTACKCLIENT_DEPRECATED __attribute__((deprecated)) #else -#define MUJINCLIENT_DEPRECATED +#define MUJINWEBSTACKCLIENT_DEPRECATED #endif #include @@ -58,21 +58,16 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace mujinclient { +namespace mujinwebstackclient { typedef mujin::Transform Transform; -enum TaskResourceOptions -{ - TRO_EnableZMQ=1, ///< create a task resource with zeromq client -}; - /// \brief (scene) file entry in mujin controller struct FileEntry { @@ -86,7 +81,7 @@ typedef double Real; /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. -class MUJINCLIENT_API WebstackClient +class MUJINWEBSTACKCLIENT_API WebstackClient { public: WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout); @@ -367,12 +362,12 @@ typedef boost::weak_ptr WebstackClientWeakPtr; \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests */ -MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); +MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); -} // namespace mujinclient +} // namespace mujinwebstackclient -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MAJOR>=0&&MUJINCLIENT_VERSION_MAJOR<=255); -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MINOR>=0&&MUJINCLIENT_VERSION_MINOR<=255); -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_PATCH>=0&&MUJINCLIENT_VERSION_PATCH<=255); +BOOST_STATIC_ASSERT(MUJINWEBSTACKCLIENT_VERSION_MAJOR>=0&&MUJINWEBSTACKCLIENT_VERSION_MAJOR<=255); +BOOST_STATIC_ASSERT(MUJINWEBSTACKCLIENT_VERSION_MINOR>=0&&MUJINWEBSTACKCLIENT_VERSION_MINOR<=255); +BOOST_STATIC_ASSERT(MUJINWEBSTACKCLIENT_VERSION_PATCH>=0&&MUJINWEBSTACKCLIENT_VERSION_PATCH<=255); #endif diff --git a/src/logging.h b/src/logging.h index 662d8c6d..b30a1818 100644 --- a/src/logging.h +++ b/src/logging.h @@ -1,6 +1,6 @@ #pragma once -#if MUJINCLIENT_LOG4CXX +#if MUJINWEBSTACKCLIENT_LOG4CXX #include diff --git a/src/mujindefinitions.cpp b/src/mujindefinitions.cpp index 27256694..6089538f 100644 --- a/src/mujindefinitions.cpp +++ b/src/mujindefinitions.cpp @@ -1,6 +1,6 @@ // -*- coding: utf-8 -*- // Copyright (C) 2012-2023 MUJIN Inc. -#include +#include namespace mujin { diff --git a/src/mujinjson.cpp b/src/mujinjson.cpp index 2654a946..6f3f1a32 100644 --- a/src/mujinjson.cpp +++ b/src/mujinjson.cpp @@ -1,6 +1,6 @@ // -*- coding: utf-8 -*- // Copyright (C) 2012-2022 MUJIN Inc. -#include +#include #include #include diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 7cde3be0..49235791 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -35,7 +35,7 @@ MUJIN_LOGGER("mujin.webstackcpp"); #define CURL_PERFORM(curl) CHECKCURLCODE(curl_easy_perform(curl), "curl_easy_perform") #define CURL_FORM_RELEASER(form) boost::shared_ptr __curlformreleaser ## form((void*)0, boost::bind(boost::function(curl_formfree), form)) -namespace mujinclient { +namespace mujinwebstackclient { using namespace mujinjson; @@ -178,7 +178,7 @@ WebstackClient::WebstackClient(const std::string& usernamepassword, const std::s // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); // just to start the cookie engine // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEDATA, &_buffer); - std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; + std::string useragent = std::string("controllerclientcpp/")+MUJINWEBSTACKCLIENT_VERSION_STRING; CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, useragent.c_str()); CURL_OPTION_SETTER(_curl, CURLOPT_FOLLOWLOCATION, 1L); // we can always follow redirect now, we don't need to detect login page @@ -386,7 +386,7 @@ void WebstackClient::_ExecuteGraphQuery(const char* operationName, const char* q if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { errorCode = itExtensions->value["errorCode"].GetString(); } - throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); + throw mujinwebstackclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } } throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); @@ -1043,9 +1043,9 @@ void WebstackClient::_EnsureWebDAVDirectories(const std::string& relativeuri, do } } -MUJINCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { return boost::make_shared(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); } -} // end namespace mujinclient +} // end namespace mujinwebstackclient From 9981d19569710b8b00a25ee055a13796882896ca Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Fri, 21 Jul 2023 10:33:19 +0900 Subject: [PATCH 455/477] Remove cmake's outputted `include` dir --- include/mujinwebstackclientcpp/config.h | 56 ------------------------- 1 file changed, 56 deletions(-) delete mode 100644 include/mujinwebstackclientcpp/config.h diff --git a/include/mujinwebstackclientcpp/config.h b/include/mujinwebstackclientcpp/config.h deleted file mode 100644 index 5cd29b8f..00000000 --- a/include/mujinwebstackclientcpp/config.h +++ /dev/null @@ -1,56 +0,0 @@ -/** \file config.h - \brief Defines MUJIN Controller Client installation-specific information. -*/ -#ifndef MUJINWEBSTACKCLIENT_DEFINITIONS_H -#define MUJINWEBSTACKCLIENT_DEFINITIONS_H - -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_MSC_VER) - #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __declspec(dllimport) - #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __declspec(dllexport) - #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL -#else - #if __GNUC__ >= 4 - #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT __attribute__ ((visibility("default"))) - #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT __attribute__ ((visibility("default"))) - #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL __attribute__ ((visibility("hidden"))) - #else - #define MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT - #define MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT - #define MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL - #endif -#endif - -// Now we use the generic helper definitions above to define MUJINWEBSTACKCLIENT_API and MUJINWEBSTACKCLIENT_LOCAL. -// MUJINWEBSTACKCLIENT_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) -// MUJINWEBSTACKCLIENT_LOCAL is used for non-api symbols. -#if defined(MUJINWEBSTACKCLIENT_DLL) || defined(MUJINWEBSTACKCLIENT_CORE_DLL) // defined if OpenRAVE is compiled as a DLL - #ifdef MUJINWEBSTACKCLIENT_DLL_EXPORTS // defined if we are building the OpenRAVE DLL (instead of using it) - #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_EXPORT - #else - #define MUJINWEBSTACKCLIENT_API MUJINWEBSTACKCLIENT_HELPER_DLL_IMPORT - #endif // MUJINWEBSTACKCLIENT_DLL_EXPORTS - #define MUJINWEBSTACKCLIENT_LOCAL MUJINWEBSTACKCLIENT_HELPER_DLL_LOCAL -#else // MUJINWEBSTACKCLIENT_DLL is not defined: this means OpenRAVE is a static lib. - #define MUJINWEBSTACKCLIENT_API - #define MUJINWEBSTACKCLIENT_LOCAL -#endif // MUJINWEBSTACKCLIENT_DLL - -#define MUJINWEBSTACKCLIENT_VERSION_MAJOR 0 -#define MUJINWEBSTACKCLIENT_VERSION_MINOR 65 -#define MUJINWEBSTACKCLIENT_VERSION_PATCH 0 -#define MUJINWEBSTACKCLIENT_VERSION_COMBINED(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch)) -#define MUJINWEBSTACKCLIENT_VERSION MUJINWEBSTACKCLIENT_VERSION_COMBINED(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH) -#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version) (((version)>>16)&0xff) -#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version) (((version)>>8)&0xff) -#define MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version) (((version))&0xff) -#define MUJINWEBSTACKCLIENT_VERSION_STRING "0.65.0" -#define MUJINWEBSTACKCLIENT_VERSION_STRING_FORMAT(version) boost::str(boost::format("%s.%s.%s")%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MAJOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_MINOR(version))%(MUJINWEBSTACKCLIENT_VERSION_EXTRACT_PATCH(version))) - -#define MUJINWEBSTACKCLIENT_VERSION_GE(major1, minor1, patch1, major2, minor2, patch2) (MUJINWEBSTACKCLIENT_VERSION_COMBINED(major1, minor1, patch1) >= MUJINWEBSTACKCLIENT_VERSION_COMBINED(major2, minor2, patch2)) -#define MUJINWEBSTACKCLIENT_VERSION_MINIMUM(major, minor, patch) MUJINWEBSTACKCLIENT_VERSION_GE(MUJINWEBSTACKCLIENT_VERSION_MAJOR, MUJINWEBSTACKCLIENT_VERSION_MINOR, MUJINWEBSTACKCLIENT_VERSION_PATCH, major, minor, patch) - -// whether log4cxx is to be used -#define MUJINWEBSTACKCLIENT_LOG4CXX 1 -#define MUJIN_USEZMQ - -#endif From c145467b6e49bd40c24348c5fc4d3654f2ee3ec8 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 25 Jul 2023 10:54:07 +0900 Subject: [PATCH 456/477] Fix build --- cmake_uninstall.cmake.in | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 cmake_uninstall.cmake.in diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in new file mode 100644 index 00000000..29409d12 --- /dev/null +++ b/cmake_uninstall.cmake.in @@ -0,0 +1,31 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF() + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") + +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"${file}\"") + IF(EXISTS "${file}") + EXECUTE_PROCESS( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") + ENDIF() + ELSEIF(IS_SYMLINK "${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") + ENDIF() + ELSE() + MESSAGE(STATUS "File \"${file}\" does not exist.") + ENDIF() +ENDFOREACH() From 9fc08132d1a303a8e2f0b87dc4ef26bc4ff31592 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 25 Jul 2023 16:39:19 +0900 Subject: [PATCH 457/477] Remove controller common's dependency on the controller client. The controller common utilities only need the webstack client. Note: for now, createwebstackclient.h provides an alias for the controllerclient since call sites expect that. This alias may CAUSE ODR VIOLATIONS. Well... suffer the wrath of multiple repos. This alias will be removed after callers have migrated. Also (side-note, mostly for my own sanity): the mujinzmq exception details have been tweaked so that we don't have to keep an enum consistent between controller common and the planning client. In particular, an instance of MEC_timeout has become MCCE_failed. There's arguments that all the MEC_ errors in mujinzmq should actually be MCCE_ZmqError, but this is hopefully extremely minor. --- src/createwebstackclient.cpp | 4 ++-- src/include/mujincontrollercommon/createwebstackclient.h | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index fa568c40..133fdff4 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -86,7 +86,7 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) } /// \brief Transparently diverge to private webstack if url is localhost -mujinclient::ControllerClientPtr CreateWebstackClient( +mujinwebstackclient::WebstackClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, @@ -94,7 +94,7 @@ mujinclient::ControllerClientPtr CreateWebstackClient( int options, double timeout) { - mujinclient::ControllerClientPtr pClient = mujinclient::CreateControllerClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); + mujinwebstackclient::WebstackClientPtr pClient = mujinwebstackclient::CreateWebstackClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); std::string unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); if (!unixendpoint.empty()) { pClient->SetUnixEndpoint(unixendpoint); diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 64aab443..4914af1b 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -6,7 +6,7 @@ #define __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ #include -#include +#include namespace mujincontrollercommon { @@ -20,7 +20,7 @@ MUJINCONTROLLERCOMMON_API bool IsWebstackLocal(const char* url); MUJINCONTROLLERCOMMON_API const char* GetUnixEndpointForLocalWebstack(const char* url); /// \brief Transparently diverge to private webstack if url is localhost -MUJINCONTROLLERCOMMON_API mujinclient::ControllerClientPtr CreateWebstackClient( +MUJINCONTROLLERCOMMON_API mujinwebstackclient::WebstackClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport = std::string(), @@ -30,4 +30,9 @@ MUJINCONTROLLERCOMMON_API mujinclient::ControllerClientPtr CreateWebstackClient( } // namespace mujincontrollercommon +namespace mujinclient { +// TODO(document/team#86): remove this once all call sites are migrated. +typedef mujinwebstackclient::WebstackClientPtr ControllerClientPtr; +} + #endif // __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ From 3245b2b63d92528f37c6579b3577c6fa08d22075 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 25 Jul 2023 16:51:21 +0900 Subject: [PATCH 458/477] Remove the unused UserInterruptException --- .../mujinwebstackclientcpp/mujinexceptions.h | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/include/mujinwebstackclientcpp/mujinexceptions.h b/src/include/mujinwebstackclientcpp/mujinexceptions.h index e45c48a2..90f92675 100644 --- a/src/include/mujinwebstackclientcpp/mujinexceptions.h +++ b/src/include/mujinwebstackclientcpp/mujinexceptions.h @@ -21,26 +21,6 @@ namespace mujinwebstackclient { #include -/// \brief exception throw when user interrupts the function -class MUJINWEBSTACKCLIENT_API UserInterruptException : public std::exception -{ -public: - UserInterruptException() : std::exception() { - } - UserInterruptException(const std::string& s) : std::exception(), _s(s) { - } - virtual ~UserInterruptException() throw() { - } - char const* what() const throw() { - return _s.c_str(); - } - const std::string& message() const { - return _s; - } - -private: - std::string _s; -}; enum MujinErrorCode { MEC_Failed=0, MEC_InvalidArguments=1, ///< passed in input arguments are not valid From dc0df88f098d5caa1c23e98722989a7688dde708 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 25 Jul 2023 17:18:52 +0900 Subject: [PATCH 459/477] Fix includes -- it's mujinwebstackclientcpp not just mujinwebstackclient --- src/include/mujincontrollercommon/createwebstackclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujincontrollercommon/createwebstackclient.h index 4914af1b..10667279 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujincontrollercommon/createwebstackclient.h @@ -6,7 +6,7 @@ #define __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ #include -#include +#include namespace mujincontrollercommon { From a8ab51f874a9732653148457bdcd87458be6901f Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 25 Jul 2023 18:27:33 +0900 Subject: [PATCH 460/477] Fix CMake, make this build --- CMakeLists.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5d8fd8b..26a57ec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,10 @@ add_definitions("-DBOOST_SPIRIT_THREADSAFE") # for json parsing # have to include before boost since the boost headers can be located in a previous installed version of this library set(MUJINWEBSTACKCLIENT_INCLUDE_LOCAL_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/include) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src/include + ${CMAKE_CURRENT_BINARY_DIR}/include +) # have to do this before every other include! include_directories(${MUJINWEBSTACKCLIENT_INCLUDE_LOCAL_DIRS}) if( MSVC ) @@ -316,8 +319,9 @@ else() message(WARNING "compiling without libzmq library") endif() -file(GLOB mujin_header_files ${CMAKE_CURRENT_SOURCE_DIR}/include/mujinwebstackclientcpp/*.h ${CMAKE_CURRENT_SOURCE_DIR}/include/mujinwebstackclientcpp/*.hpp) -install(FILES ${mujin_header_files} ${CMAKE_CURRENT_BINARY_DIR}/include/mujinwebstackclientcpp/config.h DESTINATION include/mujinwebstackclientcpp) +file(GLOB mujin_header_files ${CMAKE_CURRENT_SOURCE_DIR}/src/include/mujinwebstackclientcpp/*.h ${CMAKE_CURRENT_SOURCE_DIR}/src/include/mujinwebstackclientcpp/*.hpp) +install(FILES ${mujin_header_files} DESTINATION include/mujinwebstackclientcpp) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/mujinwebstackclientcpp/config.h DESTINATION include/mujinwebstackclientcpp) macro(build_sample name) include_directories(${LOG4CXX_INCLUDEDIR} ${libzmq_INCLUDE_DIRS}) From f2ebe62c2b5d404d95f28461f006a110359fbcee Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Wed, 26 Jul 2023 11:53:43 +0900 Subject: [PATCH 461/477] Prepare createwebstackclient and webstackclient for its use --- src/createwebstackclient.cpp | 54 ++++++++++++++++--- .../createwebstackclient.h | 6 +-- .../mujinwebstackclientcpp/webstackclient.h | 41 +++++++------- src/webstackclient.cpp | 3 +- 4 files changed, 72 insertions(+), 32 deletions(-) rename src/include/{mujincontrollercommon => mujinwebstackclientcpp}/createwebstackclient.h (88%) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 133fdff4..ae543132 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -1,9 +1,9 @@ -#include -#include +#include +#include -MUJIN_LOGGER("mujin.controllercommon.createwebstackclient"); +MUJIN_LOGGER("mujin.mujinwebstackclientcpp.createwebstackclient"); -namespace mujincontrollercommon { +namespace mujinwebstackclient { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length bool IsHostnameLocal(const char* hostname, ssize_t len) @@ -12,7 +12,26 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) len = std::strlen(hostname); } if (len == sizeof("127.0.0.1") - 1 && strncmp(hostname, "127.0.0.1", len) == 0) { - return true; + return true;/** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests + */ +MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); } if (len == sizeof("localhost") - 1 && strncmp(hostname, "localhost", len) == 0) { return true; @@ -26,7 +45,26 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) localHostname[HOST_NAME_MAX] = '\0'; const size_t localHostnameLen = std::strlen(localHostname); if ((size_t)len == localHostnameLen && strncmp(hostname, localHostname, len) == 0) { - return true; + return true;/** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests + */ +MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); } return false; } @@ -94,7 +132,7 @@ mujinwebstackclient::WebstackClientPtr CreateWebstackClient( int options, double timeout) { - mujinwebstackclient::WebstackClientPtr pClient = mujinwebstackclient::CreateWebstackClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); + WebstackClientPtr pClient = WebstackClient::CreateWebstackClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); std::string unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); if (!unixendpoint.empty()) { pClient->SetUnixEndpoint(unixendpoint); @@ -102,4 +140,4 @@ mujinwebstackclient::WebstackClientPtr CreateWebstackClient( return pClient; } -} +} // namespace mujinwebstackclient diff --git a/src/include/mujincontrollercommon/createwebstackclient.h b/src/include/mujinwebstackclientcpp/createwebstackclient.h similarity index 88% rename from src/include/mujincontrollercommon/createwebstackclient.h rename to src/include/mujinwebstackclientcpp/createwebstackclient.h index 10667279..f3639f69 100644 --- a/src/include/mujincontrollercommon/createwebstackclient.h +++ b/src/include/mujinwebstackclientcpp/createwebstackclient.h @@ -5,10 +5,10 @@ #ifndef __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ #define __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ -#include +#include #include -namespace mujincontrollercommon { +namespace mujinwebstackclient { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length MUJINCONTROLLERCOMMON_API bool IsHostnameLocal(const char* hostname, ssize_t len = -1); @@ -20,7 +20,7 @@ MUJINCONTROLLERCOMMON_API bool IsWebstackLocal(const char* url); MUJINCONTROLLERCOMMON_API const char* GetUnixEndpointForLocalWebstack(const char* url); /// \brief Transparently diverge to private webstack if url is localhost -MUJINCONTROLLERCOMMON_API mujinwebstackclient::WebstackClientPtr CreateWebstackClient( +MUJINCONTROLLERCOMMON_API WebstackClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport = std::string(), diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 71a0f859..bafd99e9 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -87,6 +87,27 @@ class MUJINWEBSTACKCLIENT_API WebstackClient WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout); virtual ~WebstackClient(); + /** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests + */ + MUJINWEBSTACKCLIENT_API static WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); + /// \brief sets the character encoding for all strings that are being input and output from the resources /// /// The default character encoding is \b utf-8, can also set it to \b Shift_JIS for windows japanese unicode, \b iso-2022-jp @@ -343,26 +364,6 @@ class MUJINWEBSTACKCLIENT_API WebstackClient typedef boost::shared_ptr WebstackClientPtr; typedef boost::weak_ptr WebstackClientWeakPtr; -/** \en \brief creates the controller with an account. This function is not thread safe. - - You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. - \param usernamepassword user:password - \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. - - \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 - - この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 - \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 - \param timeout set timeout in seconds for the initial login requests - */ -MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); } // namespace mujinwebstackclient diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 49235791..a5e65b26 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -1043,7 +1043,8 @@ void WebstackClient::_EnsureWebDAVDirectories(const std::string& relativeuri, do } } -MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) +// static +MUJINWEBSTACKCLIENT_API WebstackClientPtr WebstackClient::CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { return boost::make_shared(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); } From 48ec4970e79b260cf5ec4b909838581db7c7fd68 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 27 Jul 2023 10:33:32 +0900 Subject: [PATCH 462/477] Fix build breaks. createwebstackclient needed some care to build in its new home. In particular: its function name was colliding with the basic creator in webstackclient.h, and it needed the MUJINWEBSTACKCLIENT_API attribute. Mujin definitions is removed -- its not needed for webstack and planning client provides it. Mujin JSON too has been superceeded by its planning client counterpart, if both are included (as they are in the vision manager, through a myriad of inclusion paths). Some spooky action at a distance: we inherit from MujinControllerCommonException if there is an inclusion path that includes controller common's mujinjson. TODO(document/team#86): fix this (or document it). It's better to define what class mujinjson::MujinJSONException should inherit from as the macro than just replacing the class. This can also ensure that mujinjsonwebstack::MujinJSONException is always a std::exception (which might be better). --- src/CMakeLists.txt | 2 +- src/createwebstackclient.cpp | 4 +- .../createwebstackclient.h | 15 +- .../mujinwebstackclientcpp/mujindefinitions.h | 153 ------------------ .../mujinwebstackclientcpp/mujinexceptions.h | 4 +- .../mujinwebstackclientcpp/mujinjson.h | 22 +-- .../mujinwebstackclientcpp/webstackclient.h | 6 +- src/mujindefinitions.cpp | 21 --- src/mujinjson.cpp | 4 +- src/webstackclient.cpp | 12 +- 10 files changed, 32 insertions(+), 211 deletions(-) delete mode 100644 src/include/mujinwebstackclientcpp/mujindefinitions.h delete mode 100644 src/mujindefinitions.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aeb598ab..672733ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,8 +17,8 @@ link_directories(${MUJINWEBSTACKCLIENT_LINK_DIRS}) set(SOURCE_FILES boost_assertion_failed.cpp + createwebstackclient.cpp mujinjson.cpp - mujindefinitions.cpp utf8.h common.h common.cpp diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index ae543132..19b21893 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -1,5 +1,5 @@ #include -#include +#include "logging.h" MUJIN_LOGGER("mujin.mujinwebstackclientcpp.createwebstackclient"); @@ -116,7 +116,7 @@ const char* GetUnixEndpointForLocalWebstack(const char* url) if (IsWebstackLocal(url)) { const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); if (unixendpoint != nullptr && unixendpoint[0] != '\0') { - MUJIN_LOG_DEBUG_FORMAT("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"", unixendpoint%url); + MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"")%unixendpoint%url)); return unixendpoint; } } diff --git a/src/include/mujinwebstackclientcpp/createwebstackclient.h b/src/include/mujinwebstackclientcpp/createwebstackclient.h index f3639f69..f73c9111 100644 --- a/src/include/mujinwebstackclientcpp/createwebstackclient.h +++ b/src/include/mujinwebstackclientcpp/createwebstackclient.h @@ -11,16 +11,16 @@ namespace mujinwebstackclient { /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length -MUJINCONTROLLERCOMMON_API bool IsHostnameLocal(const char* hostname, ssize_t len = -1); +MUJINWEBSTACKCLIENT_API bool IsHostnameLocal(const char* hostname, ssize_t len = -1); /// \brief determine if the url is pointing to local webstack -MUJINCONTROLLERCOMMON_API bool IsWebstackLocal(const char* url); +MUJINWEBSTACKCLIENT_API bool IsWebstackLocal(const char* url); /// \brief determine the unix endpoint if webstack is local -MUJINCONTROLLERCOMMON_API const char* GetUnixEndpointForLocalWebstack(const char* url); +MUJINWEBSTACKCLIENT_API const char* GetUnixEndpointForLocalWebstack(const char* url); /// \brief Transparently diverge to private webstack if url is localhost -MUJINCONTROLLERCOMMON_API WebstackClientPtr CreateWebstackClient( +MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport = std::string(), @@ -28,11 +28,6 @@ MUJINCONTROLLERCOMMON_API WebstackClientPtr CreateWebstackClient( int options = 0, double timeout = 3.0); -} // namespace mujincontrollercommon - -namespace mujinclient { -// TODO(document/team#86): remove this once all call sites are migrated. -typedef mujinwebstackclient::WebstackClientPtr ControllerClientPtr; -} +} // namespace mujinwebstackclient #endif // __MUJIN_CONTROLLERCOMMON_CREATEWEBSTACKCLIENT__ diff --git a/src/include/mujinwebstackclientcpp/mujindefinitions.h b/src/include/mujinwebstackclientcpp/mujindefinitions.h deleted file mode 100644 index c585d9fb..00000000 --- a/src/include/mujinwebstackclientcpp/mujindefinitions.h +++ /dev/null @@ -1,153 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2023 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** \file mujindefinitions.h - - Includes basic struct, enum, and other definitions that are used throughout the Mujin Controller system. - */ -#ifndef MUJIN_CONTROLLERCLIENT_DEFINITIONS_H -#define MUJIN_CONTROLLERCLIENT_DEFINITIONS_H - -#include -#include - -#include - -namespace mujin { - -typedef double Real; - -inline bool FuzzyEquals(Real p, Real q, double epsilon=1e-3) { - return fabs(double(p - q)) < epsilon; -} - -template inline bool FuzzyEquals(const std::vector& p, const std::vector& q, double epsilon=1e-3) { - if (p.size() != q.size()) { - return false; - } - for (size_t i = 0; i < p.size(); ++i) { - if (!FuzzyEquals(p[i], q[i], epsilon)) { - return false; - } - } - return true; -} - -template inline bool FuzzyEquals(const T (&p)[N], const T (&q)[N], double epsilon=1e-3) { - for (size_t i = 0; i < N; ++i) { - if (!FuzzyEquals(p[i], q[i], epsilon)) { - return false; - } - } - return true; -} - -/// \brief an affine transform -struct Transform -{ - Transform() { - quaternion[0] = 1; quaternion[1] = 0; quaternion[2] = 0; quaternion[3] = 0; - translate[0] = 0; translate[1] = 0; translate[2] = 0; - } - inline bool operator!=(const Transform& other) const { - return !FuzzyEquals(quaternion, other.quaternion) || !FuzzyEquals(translate, other.translate); - } - inline bool operator==(const Transform& other) const { - return !operator!=(other); - } - Real quaternion[4]; ///< quaternion [cos(ang/2), axis*sin(ang/2)] - Real translate[3]; ///< translation x,y,z -}; - -struct AABB -{ - AABB() { - pos[0] = 0; pos[1] = 0; pos[2] = 0; - extents[0] = 0; extents[1] = 0; extents[2] = 0; - } - inline bool operator!=(const AABB& other) const { - return !FuzzyEquals(pos, other.pos) || !FuzzyEquals(pos, other.pos); - } - inline bool operator==(const AABB& other) const { - return !operator!=(other); - } - Real pos[3]; ///< center of AABB - Real extents[3]; ///< half extents of AABB -}; - -struct MUJINWEBSTACKCLIENT_API SensorSelectionInfo : public mujinjson::JsonSerializable -{ - SensorSelectionInfo() = default; - SensorSelectionInfo(const std::string& sensorNameIn, const std::string& sensorLinkNameIn) : sensorName(sensorNameIn), sensorLinkName(sensorLinkNameIn) { - } - inline bool operator<(const SensorSelectionInfo& rhs) const { - if( sensorName == rhs.sensorName ) { - return sensorLinkName < rhs.sensorLinkName; - } - return sensorName < rhs.sensorName; - } - inline bool operator==(const SensorSelectionInfo& rhs) const { - return sensorName == rhs.sensorName && sensorLinkName == rhs.sensorLinkName; - } - inline bool operator!=(const SensorSelectionInfo& rhs) const { - return sensorName != rhs.sensorName || sensorLinkName != rhs.sensorLinkName; - } - - void LoadFromJson(const rapidjson::Value& rSensorSelectionInfo) override; - void SaveToJson(rapidjson::Value& rSensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) const override; - - std::string sensorName; - std::string sensorLinkName; -}; - - -/// \brief the picking history being published from the slave. Anytime the robot goes inside of the source container, its pick history will be udpated. -struct MUJINWEBSTACKCLIENT_API PickPlaceHistoryItem -{ - std::string pickPlaceType; ///< the type of action that ocurred can be: "picked", "placed", "touched" - std::string locationName; ///< the name of the region where picking occurred for "picked", where placing occurred when "placed", and where touching occurred for "touched" - unsigned long long eventTimeStampUS; ///< time that the event ocurred in us (from Linux epoch). For "picked" this is the chuck time, for "placed this is the unchuck time, for "touched" this is the time when the robot supposedly stopped touching/disturbing the object. - std::string object_uri; ///< the object uri - Transform objectpose; ///< 7-values in world, unit is usually mm - AABB localaabb; ///< AABB of object in object frame. - unsigned long long sensorTimeStampUS; ///< sensor timestamp in us (from Linux epoch) of when the object was detected in the scene -}; - -/// \brief Holds the state of each region coming from the planning side. -struct LocationTrackingInfo -{ - std::string locationName; ///< name of the location tracking - std::string containerId; ///< containerId currently in the location - std::string containerName; ///< name of the container tracking - std::string containerUsage; ///< how the container is used - std::string cycleIndex; ///< unique cycleIndex that is tracking this location -}; - -struct LocationExecutionInfo -{ - std::string locationName; ///< name of the location tracking - std::string containerId; ///< containerId currently in the location - uint64_t forceRequestStampMS=0; ///< ms, (linux epoch) of when the requestion for results (detection or point cloud) came in. If there is no request, then this will be 0 - uint64_t lastInsideContainerStampMS = 0; ///< ms, (linux epoch) of when the robot (or something else) was inside the container and could have potentially disturbed the contents. - std::string needContainerState; ///< one of: Unknown, NewContainerNeeded, ContainerNeeded, ContainerNotNeeded. If empty, then not initialized yet, so can assume Unknown. -}; - -inline std::ostream& operator<<(std::ostream& os, const SensorSelectionInfo& rhs) -{ - os << rhs.sensorName << ":" << rhs.sensorLinkName; - return os; -} - -} // end namespace mujin - -#endif diff --git a/src/include/mujinwebstackclientcpp/mujinexceptions.h b/src/include/mujinwebstackclientcpp/mujinexceptions.h index 90f92675..6052ae34 100644 --- a/src/include/mujinwebstackclientcpp/mujinexceptions.h +++ b/src/include/mujinwebstackclientcpp/mujinexceptions.h @@ -14,8 +14,8 @@ /** \file mujinexceptions.h \brief Exception definitions. */ -#ifndef MUJIN_EXCEPTIONS_H -#define MUJIN_EXCEPTIONS_H +#ifndef MUJIN_WEBSTACK_EXCEPTIONS_H +#define MUJIN_WEBSTACK_EXCEPTIONS_H namespace mujinwebstackclient { diff --git a/src/include/mujinwebstackclientcpp/mujinjson.h b/src/include/mujinwebstackclientcpp/mujinjson.h index a5a40cc7..5ba01a71 100644 --- a/src/include/mujinwebstackclientcpp/mujinjson.h +++ b/src/include/mujinwebstackclientcpp/mujinjson.h @@ -14,8 +14,8 @@ /** \file mujinjson.h \brief Wrapper for rapidjson. */ -#ifndef MUJIN_CONTROLLERCLIENT_JSON_H -#define MUJIN_CONTROLLERCLIENT_JSON_H +#ifndef MUJIN_WEBSTACK_JSON_H +#define MUJIN_WEBSTACK_JSON_H #include #include @@ -39,17 +39,17 @@ #include -#ifndef MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY -#define MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY(rValue, key, param) \ +#ifndef MUJINJSONWEBSTACK_LOAD_REQUIRED_JSON_VALUE_BY_KEY +#define MUJINJSONWEBSTACK_LOAD_REQUIRED_JSON_VALUE_BY_KEY(rValue, key, param) \ { \ - if (!(mujinjson::LoadJsonValueByKey(rValue, key, param))) \ + if (!mujinjsonwebstack::LoadJsonValueByKey(rValue, key, param))) \ { \ - throw mujinjson::MujinJSONException(boost::str(boost::format(("[%s, %u] assert(mujinjson::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ + throw mujinjsonwebstack::MujinJSONException(boost::str(boost::format(("[%s, %u] assertmujinjsonwebstack::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ } \ } -#endif // MUJINJSON_LOAD_REQUIRED_JSON_VALUE_BY_KEY +#endif // MUJINJSONWEBSTACK_LOAD_REQUIRED_JSON_VALUE_BY_KEY -namespace mujinjson { +namespace mujinjsonwebstack { #ifndef MujinJSONException @@ -68,7 +68,7 @@ inline const char* GetErrorCodeString(MujinJSONErrorCode error) return ""; } -/// \brief Exception that MujinJSON internal methods throw; the error codes are held in \ref MujinJSONErrorCode. +/// \brief Exception thatmujinjsonwebstack internal methods throw; the error codes are held in \ref MujinJSONErrorCode. class MujinJSONException : public std::exception { public: @@ -108,6 +108,8 @@ class MujinJSONException : public std::exception MujinJSONErrorCode _error; }; +#else +using namespace mujinjson; #endif template inline std::string GetJsonString(const T& t); @@ -906,6 +908,6 @@ inline bool UpdateJsonRecursively(rapidjson::Value& sourceValue, const rapidjson return hasChanged; } -} // namespace mujinjson +} // namespace mujinjsonwebstack #endif diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index bafd99e9..8fce2d0c 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -61,13 +61,11 @@ #include #include #include -#include +//#include namespace mujinwebstackclient { -typedef mujin::Transform Transform; - /// \brief (scene) file entry in mujin controller struct FileEntry { @@ -106,7 +104,7 @@ class MUJINWEBSTACKCLIENT_API WebstackClient \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 \param timeout set timeout in seconds for the initial login requests */ - MUJINWEBSTACKCLIENT_API static WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); + MUJINWEBSTACKCLIENT_API static boost::shared_ptr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); /// \brief sets the character encoding for all strings that are being input and output from the resources /// diff --git a/src/mujindefinitions.cpp b/src/mujindefinitions.cpp deleted file mode 100644 index 6089538f..00000000 --- a/src/mujindefinitions.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2023 MUJIN Inc. -#include - -namespace mujin { - - -void SensorSelectionInfo::LoadFromJson(const rapidjson::Value& rSensorSelectionInfo) -{ - mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName); - mujinjson::LoadJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName); -} - -void SensorSelectionInfo::SaveToJson(rapidjson::Value& rSensorSelectionInfo, rapidjson::Document::AllocatorType& alloc) const -{ - rSensorSelectionInfo.SetObject(); - mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorName", sensorName, alloc); - mujinjson::SetJsonValueByKey(rSensorSelectionInfo, "sensorLinkName", sensorLinkName, alloc); -} - -} // end namespace mujin diff --git a/src/mujinjson.cpp b/src/mujinjson.cpp index 6f3f1a32..3316e692 100644 --- a/src/mujinjson.cpp +++ b/src/mujinjson.cpp @@ -6,7 +6,7 @@ #include #include -namespace mujinjson { +namespace mujinjsonwebstack { template void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer) @@ -110,4 +110,4 @@ void __InternalParseJsonFile(rapidjson::Document& d, const char* filename) return ParseJsonFile(d, filename, buffer); } -} // end namespace mujinjson +} // end namespace mujinjsonwebstack diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index a5e65b26..49f126e8 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -37,7 +37,7 @@ MUJIN_LOGGER("mujin.webstackcpp"); namespace mujinwebstackclient { -using namespace mujinjson; +using namespace mujinjsonwebstack; namespace { @@ -370,14 +370,14 @@ void WebstackClient::_ExecuteGraphQuery(const char* operationName, const char* q // parse response if (!rResultDoc.IsObject()) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjsonwebstack::DumpJson(rResultDoc), MEC_HTTPServer); } if (checkForErrors) { // look for errors in response const rapidjson::Value::ConstMemberIterator itErrors = rResultDoc.FindMember("errors"); if (itErrors != rResultDoc.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(rResultDoc))); + MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjsonwebstack::DumpJson(rResultDoc))); for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { const rapidjson::Value& rError = *itError; if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { @@ -389,13 +389,13 @@ void WebstackClient::_ExecuteGraphQuery(const char* operationName, const char* q throw mujinwebstackclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); } } - throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjsonwebstack::DumpJson(rResultDoc), MEC_HTTPServer); } } // should have data member if (!rResultDoc.HasMember("data")) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); + throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjsonwebstack::DumpJson(rResultDoc), MEC_HTTPServer); } // set output @@ -557,7 +557,7 @@ int WebstackClient::_CallGet(const std::string& desturi, rapidjson::Document& pt long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { - mujinjson::ParseJson(pt, _buffer.str()); + mujinjsonwebstack::ParseJson(pt, _buffer.str()); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { std::string error_message = GetJsonValueByKey(pt, "error_message"); From f1f3abe57bf3d6e5ece40129d88276b1bd35db30 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 27 Jul 2023 14:29:58 +0900 Subject: [PATCH 463/477] Fix copy-paste issues in createwebstackclient --- src/createwebstackclient.cpp | 42 +------------------ .../createwebstackclient.h | 20 ++++++++- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 19b21893..b1ab85d7 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -12,26 +12,7 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) len = std::strlen(hostname); } if (len == sizeof("127.0.0.1") - 1 && strncmp(hostname, "127.0.0.1", len) == 0) { - return true;/** \en \brief creates the controller with an account. This function is not thread safe. - - You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. - \param usernamepassword user:password - \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. - - \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 - - この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 - \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 - \param timeout set timeout in seconds for the initial login requests - */ -MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); + return true; } if (len == sizeof("localhost") - 1 && strncmp(hostname, "localhost", len) == 0) { return true; @@ -45,26 +26,7 @@ MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string localHostname[HOST_NAME_MAX] = '\0'; const size_t localHostnameLen = std::strlen(localHostname); if ((size_t)len == localHostnameLen && strncmp(hostname, localHostname, len) == 0) { - return true;/** \en \brief creates the controller with an account. This function is not thread safe. - - You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. - \param usernamepassword user:password - \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. - - \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 - - この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 - \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 - \param timeout set timeout in seconds for the initial login requests - */ -MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); + return true; } return false; } diff --git a/src/include/mujinwebstackclientcpp/createwebstackclient.h b/src/include/mujinwebstackclientcpp/createwebstackclient.h index f73c9111..9e23ecf0 100644 --- a/src/include/mujinwebstackclientcpp/createwebstackclient.h +++ b/src/include/mujinwebstackclientcpp/createwebstackclient.h @@ -19,7 +19,25 @@ MUJINWEBSTACKCLIENT_API bool IsWebstackLocal(const char* url); /// \brief determine the unix endpoint if webstack is local MUJINWEBSTACKCLIENT_API const char* GetUnixEndpointForLocalWebstack(const char* url); -/// \brief Transparently diverge to private webstack if url is localhost +/** \en \brief creates the controller with an account. This function is not thread safe. + + You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. + \param usernamepassword user:password + \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. + + \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 + + この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 + \param usernamepassword ユーザ:パスワード + \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 + \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. + \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. + \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 + \param timeout set timeout in seconds for the initial login requests + */ MUJINWEBSTACKCLIENT_API WebstackClientPtr CreateWebstackClient( const std::string& usernamepassword, const std::string& url, From 6e7f23f63ed71849be5ac458ebae80288aa2beab Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 27 Jul 2023 18:43:38 +0900 Subject: [PATCH 464/477] Restore implementation of GetNameFromPrimaryKey --- src/webstackclient.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 49f126e8..e9a0e2c1 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -516,6 +516,19 @@ std::string WebstackClient::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& return GetScenePrimaryKeyFromURI_UTF8(utf8line); } +std::string WebstackClient::GetNameFromPrimaryKey_UTF8(const std::string& pk) +{ + return UnescapeString(pk); +} + +std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) +{ + std::string utf8 = GetNameFromPrimaryKey_UTF8(pk); + std::wstring utf16; + utf8::utf8to16(utf8.begin(), utf8.end(), std::back_inserter(utf16)); + return utf16; +} + std::string WebstackClient::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout) { rapidjson::Document pt(rapidjson::kObjectType); From f5c3feb2aa9c7484279889cbba75a8ad49c35772 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Fri, 28 Jul 2023 08:19:05 +0900 Subject: [PATCH 465/477] Fix typo --- src/webstackclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index e9a0e2c1..757589d3 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -521,7 +521,7 @@ std::string WebstackClient::GetNameFromPrimaryKey_UTF8(const std::string& pk) return UnescapeString(pk); } -std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) +std::wstring WebstackClient::GetNameFromPrimaryKey_UTF16(const std::string& pk) { std::string utf8 = GetNameFromPrimaryKey_UTF8(pk); std::wstring utf16; From b6dfdc1a3011eac7301c4cdc098b2a8b7fe658fe Mon Sep 17 00:00:00 2001 From: rosen Date: Fri, 28 Jul 2023 12:14:14 -0400 Subject: [PATCH 466/477] do not clear allocator when executing graph query --- src/controllerclientimpl.cpp | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp index 9c79f69b..459c6efc 100644 --- a/src/controllerclientimpl.cpp +++ b/src/controllerclientimpl.cpp @@ -392,7 +392,7 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c { rResult.SetNull(); // zero output - rapidjson::Document rResultDoc(&rAlloc); + rapidjson::Value rResultDoc; { boost::mutex::scoped_lock lock(_mutex); @@ -416,7 +416,7 @@ void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const c } _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, rAlloc, 200, timeout); } // parse response @@ -743,10 +743,10 @@ int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Doc boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallGet(_uri, pt, expectedhttpcode, timeout); + return _CallGet(_uri, pt, pt.GetAllocator(), expectedhttpcode, timeout); } -int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Value& rResponse, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) { MUJIN_LOG_DEBUG(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -761,11 +761,11 @@ int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Docume long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { - mujinjson::ParseJson(pt, _buffer.str()); + mujinjson::ParseJson(rResponse, alloc, _buffer); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); + std::string error_message = GetJsonValueByKey(rResponse, "error_message"); + std::string traceback = GetJsonValueByKey(rResponse, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; @@ -879,11 +879,11 @@ int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::st boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallPost(_uri, data, pt, expectedhttpcode, timeout); + return _CallPost(_uri, data, pt, pt.GetAllocator(), expectedhttpcode, timeout); } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int ControllerClientImpl::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("POST %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -900,13 +900,13 @@ int ControllerClientImpl::_CallPost(const std::string& desturi, const std::strin long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(pt, _buffer.str()); + ParseJson(rResult, alloc, _buffer); } else { - pt.SetObject(); + rResult.SetObject(); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); + std::string error_message = GetJsonValueByKey(rResult, "error_message"); + std::string traceback = GetJsonValueByKey(rResult, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; @@ -1508,7 +1508,7 @@ void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, _UploadFileToControllerViaForm(inputStream, "", _baseuri+"upgrade/"+query, timeout); } else { rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"upgrade/"+query, "", pt, 200, timeout); + _CallPost(_baseuri+"upgrade/"+query, "", pt, pt.GetAllocator(), 200, timeout); } } @@ -1516,7 +1516,7 @@ bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progres { boost::mutex::scoped_lock lock(_mutex); rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"upgrade/", pt, 200, timeout); + _CallGet(_baseuri+"upgrade/", pt, pt.GetAllocator(), 200, timeout); if(pt.IsNull()) { return false; } @@ -1534,7 +1534,7 @@ void ControllerClientImpl::Reboot(double timeout) { boost::mutex::scoped_lock lock(_mutex); rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"reboot/", "", pt, 200, timeout); + _CallPost(_baseuri+"reboot/", "", pt, pt.GetAllocator(), 200, timeout); } void ControllerClientImpl::DeleteAllScenes(double timeout) @@ -1587,7 +1587,7 @@ void ControllerClientImpl::ModifySceneAddReferenceObjectPK(const std::string &sc pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, 200, timeout); + _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); } void ControllerClientImpl::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) @@ -1604,7 +1604,7 @@ void ControllerClientImpl::ModifySceneRemoveReferenceObjectPK(const std::string pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, 200, timeout); + _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); } void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) @@ -1994,7 +1994,7 @@ void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) std::string filename = desturi.substr(_basewebdavuri.size()); rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"file/delete/?filename="+filename, "", pt, 200, 5.0); + _CallPost(_baseuri+"file/delete/?filename="+filename, "", pt, pt.GetAllocator(), 200, 5.0); } void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) @@ -2056,7 +2056,7 @@ void ControllerClientImpl::GetDebugInfos(std::vector& debuginf void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) { rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, 200, timeout); + _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, pt.GetAllocator(), 200, timeout); fileentries.resize(pt.MemberCount()); size_t iobj = 0; for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { From ee3588bc3a8db226b99f903d953bba622d7a41c9 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 7 Aug 2023 09:51:10 +0900 Subject: [PATCH 467/477] Filter repo to only keep the ControllerClientInfo --- .../mujincontrollerclient.h | 1287 --------------- .../mujincontrollerclient.h | 27 + src/mujincontrollerclient.cpp | 1390 ----------------- 3 files changed, 27 insertions(+), 2677 deletions(-) delete mode 100644 include/mujincontrollerclient/mujincontrollerclient.h create mode 100644 src/include/mujinwebstackclientcpp/mujincontrollerclient.h diff --git a/include/mujincontrollerclient/mujincontrollerclient.h b/include/mujincontrollerclient/mujincontrollerclient.h deleted file mode 100644 index 711f7e9a..00000000 --- a/include/mujincontrollerclient/mujincontrollerclient.h +++ /dev/null @@ -1,1287 +0,0 @@ -// -*- coding: utf-8 -*- -// -// Copyright (C) 2012-2013 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** \file mujincontrollerclient.h - \brief Defines the public headers of the MUJIN Controller Client - */ -#ifndef MUJIN_CONTROLLERCLIENT_H -#define MUJIN_CONTROLLERCLIENT_H - -#ifdef _MSC_VER - -#pragma warning(disable:4251)// needs to have dll-interface to be used by clients of class -#pragma warning(disable:4190)// C-linkage specified, but returns UDT 'boost::shared_ptr' which is incompatible with C -#pragma warning(disable:4819)//The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss using native typeof - -#ifndef __PRETTY_FUNCTION__ -#define __PRETTY_FUNCTION__ __FUNCDNAME__ -#endif - -#else -#endif - -#if defined(__GNUC__) -#define MUJINCLIENT_DEPRECATED __attribute__((deprecated)) -#else -#define MUJINCLIENT_DEPRECATED -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace mujinclient { - -/// \brief connecting to a controller's webstack -class MUJINCLIENT_API ControllerClientInfo : public mujinjson::JsonSerializable -{ -public: - virtual void Reset(); - - void LoadFromJson(const rapidjson::Value& rClientInfo) override; - void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; - void SaveToJson(rapidjson::Document& rClientInfo) const override; - - bool operator==(const ControllerClientInfo &rhs) const; - bool operator!=(const ControllerClientInfo &rhs) const { - return !operator==(rhs); - } - std::string GetURL(bool bIncludeNamePassword) const; - - inline bool IsEnabled() const { - return !host.empty(); - } - - std::string host; - uint16_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port - std::string username; - std::string password; - std::vector additionalHeaders; ///< expect each value to be in the format of "Header-Name: header-value" - std::string unixEndpoint; ///< unix socket endpoint for communicating with HTTP server over unix socket -}; - -typedef mujin::Transform Transform; - -enum TaskResourceOptions -{ - TRO_EnableZMQ=1, ///< create a task resource with zeromq client -}; - -class ControllerClient; -class ObjectResource; -class RobotResource; -class SceneResource; -class TaskResource; -class BinPickingTaskResource; -class OptimizationResource; -class PlanningResultResource; -class BinPickingResultResource; -class DebugResource; - -/// \brief (scene) file entry in mujin controller -struct FileEntry -{ - std::string filename; - double modified; // in epoch seconds - size_t size; // file size in bytes -}; - -typedef boost::shared_ptr ControllerClientPtr; -typedef boost::weak_ptr ControllerClientWeakPtr; -typedef boost::shared_ptr ObjectResourcePtr; -typedef boost::weak_ptr ObjectResourceWeakPtr; -typedef boost::shared_ptr RobotResourcePtr; -typedef boost::weak_ptr RobotResourceWeakPtr; -typedef boost::shared_ptr SceneResourcePtr; -typedef boost::weak_ptr SceneResourceWeakPtr; -typedef boost::shared_ptr TaskResourcePtr; -typedef boost::weak_ptr TaskResourceWeakPtr; -typedef boost::shared_ptr BinPickingTaskResourcePtr; -typedef boost::weak_ptr BinPickingTaskResourceWeakPtr; -typedef boost::shared_ptr OptimizationResourcePtr; -typedef boost::weak_ptr OptimizationResourceWeakPtr; -typedef boost::shared_ptr PlanningResultResourcePtr; -typedef boost::weak_ptr PlanningResultResourceWeakPtr; -typedef boost::shared_ptr BinPickingResultResourcePtr; -typedef boost::weak_ptr BinPickingResultResourceWeakPtr; -typedef boost::shared_ptr DebugResourcePtr; -typedef boost::weak_ptr DebugResourceWeakPtr; -typedef double Real; - -/// \brief status code for a job -/// -/// Definitions are very similar to http://ros.org/doc/api/actionlib_msgs/html/msg/GoalStatus.html -enum JobStatusCode { - JSC_Pending = 0, ///< The goal has yet to be processed - JSC_Active = 1, ///< The goal is currently being processed - JSC_Preempted = 2, ///< The goal received a cancel request after it started executing and has since completed its execution. - JSC_Succeeded = 3, ///< The goal was achieved successfully. - JSC_Aborted = 4, ///< The goal was aborted during execution due to some failure - JSC_Rejected = 5, ///< The goal was rejected without being processed, because the goal was unattainable or invalid. - JSC_Preempting = 6, ///< The goal received a cancel request after it started executing and has not yet completed execution - JSC_Recalling = 7, ///< The goal received a cancel request before it started executing, but the server has not yet confirmed that the goal is canceled. - JSC_Recalled = 8, ///< The goal received a cancel request before it started executing and was successfully cancelled - JSC_Lost = 9, ///< An error happened and the job stopped being tracked. - JSC_Unknown = 0xffffffff, ///< the job is unknown -}; - - -/// \brief get status code from string representation -/// -/// \param str string representation of status -/// \return JobStatusCode equivalent -JobStatusCode GetStatusCode(const std::string& str); - -struct JobStatus -{ - JobStatus() : code(JSC_Unknown) { - } - JobStatusCode code; ///< status code on whether the job is active - std::string type; ///< the type of job running - std::string message; ///< current message of the job - double elapsedtime; ///< how long the job has been running for in seconds - std::string pk; ///< the primary key to differentiate this job -}; - -struct InstanceObjectState -{ - Transform transform; ///< the transform of this instance object - std::vector dofvalues; ///< the joint values -}; - -typedef std::map EnvironmentState; - -struct SceneInformation -{ - std::string pk; ///< primary key - std::string uri; ///< uri of the file pointed to - std::string datemodified; ///< late date modified - std::string name; -}; - -/// \brief holds information about the itlplanning task parameters -class ITLPlanningTaskParameters -{ -public: - ITLPlanningTaskParameters() { - SetDefaults(); - } - virtual void SetDefaults() { - startfromcurrent = 0; - returnmode = "start"; - vrcruns = 1; - ignorefigure = 1; - unit = "mm"; - optimizationvalue = 1; - program.clear(); - } - - int startfromcurrent; ///< Will start planning from the current robot joint values, otherwise will start at the first waypoint in the program. - - /// specifies the final movement of the robot. There's 3 different modes: - /// - \b "" - (empty string) meaning robot doesn't return to anything - /// - \b "start" - robot returns to wherever it started - /// - \b "final" - robot returns to the final_envstate - std::string returnmode; - - int vrcruns; ///< Use the Robot Virtual Controller for retiming and extra validation. Makes planning slow, but robot timing because very accurate. - int ignorefigure; ///< if 1, ignores the figure/structure flags for every goal parameter. These flags fix the configuration of the robot from the multitute of possibilities. If 0, will attempt to use the flags and error if task is not possible with them. - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - Real optimizationvalue; ///< value in [0,1]. 0 is no optimization (fast), 1 is full optimization (slow) - std::string program; ///< itl program - std::string parameters; ///< parameters (json) - - EnvironmentState initial_envstate; ///< initial environment state to set the ITL task to. - EnvironmentState final_envstate; ///< final environment state that describes where the robot should end at. If returnmode is set to final, then use this state. -}; - -/// program is wincaps rc8 pac script -class DensoWaveWincapsTaskParameters : public ITLPlanningTaskParameters -{ -public: - DensoWaveWincapsTaskParameters() : ITLPlanningTaskParameters() { - SetDefaults(); - } - void SetDefaults() { - ITLPlanningTaskParameters::SetDefaults(); - preservespeedparameters = 0; - } - int preservespeedparameters; ///< if 1, preserves all SPEED/ACCEL commands as best as possible. -}; - -/// \brief placement optimization for a robot or another target. -struct RobotPlacementOptimizationParameters -{ - RobotPlacementOptimizationParameters() { - SetDefaults(); - } - inline void SetDefaults() { - unit = "mm"; - topstorecandidates = 20; - targetname.clear(); - framename.clear(); - minrange[0] = -400; minrange[1] = -400; minrange[2] = 0; minrange[3] = -180; - maxrange[0] = 400; maxrange[1] = 400; maxrange[2] = 400; maxrange[3] = 90; - stepsize[0] = 100; stepsize[1] = 100; stepsize[2] = 100; stepsize[3] = 90; - ignorebasecollision = 0; - } - std::string targetname; ///< the name of the target object to optimize for. Cannot be blank. Has to start with "0 instobject " is targetting an environment instance object. For Example "0 instobject myrobot". - std::string framename; ///< The name of the frame to define the optimization parameters in. If blank, will use the targetname's coordinate system. For environment inst object frames, has to be "0 instobject mytargetname" - Real maxrange[4]; ///< X, Y, Z, Angle (deg) - Real minrange[4]; ///< X, Y, Z, Angle (deg) - Real stepsize[4]; ///< X, Y, Z, Angle (deg) - int ignorebasecollision; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. - - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. -}; - -struct PlacementsOptimizationParameters -{ - PlacementsOptimizationParameters() { - SetDefaults(); - } - inline void SetDefaults() { - unit = "mm"; - topstorecandidates = 20; - for(size_t itarget = 0; itarget < targetnames.size(); ++itarget) { - targetnames[itarget].clear(); - framenames[itarget].clear(); - ignorebasecollisions[itarget] = 0; - } - minranges[0][0] = -400; minranges[0][1] = -400; minranges[0][2] = 0; minranges[0][3] = -180; - maxranges[0][0] = 400; maxranges[0][1] = 400; maxranges[0][2] = 400; maxranges[0][3] = 90; - stepsizes[0][0] = 100; stepsizes[0][1] = 100; stepsizes[0][2] = 100; stepsizes[0][3] = 90; - minranges[1][0] = -100; minranges[1][1] = -100; minranges[1][2] = 0; minranges[1][3] = 0; - maxranges[1][0] = 100; maxranges[1][1] = 100; maxranges[1][2] = 100; maxranges[1][3] = 0; - stepsizes[1][0] = 100; stepsizes[1][1] = 100; stepsizes[1][2] = 100; stepsizes[1][3] = 90; - } - - // for every target, there's one setting: - boost::array targetnames; ///< the primary key of the target object to optimize for. If blank, will use robot. Has to start with "0 instobject " for environment inst object targets. - boost::array framenames; ///< The primary key of the frame to define the optimization parameters in. If blank, will use the target's coordinate system. Has to start iwth "0 instobject " for environment inst object frames. - boost::array maxranges; ///< X, Y, Z, Angle (deg) - boost::array minranges; ///< X, Y, Z, Angle (deg) - boost::array stepsizes; ///< X, Y, Z, Angle (deg) - boost::array ignorebasecollisions; ///< If 1, when moving the robot, allow collisions of the base with the environment, this allows users to search for a base placement and while ignoring small obstacles. By default this is 0. - - // shared settings - std::string unit; ///< the unit that information is used in. m, mm, nm, inch, etc - int topstorecandidates; ///< In order to speed things up, store at least the top (fastest) N candidates. Candidates beyond the top N will not be computed. -}; - -/// \brief program data for an individual robot -class RobotProgramData -{ -public: - RobotProgramData() { - } - RobotProgramData(const std::string& programdata_, const std::string& type_) : programdata(programdata_), type(type_) { - } - std::string programdata; ///< the program data - std::string type; ///< the type of program -}; - -/// \brief program data for all robots. -class RobotControllerPrograms -{ -public: - std::map programs; ///< the keys are the robot instance primary keys of the scene -}; - -/// \brief Creates on MUJIN Controller instance. -/// -/// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. -class MUJINCLIENT_API ControllerClient -{ -public: - virtual ~ControllerClient() { - } - -// \brief Returns a list of filenames in the user system of a particular type -// -// \param scenetype the type of scene possible values are: -// - mujincollada -// - wincaps -// - rttoolbox -// - cecrobodiaxml -// - stl -// - x -// - vrml -// - stl -// -// virtual void GetSceneFilenames(const std::string& scenetype, std::vector& scenefilenames) = 0; - - /// \brief sets the character encoding for all strings that are being input and output from the resources - /// - /// The default character encoding is \b utf-8, can also set it to \b Shift_JIS for windows japanese unicode, \b iso-2022-jp - /// List of possible sets: http://www.iana.org/assignments/character-sets/character-sets.xml - virtual void SetCharacterEncoding(const std::string& newencoding) = 0; - - /// \brief sets the language code for all output - /// - /// Check out http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes - virtual void SetLanguage(const std::string& language) = 0; - - /// \brief sets the user agent to be sent with each http request - virtual void SetUserAgent(const std::string& userAgent) = 0; - - /// \brief sets additional http headers to be included on all requests - /// - /// \param additionalHeaders expect each value to be in the format of "Header-Name: header-value" - virtual void SetAdditionalHeaders(const std::vector& additionalHeaders) = 0; - - /// \brief returns the username logged into this controller - virtual const std::string& GetUserName() const = 0; - - /// \brief returns the URI used to setup the connection - virtual const std::string& GetBaseURI() const = 0; - - /// \brief full connection URI with username and password. http://username@password:path - virtual std::string GetURIWithUsernamePassword() const = 0; - - /// \brief returns the client info used to construct this client - virtual const ControllerClientInfo& GetClientInfo() const = 0; - - /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. - /// - /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - /// \param userpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - virtual void SetProxy(const std::string& serverport, const std::string& userpw) = 0; - - /// \brief If necessary, changes the unix domain socket to be used to communicate to the controller server. Setting unix endpoint disables previously set proxy. - /// - /// \param unixendpoint Specify the file path to the unix domain socket to connect to. - virtual void SetUnixEndpoint(const std::string& unixendpoint) = 0; - - /// \brief Restarts the MUJIN Controller Server and destroys any optimizaiton jobs. - /// - /// If the server is not responding, call this method to clear the server state and initialize everything. - /// The method is blocking, when it returns the MUJIN Controller would have been restarted. - virtual void RestartServer(double timeout = 5.0) = 0; - - /// \brief Execute GraphQL query or mutation against Mujin Controller. - /// - /// Throws an exception if there are any errors - /// \param rResultData The "data" field of the result if the query returns without problems - virtual void ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResultData, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; - - /// \brief Execute the GraphQL query or mutation against Mujin Controller and return any output as-is without doing any error processing - /// - /// \param rResult The entire result field of the query. Should have keys "data" and "errors". Each error should have keys: "message", "locations", "path", "extensions". And "extensions" has keys "errorCode". - virtual void ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout = 60.0) = 0; - - /// \brief returns the mujin controller version - virtual std::string GetVersion() = 0; - - /// \brief sends the cancel message to all jobs. - /// - /// The method is non-blocking - virtual void CancelAllJobs() = 0; - - /// \brief get all the run-time statuses - /// - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatuses(std::vector& statuses, int options=0) = 0; - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetScenePrimaryKeys(std::vector& scenekeys) = 0; - - /** \brief Register a scene to be used by the MUJIN Controller - - \param uri utf-8 encoded URI of the file on the MUJIN Controller to import. Usually starts with \b mujin:/ - \param scenetype The format of the source file. Can be: - - **mujincollada** - - **wincaps** (DensoWave WINCAPS III) - - **rttoolbox** (Mitsubishi RT ToolBox) - - **x** (DirectX) - - **vrml** - - **stl** - - **cecrobodiaxml** (CEC RoboDiA XML environments) - */ - virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) = 0; - - /// \brief registers scene with default scene type - virtual SceneResourcePtr RegisterScene_UTF8(const std::string& uri) - { - return RegisterScene_UTF8(uri,GetDefaultSceneType()); - } - - /// \see RegisterScene_UTF8 - /// - /// \param uri utf-16 encoded URI - virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) = 0; - - /// \brief registers scene with default scene type - virtual SceneResourcePtr RegisterScene_UTF16(const std::wstring& uri) - { - return RegisterScene_UTF16(uri,GetDefaultSceneType()); - } - - /** \brief import a scene into COLLADA format using from scene identified by a URI - - \param sourceuri URL-encoded UTF-8 original URI to import from. For MUJIN network files use mujin:/mypath/myfile.ext - \param sourcescenetype The format of the source file. Can be: - - **mujincollada** - - **wincaps** (DensoWave WINCAPS III) - - **rttoolbox** (Mitsubishi RT ToolBox) - - **x** (DirectX) - - **vrml** - - **stl** - - **cecrobodiaxml** (CEC RoboDiA XML environments) - \param newuri UTF-8 encoded new URI to save the imported results. Default is to save to MUJIN COLLADA, so end with .mujin.dae . Use mujin:/mypath/myfile.mujin.dae - \param overwrite if true, will overwrite any existing scenes at newuri with the new scene. - */ - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF8(const std::string& sourceuri, const std::string& sourcescenetype, const std::string& newuri, bool overwrite=false) = 0; - - /// \see ImportSceneToCOLLADA_UTF8 - /// - /// \param sourceuri utf-16 encoded - /// \param newuri utf-16 encoded - virtual SceneResourcePtr ImportSceneToCOLLADA_UTF16(const std::wstring& sourceuri, const std::string& sourcescenetype, const std::wstring& newuri, bool overwrite=false) = 0; - - /** \brief Recommended way of uploading a scene's files into the network filesystem. - - Depending on the scenetype, can upload entire directory trees. - \param sourcefilename UTF-8 encoded local filesystem location of the top-level file. If the scenetype requires many files, will upload all of them. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. - \param destinationdir UTF-8 encoded destination folder in the network file system. Should always have trailing slash. By default prefix with "mujin:/". Use the / separator for different paths. - \param scenetype UTF-8 encoded type of scene uploading. - \throw mujin_exception if the upload fails, will throw an exception - */ - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir, const std::string& scenetype) = 0; - - /// \see SyncUpload_UTF8 - virtual void SyncUpload_UTF8(const std::string& sourcefilename, const std::string& destinationdir) - { - SyncUpload_UTF8(sourcefilename, destinationdir, GetDefaultSceneType()); - } - - /// \see SyncUpload_UTF8 - /// - /// \param sourcefilename UTF-16 encoded. For Windows systems, the \ path separator has to be used. For Unix systems, the / path separator has to be used. - /// \param destinationdir UTF-16 encoded - /// \param scenetype UTF-16 encoded - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir, const std::string& scenetype) = 0; - - /// \see SyncUpload - virtual void SyncUpload_UTF16(const std::wstring& sourcefilename, const std::wstring& destinationdir) - { - SyncUpload_UTF16(sourcefilename, destinationdir, GetDefaultSceneType()); - } - - /// \brief Uploads a single file to the controller network filesystem. - /// - /// Overwrites the file if it already exists - /// \param filename utf-8 encoded path of the file on the system - /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. - virtual void UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) = 0; - - /// \brief \see UploadFileToController_UTF8 - /// - /// \param filename utf-16 encoded - /// \param desturi UTF-16 encoded - virtual void UploadFileToController_UTF16(const std::wstring& filename, const std::wstring& desturi) = 0; - - /// \brief Uploads binary data to a single file on the controller network filesystem. - /// - /// Overwrites the destination uri if it already exists - /// \param data binary data to upload to the uri - /// \param size binary data size in bytes - /// \param desturi UTF-8 encoded destination file in the network filesystem. By default prefix with "mujin:/". Use the / separator for different paths. - virtual void UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) = 0; - - /// \brief \see UploadDataToController_UTF8 - /// - /// \param data binary data to upload to the uri - /// \param size binary data size in bytes - /// \param desturi UTF-16 encoded - virtual void UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) = 0; - - /// \brief Build a backup of config/media and download it. - /// - /// \param outputStream filled with the contents of the backup. the backup is tar.gz format. - /// \param config whether to backup config. By default true. - /// \param media whether to include media files in the backup. By default true - /// \param backupscenepks comma separated list of scenes to backup. By default empty. - virtual void SaveBackup(std::ostream& outputStream, bool config = true, bool media = true, const std::string& backupscenepks = "", double timeout = 60.0) = 0; - - /// \brief Restore backup archive into controller. Restaring might be required after restoration. - /// - /// \param inputStream the stream represententing the backup. It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). - /// \param config whether to restore config. By default true (if the backup file has config). - /// \param media whether to restore media. By default true (if the backup file has media). - virtual void RestoreBackup(std::istream& inputStream, bool config = true, bool media = true, double timeout = 60.0) = 0; - - /// \brief Upgrade controller's software. - /// - /// \param inputStream the stream represententing the software file provided by MUJIN. - /// It needs to be seekable to get the size for uploading (ifstream subclass is applicable for files). - /// Pass stream with size 0 to use previously uploaded file. - /// \param autorestart whether to restart automatically after upgrading. if false, Reboot() can be called later. - /// \param uploadonly whether to upload only (so that upgrade can be continued later without uploading). - virtual void Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout = 600.0) = 0; - - /// \brief Get upgrade status. - /// - /// \param status upgrade status - /// \param progress progress 0 to 1 - /// \return true if the status was received (false means upgrade was not started yet). - virtual bool GetUpgradeStatus(std::string& status, double &progress, double timeout = 5.0) = 0; - - /// \brief Cancel the current upgrade process. - virtual void CancelUpgrade(double timeout = 5.0) = 0; - - /// \brief (Request to) reboot controller. - virtual void Reboot(double timeout = 5.0) = 0; - - /// \brief Delete all scenes. - virtual void DeleteAllScenes(double timeout = 5.0) = 0; - - /// \brief Delete all itl programs. - virtual void DeleteAllITLPrograms(double timeout = 5.0) = 0; - - /** \brief Recursively uploads a directory to the controller network filesystem. - - Creates directories along the way if they don't exist. - By default, overwrites all the files - \param copydir is utf-8 encoded. Cannot have trailing slashes '/', '\' - \param desturi UTF-8 encoded destination file in the network filesystem. If it has a trailing slash, then copydir is inside that URL. If there is no trailing slash, the copydir directory is renamed to the URI. By default prefix with "mujin:/". Use the / separator for different paths. - */ - virtual void UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) = 0; - - /// \brief \see UploadDirectoryToController_UTF8 - /// - /// \param copydir is utf-16 encoded - /// \param desturi UTF-16 encoded - virtual void UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) = 0; - - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) = 0; - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) = 0; - - /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header - /// \param remotetimeval will output the modified date in response - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; - - /// \param localtimeval seconds since epoch, will use input as If-Modified-Since header - /// \param remotetimeval will output the modified date in response - /// \param vdata filled with the contents of the file on the controller filesystem - virtual void DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long &remotetimeval, std::vector& vdata, double timeout = 5.0) = 0; - - /// \brief returns seconds since epoch, last modified time from server header - virtual long GetModifiedTime(const std::string& uri, double timeout = 5.0) = 0; - - /// \brief Deletes a file on the controller network filesystem. - /// - /// \param uri UTF-8 encoded file in the network filesystem to delete. - virtual void DeleteFileOnController_UTF8(const std::string& uri) = 0; - - /// \brief \see DeleteFileOnController_UTF8 - /// - /// \param uri UTF-16 encoded file in the network filesystem to delete. - virtual void DeleteFileOnController_UTF16(const std::wstring& uri) = 0; - - /// \brief Recursively deletes a directory on the controller network filesystem. - /// - /// \param uri UTF-8 encoded file in the network filesystem to delete. - virtual void DeleteDirectoryOnController_UTF8(const std::string& uri) = 0; - - /// \brief Get file list in specified directory. - /// - /// \param dirname UTF-8 encoded dirname to query. - virtual void ListFilesInController(std::vector& fileentries, const std::string &dirname="/", double timeout = 5.0) = 0; - - /// \brief \see DeleteDirectoryOnController_UTF8 - /// - /// \param uri UTF-16 encoded - virtual void DeleteDirectoryOnController_UTF16(const std::wstring& uri) = 0; - - virtual void ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; - - virtual void ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout = 5.0) = 0; - - virtual void SetDefaultSceneType(const std::string& scenetype) = 0; - - virtual const std::string& GetDefaultSceneType() = 0; - - virtual void SetDefaultTaskType(const std::string& tasktype) = 0; - - virtual const std::string& GetDefaultTaskType() = 0; - - /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-8 encoded) - - For example, the URI - - mujin:/検証動作_121122.mujin.dae - - is represented as: - - "mujin:/\xe6\xa4\x9c\xe8\xa8\xbc\xe5\x8b\x95\xe4\xbd\x9c_121122.mujin.dae" - - Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" - \param uri utf-8 encoded URI - */ - virtual std::string GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) = 0; - - /** \brief Get the url-encoded primary key of a scene from a scene uri (utf-16 encoded) - - If input URL is L"mujin:/\u691c\u8a3c\u52d5\u4f5c_121122.mujin.dae" - Return value will be: "%E6%A4%9C%E8%A8%BC%E5%8B%95%E4%BD%9C_121122" - - \param uri utf-16 encoded URI - */ - virtual std::string GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) = 0; - - /// \brief returns the primary key of a name - /// - /// \param name utf-8 encoded - virtual std::string GetPrimaryKeyFromName_UTF8(const std::string& name) = 0; - - /// \brief returns the primary key of a name - /// - /// \param name utf-16 encoded - virtual std::string GetPrimaryKeyFromName_UTF16(const std::wstring& name) = 0; - - /// \brief returns the uncoded name from a primary key - /// - /// \return utf-8 encoded name - virtual std::string GetNameFromPrimaryKey_UTF8(const std::string& pk) = 0; - - /// \brief returns the uncoded name from a primary key - /// - /// \return utf-16 encoded name - virtual std::wstring GetNameFromPrimaryKey_UTF16(const std::string& pk) = 0; - - virtual std::string CreateObjectGeometry(const std::string& objectPk, const std::string& name, const std::string& linkPk, const std::string& geomtype, double timeout = 5) = 0; - - /// \brief set geometry mesh to an object - /// \param objectPk primary key for the object to set mesh data to - /// \param geometryPk primary key for the geometry - /// \param data stl format binary mesh data - /// \param unit length unit of mesh - /// \param timeout timeout of uploading mesh - /// - virtual std::string SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& data, const std::string& unit = "mm", double timeout = 5) = 0; - - /// \brief get debug infos - virtual void GetDebugInfos(std::vector& debuginfos, double timeout = 5) = 0; -}; - -class MUJINCLIENT_API WebResource -{ -public: - WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk); - virtual ~WebResource() { - } - - inline ControllerClientPtr GetController() const { - return __controller; - } - inline const std::string& GetResourceName() const { - return __resourcename; - } - inline const std::string& GetPrimaryKey() const { - return __pk; - } - - /// \brief gets an attribute of this web resource - template - inline T Get(const std::string& field, double timeout = 5.0) { - rapidjson::Document pt(rapidjson::kObjectType); - GetWrap(pt, field, timeout); - return mujinjson::GetJsonValueByKey(pt, field.c_str()); - } - - /// \brief sets an attribute of this web resource - virtual void Set(const std::string& field, const std::string& newvalue, double timeout = 5.0); - - /// \brief sets an attribute of this web resource - virtual void SetJSON(const std::string& json, double timeout = 5.0); - - /// \brief delete the resource and all its child resources - virtual void Delete(double timeout = 5.0); - - /// \brief copy the resource and all its child resources to a new name - virtual void Copy(const std::string& newname, int options, double timeout = 5.0); - -private: - virtual void GetWrap(rapidjson::Document& pt, const std::string& field, double timeout = 5.0); - - ControllerClientPtr __controller; - std::string __resourcename, __pk; -}; - -class MUJINCLIENT_API ObjectResource : public WebResource -{ -public: - class MUJINCLIENT_API GeometryResource : public WebResource { -public: - GeometryResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~GeometryResource() { - } - std::string name; - std::string pk; - std::string objectpk; - std::string linkpk; - std::string geomtype; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - bool visible; - Real diffusecolor[4]; - Real transparency; - Real half_extents[3]; - Real height; - Real radius; - Real topRadius; - Real bottomRadius; - - virtual void GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices); - virtual void SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout = 5.0); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on - virtual int GetVisible(); - }; - typedef boost::shared_ptr GeometryResourcePtr; - - class MUJINCLIENT_API IkParamResource : public WebResource { -public: - IkParamResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~IkParamResource() { - } - std::string name; - std::string pk; - std::string iktype; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translation[3]; - Real direction[3]; - Real angle; - }; - typedef boost::shared_ptr IkParamResourcePtr; - - class MUJINCLIENT_API LinkResource : public WebResource { -public: - LinkResource(ControllerClientPtr controller, const std::string& objectpk, const std::string& pk); - virtual ~LinkResource() { - } - - virtual GeometryResourcePtr AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& name, const std::string& unit, double timeout = 5.0); - virtual GeometryResourcePtr AddPrimitiveGeometry(const std::string& name, const std::string& geomtype, double timeout = 5.0); - - virtual GeometryResourcePtr GetGeometryFromName(const std::string& geometryName); - - virtual void GetGeometries(std::vector& links); - - virtual boost::shared_ptr AddChildLink(const std::string& name, const Real quaternion[4], const Real translate[3]); - - virtual void SetCollision(bool collision); - /// 0 -> off, 1 -> on - virtual int GetCollision(); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetVisible(); - - std::vector attachmentpks; - std::string name; - std::string pk; - std::string objectpk; - std::string parentlinkpk; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - bool collision; - }; - typedef boost::shared_ptr LinkResourcePtr; - - - ObjectResource(ControllerClientPtr controller, const std::string& pk); - virtual ~ObjectResource() { - } - virtual void GetLinks(std::vector& links); - - virtual void GetIkParams(std::vector& ikparams); - - virtual LinkResourcePtr AddLink(const std::string& name, const Real quaternion[4], const Real translate[3]); - virtual IkParamResourcePtr AddIkParam(const std::string& name, const std::string& iktype); - - virtual void SetCollision(bool collision); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetCollision(); - virtual void SetVisible(bool visible); - /// 0 -> off, 1 -> on, 2 -> partial - virtual int GetVisible(); - - std::string name; - int nundof; - std::string datemodified; - std::string geometry; - bool isrobot; - std::string pk; - std::string resource_uri; - std::string scenepk; - std::string unit; - std::string uri; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - -protected: - ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); - -}; - -class MUJINCLIENT_API RobotResource : public ObjectResource -{ -public: - class MUJINCLIENT_API ToolResource : public WebResource { -public: - ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); - virtual ~ToolResource() { - } - - std::string name; - std::string frame_origin; - std::string frame_tip; - std::string pk; - Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - typedef boost::shared_ptr ToolResourcePtr; - - class MUJINCLIENT_API AttachedSensorResource : public WebResource { -public: - AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk); - virtual ~AttachedSensorResource() { - } - - std::string name; - std::string frame_origin; - std::string pk; - //Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - std::string sensortype; - - struct SensorData { -public: - bool operator!=(const SensorData& other) const { - return std::memcmp(distortion_coeffs, other.distortion_coeffs, 5 * sizeof(Real)) != 0 || - distortion_model != other.distortion_model || - focal_length != other.focal_length || - std::memcmp(image_dimensions, other.image_dimensions, 3 * sizeof(int)) != 0 || - std::memcmp(intrinsic, other.intrinsic, 6 * sizeof(Real)) != 0 || - measurement_time != other.measurement_time || - extra_parameters != other.extra_parameters; - } - bool operator==(const SensorData& other) const { - return !operator!=(other); - } - Real distortion_coeffs[5]; - std::string distortion_model; - Real focal_length; - int image_dimensions[3]; - Real intrinsic[6]; - Real measurement_time; - std::vector extra_parameters; - }; - SensorData sensordata; - }; - - typedef boost::shared_ptr AttachedSensorResourcePtr; - - RobotResource(ControllerClientPtr controller, const std::string& pk); - virtual ~RobotResource() { - } - - virtual void GetTools(std::vector& tools); - virtual void GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies = true); - - // attachments - // ikparams - // images - int numdof; - std::string simulation_file; -}; - -class MUJINCLIENT_API SceneResource : public WebResource -{ -public: - class InstObject; - typedef boost::shared_ptr InstObjectPtr; - /// \brief nested resource in the scene describe an object in the scene - class MUJINCLIENT_API InstObject : public WebResource - { -public: - InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk); - virtual ~InstObject() { - } - - class MUJINCLIENT_API Link { -public: - std::string name; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - - class MUJINCLIENT_API Tool { -public: - std::string name; - Real direction[3]; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - - class MUJINCLIENT_API Grab { -public: - std::string instobjectpk; ///< grabed_instobject_pk - std::string grabbed_linkpk; - std::string grabbing_linkpk; - - std::string Serialize() { - return boost::str(boost::format("{\"instobjectpk\": \"%s\", \"grabbed_linkpk\": \"%s\", \"grabbing_linkpk\": \"%s\"}")%instobjectpk%grabbed_linkpk%grabbing_linkpk); - } - - bool operator==(const Grab grab) { - if (this->instobjectpk == grab.instobjectpk - && this->grabbed_linkpk == grab.grabbed_linkpk - && this->grabbing_linkpk == grab.grabbing_linkpk) { - return true; - } - return false; - } - }; - - class MUJINCLIENT_API AttachedSensor { -public: - std::string name; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - }; - - void SetTransform(const Transform& t); - void SetDOFValues(); - virtual void GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); - virtual void ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk); - - - std::vector dofvalues; - std::string name; - std::string pk; - std::string object_pk; - std::string reference_object_pk; - std::string reference_uri; - Real quaternion[4]; // quaternion [w, x, y, z] = [cos(angle/2), sin(angle/2)*rotation_axis] - Real translate[3]; - std::vector grabs; - std::vector links; - std::vector tools; - std::vector attachedsensors; - }; - - SceneResource(ControllerClientPtr controller, const std::string& pk); - virtual ~SceneResource() { - } - - virtual void SetInstObjectsState(const std::vector& instobjects, const std::vector& states); - - /** \brief Gets or creates the a task part of the scene - - If task exists already, validates it with tasktype. - \param taskname utf-8 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown - \param tasktype The type of task to create. Supported types are: - - itlplanning - */ - - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options=0); - - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF8(const std::string& taskname, int options=0) - { - return GetOrCreateTaskFromName_UTF8(taskname, GetController()->GetDefaultTaskType(), options); - } - - virtual TaskResourcePtr GetTaskFromName_UTF8(const std::string& taskname, int options=0); - - /** \brief Gets or creates the a task part of the scene - - If task exists already, validates it with tasktype. - \param taskname utf-16 encoded name of the task to search for or create. If the name already exists and is not tasktype, an exception is thrown - \param tasktype The type of task to create. Supported types are: - - itlplanning - */ - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options=0); - - virtual TaskResourcePtr GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, int options=0) - { - return GetOrCreateTaskFromName_UTF16(taskname, GetController()->GetDefaultTaskType(), options); - } - - virtual TaskResourcePtr GetTaskFromName_UTF16(const std::wstring& taskname, int options=0); - - - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype="binpicking", int options=0); - virtual BinPickingTaskResourcePtr GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype="binpicking", int options=0); - - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetTaskPrimaryKeys(std::vector& taskkeys); - - virtual void GetTaskNames(std::vector& names); - - /// \brief gets a list of all the instance objects of the scene - virtual void GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos); - virtual void GetInstObjects(std::vector& instobjects); - virtual bool FindInstObject(const std::string& name, InstObjectPtr& instobject); - - /// \brief creates an inst object in scene - /// \param name name of the object to create - /// \param referenceUri uri to reference. Leave empty to reference nothing. - /// \param quaternion quaternion of the object - /// \param translate translation of the object - /// \return pointer to inst object created - virtual SceneResource::InstObjectPtr CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout = 300); - - /// \brief deletes an inst object in scene - /// \param pk primary key of the object to delete - virtual void DeleteInstObject(const std::string& pk); - - virtual SceneResourcePtr Copy(const std::string& name); -}; - -class MUJINCLIENT_API TaskResource : public WebResource -{ -public: - TaskResource(ControllerClientPtr controller, const std::string& pk); - virtual ~TaskResource() { - } - - /// \brief execute the task. - /// - /// This operation is non-blocking and will return immediately after the execution is started. In order to check if the task is running or is complete, use \ref GetRunTimeStatus() and \ref GetResult() - /// \return true if task was executed fine - virtual bool Execute(); - - /// \brief if the task is currently executing, send a cancel request - virtual void Cancel(); - - /// \brief get the run-time status of the executed task. - /// - /// This will only work if the task has been previously Executed with execute - /// If the task is not currently running, will set status.code to JSC_Unknown - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatus(JobStatus& status, int options = 1); - - /// \brief Gets or creates the a optimization part of the scene - /// - /// \param optimizationname the name of the optimization to search for or create - /// \param optimizaitontype The type of optimization, can be "robotplacement" or "placements" - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); - - /// \brief \see GetOrCreateOptimizationFromName_UTF8 - virtual OptimizationResourcePtr GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype=std::string("robotplacement")); - - /// \brief gets a list of all the scene primary keys currently available to the user - virtual void GetOptimizationPrimaryKeys(std::vector& optimizationkeys); - - /// \brief Get the task info for tasks of type itlplanning - virtual void GetTaskParameters(ITLPlanningTaskParameters& taskparameters); - - /// \brief Set new task info for tasks of type itlplanning - virtual void SetTaskParameters(const ITLPlanningTaskParameters& taskparameters); - - /// \brief gets the result of the task execution. If no result has been computed yet, will return a NULL pointer. - virtual PlanningResultResourcePtr GetResult(); - -protected: - std::string _jobpk; ///< the job primary key used to track the status of the running task after \ref Execute is called -}; - -class MUJINCLIENT_API OptimizationResource : public WebResource -{ -public: - OptimizationResource(ControllerClientPtr controller, const std::string& pk); - virtual ~OptimizationResource() { - } - - /// \brief execute the optimization - /// - /// \param bClearOldResults if true, will clear the old optimiation results. If false, will keep the old optimization results and only compute those that need to be computed. - virtual void Execute(bool bClearOldResults=true); - - /// \brief if the optimization is currently executing, send a cancel request - virtual void Cancel(); - - /// \brief Set new task info for tasks of type robotplanning - void SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams); - - /// \brief Set new task info for tasks of type placements - void SetOptimizationParameters(const PlacementsOptimizationParameters& optparams); - - /// \brief get the run-time status of the executed optimization. - /// - /// This will only work if the optimization has been previously Executed with execute - /// If the task is not currently running, will set status.code to JSC_Unknown - /// \param options if options is 1, also get the message - virtual void GetRunTimeStatus(JobStatus& status, int options = 1); - - /// \brief Gets the results of the optimization execution ordered by task_time. - /// - /// \param startoffset The offset to retrieve the results from. Ordered - /// \param num The number of results to get starting at startoffset. If 0, will return ALL results. - virtual void GetResults(std::vector& results, int startoffset=0, int num=0); - -protected: - std::string _jobpk; ///< the job primary key used to track the status of the running optimization after \ref Execute is called -}; - -class MUJINCLIENT_API PlanningResultResource : public WebResource -{ -public: - PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk); - PlanningResultResource(ControllerClientPtr controller, const std::string& pk); - virtual ~PlanningResultResource() { - } - - /// \brief Get all the transforms the results are storing. Depending on the optimization, can be more than just the robot - virtual void GetEnvironmentState(EnvironmentState& envstate); - - /** \brief Gets the raw program information - - \param[in] programtype The type of program to return. Possible values are: - - auto - special type that returns the most suited programs - - mujinxml - \b xml - - melfabasicv - \b json with Mitsubishi-specific programs - - densowaverc8pac - \b json with DensoWave-specific programs - - cecrobodiasim - zip file - - If \b auto is set, then the robot-maker specific program is returned if possible. If not possible, then mujin xml is returned. All the programs for all robots planned are returned. - - \param[out] outputdata The raw program data - */ - virtual void GetAllRawProgramData(std::string& outputdata, const std::string& programtype="auto"); - - /** \brief Gets the raw program information of a specific robot, if supported. - - \param[in] robotpk The primary key of the robot instance in the scene. - \param[out] outputdata The raw program data - \param[in] programtype The type of program to return. - \throw mujin_exception If robot program is not supported, will throw an exception - */ - virtual void GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype="auto"); - - /// \brief Gets parsed program information - /// - /// If the robot doesn't have a recognizable controller, then no programs might be returned. - /// \param[out] programs The programs for each robot. The best suited program for each robot is determined from its controller. - /// \param[in] programtype The type of program to return. - virtual void GetPrograms(RobotControllerPrograms& programs, const std::string& programtype="auto"); -}; - -class MUJINCLIENT_API DebugResource : public WebResource -{ -public: - DebugResource(ControllerClientPtr controller, const std::string& pk); - virtual ~DebugResource() { - } - - /// \brief download the encrypted debug log to outputStream - virtual void Download(std::ostream &outputStream, double timeout = 60.0); - - //std::string datemodified; - std::string description; - //std::string downloadUri; - std::string name; - std::string pk; - std::string resource_uri; - size_t size; - -protected: - DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk); -}; - -/** \en \brief creates the controller with an account. This function is not thread safe. - - You must not call it when any other thread in the program (i.e. a thread sharing the same memory) is running. - \param usernamepassword user:password - \param url the URI-encoded URL of controller server, it needs to have a trailing slash. It can also be in the form of https://username@server/ in order to force login of a particular user. - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options extra options for connecting to the controller. If 0x1 is set, the client will optimize usage to only allow GET calls. Set 0x80000000 if using a development server. - - \ja \brief MUJINコントローラのクライアントを作成する。この関数はスレッドセーフではない。 - - この関数はスレッドセーフではないため、呼び出す時に他のスレッドが走っていないようにご注意ください。 - \param usernamepassword ユーザ:パスワード - \param url コントローラにアクセスするためのURLです。スラッシュ「/」で終わる必要があります。強制的にユーザも指定出来ます、例えばhttps://username@server/。 - \param proxyserverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. - \param proxyuserpw If non-empty, [user name]:[password] to use for the connection to the HTTP proxy. - \param options 1が指定されたら、クライアントがGETのみを呼び出し出来ます。それで初期化がもっと速くなれます。 - \param timeout set timeout in seconds for the initial login requests - */ -MUJINCLIENT_API ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& url, const std::string& proxyserverport=std::string(), const std::string& proxyuserpw=std::string(), int options=0, double timeout=3.0); - -/// \brief called at the very end of an application to safely destroy all controller client resources -MUJINCLIENT_API void DestroyControllerClient(); - -/// \deprecated 14/03/14 -MUJINCLIENT_API void ControllerClientDestroy() MUJINCLIENT_DEPRECATED; - -/// \brief Compute a 3x4 matrix from a Transform -MUJINCLIENT_API void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform); - -/** \brief Compute Euler angles in ZXY order (T = Z*X*Y) from a 3x4 matrix - - Rx = Matrix(3,3,[1,0,0,0,cos(x),-sin(x),0,sin(x),cos(x)]) - Ry = Matrix(3,3,[cos(y),0,sin(y),0,1,0,-sin(y),0,cos(y)]) - Rz = Matrix(3,3,[cos(z),-sin(z),0,sin(z),cos(z),0,0,0,1]) - Rz*Rx*Ry - - [-sin(x)*sin(y)*sin(z) + cos(y)*cos(z), -sin(z)*cos(x), sin(x)*sin(z)*cos(y) + sin(y)*cos(z)] - [ sin(x)*sin(y)*cos(z) + sin(z)*cos(y), cos(x)*cos(z), -sin(x)*cos(y)*cos(z) + sin(y)*sin(z)] - [ -sin(y)*cos(x), sin(x), cos(x)*cos(y)] - - */ -MUJINCLIENT_API void ComputeZXYFromMatrix(Real ZXY[3], const Real matrix[12]); - -MUJINCLIENT_API void ComputeZXYFromTransform(Real ZXY[3], const Transform &transform); - -MUJINCLIENT_API void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os); - - -} // namespace mujinclient - -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MAJOR>=0&&MUJINCLIENT_VERSION_MAJOR<=255); -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_MINOR>=0&&MUJINCLIENT_VERSION_MINOR<=255); -BOOST_STATIC_ASSERT(MUJINCLIENT_VERSION_PATCH>=0&&MUJINCLIENT_VERSION_PATCH<=255); - -#endif diff --git a/src/include/mujinwebstackclientcpp/mujincontrollerclient.h b/src/include/mujinwebstackclientcpp/mujincontrollerclient.h new file mode 100644 index 00000000..51c73c28 --- /dev/null +++ b/src/include/mujinwebstackclientcpp/mujincontrollerclient.h @@ -0,0 +1,27 @@ +/// \brief connecting to a controller's webstack +class MUJINCLIENT_API ControllerClientInfo : public mujinjson::JsonSerializable +{ +public: + virtual void Reset(); + + void LoadFromJson(const rapidjson::Value& rClientInfo) override; + void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; + void SaveToJson(rapidjson::Document& rClientInfo) const override; + + bool operator==(const ControllerClientInfo &rhs) const; + bool operator!=(const ControllerClientInfo &rhs) const { + return !operator==(rhs); + } + std::string GetURL(bool bIncludeNamePassword) const; + + inline bool IsEnabled() const { + return !host.empty(); + } + + std::string host; + uint16_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port + std::string username; + std::string password; + std::vector additionalHeaders; ///< expect each value to be in the format of "Header-Name: header-value" + std::string unixEndpoint; ///< unix socket endpoint for communicating with HTTP server over unix socket +}; diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp index 09eb3356..c8d1010c 100644 --- a/src/mujincontrollerclient.cpp +++ b/src/mujincontrollerclient.cpp @@ -1,36 +1,3 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2013 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "common.h" -#include "controllerclientimpl.h" -#include // for sleep -#include - -#include - -#ifdef MUJIN_USEZMQ -#include "binpickingtaskzmq.h" -#endif - -#include "logging.h" -#include "mujincontrollerclient/mujinjson.h" - -MUJIN_LOGGER("mujin.controllerclientcpp"); - -namespace mujinclient { - -using namespace mujinjson; - void ControllerClientInfo::Reset() { host.clear(); @@ -110,1360 +77,3 @@ std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const } return url; } - -void ExtractEnvironmentStateFromPTree(const rapidjson::Value& envstatejson, EnvironmentState& envstate) -{ - // FIXME: is this a dict or array? - envstate.clear(); - for (rapidjson::Document::ConstValueIterator it = envstatejson.Begin(); it != envstatejson.End(); ++it) { - InstanceObjectState objstate; - std::string name = GetJsonValueByKey(*it, "name"); - std::vector quat = GetJsonValueByKey >(*it, "quat_"); - BOOST_ASSERT(quat.size() == 4); - Real dist2 = 0; - for (int i = 0; i < 4; i++ ) { - Real f = quat[i] * quat[i]; - dist2 += f; - objstate.transform.quaternion[i] = f; - } - // normalize the quaternion - if( dist2 > 0 ) { - Real fnorm =1/std::sqrt(dist2); - objstate.transform.quaternion[0] *= fnorm; - objstate.transform.quaternion[1] *= fnorm; - objstate.transform.quaternion[2] *= fnorm; - objstate.transform.quaternion[3] *= fnorm; - } - LoadJsonValueByKey(*it, "translation_", objstate.transform.translate); - LoadJsonValueByKey(*it, "dofvalues", objstate.dofvalues); - envstate[name] = objstate; - } -} - -void SerializeEnvironmentStateToJSON(const EnvironmentState& envstate, std::ostream& os) -{ - os << "["; - bool bhaswritten = false; - FOREACHC(itstate, envstate) { - if( itstate->first.size() > 0 ) { - if( bhaswritten ) { - os << ","; - } - os << "{ \"name\":\"" << itstate->first << "\", \"translation_\":["; - for(int i = 0; i < 3; ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.transform.translate[i]; - } - os << "], \"quat_\":["; - for(int i = 0; i < 4; ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.transform.quaternion[i]; - } - os << "], \"dofvalues\":["; - for(size_t i = 0; i < itstate->second.dofvalues.size(); ++i) { - if( i > 0 ) { - os << ","; - } - os << itstate->second.dofvalues.at(i); - } - os << "] }"; - bhaswritten = true; - } - } - os << "]"; -} - -WebResource::WebResource(ControllerClientPtr controller, const std::string& resourcename, const std::string& pk) : __controller(controller), __resourcename(resourcename), __pk(pk) -{ - BOOST_ASSERT(__pk.size()>0); -} - -void WebResource::GetWrap(rapidjson::Document& pt, const std::string& field, double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=%s")%GetResourceName()%GetPrimaryKey()%field), pt, 200, timeout); -} - -void WebResource::Set(const std::string& field, const std::string& newvalue, double timeout) -{ - throw MujinException("not implemented"); -} - -void WebResource::SetJSON(const std::string& json, double timeout) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), json, pt, 202, timeout); -} - -void WebResource::Delete(double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("%s/%s/")%GetResourceName()%GetPrimaryKey()), 204, timeout); -} - -void WebResource::Copy(const std::string& newname, int options, double timeout) -{ - throw MujinException("not implemented yet"); -} - -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "object", pk_), pk(pk_) -{ -} - -ObjectResource::ObjectResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) -{ -} - -ObjectResource::LinkResource::LinkResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/link")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) -{ -} - -ObjectResource::GeometryResource::GeometryResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/geometry")%objectpk_), pk_), pk(pk_), objectpk(objectpk_) -{ -} - -ObjectResource::IkParamResource::IkParamResource(ControllerClientPtr controller, const std::string& objectpk_, const std::string& pk_) : WebResource(controller, str(boost::format("object/%s/ikparam")%objectpk_), pk_), pk(pk_) -{ -} - -void ObjectResource::GeometryResource::GetMesh(std::string& primitive, std::vector >& indices, std::vector >& vertices) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("%s/%s/?format=json&limit=0&mesh=true")%GetResourceName()%GetPrimaryKey())); - controller->CallGet(relativeuri, pt); - rapidjson::Value& objects = pt["mesh"]; - LoadJsonValueByKey(objects,"primitive",primitive); - LoadJsonValueByKey(objects,"indices",indices); - LoadJsonValueByKey(objects,"vertices",vertices); -} - -void ObjectResource::GeometryResource::SetGeometryFromRawSTL(const std::vector& rawstldata, const std::string& unit, double timeout) -{ - GETCONTROLLERIMPL(); - if (this->geomtype != "mesh") { - throw MUJIN_EXCEPTION_FORMAT("geomtype is not mesh: %s", this->geomtype, MEC_InvalidArguments); - } - controller->SetObjectGeometryMesh(this->objectpk, this->pk, rawstldata, unit, timeout); -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddGeometryFromRawSTL(const std::vector& rawstldata, const std::string& geomname, const std::string& unit, double timeout) -{ - GETCONTROLLERIMPL(); - const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, "mesh", timeout); - - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = geomname; - geometry->geomtype = "mesh"; - geometry->linkpk = linkpk; - geometry->SetGeometryFromRawSTL(rawstldata, unit, timeout); - return geometry; -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::AddPrimitiveGeometry(const std::string& geomname, const std::string& geomtype, double timeout) -{ - GETCONTROLLERIMPL(); - const std::string& linkpk = GetPrimaryKey(); - const std::string geometryPk = controller->CreateObjectGeometry(this->objectpk, geomname, linkpk, geomtype, timeout); - - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, geometryPk)); - geometry->name = geomname; - geometry->geomtype = geomtype; - geometry->linkpk = linkpk; - return geometry; -} - -ObjectResource::GeometryResourcePtr ObjectResource::LinkResource::GetGeometryFromName(const std::string& geometryName) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); - controller->CallGet(relativeuri, pt); - if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { - rapidjson::Value& objects = pt["geometries"]; - for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string geomname = it->HasMember("name") ? GetJsonValueByKey(*it, "name") : GetJsonValueByKey(*it, "pk"); - if (geomname == geometryName && (*it)["linkpk"].GetString() == this->pk) { - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->name = geomname; - LoadJsonValueByKey(*it,"linkpk",geometry->linkpk); - LoadJsonValueByKey(*it,"visible",geometry->visible); - LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); - LoadJsonValueByKey(*it,"transparency",geometry->transparency); - LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); - LoadJsonValueByKey(*it,"translate",geometry->translate); - LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); - - /// geomtype /// - // mesh - // box: half_extents - // cylinder: height, topRadius, bottomRadius - // sphere: radius - LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); - LoadJsonValueByKey(*it,"height",geometry->height); - LoadJsonValueByKey(*it,"radius",geometry->radius); - LoadJsonValueByKey(*it,"topRadius",geometry->topRadius); - LoadJsonValueByKey(*it,"bottomRadius",geometry->bottomRadius); - return geometry; - } - } - } - throw MUJIN_EXCEPTION_FORMAT("link %s does not have geometry named %s", this->name%geometryName, MEC_InvalidArguments); -} - -void ObjectResource::LinkResource::GetGeometries(std::vector& geometries) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - const std::string relativeuri(str(boost::format("object/%s/geometry/?format=json&limit=0&fields=geometries")%this->objectpk)); - controller->CallGet(relativeuri, pt); - if (pt.IsObject() && pt.HasMember("geometries") && pt["geometries"].IsArray()) { - rapidjson::Value& objects = pt["geometries"]; - geometries.clear(); - for (rapidjson::Document::ConstValueIterator it = objects.Begin(); it != objects.End(); ++it) { - const std::string linkpk = GetJsonValueByKey(*it, "linkpk"); - if (linkpk == this->pk) { - ObjectResource::GeometryResourcePtr geometry(new GeometryResource(controller, this->objectpk, GetJsonValueByKey(*it, "pk"))); - geometry->linkpk = linkpk; - LoadJsonValueByKey(*it,"name",geometry->name,geometry->pk); - LoadJsonValueByKey(*it,"visible",geometry->visible); - LoadJsonValueByKey(*it,"geomtype",geometry->geomtype); - LoadJsonValueByKey(*it,"transparency",geometry->transparency); - LoadJsonValueByKey(*it,"quaternion",geometry->quaternion); - LoadJsonValueByKey(*it,"translate",geometry->translate); - LoadJsonValueByKey(*it,"diffusecolor",geometry->diffusecolor); - - LoadJsonValueByKey(*it,"half_extents",geometry->half_extents); - LoadJsonValueByKey(*it,"height",geometry->height); - LoadJsonValueByKey(*it,"radius",geometry->radius); - LoadJsonValueByKey(*it,"topRadius",geometry->topRadius); - LoadJsonValueByKey(*it,"bottomRadius",geometry->bottomRadius); - geometries.push_back(geometry); - } - } - } -} - -void ObjectResource::LinkResource::SetCollision(bool hasCollision) -{ - this->SetJSON(mujinjson::GetJsonStringByKey("collision", hasCollision)); - this->collision = hasCollision; -} -void ObjectResource::SetCollision(bool collision) -{ - std::vector links; - this->GetLinks(links); - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - link->SetCollision(collision); - } -} -int ObjectResource::LinkResource::GetCollision() -{ - return this->collision; -} -int ObjectResource::GetCollision() -{ - std::vector links; - this->GetLinks(links); - int ret=0; - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - ret|=link->GetCollision()+1; - } - return ret-1; -} - -void ObjectResource::GeometryResource::SetVisible(bool isVisible) -{ - this->SetJSON(mujinjson::GetJsonStringByKey("visible",isVisible)); - this->visible = isVisible; -} -void ObjectResource::LinkResource::SetVisible(bool visible) -{ - std::vector geometries; - this->GetGeometries(geometries); - BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ - geometry->SetVisible(visible); - } -} -void ObjectResource::SetVisible(bool visible) -{ - std::vector links; - this->GetLinks(links); - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - link->SetVisible(visible); - } -} -int ObjectResource::GeometryResource::GetVisible() -{ - return this->visible; -} -int ObjectResource::LinkResource::GetVisible() -{ - std::vector geometries; - this->GetGeometries(geometries); - int ret=0; - BOOST_FOREACH(ObjectResource::GeometryResourcePtr &geometry, geometries){ - ret|=geometry->GetVisible()+1; - } - return ret-1; -} -int ObjectResource::GetVisible() -{ - std::vector links; - this->GetLinks(links); - int ret=0; - BOOST_FOREACH(ObjectResource::LinkResourcePtr &link, links){ - ret|=link->GetVisible()+1; - } - return ret-1; -} - -void ObjectResource::GetLinks(std::vector& links) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("object/%s/link/?format=json&limit=0&fields=links")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["links"]; - links.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - LinkResourcePtr link(new LinkResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - LoadJsonValueByKey(*it,"parentlinkpk",link->parentlinkpk); - LoadJsonValueByKey(*it,"name",link->name); - LoadJsonValueByKey(*it,"collision",link->collision); - LoadJsonValueByKey(*it,"attachmentpks",link->attachmentpks); - LoadJsonValueByKey(*it,"quaternion",link->quaternion); - LoadJsonValueByKey(*it,"translate",link->translate); - links[i++] = link; - } -} - -ObjectResource::LinkResourcePtr ObjectResource::AddLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) -{ - GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->pk, "", objname, quaternion_, translate_); - - ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->pk, linkPk)); - link->name = objname; - link->parentlinkpk = ""; - return link; -} - -ObjectResource::LinkResourcePtr ObjectResource::LinkResource::AddChildLink(const std::string& objname, const Real quaternion_[4], const Real translate_[3]) -{ - GETCONTROLLERIMPL(); - const std::string linkPk = controller->CreateLink(this->objectpk, this->pk, objname, quaternion_, translate_); - - ObjectResource::LinkResourcePtr link(new LinkResource(controller, this->objectpk, linkPk)); - link->name = objname; - link->parentlinkpk = this->pk; - return link; -} - -ObjectResource::IkParamResourcePtr ObjectResource::AddIkParam(const std::string& objname, const std::string& iktype) -{ - GETCONTROLLERIMPL(); - const std::string ikparamPk = controller->CreateIkParam(this->pk, objname, iktype); - - return ObjectResource::IkParamResourcePtr(new IkParamResource(controller, this->pk, ikparamPk)); -} - -void ObjectResource::GetIkParams(std::vector& ikparams) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("object/%s/ikparam/?format=json&limit=0&fields=ikparams")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["ikparams"]; - ikparams.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - IkParamResourcePtr ikparam(new IkParamResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - LoadJsonValueByKey(*it,"name",ikparam->name); - LoadJsonValueByKey(*it,"iktype",ikparam->iktype); - LoadJsonValueByKey(*it,"quaternion",ikparam->quaternion); - LoadJsonValueByKey(*it,"direction",ikparam->direction); - LoadJsonValueByKey(*it,"translation",ikparam->translation); - LoadJsonValueByKey(*it,"angle",ikparam->angle); - ikparams[i++] = ikparam; - } -} - -RobotResource::RobotResource(ControllerClientPtr controller, const std::string& pk_) : ObjectResource(controller, "robot", pk_) -{ -} - -RobotResource::ToolResource::ToolResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/tool")%robotobjectpk), pk_), pk(pk_) -{ -} - -void RobotResource::GetTools(std::vector& tools) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/tool/?format=json&limit=0&fields=tools")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["tools"]; - tools.resize(objects.Size()); - size_t i = 0; -// FOREACH(v, objects) { - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - ToolResourcePtr tool(new ToolResource(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - - LoadJsonValueByKey(*it, "name", tool->name); - LoadJsonValueByKey(*it, "frame_orgin", tool->frame_origin); - LoadJsonValueByKey(*it, "frame_tip", tool->frame_tip); - LoadJsonValueByKey(*it, "direction", tool->direction); - LoadJsonValueByKey(*it, "quaternion", tool->quaternion); - LoadJsonValueByKey(*it, "translate", tool->translate); - - tools[i++] = tool; - } -} - -RobotResource::AttachedSensorResource::AttachedSensorResource(ControllerClientPtr controller, const std::string& robotobjectpk, const std::string& pk_) : WebResource(controller, str(boost::format("robot/%s/attachedsensor")%robotobjectpk), pk_), pk(pk_) -{ -} - -void RobotResource::GetAttachedSensors(std::vector& attachedsensors, bool useConnectedBodies) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json&limit=0&fields=attachedsensors")%GetPrimaryKey()), pt); - - rapidjson::Value& rAttachedSensors = pt["attachedsensors"]; - attachedsensors.resize(rAttachedSensors.Size()); - size_t attachedSensorIdx = 0; - for (rapidjson::Document::ValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - AttachedSensorResourcePtr attachedsensor(new AttachedSensorResource(controller, GetPrimaryKey(), GetJsonValueByKey(*itAttachedSensor, "pk"))); - - LoadJsonValueByKey(*itAttachedSensor, "name", attachedsensor->name); - LoadJsonValueByKey(*itAttachedSensor, "frame_origin", attachedsensor->frame_origin); - LoadJsonValueByKey(*itAttachedSensor, "sensortype", attachedsensor->sensortype); - LoadJsonValueByKey(*itAttachedSensor, "quaternion", attachedsensor->quaternion); - LoadJsonValueByKey(*itAttachedSensor, "translate", attachedsensor->translate); - std::vector distortionCoeffs = GetJsonValueByPath > (*itAttachedSensor, "/sensordata/distortion_coeffs"); - - BOOST_ASSERT(distortionCoeffs.size() <= 5); - for (size_t i = 0; i < distortionCoeffs.size(); i++) { - attachedsensor->sensordata.distortion_coeffs[i] = distortionCoeffs[i]; - } - attachedsensor->sensordata.distortion_model = GetJsonValueByPath(*itAttachedSensor, "/sensordata/distortion_model"); - attachedsensor->sensordata.focal_length = GetJsonValueByPath(*itAttachedSensor, "/sensordata/focal_length"); - attachedsensor->sensordata.measurement_time= GetJsonValueByPath(*itAttachedSensor, "/sensordata/measurement_time"); - std::vector intrinsics = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/intrinsic"); - BOOST_ASSERT(intrinsics.size() <= 6); - for (size_t i = 0; i < intrinsics.size(); i++) { - attachedsensor->sensordata.intrinsic[i] = intrinsics[i]; - } - std::vector imgdim = GetJsonValueByPath >(*itAttachedSensor, "/sensordata/image_dimensions"); - BOOST_ASSERT(imgdim.size() <= 3); - for (size_t i = 0; i < imgdim.size(); i++) { - attachedsensor->sensordata.image_dimensions[i] = imgdim[i]; - } - - if (rapidjson::Pointer("/sensordata/extra_parameters").Get(*itAttachedSensor)) { - std::string parameters_string = GetJsonValueByPath(*itAttachedSensor, "/sensordata/extra_parameters"); - //std::cout << "extra param " << parameters_string << std::endl; - std::list results; - boost::split(results, parameters_string, boost::is_any_of(" ")); - results.remove(""); - attachedsensor->sensordata.extra_parameters.resize(results.size()); - size_t iparam = 0; - BOOST_FOREACH(std::string p, results) { - //std::cout << "'"<< p << "'"<< std::endl; - try { - attachedsensor->sensordata.extra_parameters[iparam++] = boost::lexical_cast(p); - } catch (...) { - //lexical_cast fails... - } - } - } else { - //std::cout << "no asus param" << std::endl; - } - - attachedsensors[attachedSensorIdx++] = attachedsensor; - } - - rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%GetPrimaryKey()), rRobotConnectedBodies); - rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; - if (useConnectedBodies && rConnectedBodies.IsArray() && rConnectedBodies.Size() > 0) { - for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { - std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); - std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); - rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { - if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { - continue; - } - std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - RobotResourcePtr connectedbodyrobot(new RobotResource(controller,connectedBodyObjectPk)); - std::vector connectedbodyattachedsensors; - - connectedbodyrobot->GetAttachedSensors(connectedbodyattachedsensors, false); - - for (size_t i = 0; i < connectedbodyattachedsensors.size(); i++) { - std::string resolvedSensorName = str(boost::format("%s_%s")%connectedBodyName%connectedbodyattachedsensors[i]->name); - connectedbodyattachedsensors[i]->name = resolvedSensorName; - } - - attachedsensors.reserve(attachedsensors.size() + connectedbodyattachedsensors.size()); - attachedsensors.insert(attachedsensors.end(), connectedbodyattachedsensors.begin(), connectedbodyattachedsensors.end()); - } - } - } -} - -SceneResource::InstObject::InstObject(ControllerClientPtr controller, const std::string& scenepk, const std::string& pk_) : WebResource(controller, str(boost::format("scene/%s/instobject")%scenepk), pk_), pk(pk_) -{ -} - -void SceneResource::InstObject::SetTransform(const Transform& t) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt; - std::string data = str(boost::format("{\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f]}")%t.quaternion[0]%t.quaternion[1]%t.quaternion[2]%t.quaternion[3]%t.translate[0]%t.translate[1]%t.translate[2]); - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); -} - -void SceneResource::InstObject::SetDOFValues() -{ - GETCONTROLLERIMPL(); - std::stringstream ss; - ss << "{\"dofvalues\":"; - ss << "["; - if( this->dofvalues.size() > 0 ) { - for (unsigned int i = 0; i < this->dofvalues.size(); i++) { - ss << this->dofvalues[i]; - if( i != this->dofvalues.size()-1) { - ss << ", "; - } - } - } - ss << "]}"; - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); -} - - -void SceneResource::InstObject::GrabObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) -{ - SceneResource::InstObject::Grab grab; - grab.instobjectpk = grabbedobject->pk; - grab.grabbed_linkpk = grabbedobjectlinkpk; - grab.grabbing_linkpk = grabbinglinkpk; - //TODO do not use this->grabs. this is the cached information - for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { - if (this->grabs[igrab] == grab) { - std::stringstream ss; - ss << grabbedobject->name << "is already grabbed"; - MUJIN_LOG_ERROR(ss.str()); - return; - } - } - std::stringstream ss; - ss << "{\"grabs\":"; - ss << "["; - if( this->grabs.size() > 0 ) { - for (unsigned int i = 0; i < this->grabs.size(); i++) { - ss << this->grabs[i].Serialize() << ", "; - } - } - ss << grab.Serialize(); - ss << "]}"; - GETCONTROLLERIMPL(); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); -} - -void SceneResource::InstObject::ReleaseObject(InstObjectPtr grabbedobject, std::string& grabbedobjectlinkpk, std::string& grabbinglinkpk) -{ - SceneResource::InstObject::Grab grab; - grab.instobjectpk = grabbedobject->pk; - grab.grabbed_linkpk = grabbedobjectlinkpk; - grab.grabbing_linkpk = grabbinglinkpk; - for (size_t igrab = 0; igrab < this->grabs.size(); igrab++) { - if (this->grabs[igrab] == grab) { - this->grabs.erase(std::remove(this->grabs.begin(), this->grabs.end(), this->grabs[igrab]), this->grabs.end()); - std::stringstream ss; - ss << "{\"grabs\":"; - ss << "["; - if( this->grabs.size() > 0 ) { - for (unsigned int i = 0; i < this->grabs.size(); i++) { - ss << this->grabs[i].Serialize() << ", "; - } - if( igrab != this->grabs.size()-1) { - ss << ", "; - } - } - ss << "]}"; - GETCONTROLLERIMPL(); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/?format=json")%GetResourceName()%GetPrimaryKey()), ss.str(), pt); - } - } - std::stringstream ss; - ss << grabbedobject->name << "is not grabbed"; - MUJIN_LOG_ERROR(ss.str()); - -} - -SceneResource::SceneResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller, "scene", pk) -{ - // get something from the scene? - //this->Get(""); -} - -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); - // task exists - std::string pk; - - std::string tasktype_internal = tasktype; - if( tasktype == "realtimeitlplanning" ) { - tasktype_internal = "realtimeitlplanning3"; - } - - if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { - rapidjson::Value& objects = pt["objects"]; - pk = GetJsonValueByKey(objects[0], "pk"); - std::string currenttasktype = GetJsonValueByKey(objects[0], "tasktype"); - if( currenttasktype != tasktype_internal && (currenttasktype != "realtimeitlplanning" || tasktype_internal != "realtimeitlplanning3")) { - throw MUJIN_EXCEPTION_FORMAT("task pk %s exists and has type %s, expected is %s", pk%currenttasktype%tasktype_internal, MEC_InvalidState); - } - } - else { - pt.SetObject(); - controller->CallPost(str(boost::format("scene/%s/task/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"tasktype\":\"%s\", \"scenepk\":\"%s\"}")%taskname%tasktype_internal%GetPrimaryKey()), pt); - LoadJsonValueByKey(pt, "pk", pk); - } - - if( pk.size() == 0 ) { - return TaskResourcePtr(); - } - - if( tasktype_internal == "binpicking" || tasktype_internal == "realtimeitlplanning3") { - BinPickingTaskResourcePtr task; - if( options & 1 ) { -#ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey(), tasktype_internal)); -#else - throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); -#endif - } - else { - task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); - } - return task; - } - else if( tasktype_internal == "cablepicking" ) { // TODO create CablePickingTaskResource - BinPickingTaskResourcePtr task; - if( options & 1 ) { -#ifdef MUJIN_USEZMQ - task.reset(new BinPickingTaskZmqResource(GetController(), pk, GetPrimaryKey())); -#else - throw MujinException("cannot create binpicking zmq task since not compiled with zeromq library", MEC_Failed); -#endif - } - else { - task.reset(new BinPickingTaskResource(GetController(), pk, GetPrimaryKey())); - } - return task; - } - else { - TaskResourcePtr task(new TaskResource(GetController(), pk)); - return task; - } -} - -void SceneResource::SetInstObjectsState(const std::vector& instobjects, const std::vector& states) -{ - GETCONTROLLERIMPL(); - if (instobjects.size() != states.size()) { - throw MUJIN_EXCEPTION_FORMAT("the size of instobjects (%d) and the one of states (%d) must be the same",instobjects.size()%states.size(),MEC_InvalidArguments); - } - boost::format transformtemplate("{\"pk\":\"%s\",\"quaternion\":[%.15f, %.15f, %.15f, %.15f], \"translate\":[%.15f, %.15f, %.15f] %s}"); - std::string datastring, sdofvalues; - for(size_t i = 0; i < instobjects.size(); ++i) { - const Transform& transform = states[i].transform; - if( states[i].dofvalues.size() > 0 ) { - sdofvalues = str(boost::format(", \"dofvalues\":[%.15f")%states[i].dofvalues.at(0)); - for(size_t j = 1; j < states[i].dofvalues.size(); ++j) { - sdofvalues += str(boost::format(", %.15f")%states[i].dofvalues.at(j)); - } - sdofvalues += "]"; - } - else { - sdofvalues = ""; - } - datastring += str(transformtemplate%instobjects[i]->pk%transform.quaternion[0]%transform.quaternion[1]%transform.quaternion[2]%transform.quaternion[3]%transform.translate[0]%transform.translate[1]%transform.translate[2]%sdofvalues); - if ( i != instobjects.size()-1) { - datastring += ","; - } - } - std::string data = str(boost::format("{\"objects\": [%s]}")%datastring); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("%s/%s/instobject/?format=json")%GetResourceName()%GetPrimaryKey()), data, pt); -} - -TaskResourcePtr SceneResource::GetTaskFromName_UTF8(const std::string& taskname, int options) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=1&name=%s&fields=pk,tasktype")%GetPrimaryKey()%controller->EscapeString(taskname)), pt); - // task exists - - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { - throw MUJIN_EXCEPTION_FORMAT("could not find task with name %s", taskname, MEC_InvalidState); - } - - std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); - TaskResourcePtr task(new TaskResource(GetController(), pk)); - return task; -} - -TaskResourcePtr SceneResource::GetOrCreateTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) -{ - std::string taskname_utf8; - utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetOrCreateTaskFromName_UTF8(taskname_utf8, tasktype, options); -} - -TaskResourcePtr SceneResource::GetTaskFromName_UTF16(const std::wstring& taskname, int options) -{ - std::string taskname_utf8; - utf8::utf16to8(taskname.begin(), taskname.end(), std::back_inserter(taskname_utf8)); - return GetTaskFromName_UTF8(taskname_utf8, options); -} - -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF8(const std::string& taskname, const std::string& tasktype, int options) -{ - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF8(taskname, tasktype, options)); -} - -BinPickingTaskResourcePtr SceneResource::GetOrCreateBinPickingTaskFromName_UTF16(const std::wstring& taskname, const std::string& tasktype, int options) -{ - return boost::dynamic_pointer_cast(GetOrCreateTaskFromName_UTF16(taskname, tasktype, options)); -} - -void SceneResource::GetTaskPrimaryKeys(std::vector& taskkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - taskkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - taskkeys[i++] = GetJsonValueByKey(*it, "pk"); - } -} - -void SceneResource::GetTaskNames(std::vector& taskkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/task/?format=json&limit=0&fields=name")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - taskkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - taskkeys[i++] = GetJsonValueByKey(*it, "name"); - } -} - -void SceneResource::GetAllSensorSelectionInfos(std::vector& allSensorSelectionInfos) -{ - GETCONTROLLERIMPL(); - allSensorSelectionInfos.clear(); - rapidjson::Document rInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,connectedBodies,object_pk,name")%GetPrimaryKey()), rInstObjects); - for (rapidjson::Document::ConstValueIterator itInstObject = rInstObjects["objects"].Begin(); itInstObject != rInstObjects["objects"].End(); ++itInstObject) { - const std::string sensorName = GetJsonValueByKey(*itInstObject, "name"); - const std::string objectPk = GetJsonValueByKey(*itInstObject, "object_pk"); - if ( itInstObject->HasMember("attachedsensors") && (*itInstObject)["attachedsensors"].IsArray() && (*itInstObject)["attachedsensors"].Size() > 0) { - rapidjson::Document rRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%objectPk), rRobotAttachedSensors); - const rapidjson::Value& rAttachedSensors = rRobotAttachedSensors["attachedsensors"]; - for (rapidjson::Document::ConstValueIterator itAttachedSensor = rAttachedSensors.Begin(); itAttachedSensor != rAttachedSensors.End(); ++itAttachedSensor) { - const std::string sensorLinkName = GetJsonValueByKey(*itAttachedSensor, "linkName"); - allSensorSelectionInfos.emplace_back(sensorName, sensorLinkName); - } - } - if ( itInstObject->HasMember("connectedBodies") && (*itInstObject)["connectedBodies"].IsArray() && (*itInstObject)["connectedBodies"].Size() > 0 ) { - rapidjson::Document rRobotConnectedBodies(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/connectedBody/?format=json")%objectPk), rRobotConnectedBodies); - rapidjson::Value& rConnectedBodies = rRobotConnectedBodies["connectedBodies"]; - for (rapidjson::Document::ConstValueIterator itConnectedBody = rConnectedBodies.Begin(); itConnectedBody != rConnectedBodies.End(); ++itConnectedBody) { - const std::string connectedBodyScenePk = controller->GetScenePrimaryKeyFromURI_UTF8(GetJsonValueByKey(*itConnectedBody, "url")); - const std::string connectedBodyName = GetJsonValueByKey(*itConnectedBody, "name"); - rapidjson::Document rConnectedBodyInstObjects(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0&fields=attachedsensors,object_pk,name")%connectedBodyScenePk), rConnectedBodyInstObjects); - for (rapidjson::Document::ConstValueIterator itConnectedBodyInstObject = rConnectedBodyInstObjects["objects"].Begin(); itConnectedBodyInstObject != rConnectedBodyInstObjects["objects"].End(); ++itConnectedBodyInstObject) { - if (!itConnectedBodyInstObject->HasMember("attachedsensors") || !(*itConnectedBodyInstObject)["attachedsensors"].IsArray() || (*itConnectedBodyInstObject)["attachedsensors"].Size() == 0) { - continue; - } - std::string connectedBodyObjectPk = GetJsonValueByKey(*itConnectedBodyInstObject, "object_pk"); - rapidjson::Document rConnectedBodyRobotAttachedSensors(rapidjson::kObjectType); - controller->CallGet(str(boost::format("robot/%s/attachedsensor/?format=json")%connectedBodyObjectPk), rConnectedBodyRobotAttachedSensors); - rapidjson::Value& rConnectedBodyAttachedSensors = rConnectedBodyRobotAttachedSensors["attachedsensors"]; - for (rapidjson::Document::ConstValueIterator itConnectedBodyAttachedSensor = rConnectedBodyAttachedSensors.Begin(); itConnectedBodyAttachedSensor != rConnectedBodyAttachedSensors.End(); ++itConnectedBodyAttachedSensor) { - const std::string sensorLinkName = GetJsonValueByKey(*itConnectedBodyAttachedSensor, "linkName"); - allSensorSelectionInfos.emplace_back(sensorName, connectedBodyName+"_"+sensorLinkName); - } - } - } - } - } -} - -void SceneResource::GetInstObjects(std::vector& instobjects) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("scene/%s/instobject/?format=json&limit=0")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - - instobjects.resize(objects.Size()); - size_t iobj = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - InstObjectPtr instobject(new InstObject(controller, GetPrimaryKey(), GetJsonValueByKey(*it, "pk"))); - - LoadJsonValueByKey(*it, "name", instobject->name); - LoadJsonValueByKey(*it, "object_pk", instobject->object_pk); - LoadJsonValueByKey(*it, "reference_object_pk", instobject->reference_object_pk, std::string()); - LoadJsonValueByKey(*it, "reference_uri", instobject->reference_uri); - LoadJsonValueByKey(*it, "dofvalues", instobject->dofvalues); - LoadJsonValueByKey(*it, "quaternion", instobject->quaternion); - LoadJsonValueByKey(*it, "translate", instobject->translate); - - if (it->HasMember("links")) { - rapidjson::Value& jsonlinks = (*it)["links"]; - instobject->links.resize(jsonlinks.Size()); - size_t ilink = 0; - for (rapidjson::Document::ValueIterator itlink = jsonlinks.Begin(); itlink != jsonlinks.End(); ++itlink) { - InstObject::Link& link = instobject->links[ilink]; - LoadJsonValueByKey(*itlink, "name", link.name); - LoadJsonValueByKey(*itlink, "quaternion", link.quaternion); - LoadJsonValueByKey(*itlink, "translate", link.translate); - ilink++; - } - } - - if (it->HasMember("tools")) { - rapidjson::Value& jsontools = (*it)["tools"]; - instobject->tools.resize(jsontools.Size()); - size_t itool = 0; - for (rapidjson::Document::ValueIterator ittool = jsontools.Begin(); ittool != jsontools.End(); ++ittool) { - InstObject::Tool &tool = instobject->tools[itool]; - LoadJsonValueByKey(*ittool, "name", tool.name); - LoadJsonValueByKey(*ittool, "quaternion", tool.quaternion); - LoadJsonValueByKey(*ittool, "translate", tool.translate); - LoadJsonValueByKey(*ittool, "direction", tool.direction); - itool++; - } - } - - if (it->HasMember("grabs")) { - rapidjson::Value& jsongrabs = (*it)["grabs"]; - instobject->grabs.resize(jsongrabs.Size()); - size_t igrab = 0; - for (rapidjson::Document::ValueIterator itgrab = jsongrabs.Begin(); itgrab != jsongrabs.End(); ++itgrab) { - InstObject::Grab &grab = instobject->grabs[igrab]; - LoadJsonValueByKey(*itgrab, "instobjectpk", grab.instobjectpk); - LoadJsonValueByKey(*itgrab, "grabbed_linkpk", grab.grabbed_linkpk); - LoadJsonValueByKey(*itgrab, "grabbing_linkpk", grab.grabbing_linkpk); - igrab++; - } - } - - if (it->HasMember("attachedsensors")) { - rapidjson::Value& jsonattachedsensors = (*it)["attachedsensors"]; - instobject->attachedsensors.resize(jsonattachedsensors.Size()); - size_t iattchedsensor = 0; - for (rapidjson::Document::ValueIterator itsensor = jsonattachedsensors.Begin(); - itsensor != jsonattachedsensors.End(); ++itsensor) { - InstObject::AttachedSensor& sensor = instobject->attachedsensors[iattchedsensor]; - LoadJsonValueByKey(*itsensor, "name", sensor.name); - LoadJsonValueByKey(*itsensor, "quaternion", sensor.quaternion); - LoadJsonValueByKey(*itsensor, "translate", sensor.translate); - iattchedsensor++; - } - } - instobjects.at(iobj++) = instobject; - } -} - -bool SceneResource::FindInstObject(const std::string& name, SceneResource::InstObjectPtr& instobject) -{ - - std::vector instobjects; - this->GetInstObjects(instobjects); - for(size_t i = 0; i < instobjects.size(); ++i) { - if (instobjects[i]->name == name) { - instobject = instobjects[i]; - return true; - } - } - return false; -} - -SceneResource::InstObjectPtr SceneResource::CreateInstObject(const std::string& name, const std::string& referenceUri, const Real quaternion[4], const Real translate[3], double timeout) -{ - GETCONTROLLERIMPL(); - const std::string uri(str(boost::format("scene/%s/instobject/?format=json&fields=pk,object_pk,reference_object_pk,reference_uri,dofvalues,quaternion,translate")%GetPrimaryKey())); - std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); - if (!referenceUri.empty()) { - data += ", \"reference_uri\": \"" + referenceUri + "\""; - } - data += "}"; - - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost(uri, data, pt, 201, timeout); - std::string inst_pk = GetJsonValueByKey(pt, "pk"); - SceneResource::InstObjectPtr instobject(new SceneResource::InstObject(GetController(), GetPrimaryKey(), inst_pk)); - LoadJsonValueByKey(pt, "object_pk", instobject->object_pk); - LoadJsonValueByKey(pt, "reference_object_pk", instobject->reference_object_pk, std::string()); - LoadJsonValueByKey(pt, "reference_uri", instobject->reference_uri); - LoadJsonValueByKey(pt, "dofvalues", instobject->dofvalues); - LoadJsonValueByKey(pt, "quaternion", instobject->quaternion); - LoadJsonValueByKey(pt, "translate", instobject->translate); - return instobject; -} - -void SceneResource::DeleteInstObject(const std::string& pk) -{ - GETCONTROLLERIMPL(); - controller->CallDelete(str(boost::format("scene/%s/instobject/%s/")%GetPrimaryKey()%pk), 204); -} - -SceneResourcePtr SceneResource::Copy(const std::string& name) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost("scene/?format=json", str(boost::format("{\"name\":\"%s\", \"reference_pk\":\"%s\", \"overwrite\": \"1\"}")%name%GetPrimaryKey()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(GetController(), pk)); - return scene; -} - -TaskResource::TaskResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"task",pk) -{ -} - -bool TaskResource::Execute() -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost("job/", str(boost::format("{\"resource_type\":\"task\", \"target_pk\":%s}")%GetPrimaryKey()), pt, 200); - _jobpk = GetJsonValueByKey(pt, "jobpk"); - return true; -} - -void TaskResource::Cancel() -{ - // have to look through all jobs for the task - BOOST_ASSERT(0); -} - -JobStatusCode GetStatusCode(const std::string& str) -{ - MUJIN_LOG_INFO(str); - if (str == "pending") return JSC_Pending; - if (str == "active") return JSC_Active; - if (str == "preempted") return JSC_Preempted; - if (str == "succeeded") return JSC_Succeeded; - if (str == "aborted") return JSC_Aborted; - if (str == "rejected") return JSC_Rejected; - if (str == "preempting") return JSC_Preempting; - if (str == "recalling") return JSC_Recalling; - if (str == "recalled") return JSC_Recalled; - if (str == "lost") return JSC_Lost; - if (str == "unknown") return JSC_Unknown; - throw MUJIN_EXCEPTION_FORMAT("unknown staus %s", str, MEC_InvalidArguments); -} - -void TaskResource::GetRunTimeStatus(JobStatus& status, int options) -{ - status.code = JSC_Unknown; - if( _jobpk.size() > 0 ) { - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); - if( options & 1 ) { - url += std::string(",status_text"); - } - controller->CallGet(url, pt); - //pt.get("error_message") - LoadJsonValueByKey(pt, "pk", status.pk); - //LoadJsonValueByKey(pt, "status", status.code); - status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); - LoadJsonValueByKey(pt, "elapsedtime", status.elapsedtime); - LoadJsonValueByKey(pt, "fname", status.type); - if( options & 1 ) { - LoadJsonValueByKey(pt, "status_text", status.message); - } - } -} - -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF8(const std::string& optimizationname, const std::string& optimizationtype) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=1&name=%s&fields=pk,optimizationtype")%GetPrimaryKey()%controller->EscapeString(optimizationname)), pt); - // optimization exists - if (pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) { - rapidjson::Value& object = pt["objects"][0]; - std::string pk = GetJsonValueByKey(object, "pk"); - std::string currentoptimizationtype = GetJsonValueByKey(object, "optimizationtype"); - if( currentoptimizationtype != optimizationtype ) { - throw MUJIN_EXCEPTION_FORMAT("optimization pk %s exists and has type %s, expected is %s", pk%currentoptimizationtype%optimizationtype, MEC_InvalidState); - } - OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); - return optimization; - } - - pt.SetObject(); - controller->CallPost(str(boost::format("task/%s/optimization/?format=json&fields=pk")%GetPrimaryKey()), str(boost::format("{\"name\":\"%s\", \"optimizationtype\":\"%s\", \"taskpk\":\"%s\"}")%optimizationname%optimizationtype%GetPrimaryKey()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - OptimizationResourcePtr optimization(new OptimizationResource(GetController(), pk)); - return optimization; -} - -OptimizationResourcePtr TaskResource::GetOrCreateOptimizationFromName_UTF16(const std::wstring& optimizationname, const std::string& optimizationtype) -{ - std::string optimizationname_utf8; - utf8::utf16to8(optimizationname.begin(), optimizationname.end(), std::back_inserter(optimizationname_utf8)); - return GetOrCreateOptimizationFromName_UTF8(optimizationname_utf8, optimizationtype); -} - -void TaskResource::GetOptimizationPrimaryKeys(std::vector& optimizationkeys) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/optimization/?format=json&limit=0&fields=pk")%GetPrimaryKey()), pt); - rapidjson::Value& objects = pt["objects"]; - - optimizationkeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - LoadJsonValueByKey(*it, "pk", optimizationkeys[i++]); - } -} - -void TaskResource::GetTaskParameters(ITLPlanningTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/?format=json&fields=taskparameters,tasktype")%GetPrimaryKey()), pt); - std::string tasktype = GetJsonValueByKey(pt, "tasktype"); - if( tasktype != "itlplanning" ) { - throw MUJIN_EXCEPTION_FORMAT("task %s is type %s, expected itlplanning", GetPrimaryKey()%tasktype, MEC_InvalidArguments); - } - rapidjson::Value& taskparametersjson = pt["taskparameters"]; - taskparameters.SetDefaults(); - bool bhasreturnmode = false, bhasreturntostart = false, breturntostart = false; - for (rapidjson::Document::MemberIterator v = taskparametersjson.MemberBegin(); v != taskparametersjson.MemberEnd(); ++v) { - if( std::string(v->name.GetString()) == "startfromcurrent" ) { - taskparameters.startfromcurrent = std::string("True") == v->value.GetString(); - } - else if(std::string(v->name.GetString()) == "returntostart" ) { - bhasreturntostart = true; - breturntostart = std::string("True") == v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "returnmode" ) { - taskparameters.returnmode = v->value.GetString(); - bhasreturnmode = true; - } - else if( std::string(v->name.GetString()) == "ignorefigure" ) { - taskparameters.ignorefigure = std::string("True") == v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "vrcruns" ) { - //taskparameters.vrcruns = boost::lexical_cast(v->value); - LoadJsonValueByKey(taskparametersjson, "vrcruns", taskparameters.vrcruns); - } - else if( std::string(v->name.GetString()) == "unit" ) { - taskparameters.unit = v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "optimizationvalue" ) { - LoadJsonValueByKey(taskparametersjson, "optimizationvalue", taskparameters.optimizationvalue); - //taskparameters.optimizationvalue = boost::lexical_cast(v->second.data()); - } - else if( std::string(v->name.GetString()) == "program" ) { - taskparameters.program = v->value.GetString(); - } - else if( std::string(v->name.GetString()) == "parameters" ) { - taskparameters.parameters = DumpJson(v->value,2); - } - else if( std::string(v->name.GetString()) == "initial_envstate" ) { - ExtractEnvironmentStateFromPTree(v->value, taskparameters.initial_envstate); - } - else if( std::string(v->name.GetString()) == "final_envstate" ) { - ExtractEnvironmentStateFromPTree(v->value, taskparameters.final_envstate); - } - else { - std::stringstream ss; - ss << "unsupported ITL task parameter " << v->name.GetString(); - MUJIN_LOG_ERROR(ss.str()); - } - } - // for back compat - if( !bhasreturnmode && bhasreturntostart ) { - taskparameters.returnmode = breturntostart ? "start" : ""; - } -} - -void TaskResource::SetTaskParameters(const ITLPlanningTaskParameters& taskparameters) -{ - GETCONTROLLERIMPL(); - std::string startfromcurrent = taskparameters.startfromcurrent ? "True" : "False"; - std::string ignorefigure = taskparameters.ignorefigure ? "True" : "False"; - std::string vrcruns = boost::lexical_cast(taskparameters.vrcruns); - - std::stringstream ssinitial_envstate; - if( taskparameters.initial_envstate.size() > 0 ) { - ssinitial_envstate << std::setprecision(std::numeric_limits::digits10+1); - ssinitial_envstate << ", \"initial_envstate\":"; - SerializeEnvironmentStateToJSON(taskparameters.initial_envstate, ssinitial_envstate); - } - std::stringstream ssfinal_envstate; - if( taskparameters.final_envstate.size() > 0 ) { - ssfinal_envstate << std::setprecision(std::numeric_limits::digits10+1); - ssfinal_envstate << ", \"final_envstate\":"; - SerializeEnvironmentStateToJSON(taskparameters.final_envstate, ssfinal_envstate); - } - - // because program will inside string, encode newlines - std::string program; - std::vector< std::pair > serachpairs(3); - serachpairs[0].first = "\""; serachpairs[0].second = "\\\""; - serachpairs[1].first = "\n"; serachpairs[1].second = "\\n"; - serachpairs[2].first = "\r\n"; serachpairs[2].second = "\\n"; - SearchAndReplace(program, taskparameters.program, serachpairs); - std::string taskgoalput = str(boost::format("{\"tasktype\": \"itlplanning\", \"taskparameters\":{\"optimizationvalue\":%f, \"program\":\"%s\", \"parameters\":%s, \"unit\":\"%s\", \"returnmode\":\"%s\", \"startfromcurrent\":\"%s\", \"ignorefigure\":\"%s\", \"vrcruns\":%d %s %s } }")%taskparameters.optimizationvalue%program%taskparameters.parameters%taskparameters.unit%taskparameters.returnmode%startfromcurrent%ignorefigure%vrcruns%ssinitial_envstate.str()%ssfinal_envstate.str()); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("task/%s/?format=json&fields=")%GetPrimaryKey()), taskgoalput, pt); -} - -PlanningResultResourcePtr TaskResource::GetResult() -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("task/%s/result/?format=json&limit=1&optimization=None&fields=pk")%GetPrimaryKey()), pt); - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0) ) { - return PlanningResultResourcePtr(); - } - std::string pk = GetJsonValueByKey(pt["objects"][0], "pk"); - PlanningResultResourcePtr result(new PlanningResultResource(GetController(), pk)); - return result; -} - -OptimizationResource::OptimizationResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"optimization",pk) -{ -} - -void OptimizationResource::Execute(bool bClearOldResults) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallPost(str(boost::format("optimization/%s/")%GetPrimaryKey()), str(boost::format("{\"clear\":%d}")%bClearOldResults), pt, 200); - _jobpk = GetJsonValueByKey(pt, "jobpk"); -} - -void OptimizationResource::Cancel() -{ - BOOST_ASSERT(0); -} - -void OptimizationResource::GetRunTimeStatus(JobStatus& status, int options) -{ - status.code = JSC_Unknown; - if( _jobpk.size() > 0 ) { - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = str(boost::format("job/%s/?format=json&fields=pk,status,fnname,elapsedtime")%_jobpk); - if( options & 1 ) { - url += std::string(",status_text"); - } - controller->CallGet(url, pt); - //pt.get("error_message") - LoadJsonValueByKey(pt, "pk", status.pk); - // LoadJsonValueByKey(pt, "status", status.code); - status.code = GetStatusCode(GetJsonValueByKey(pt, "status")); - LoadJsonValueByKey(pt, "fname", status.type); - LoadJsonValueByKey(pt, "elpasedtime", status.elapsedtime); - if( options & 1 ) { - LoadJsonValueByKey(pt, "status-text", status.message); - } - } -} - -void OptimizationResource::SetOptimizationParameters(const RobotPlacementOptimizationParameters& optparams) -{ - GETCONTROLLERIMPL(); - std::string ignorebasecollision = optparams.ignorebasecollision ? "True" : "False"; - std::string optimizationgoalput = str(boost::format("{\"optimizationtype\":\"robotplacement\", \"optimizationparameters\":{\"targetname\":\"%s\", \"frame\":\"%s\", \"ignorebasecollision\":\"%s\", \"unit\":\"%s\", \"maxrange_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize_\":[ %.15f, %.15f, %.15f, %.15f], \"topstorecandidates\":%d} }")%optparams.targetname%optparams.framename%ignorebasecollision%optparams.unit%optparams.maxrange[0]%optparams.maxrange[1]%optparams.maxrange[2]%optparams.maxrange[3]%optparams.minrange[0]%optparams.minrange[1]%optparams.minrange[2]%optparams.minrange[3]%optparams.stepsize[0]%optparams.stepsize[1]%optparams.stepsize[2]%optparams.stepsize[3]%optparams.topstorecandidates); - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput, pt); -} - -void OptimizationResource::SetOptimizationParameters(const PlacementsOptimizationParameters& optparams) -{ - GETCONTROLLERIMPL(); - std::stringstream optimizationgoalput; - optimizationgoalput << str(boost::format("{\"optimizationtype\":\"placements\", \"optimizationparameters\":{ \"unit\":\"%s\", \"topstorecandidates\":%d")%optparams.unit%optparams.topstorecandidates); - for(size_t itarget = 0; itarget < optparams.targetnames.size(); ++itarget) { - std::string ignorebasecollision = optparams.ignorebasecollisions[itarget] ? "True" : "False"; - std::string suffix; - if( itarget > 0 ) { - suffix = boost::lexical_cast(itarget+1); - } - optimizationgoalput << str(boost::format(", \"targetname%s\":\"%s\", \"frame%s\":\"%s\", \"ignorebasecollision%s\":\"%s\", , \"maxrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"minrange%s_\":[ %.15f, %.15f, %.15f, %.15f], \"stepsize%s_\":[ %.15f, %.15f, %.15f, %.15f]")%suffix%optparams.targetnames[itarget]%suffix%optparams.framenames[itarget]%suffix%ignorebasecollision%suffix%optparams.maxranges[itarget][0]%optparams.maxranges[itarget][1]%optparams.maxranges[itarget][2]%optparams.maxranges[itarget][3]%suffix%optparams.minranges[itarget][0]%optparams.minranges[itarget][1]%optparams.minranges[itarget][2]%optparams.minranges[itarget][3]%suffix%optparams.stepsizes[itarget][0]%optparams.stepsizes[itarget][1]%optparams.stepsizes[itarget][2]%optparams.stepsizes[itarget][3]); - } - optimizationgoalput << "} }"; - rapidjson::Document pt; - controller->CallPutJSON(str(boost::format("optimization/%s/?format=json&fields=")%GetPrimaryKey()), optimizationgoalput.str(), pt); -} - -void OptimizationResource::GetResults(std::vector& results, int startoffset, int num) -{ - GETCONTROLLERIMPL(); - std::string querystring = str(boost::format("optimization/%s/result/?format=json&fields=pk&order_by=task_time&offset=%d&limit=%d")%GetPrimaryKey()%startoffset%num); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(querystring, pt); - if (!(pt.IsObject() && pt.HasMember("objects") && pt["objects"].IsArray() && pt["objects"].Size() > 0)) { - return; - } - rapidjson::Value& objects = pt["objects"]; - results.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - results[i++].reset(new PlanningResultResource(controller, GetJsonValueByKey(*it, "pk"))); - } -} - -PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& resulttype, const std::string& pk) : WebResource(controller,resulttype,pk) -{ -} - -PlanningResultResource::PlanningResultResource(ControllerClientPtr controller, const std::string& pk) : WebResource(controller,"planningresult",pk) -{ -} - -void PlanningResultResource::GetEnvironmentState(EnvironmentState& envstate) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - controller->CallGet(str(boost::format("%s/%s/?format=json&fields=envstate")%GetResourceName()%GetPrimaryKey()), pt); - ExtractEnvironmentStateFromPTree(pt["envstate"], envstate); -} - -void PlanningResultResource::GetAllRawProgramData(std::string& outputdata, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/?type=%s")%GetResourceName()%GetPrimaryKey()%programtype), outputdata); -} - -void PlanningResultResource::GetRobotRawProgramData(std::string& outputdata, const std::string& robotpk, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/program/%s/?type=%s")%GetResourceName()%GetPrimaryKey()%robotpk%programtype), outputdata); -} - -void PlanningResultResource::GetPrograms(RobotControllerPrograms& programs, const std::string& programtype) -{ - GETCONTROLLERIMPL(); - rapidjson::Document pt(rapidjson::kObjectType); - programs.programs.clear(); - controller->CallGet(str(boost::format("%s/%s/program/?format=json&type=%s")%GetResourceName()%GetPrimaryKey()%programtype), pt); - for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { - std::string robotpk = it->name.GetString(); - std::string program = GetJsonValueByKey(it->value, "program"); - std::string currenttype = GetJsonValueByKey(it->value, "type"); - programs.programs[robotpk] = RobotProgramData(program, currenttype); - } -} - -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& pk_) : WebResource(controller, "debug", pk_), pk(pk_) -{ -} - -DebugResource::DebugResource(ControllerClientPtr controller, const std::string& resource, const std::string& pk_) : WebResource(controller, resource, pk_), pk(pk_) -{ -} - -void DebugResource::Download(std::ostream& outputStream, double timeout) -{ - GETCONTROLLERIMPL(); - controller->CallGet(str(boost::format("%s/%s/download/")%GetResourceName()%GetPrimaryKey()), outputStream, 200, timeout); -} - -ControllerClientPtr CreateControllerClient(const std::string& usernamepassword, const std::string& baseurl, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) -{ - return ControllerClientPtr(new ControllerClientImpl(usernamepassword, baseurl, proxyserverport, proxyuserpw, options, timeout)); -} - -void ControllerClientDestroy() -{ - DestroyControllerClient(); -} - -void DestroyControllerClient() -{ -} - -void ComputeMatrixFromTransform(Real matrix[12], const Transform &transform) -{ - throw MujinException("not implemented yet"); -// length2 = numpy.sum(quat**2) -// ilength2 = 2.0/length2 -// qq1 = ilength2*quat[1]*quat[1] -// qq2 = ilength2*quat[2]*quat[2] -// qq3 = ilength2*quat[3]*quat[3] -// T = numpy.eye(4) -// T[0,0] = 1 - qq2 - qq3 -// T[0,1] = ilength2*(quat[1]*quat[2] - quat[0]*quat[3]) -// T[0,2] = ilength2*(quat[1]*quat[3] + quat[0]*quat[2]) -// T[1,0] = ilength2*(quat[1]*quat[2] + quat[0]*quat[3]) -// T[1,1] = 1 - qq1 - qq3 -// T[1,2] = ilength2*(quat[2]*quat[3] - quat[0]*quat[1]) -// T[2,0] = ilength2*(quat[1]*quat[3] - quat[0]*quat[2]) -// T[2,1] = ilength2*(quat[2]*quat[3] + quat[0]*quat[1]) -// T[2,2] = 1 - qq1 - qq2 -} - -void ComputeZXYFromMatrix(Real ZXY[3], Real matrix[12]) -{ - throw MujinException("not implemented yet"); -// if abs(T[2][0]) < 1e-10 and abs(T[2][2]) < 1e-10: -// sinx = T[2][1] -// x = numpy.pi/2 if sinx > 0 else -numpy.pi/2 -// z = 0.0 -// y = numpy.arctan2(sinx*T[1][0],T[0][0]) -// else: -// y = numpy.arctan2(-T[2][0],T[2][2]) -// siny = numpy.sin(y) -// cosy = numpy.cos(y) -// Ryinv = numpy.array([[cosy,0,-siny],[0,1,0],[siny,0,cosy]]) -// Rzx = numpy.dot(T[0:3,0:3],Ryinv) -// x = numpy.arctan2(Rzx[2][1],Rzx[2][2]) -// z = numpy.arctan2(Rzx[1][0],Rzx[0][0]) -// return numpy.array([x,y,z]) -} - -void ComputeZXYFromTransform(Real ZXY[3], const Transform& transform) -{ - throw MujinException("not implemented yet"); - //zxyFromMatrix(matrixFromTransform()) -} - -} From 59ce4d3f3774d7c9c0653c08524bdad08b00b194 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 7 Aug 2023 11:56:10 +0900 Subject: [PATCH 468/477] Integrate the WebstackClientInfo into the WebstackClient --- src/controllerclientimpl.cpp | 2073 ----------------- .../mujincontrollerclient.h | 27 - .../mujinwebstackclientcpp/webstackclient.h | 36 +- src/mujincontrollerclient.cpp | 79 - src/webstackclient.cpp | 161 +- 5 files changed, 186 insertions(+), 2190 deletions(-) delete mode 100644 src/controllerclientimpl.cpp delete mode 100644 src/include/mujinwebstackclientcpp/mujincontrollerclient.h delete mode 100644 src/mujincontrollerclient.cpp diff --git a/src/controllerclientimpl.cpp b/src/controllerclientimpl.cpp deleted file mode 100644 index 459c6efc..00000000 --- a/src/controllerclientimpl.cpp +++ /dev/null @@ -1,2073 +0,0 @@ -// -*- coding: utf-8 -*- -// Copyright (C) 2012-2013 MUJIN Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "common.h" -#include "controllerclientimpl.h" - -#include -#include -#include -#include - -#define SKIP_PEER_VERIFICATION // temporary -//#define SKIP_HOSTNAME_VERIFICATION - -#include "logging.h" - -MUJIN_LOGGER("mujin.controllerclientcpp"); - -#define CURL_OPTION_SAVER(curl, curlopt, curvalue) boost::shared_ptr __curloptionsaver ## curlopt((void*)0, boost::bind(boost::function(curl_easy_setopt), curl, curlopt, curvalue)) -#define CURL_OPTION_SETTER(curl, curlopt, newvalue) CHECKCURLCODE(curl_easy_setopt(curl, curlopt, newvalue), "curl_easy_setopt " # curlopt) -#define CURL_OPTION_SAVE_SETTER(curl, curlopt, curvalue, newvalue) CURL_OPTION_SAVER(curl, curlopt, curvalue); CURL_OPTION_SETTER(curl, curlopt, newvalue) -#define CURL_INFO_GETTER(curl, curlinfo, outvalue) CHECKCURLCODE(curl_easy_getinfo(curl, curlinfo, outvalue), "curl_easy_getinfo " # curlinfo) -#define CURL_PERFORM(curl) CHECKCURLCODE(curl_easy_perform(curl), "curl_easy_perform") -#define CURL_FORM_RELEASER(form) boost::shared_ptr __curlformreleaser ## form((void*)0, boost::bind(boost::function(curl_formfree), form)) - -namespace mujinclient { - -using namespace mujinjson; - -/// \brief given a port string "80", fill ControllerClientInfo httpPort -static void _ParseClientInfoPort(const char* port, size_t length, ControllerClientInfo& clientInfo) -{ - clientInfo.httpPort = 0; - for (; length > 0; ++port, --length) { - clientInfo.httpPort = clientInfo.httpPort * 10 + (*port - '0'); - } -} - -/// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse ControllerClientInfo -static void _ParseClientInfoFromURL(const char* url, ControllerClientInfo& clientInfo) -{ - clientInfo.Reset(); - const char* colonSlashSlash = strstr(url, "://"); - if (colonSlashSlash == nullptr) { - return; - } - const char* hostname = colonSlashSlash + sizeof("://") - 1; - const char* at = strstr(hostname, "@"); // not found is ok - const char* slash = strstr(hostname, "/"); // not found is ok - if (at != nullptr && (slash == nullptr || at < slash)) { - // if the at is before the slash, i.e. for the username:password - const char* usernamePassword = hostname; - hostname = at + sizeof("@") - 1; - const char* colon = strstr(usernamePassword, ":"); // not found is ok - if (colon != nullptr) { - const char* password = colon + sizeof(":") - 1; - clientInfo.username = std::string(usernamePassword, colon - usernamePassword); - clientInfo.password = std::string(password, at - password); - } else { - clientInfo.username = std::string(usernamePassword, at - usernamePassword); - } - } - const char* port = strstr(hostname, ":"); // not found is ok - if (slash == nullptr) { - if (port == nullptr) { - // no port, no slash - clientInfo.host = hostname; - } else { - // has port, no slash - const char* portStart = port + sizeof(":") - 1; - _ParseClientInfoPort(portStart, strlen(portStart), clientInfo); - clientInfo.host = std::string(hostname, port - hostname); - } - } else { - if (port != nullptr && port < slash) { - // has port before slash - const char* portStart = port + sizeof(":") - 1; - _ParseClientInfoPort(portStart, slash - portStart, clientInfo); - clientInfo.host = std::string(hostname, port - hostname); - } else { - // no port, but has slash - clientInfo.host = std::string(hostname, slash - hostname); - } - } -} - -template -std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function& ConvertToFileSystemEncoding) -{ - // scenefilenames is the WPJ file, so have to open it up to see what directory it points to - // note that the encoding is utf-16 - // - // .\threegoaltouch\threegoaltouch.WCN; - // - // first have to get the raw utf-16 data -#if defined(_WIN32) || defined(_WIN64) - std::ifstream wpjfilestream(sourcefilename.c_str(), std::ios::binary|std::ios::in); -#else - // linux doesn't mix ifstream and wstring - std::ifstream wpjfilestream(ConvertToFileSystemEncoding(sourcefilename).c_str(), std::ios::binary|std::ios::in); -#endif - if( !wpjfilestream ) { - throw MUJIN_EXCEPTION_FORMAT("failed to open file %s", ConvertToFileSystemEncoding(sourcefilename), MEC_InvalidArguments); - } - std::wstringstream utf16stream; - bool readbom = false; - while(!wpjfilestream.eof() ) { - unsigned short c; - wpjfilestream.read(reinterpret_cast(&c),sizeof(c)); - if( !wpjfilestream ) { - break; - } - // skip the first character (BOM) due to a bug in boost property_tree (should be fixed in 1.49) - if( readbom || c != 0xfeff ) { - utf16stream << static_cast(c); - } - else { - readbom = true; - } - } - boost::property_tree::wptree wpj; - boost::property_tree::read_xml(utf16stream, wpj); - boost::property_tree::wptree& clsProject = wpj.get_child(L"clsProject"); - boost::property_tree::wptree& WCNPath = clsProject.get_child(L"WCNPath"); - std::wstring strWCNPath = WCNPath.data(); - if( strWCNPath.size() > 0 ) { - // post process the string to get the real filesystem directory - if( strWCNPath.at(strWCNPath.size()-1) == L';') { - strWCNPath.resize(strWCNPath.size()-1); - } - - if( strWCNPath.size() >= 2 && (strWCNPath[0] == L'.' && strWCNPath[1] == L'\\') ) { - // don't need the prefix - strWCNPath = strWCNPath.substr(2); - } - } - - return strWCNPath; -} - -ControllerClientImpl::ControllerClientImpl(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) -{ - BOOST_ASSERT( !baseuri.empty() ); - const size_t usernameindex = usernamepassword.find_first_of(':'); - BOOST_ASSERT(usernameindex != std::string::npos ); - _username = usernamepassword.substr(0, usernameindex); - const std::string password = usernamepassword.substr(usernameindex + 1); - - _httpheadersjson = NULL; - _httpheadersstl = NULL; - _httpheadersmultipartformdata = NULL; - - size_t authorityindex = baseuri.find("//"); - if( authorityindex != std::string::npos ) { - _fulluri = baseuri.substr(0,authorityindex+2) + usernamepassword + "@" + baseuri.substr(authorityindex+2); - } - else { - // no idea what to do here.. - _fulluri = std::string("//") + usernamepassword + "@" + baseuri; - } - - _ParseClientInfoFromURL(baseuri.c_str(), _clientInfo); - _clientInfo.username = _username; - _clientInfo.password = password; - - _baseuri = baseuri; - // ensure trailing slash - if( _baseuri[_baseuri.size()-1] != '/' ) { - _baseuri.push_back('/'); - } - _baseapiuri = _baseuri + std::string("api/v1/"); - // hack for now since webdav server and api server could be running on different ports - if( boost::algorithm::ends_with(_baseuri, ":8000/") || (options&0x80000000) ) { - // testing on localhost, however the webdav server is running on port 80... - _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%_username); - } - else { - _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_username); - } - - //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); - _curl = curl_easy_init(); - BOOST_ASSERT(!!_curl); - -#ifdef _DEBUG - // CURL_OPTION_SETTER(_curl, CURLOPT_VERBOSE, 1L); -#endif - _errormessage.resize(CURL_ERROR_SIZE); - CURL_OPTION_SETTER(_curl, CURLOPT_ERRORBUFFER, &_errormessage[0]); - -#ifdef SKIP_PEER_VERIFICATION - /* - * if you want to connect to a site who isn't using a certificate that is - * signed by one of the certs in the ca bundle you have, you can skip the - * verification of the server's certificate. this makes the connection - * a lot less secure. - * - * if you have a ca cert for the server stored someplace else than in the - * default bundle, then the curlopt_capath option might come handy for - * you. - */ - CURL_OPTION_SETTER(_curl, CURLOPT_SSL_VERIFYPEER, 0L); -#endif - -#ifdef SKIP_HOSTNAME_VERIFICATION - /* - * If the site you're connecting to uses a different host name that what - * they have mentioned in their server certificate's commonName (or - * subjectAltName) fields, libcurl will refuse to connect. You can skip - * this check, but this will make the connection less secure. - */ - CURL_OPTION_SETTER(_curl, CURLOPT_SSL_VERIFYHOST, 0L); -#endif - - if( proxyserverport.size() > 0 ) { - SetProxy(proxyserverport, proxyuserpw); - } - - CURL_OPTION_SETTER(_curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - CURL_OPTION_SETTER(_curl, CURLOPT_USERPWD, usernamepassword.c_str()); - - // need to set the following? - //CURLOPT_USERAGENT - //CURLOPT_TCP_KEEPIDLE - //CURLOPT_TCP_KEEPALIVE - //CURLOPT_TCP_KEEPINTVL - - CURL_OPTION_SETTER(_curl, CURLOPT_COOKIEFILE, ""); // just to start the cookie engine - - // save everything to _buffer, neceesary to do it before first POST/GET calls or data will be output to stdout - // these should be set on individual calls - // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEFUNCTION, _WriteStringStreamCallback); // just to start the cookie engine - // CURL_OPTION_SETTER(_curl, CURLOPT_WRITEDATA, &_buffer); - - std::string useragent = std::string("controllerclientcpp/")+MUJINCLIENT_VERSION_STRING; - CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, useragent.c_str()); - - CURL_OPTION_SETTER(_curl, CURLOPT_FOLLOWLOCATION, 1L); // we can always follow redirect now, we don't need to detect login page - CURL_OPTION_SETTER(_curl, CURLOPT_MAXREDIRS, 10L); - CURL_OPTION_SETTER(_curl, CURLOPT_NOSIGNAL, 1L); - - CURL_OPTION_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0L); - CURL_OPTION_SETTER(_curl, CURLOPT_POSTFIELDS, NULL); - - // csrftoken can be any non-empty string - _csrfmiddlewaretoken = "csrftoken"; - std::string cookie = "Set-Cookie: csrftoken=" + _csrfmiddlewaretoken; -#if CURL_AT_LEAST_VERSION(7,60,0) - // with https://github.com/curl/curl/commit/b8d5036ec9b702d6392c97a6fc2e141d6c7cce1f, setting domain param to cookie is required. - if(_baseuri.find('/') == _baseuri.size()-1) { - // _baseuri should be hostname with trailing slash - cookie += "; domain="; - cookie += _baseuri.substr(0,_baseuri.size()-1); - } else { - CURLU *url = curl_url(); - BOOST_SCOPE_EXIT_ALL(&url) { - curl_url_cleanup(url); - }; - CHECKCURLUCODE(curl_url_set(url, CURLUPART_URL, _baseuri.c_str(), 0), "cannot parse url"); - char *host = NULL; - BOOST_SCOPE_EXIT_ALL(&host) { - if(host) { - curl_free(host); - } - }; - CHECKCURLUCODE(curl_url_get(url, CURLUPART_HOST, &host, 0), "cannot determine hostname from url"); - cookie += "; domain="; - cookie += host; - } -#endif - CURL_OPTION_SETTER(_curl, CURLOPT_COOKIELIST, cookie.c_str()); - - _charset = "utf-8"; - _language = "en-us"; -#if defined(_WIN32) || defined(_WIN64) - UINT codepage = GetACP(); - std::map::const_iterator itcodepage = encoding::GetCodePageMap().find(codepage); - if( itcodepage != encoding::GetCodePageMap().end() ) { - _charset = itcodepage->second; - } -#endif - MUJIN_LOG_VERBOSE("setting character set to " << _charset); - _SetupHTTPHeadersJSON(); - _SetupHTTPHeadersSTL(); - _SetupHTTPHeadersMultipartFormData(); -} - -ControllerClientImpl::~ControllerClientImpl() -{ - if( !!_httpheadersjson ) { - curl_slist_free_all(_httpheadersjson); - } - if( !!_httpheadersstl ) { - curl_slist_free_all(_httpheadersstl); - } - if( !!_httpheadersmultipartformdata ) { - curl_slist_free_all(_httpheadersmultipartformdata); - } - curl_easy_cleanup(_curl); -} - -std::string ControllerClientImpl::GetVersion() -{ - if (!_profile.IsObject()) { - _profile.SetObject(); - CallGet("profile/", _profile); - } - return GetJsonValueByKey(_profile, "version"); -} - -const std::string& ControllerClientImpl::GetUserName() const -{ - return _username; -} - -const std::string& ControllerClientImpl::GetBaseURI() const -{ - return _baseuri; -} - -const ControllerClientInfo& ControllerClientImpl::GetClientInfo() const -{ - return _clientInfo; -} - -void ControllerClientImpl::SetCharacterEncoding(const std::string& newencoding) -{ - boost::mutex::scoped_lock lock(_mutex); - _charset = newencoding; - _SetupHTTPHeadersJSON(); - // the following two format does not need charset - // _SetupHTTPHeadersSTL(); - // _SetupHTTPHeadersMultipartFormData(); -} - -void ControllerClientImpl::SetProxy(const std::string& serverport, const std::string& userpw) -{ - // mutally exclusive with unix endpoint settings - CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, NULL); - CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, serverport.c_str()); - CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); - _clientInfo.unixEndpoint.clear(); -} - -void ControllerClientImpl::SetUnixEndpoint(const std::string& unixendpoint) -{ - // mutually exclusive with proxy settings - CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); - CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, NULL); - CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); - _clientInfo.unixEndpoint = unixendpoint; -} - -void ControllerClientImpl::SetLanguage(const std::string& language) -{ - boost::mutex::scoped_lock lock(_mutex); - if (language!= "") { - _language = language; - } - _SetupHTTPHeadersJSON(); - // the following two format does not need language - // _SetupHTTPHeadersSTL(); - // _SetupHTTPHeadersMultipartFormData(); -} - -void ControllerClientImpl::SetUserAgent(const std::string& userAgent) -{ - CURL_OPTION_SETTER(_curl, CURLOPT_USERAGENT, userAgent.c_str()); -} - -void ControllerClientImpl::SetAdditionalHeaders(const std::vector& additionalHeaders) -{ - boost::mutex::scoped_lock lock(_mutex); - _additionalHeaders = additionalHeaders; - _clientInfo.additionalHeaders = additionalHeaders; - _SetupHTTPHeadersJSON(); - _SetupHTTPHeadersSTL(); - _SetupHTTPHeadersMultipartFormData(); -} - -void ControllerClientImpl::_ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout, bool checkForErrors, bool returnRawResponse) -{ - rResult.SetNull(); // zero output - - rapidjson::Value rResultDoc; - - { - boost::mutex::scoped_lock lock(_mutex); - - rapidjson::StringBuffer& rRequestStringBuffer = _rRequestStringBufferCache; - rRequestStringBuffer.Clear(); - - { - // use the callers allocator to construct the request body - rapidjson::Value rRequest, rValue; - rRequest.SetObject(); - rValue.SetString(operationName, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("operationName"), rValue, rAlloc); - rValue.SetString(query, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("query"), rValue, rAlloc); - rValue.CopyFrom(rVariables, rAlloc); - rRequest.AddMember(rapidjson::Document::StringRefType("variables"), rValue, rAlloc); - - rapidjson::Writer writer(rRequestStringBuffer); - rRequest.Accept(writer); - } - - _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, rAlloc, 200, timeout); - } - - // parse response - if (!rResultDoc.IsObject()) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not return valid response \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } - - if (checkForErrors) { - // look for errors in response - const rapidjson::Value::ConstMemberIterator itErrors = rResultDoc.FindMember("errors"); - if (itErrors != rResultDoc.MemberEnd() && itErrors->value.IsArray() && itErrors->value.Size() > 0) { - MUJIN_LOG_VERBOSE(str(boost::format("graph query has errors \"%s\": %s")%operationName%mujinjson::DumpJson(rResultDoc))); - for (rapidjson::Value::ConstValueIterator itError = itErrors->value.Begin(); itError != itErrors->value.End(); ++itError) { - const rapidjson::Value& rError = *itError; - if (rError.IsObject() && rError.HasMember("message") && rError["message"].IsString()) { - const char* errorCode = "unknown"; - const rapidjson::Value::ConstMemberIterator itExtensions = rError.FindMember("extensions"); - if (itExtensions != rError.MemberEnd() && itExtensions->value.IsObject() && itExtensions->value.HasMember("errorCode") && itExtensions->value["errorCode"].IsString()) { - errorCode = itExtensions->value["errorCode"].GetString(); - } - throw mujinclient::MujinGraphQueryError(boost::str(boost::format("[%s:%d] graph query has errors \"%s\": %s")%(__PRETTY_FUNCTION__)%(__LINE__)%operationName%rError["message"].GetString()), errorCode); - } - } - throw MUJIN_EXCEPTION_FORMAT("graph query has undefined errors \"%s\": %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } - } - - // should have data member - if (!rResultDoc.HasMember("data")) { - throw MUJIN_EXCEPTION_FORMAT("Execute graph query does not have 'data' field in \"%s\", invalid response: %s", operationName%mujinjson::DumpJson(rResultDoc), MEC_HTTPServer); - } - - // set output - if (returnRawResponse) { - rResult.Swap(rResultDoc); - } else { - rResult = rResultDoc["data"]; - } -} - -void ControllerClientImpl::ExecuteGraphQuery(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) -{ - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, true, false); -} - -void ControllerClientImpl::ExecuteGraphQueryRaw(const char* operationName, const char* query, const rapidjson::Value& rVariables, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& rAlloc, double timeout) -{ - _ExecuteGraphQuery(operationName, query, rVariables, rResult, rAlloc, timeout, false, true); -} - -void ControllerClientImpl::RestartServer(double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - _uri = _baseuri + std::string("restartserver/"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT0("Failed to restart server, please try again or contact MUJIN support", MEC_HTTPServer); - } -} - -void ControllerClientImpl::CancelAllJobs() -{ - CallDelete("job/?format=json", 204); -} - -void ControllerClientImpl::GetRunTimeStatuses(std::vector& statuses, int options) -{ - rapidjson::Document pt(rapidjson::kObjectType); - std::string url = "job/?format=json&fields=pk,status,fnname,elapsedtime"; - if( options & 1 ) { - url += std::string(",status_text"); - } - CallGet(url, pt); - rapidjson::Value& objects = pt["objects"]; - size_t i = 0; - statuses.resize(objects.Size()); - for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { - - statuses[i].pk = GetJsonValueByKey(*it, "pk"); - statuses[i].code = GetStatusCode(GetJsonValueByKey(*it, "status")); - statuses[i].type = GetJsonValueByKey(*it, "fnname"); - statuses[i].elapsedtime = GetJsonValueByKey(*it, "elapsedtime"); - if( options & 1 ) { - statuses[i].message = GetJsonValueByKey(*it, "status_text"); - } - i++; - } -} - -void ControllerClientImpl::GetScenePrimaryKeys(std::vector& scenekeys) -{ - rapidjson::Document pt(rapidjson::kObjectType); - CallGet("scene/?format=json&limit=0&fields=pk", pt); - rapidjson::Value& objects = pt["objects"]; - scenekeys.resize(objects.Size()); - size_t i = 0; - for (rapidjson::Document::ValueIterator it=objects.Begin(); it != objects.End(); ++it) { - scenekeys[i++] = GetJsonValueByKey(*it, "pk"); - } -} - -SceneResourcePtr ControllerClientImpl::RegisterScene_UTF8(const std::string& uri, const std::string& scenetype) -{ - BOOST_ASSERT(scenetype.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF8("scene/?format=json&fields=pk", str(boost::format("{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} - -SceneResourcePtr ControllerClientImpl::RegisterScene_UTF16(const std::wstring& uri, const std::string& scenetype) -{ - BOOST_ASSERT(scenetype.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF16("scene/?format=json&fields=pk", str(boost::wformat(L"{\"uri\":\"%s\", \"scenetype\":\"%s\"}")%uri%scenetype.c_str()), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} - -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF8(const std::string& importuri, const std::string& importformat, const std::string& newuri, bool overwrite) -{ - BOOST_ASSERT(importformat.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF8(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::format("{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat%newuri), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} - -SceneResourcePtr ControllerClientImpl::ImportSceneToCOLLADA_UTF16(const std::wstring& importuri, const std::string& importformat, const std::wstring& newuri, bool overwrite) -{ - BOOST_ASSERT(importformat.size()>0); - rapidjson::Document pt(rapidjson::kObjectType); - CallPost_UTF16(str(boost::format("scene/?format=json&fields=pk&overwrite=%d")%overwrite), str(boost::wformat(L"{\"reference_uri\":\"%s\", \"reference_scenetype\":\"%s\", \"uri\":\"%s\"}")%importuri%importformat.c_str()%newuri), pt); - std::string pk = GetJsonValueByKey(pt, "pk"); - SceneResourcePtr scene(new SceneResource(shared_from_this(), pk)); - return scene; -} - -void ControllerClientImpl::SyncUpload_UTF8(const std::string& _sourcefilename, const std::string& destinationdir, const std::string& scenetype) -{ - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? - boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - if( destinationdir.size() >= 7 && destinationdir.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - baseuploaduri += _EncodeWithoutSeparator(destinationdir.substr(7)); - _EnsureWebDAVDirectories(destinationdir.substr(7)); - } - else { - baseuploaduri = destinationdir; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - - std::string sourcefilename = _sourcefilename; -#if defined(_WIN32) || defined(_WIN64) - // check if / is used anywhere and send a warning if it is - if( sourcefilename.find_first_of('/') != std::string::npos ) { - std::stringstream ss; - ss << "scene filename '" << sourcefilename << "' is using /, so replacing this with \\"; - MUJIN_LOG_INFO(ss.str()); - for(size_t i = 0; i < sourcefilename.size(); ++i) { - if( sourcefilename[i] == '/' ) { - sourcefilename[i] = '\\'; - } - } - } -#endif - - size_t nBaseFilenameStartIndex = sourcefilename.find_last_of(s_filesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename, encoding::ConvertUTF8ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNPath; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNPath)); - std::string strWCNURI = strWCNPath; - size_t lastindex = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - strWCNPath[i] = s_filesep; - lastindex = i; - } - } - std::string sCopyDir = sourcefilename.substr(0,nBaseFilenameStartIndex) + strWCNPath.substr(0,lastindex); - _UploadDirectoryToController_UTF8(sCopyDir, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex))); - } - } - else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - if( nBaseFilenameStartIndex > 0 ) { - // sourcefilename[nBaseFilenameStartIndex] should be == s_filesep - _UploadDirectoryToController_UTF8(sourcefilename.substr(0,nBaseFilenameStartIndex), baseuploaduri); - } - return; - } - - // sourcefilenamebase is utf-8 - std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilename.substr(nBaseFilenameStartIndex)); - _UploadFileToController_UTF8(sourcefilename, uploadfileuri); - - /* webdav operations - const char *postdata = - "" - "SELECT \"http://schemas.microsoft.com/repl/contenttag\"" - " from SCOPE ('deep traversal of \"/exchange/adb/Calendar/\"') " - "WHERE \"DAV:isfolder\" = True\r\n"; - */ -} - -void ControllerClientImpl::SyncUpload_UTF16(const std::wstring& _sourcefilename_utf16, const std::wstring& destinationdir_utf16, const std::string& scenetype) -{ - // TODO use curl_multi_perform to allow uploading of multiple files simultaneously - // TODO should LOCK with WebDAV repository? - boost::mutex::scoped_lock lock(_mutex); - std::string baseuploaduri; - std::string destinationdir_utf8; - utf8::utf16to8(destinationdir_utf16.begin(), destinationdir_utf16.end(), std::back_inserter(destinationdir_utf8)); - - if( destinationdir_utf8.size() >= 7 && destinationdir_utf8.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - std::string s = destinationdir_utf8.substr(7); - baseuploaduri += _EncodeWithoutSeparator(s); - _EnsureWebDAVDirectories(s); - } - else { - baseuploaduri = destinationdir_utf8; - } - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - - std::wstring sourcefilename_utf16 = _sourcefilename_utf16; -#if defined(_WIN32) || defined(_WIN64) - // check if / is used anywhere and send a warning if it is - if( sourcefilename_utf16.find_first_of(L'/') != std::wstring::npos ) { - std::stringstream ss; - ss << "scene filename '" << encoding::ConvertUTF16ToFileSystemEncoding(sourcefilename_utf16) << "' is using /, so replacing this with \\"; - MUJIN_LOG_INFO(ss.str()); - for(size_t i = 0; i < sourcefilename_utf16.size(); ++i) { - if( sourcefilename_utf16[i] == L'/' ) { - sourcefilename_utf16[i] = L'\\'; - } - } - - boost::replace_all(sourcefilename_utf16, L"/", L"\\"); - } -#endif - - size_t nBaseFilenameStartIndex = sourcefilename_utf16.find_last_of(s_wfilesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - - if( scenetype == "wincaps" ) { - std::wstring strWCNPath_utf16 = ParseWincapsWCNPath(sourcefilename_utf16, encoding::ConvertUTF16ToFileSystemEncoding); - if( strWCNPath_utf16.size() > 0 ) { - std::string strWCNURI; - utf8::utf16to8(strWCNPath_utf16.begin(), strWCNPath_utf16.end(), std::back_inserter(strWCNURI)); - size_t lastindex_utf8 = 0; - for(size_t i = 0; i < strWCNURI.size(); ++i) { - if( strWCNURI[i] == '\\' ) { - strWCNURI[i] = '/'; - lastindex_utf8 = i; - } - } - size_t lastindex_utf16 = 0; - for(size_t i = 0; i < strWCNPath_utf16.size(); ++i) { - if( strWCNPath_utf16[i] == '\\' ) { - strWCNPath_utf16[i] = s_wfilesep; - lastindex_utf16 = i; - } - } - std::wstring sCopyDir_utf16 = sourcefilename_utf16.substr(0,nBaseFilenameStartIndex) + strWCNPath_utf16.substr(0,lastindex_utf16); - _UploadDirectoryToController_UTF16(sCopyDir_utf16, baseuploaduri+_EncodeWithoutSeparator(strWCNURI.substr(0,lastindex_utf8))); - } - } - else if( scenetype == "rttoolbox" || scenetype == "cecrobodiaxml" ) { - if( nBaseFilenameStartIndex > 0 ) { - // sourcefilename_utf16[nBaseFilenameStartIndex] should be == s_filesep - _UploadDirectoryToController_UTF16(sourcefilename_utf16.substr(0,nBaseFilenameStartIndex), baseuploaduri); - } - return; - } - - // sourcefilenamebase is utf-8 - std::string sourcefilenamedir_utf8; - utf8::utf16to8(sourcefilename_utf16.begin()+nBaseFilenameStartIndex, sourcefilename_utf16.end(), std::back_inserter(sourcefilenamedir_utf8)); - std::string uploadfileuri = baseuploaduri + EscapeString(sourcefilenamedir_utf8); - _UploadFileToController_UTF16(sourcefilename_utf16, uploadfileuri); -} - -/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::CallGet(const std::string& relativeuri, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - return _CallGet(_uri, pt, pt.GetAllocator(), expectedhttpcode, timeout); -} - -int ControllerClientImpl::_CallGet(const std::string& desturi, rapidjson::Value& rResponse, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_DEBUG(str(boost::format("GET %s")%desturi)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( _buffer.rdbuf()->in_avail() > 0 ) { - mujinjson::ParseJson(rResponse, alloc, _buffer); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(rResponse, "error_message"); - std::string traceback = GetJsonValueByKey(rResponse, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); - } - return http_code; -} - -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::string& outputdata, int expectedhttpcode, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - return _CallGet(_uri, outputdata, expectedhttpcode, timeout); -} - -int ControllerClientImpl::_CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - outputdata = _buffer.str(); - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - if( outputdata.size() > 0 ) { - rapidjson::Document d; - ParseJson(d, _buffer.str()); - std::string error_message = GetJsonValueByKey(d, "error_message"); - std::string traceback = GetJsonValueByKey(d, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); - } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); - } - return http_code; -} - -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::ostream& outputStream, int expectedhttpcode, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - return _CallGet(_uri, outputStream, expectedhttpcode, timeout); -} - -int ControllerClientImpl::_CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteOStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &outputStream); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - // outputStream is not always seekable; ignore any error message. - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s (outputStream might have information)", desturi%http_code, MEC_HTTPServer); - } - return http_code; -} - -int ControllerClientImpl::CallGet(const std::string& relativeuri, std::vector& outputdata, int expectedhttpcode, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - return _CallGet(_uri, outputdata, expectedhttpcode, timeout); -} - -int ControllerClientImpl::_CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_VERBOSE(str(boost::format("GET %s")%desturi)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteVectorCallback); - outputdata.resize(0); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &outputdata); - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPGET, 0L, 1L); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - if( outputdata.size() > 0 ) { - rapidjson::Document d; - std::stringstream ss; - ss.write((const char*)&outputdata[0], outputdata.size()); - ParseJson(d, ss.str()); - std::string error_message = GetJsonValueByKey(d, "error_message"); - std::string traceback = GetJsonValueByKey(d, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); - } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); - } - return http_code; -} - -/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::CallPost(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_DEBUG(str(boost::format("POST %s%s")%_baseapiuri%relativeuri)); - boost::mutex::scoped_lock lock(_mutex); - _uri = _baseapiuri; - _uri += relativeuri; - return _CallPost(_uri, data, pt, pt.GetAllocator(), expectedhttpcode, timeout); -} - -/// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int ControllerClientImpl::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_VERBOSE(str(boost::format("POST %s")%desturi)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POST, 0L, 1L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0, data.size()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDS, NULL, data.size() > 0 ? data.c_str() : NULL); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(rResult, alloc, _buffer); - } else { - rResult.SetObject(); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(rResult, "error_message"); - std::string traceback = GetJsonValueByKey(rResult, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); - } - return http_code; -} - -int ControllerClientImpl::CallPost_UTF8(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return CallPost(relativeuri, encoding::ConvertUTF8ToFileSystemEncoding(data), pt, expectedhttpcode, timeout); -} - -int ControllerClientImpl::CallPost_UTF16(const std::string& relativeuri, const std::wstring& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return CallPost(relativeuri, encoding::ConvertUTF16ToFileSystemEncoding(data), pt, expectedhttpcode, timeout); -} - -int ControllerClientImpl::_CallPut(const std::string& relativeuri, const void* pdata, size_t nDataSize, rapidjson::Document& pt, curl_slist* headers, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_DEBUG(str(boost::format("PUT %s%s")%_baseapiuri%relativeuri)); - boost::mutex::scoped_lock lock(_mutex); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, headers); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - _uri = _baseapiuri; - _uri += relativeuri; - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "PUT"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDSIZE, 0, nDataSize); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_POSTFIELDS, NULL, pdata); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(pt, _buffer.str()); - } else { - pt.SetObject(); - } - if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP PUT to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } - return http_code; -} - -int ControllerClientImpl::CallPutSTL(const std::string& relativeuri, const std::vector& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return _CallPut(relativeuri, static_cast (&data[0]), data.size(), pt, _httpheadersstl, expectedhttpcode, timeout); -} - -int ControllerClientImpl::CallPutJSON(const std::string& relativeuri, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) -{ - return _CallPut(relativeuri, static_cast(&data[0]), data.size(), pt, _httpheadersjson, expectedhttpcode, timeout); -} - -void ControllerClientImpl::CallDelete(const std::string& relativeuri, int expectedhttpcode, double timeout) -{ - MUJIN_LOG_DEBUG(str(boost::format("DELETE %s%s")%_baseapiuri%relativeuri)); - boost::mutex::scoped_lock lock(_mutex); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - _uri = _baseapiuri; - _uri += relativeuri; - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "DELETE"); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != expectedhttpcode ) { - rapidjson::Document d; - ParseJson(d, _buffer.str()); - std::string error_message = GetJsonValueByKey(d, "error_message"); - std::string traceback = GetJsonValueByKey(d, "traceback"); - throw MUJIN_EXCEPTION_FORMAT("HTTP DELETE to '%s' returned HTTP status %s: %s", relativeuri%http_code%error_message, MEC_HTTPServer); - } -} - -std::stringstream& ControllerClientImpl::GetBuffer() -{ - return _buffer; -} - -void ControllerClientImpl::SetDefaultSceneType(const std::string& scenetype) -{ - _defaultscenetype = scenetype; -} - -const std::string& ControllerClientImpl::GetDefaultSceneType() -{ - return _defaultscenetype; -} - -void ControllerClientImpl::SetDefaultTaskType(const std::string& tasktype) -{ - _defaulttasktype = tasktype; -} - -const std::string& ControllerClientImpl::GetDefaultTaskType() -{ - return _defaulttasktype; -} - -std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF8(const std::string& uri) -{ - size_t index = uri.find(":/"); - if (index == std::string::npos) { - throw MUJIN_EXCEPTION_FORMAT("bad URI: %s", uri, MEC_InvalidArguments); - } - return EscapeString(uri.substr(index+2)); -} - -std::string ControllerClientImpl::GetScenePrimaryKeyFromURI_UTF16(const std::wstring& uri) -{ - std::string utf8line; - utf8::utf16to8(uri.begin(), uri.end(), std::back_inserter(utf8line)); - return GetScenePrimaryKeyFromURI_UTF8(utf8line); -} - -std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF8(const std::string& name) -{ - return EscapeString(name); -} - -std::string ControllerClientImpl::GetPrimaryKeyFromName_UTF16(const std::wstring& name) -{ - std::string name_utf8; - utf8::utf16to8(name.begin(), name.end(), std::back_inserter(name_utf8)); - return GetPrimaryKeyFromName_UTF8(name_utf8); -} - -std::string ControllerClientImpl::GetNameFromPrimaryKey_UTF8(const std::string& pk) -{ - return UnescapeString(pk); -} - -std::wstring ControllerClientImpl::GetNameFromPrimaryKey_UTF16(const std::string& pk) -{ - std::string utf8 = GetNameFromPrimaryKey_UTF8(pk); - std::wstring utf16; - utf8::utf8to16(utf8.begin(), utf8.end(), std::back_inserter(utf16)); - return utf16; -} - -std::string ControllerClientImpl::CreateObjectGeometry(const std::string& objectPk, const std::string& geometryName, const std::string& linkPk, const std::string& geomtype, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string geometryData("{\"name\":\"" + geometryName + "\", \"linkpk\":\"" + linkPk + "\", \"geomtype\": \"" + geomtype + "\"}"); - const std::string uri(str(boost::format("object/%s/geometry/") % objectPk)); - - CallPost(uri, geometryData, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::CreateIkParam(const std::string& objectPk, const std::string& name, const std::string& iktype, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string ikparamData("{\"name\":\"" + name + "\", \"iktype\":\"" + iktype + "\"}"); - const std::string uri(str(boost::format("object/%s/ikparam/") % objectPk)); - - CallPost(uri, ikparamData, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::CreateLink(const std::string& objectPk, const std::string& parentlinkPk, const std::string& name, const Real quaternion[4], const Real translate[3], double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - std::string data(str(boost::format("{\"name\":\"%s\", \"quaternion\":[%.15f,%.15f,%.15f,%.15f], \"translate\":[%.15f,%.15f,%.15f]")%name%quaternion[0]%quaternion[1]%quaternion[2]%quaternion[3]%translate[0]%translate[1]%translate[2])); - if (!parentlinkPk.empty()) { - data += ", \"parentlinkpk\": \"" + parentlinkPk + "\""; - } - data += "}"; - const std::string uri(str(boost::format("object/%s/link/") % objectPk)); - - CallPost(uri, data, pt, 201, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -std::string ControllerClientImpl::SetObjectGeometryMesh(const std::string& objectPk, const std::string& geometryPk, const std::vector& meshData, const std::string& unit, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - const std::string uri(str(boost::format("object/%s/geometry/%s/?unit=%s")%objectPk%geometryPk%unit)); - CallPutSTL(uri, meshData, pt, 202, timeout); - return GetJsonValueByKey(pt, "pk"); -} - -int ControllerClientImpl::_WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData) -{ - if (writerData == NULL) { - return 0; - } - writerData->write(data, size*nmemb); - return size * nmemb; -} - -int ControllerClientImpl::_WriteOStreamCallback(char *data, size_t size, size_t nmemb, std::ostream *writerData) -{ - if (writerData == NULL) { - return 0; - } - writerData->write(data, size*nmemb); - return size * nmemb; -} - -int ControllerClientImpl::_WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData) -{ - if (writerData == NULL) { - return 0; - } - writerData->insert(writerData->end(), data, data+size*nmemb); - return size * nmemb; -} - -int ControllerClientImpl::_ReadIStreamCallback(char *data, size_t size, size_t nmemb, std::istream *readerData) -{ - if (readerData == NULL) { - return 0; - } - return readerData->read(data, size*nmemb).gcount(); -} - -void ControllerClientImpl::_SetupHTTPHeadersJSON() -{ - // set the header to only send json - std::string s = std::string("Content-Type: application/json; charset=") + _charset; - if( !!_httpheadersjson ) { - curl_slist_free_all(_httpheadersjson); - } - _httpheadersjson = curl_slist_append(NULL, s.c_str()); - s = str(boost::format("Accept-Language: %s,en-us")%_language); - _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); //,en;q=0.7,ja;q=0.3',") - s = str(boost::format("Accept-Charset: %s")%_charset); - _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); - //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept:"); // necessary? - s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - _httpheadersjson = curl_slist_append(_httpheadersjson, s.c_str()); - _httpheadersjson = curl_slist_append(_httpheadersjson, "Connection: Keep-Alive"); - _httpheadersjson = curl_slist_append(_httpheadersjson, "Keep-Alive: 20"); // keep alive for 20s? - // test on windows first - //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { - _httpheadersjson = curl_slist_append(_httpheadersjson, additionalHeader.c_str()); - } -} - -void ControllerClientImpl::_SetupHTTPHeadersSTL() -{ - // set the header to only send stl - std::string s = std::string("Content-Type: application/sla"); - if( !!_httpheadersstl ) { - curl_slist_free_all(_httpheadersstl); - } - _httpheadersstl = curl_slist_append(NULL, s.c_str()); - //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept:"); // necessary? - s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - _httpheadersstl = curl_slist_append(_httpheadersstl, s.c_str()); - _httpheadersstl = curl_slist_append(_httpheadersstl, "Connection: Keep-Alive"); - _httpheadersstl = curl_slist_append(_httpheadersstl, "Keep-Alive: 20"); // keep alive for 20s? - // test on windows first - //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { - _httpheadersstl = curl_slist_append(_httpheadersstl, additionalHeader.c_str()); - } -} - -void ControllerClientImpl::_SetupHTTPHeadersMultipartFormData() -{ - // set the header to only send stl - std::string s = std::string("Content-Type: multipart/form-data"); - if( !!_httpheadersmultipartformdata ) { - curl_slist_free_all(_httpheadersmultipartformdata); - } - _httpheadersmultipartformdata = curl_slist_append(NULL, s.c_str()); - //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept:"); // necessary? - s = std::string("X-CSRFToken: ")+_csrfmiddlewaretoken; - _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, s.c_str()); - _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Connection: Keep-Alive"); - _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Keep-Alive: 20"); // keep alive for 20s? - // test on windows first - //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { - _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, additionalHeader.c_str()); - } -} - -std::string ControllerClientImpl::_EncodeWithoutSeparator(const std::string& raw) -{ - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < raw.size(); ++i) { - if( raw[i] == '/' ) { - if( startindex != i ) { - output += EscapeString(raw.substr(startindex, i-startindex)); - startindex = i+1; - } - output += '/'; - } - } - if( startindex != raw.size() ) { - output += EscapeString(raw.substr(startindex)); - } - return output; -} - -void ControllerClientImpl::_EnsureWebDAVDirectories(const std::string& relativeuri, double timeout) -{ - if (relativeuri.empty()) { - return; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - std::list listCreateDirs; - std::string output; - size_t startindex = 0; - for(size_t i = 0; i < relativeuri.size(); ++i) { - if( relativeuri[i] == '/' ) { - if( startindex != i ) { - listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex, i-startindex))); - startindex = i+1; - } - } - } - if( startindex != relativeuri.size() ) { - listCreateDirs.push_back(EscapeString(relativeuri.substr(startindex))); - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - - std::string totaluri = ""; - for(std::list::iterator itdir = listCreateDirs.begin(); itdir != listCreateDirs.end(); ++itdir) { - // first have to create the directory structure up to destinationdir - if( totaluri.size() > 0 ) { - totaluri += '/'; - } - totaluri += *itdir; - _uri = _basewebdavuri + totaluri; - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, _uri.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - /* creating directories - - Responses from a MKCOL request MUST NOT be cached as MKCOL has non-idempotent semantics. - - 201 (Created) - The collection or structured resource was created in its entirety. - - 403 (Forbidden) - This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members. - - 405 (Method Not Allowed) - MKCOL can only be executed on a deleted/non-existent resource. - - 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections have been created. - - 415 (Unsupported Media Type)- The server does not support the request type of the body. - - 507 (Insufficient Storage) - The resource does not have sufficient space to record the state of the resource after the execution of this method. - - */ - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed with HTTP status %d: %s", http_code%_errormessage, MEC_HTTPServer); - } - } -} - -std::string ControllerClientImpl::_PrepareDestinationURI_UTF8(const std::string& rawuri, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) -{ - std::string baseuploaduri; - if( rawuri.size() >= 7 && rawuri.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - std::string s = rawuri.substr(7); - baseuploaduri += _EncodeWithoutSeparator(s); - if( bEnsurePath ) { - if( !bIsDirectory ) { - size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); - if( nBaseFilenameStartIndex != std::string::npos ) { - s = s.substr(0, nBaseFilenameStartIndex); - } else { - s = ""; - } - } - _EnsureWebDAVDirectories(s); - } - } - else { - if( !bEnsureSlash ) { - return rawuri; - } - baseuploaduri = rawuri; - } - if( bEnsureSlash ) { - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - } - return baseuploaduri; -} - -std::string ControllerClientImpl::_PrepareDestinationURI_UTF16(const std::wstring& rawuri_utf16, bool bEnsurePath, bool bEnsureSlash, bool bIsDirectory) -{ - std::string baseuploaduri; - std::string desturi_utf8; - utf8::utf16to8(rawuri_utf16.begin(), rawuri_utf16.end(), std::back_inserter(desturi_utf8)); - - if( desturi_utf8.size() >= 7 && desturi_utf8.substr(0,7) == "mujin:/" ) { - baseuploaduri = _basewebdavuri; - std::string s = desturi_utf8.substr(7); - baseuploaduri += _EncodeWithoutSeparator(s); - if( bEnsurePath ) { - if( !bIsDirectory ) { - size_t nBaseFilenameStartIndex = s.find_last_of(s_filesep); - if( nBaseFilenameStartIndex != std::string::npos ) { - s = s.substr(0, nBaseFilenameStartIndex); - } else { - s = ""; - } - } - _EnsureWebDAVDirectories(s); - } - } - else { - if( !bEnsureSlash ) { - return desturi_utf8; - } - baseuploaduri = desturi_utf8; - } - if( bEnsureSlash ) { - // ensure trailing slash - if( baseuploaduri[baseuploaduri.size()-1] != '/' ) { - baseuploaduri.push_back('/'); - } - } - return baseuploaduri; -} - -void ControllerClientImpl::UploadFileToController_UTF8(const std::string& filename, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF8(filename, _PrepareDestinationURI_UTF8(desturi, false)); -} - -void ControllerClientImpl::UploadFileToController_UTF16(const std::wstring& filename_utf16, const std::wstring& desturi_utf16) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadFileToController_UTF16(filename_utf16, _PrepareDestinationURI_UTF16(desturi_utf16, false)); -} - -void ControllerClientImpl::UploadDataToController_UTF8(const void* data, size_t size, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - const std::string filename = _PrepareDestinationURI_UTF8(desturi, false).substr(_basewebdavuri.size()); - _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); -} - -void ControllerClientImpl::UploadDataToController_UTF16(const void* data, size_t size, const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - const std::string filename = _PrepareDestinationURI_UTF16(desturi, false).substr(_basewebdavuri.size()); - _UploadDataToControllerViaForm(data, size, filename, _baseuri + "fileupload"); -} - -void ControllerClientImpl::UploadDirectoryToController_UTF8(const std::string& copydir, const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF8(copydir, _PrepareDestinationURI_UTF8(desturi, false, false, true)); -} - -void ControllerClientImpl::UploadDirectoryToController_UTF16(const std::wstring& copydir, const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _UploadDirectoryToController_UTF16(copydir, _PrepareDestinationURI_UTF16(desturi, false, false, true)); -} - -void ControllerClientImpl::DownloadFileFromController_UTF8(const std::string& desturi, std::vector& vdata) -{ - boost::mutex::scoped_lock lock(_mutex); - _CallGet(_PrepareDestinationURI_UTF8(desturi, false), vdata); -} - -void ControllerClientImpl::DownloadFileFromController_UTF16(const std::wstring& desturi, std::vector& vdata) -{ - boost::mutex::scoped_lock lock(_mutex); - _CallGet(_PrepareDestinationURI_UTF16(desturi, false), vdata); -} - -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF8(const std::string& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF8(desturi, false), localtimeval, remotetimeval, vdata, timeout); -} - -void ControllerClientImpl::DownloadFileFromControllerIfModifiedSince_UTF16(const std::wstring& desturi, long localtimeval, long& remotetimeval, std::vector& vdata, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - _DownloadFileFromController(_PrepareDestinationURI_UTF16(desturi, false), localtimeval, remotetimeval, vdata, timeout); -} - -long ControllerClientImpl::GetModifiedTime(const std::string& uri, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - - // Copied from https://curl.haxx.se/libcurl/c/CURLINFO_FILETIME.html - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - - // in order to resolve cache correctly, need to go thorugh file/download endpoint - std::string apiendpoint = _baseuri + "file/download/?filename="; - if( uri.size() >= 7 && uri.substr(0,7) == "mujin:/" ) { - apiendpoint += _EncodeWithoutSeparator(uri.substr(7)); - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, apiendpoint.c_str()); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_NOBODY, 0L, 1L); - CURL_PERFORM(_curl); - - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("Cannot get modified date of %s for HTTP HEAD call: return is %s", uri%http_code, MEC_HTTPServer); - } - - long filetime=-1; - CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &filetime); - return filetime; -} - -void ControllerClientImpl::_DownloadFileFromController(const std::string& desturi, long localtimeval, long &remotetimeval, std::vector& outputdata, double timeout) -{ - remotetimeval = 0; - - // ask for remote file time - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_FILETIME, 0L, 1L); - - // use if modified since if local file time is provided - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE, localtimeval > 0 ? CURL_TIMECOND_IFMODSINCE : CURL_TIMECOND_NONE); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEVALUE, 0L, localtimeval > 0 ? localtimeval : 0L); - - // do the get call - long http_code = _CallGet(desturi, outputdata, 0, timeout); - if ((http_code != 200 && http_code != 304)) { - if (outputdata.size() > 0) { - std::stringstream ss; - ss.write((const char*)&outputdata[0], outputdata.size()); - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%ss.str(), MEC_HTTPServer); - } - throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s", desturi%http_code, MEC_HTTPServer); - } - - // retrieve remote file time - if (http_code != 304) { - // got the entire file so fill in the timestamp of that file - CURL_INFO_GETTER(_curl, CURLINFO_FILETIME, &remotetimeval); - } -} - -void ControllerClientImpl::SaveBackup(std::ostream& outputStream, bool config, bool media, const std::string& backupscenepks, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false")+"&backupscenepks="+backupscenepks; - _CallGet(_baseuri+"backup/"+query, outputStream, 200, timeout); -} - -void ControllerClientImpl::RestoreBackup(std::istream& inputStream, bool config, bool media, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?config=")+(config ? "true" : "false")+"&media="+(media ? "true" : "false"); - _UploadFileToControllerViaForm(inputStream, "", _baseuri+"backup/"+query, timeout); -} - -void ControllerClientImpl::Upgrade(std::istream& inputStream, bool autorestart, bool uploadonly, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - std::string query=std::string("?autorestart=")+(autorestart ? "1" : "0")+("&uploadonly=")+(uploadonly ? "1" : "0"); - - std::streampos originalPos = inputStream.tellg(); - inputStream.seekg(0, std::ios::end); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); - } - std::streampos contentLength = inputStream.tellg() - originalPos; - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); - } - inputStream.seekg(originalPos, std::ios::beg); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); - } - - if(contentLength) { - _UploadFileToControllerViaForm(inputStream, "", _baseuri+"upgrade/"+query, timeout); - } else { - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"upgrade/"+query, "", pt, pt.GetAllocator(), 200, timeout); - } -} - -bool ControllerClientImpl::GetUpgradeStatus(std::string& status, double &progress, double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"upgrade/", pt, pt.GetAllocator(), 200, timeout); - if(pt.IsNull()) { - return false; - } - status = GetJsonValueByKey(pt, "status"); - progress = GetJsonValueByKey(pt, "progress"); - return true; -} - -void ControllerClientImpl::CancelUpgrade(double timeout) -{ - CallDelete(_baseuri+"upgrade/", 200, timeout); -} - -void ControllerClientImpl::Reboot(double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"reboot/", "", pt, pt.GetAllocator(), 200, timeout); -} - -void ControllerClientImpl::DeleteAllScenes(double timeout) -{ - boost::mutex::scoped_lock lock(_mutex); - rapidjson::Document pt(rapidjson::kObjectType); - CallDelete("scene/", 204, timeout); -} - -void ControllerClientImpl::DeleteAllITLPrograms(double timeout) -{ - CallDelete("itl/", 204, timeout); -} - -void ControllerClientImpl::DeleteFileOnController_UTF8(const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteFileOnController(_PrepareDestinationURI_UTF8(desturi, false)); -} - -void ControllerClientImpl::DeleteFileOnController_UTF16(const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteFileOnController(_PrepareDestinationURI_UTF16(desturi, false)); -} - -void ControllerClientImpl::DeleteDirectoryOnController_UTF8(const std::string& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteDirectoryOnController(_PrepareDestinationURI_UTF8(desturi, false, false, true)); -} - -void ControllerClientImpl::DeleteDirectoryOnController_UTF16(const std::wstring& desturi) -{ - boost::mutex::scoped_lock lock(_mutex); - _DeleteDirectoryOnController(_PrepareDestinationURI_UTF16(desturi, false, false, true)); -} - -void ControllerClientImpl::ModifySceneAddReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) -{ - rapidjson::Document pt, pt2; - rapidjson::Value value; - - pt.SetObject(); - - value.SetString(scenepk.c_str(), pt.GetAllocator()); - pt.AddMember("scenepk", value, pt.GetAllocator()); - - value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); - pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); - - boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); -} - -void ControllerClientImpl::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) -{ - rapidjson::Document pt, pt2; - rapidjson::Value value; - - pt.SetObject(); - - value.SetString(scenepk.c_str(), pt.GetAllocator()); - pt.AddMember("scenepk", value, pt.GetAllocator()); - - value.SetString(referenceobjectpk.c_str(), pt.GetAllocator()); - pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); - - boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); -} - -void ControllerClientImpl::_UploadDirectoryToController_UTF8(const std::string& copydir_utf8, const std::string& rawuri) -{ - BOOST_ASSERT(rawuri.size()>0 && copydir_utf8.size()>0); - - // if there's a trailing slash, have to get rid of it - std::string uri; - if( rawuri.at(rawuri.size()-1) == '/' ) { - if( copydir_utf8.at(copydir_utf8.size()-1) != s_filesep ) { - // append the copydir_utf8 name to rawuri - size_t nBaseFilenameStartIndex = copydir_utf8.find_last_of(s_filesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - uri = rawuri + EscapeString(copydir_utf8.substr(nBaseFilenameStartIndex)); - } - else { - // copydir also ends in a fileseparator, so remove the file separator from rawuri - uri = rawuri.substr(0, rawuri.size()-1); - } - } - else { - if (copydir_utf8.at(copydir_utf8.size()-1) == s_filesep) { - throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", copydir_utf8%s_filesep, MEC_InvalidArguments); - } - uri = rawuri; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - - { - // make sure the directory is created - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::string sCopyDir_FS = encoding::ConvertUTF8ToFileSystemEncoding(copydir_utf8); - // remove the fileseparator if it exists - std::stringstream ss; - ss << "uploading " << sCopyDir_FS << " -> " << uri; - MUJIN_LOG_INFO(ss.str()); - -#if defined(_WIN32) || defined(_WIN64) - bool bhasseparator = false; - if( sCopyDir_FS.size() > 0 && sCopyDir_FS.at(sCopyDir_FS.size()-1) == s_filesep ) { - sCopyDir_FS.resize(sCopyDir_FS.size()-1); - bhasseparator = true; - } - - WIN32_FIND_DATAA ffd; - std::string searchstr = sCopyDir_FS + std::string("\\*"); - HANDLE hFind = FindFirstFileA(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", sCopyDir_FS, MEC_Assert); - } - - do { - std::string filename = std::string(ffd.cFileName); - if( filename != "." && filename != ".." ) { - std::string filename_utf8 = encoding::ConvertMBStoUTF8(filename); - std::string newcopydir_utf8; - if( bhasseparator ) { - newcopydir_utf8 = copydir_utf8 + filename_utf8; - } - else { - newcopydir_utf8 = str(boost::format("%s%c%s")%copydir_utf8%s_filesep%filename_utf8); - } - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToController_UTF8(newcopydir_utf8, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToController_UTF8(newcopydir_utf8, newuri); - } - } - } while(FindNextFileA(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%sCopyDir_FS, MEC_HTTPServer); - } - -#else - boost::filesystem::path bfpcopydir(copydir_utf8); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { -#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename().string()); -#else - std::string dirfilename = encoding::ConvertFileSystemEncodingToUTF8(itdir->path().filename()); -#endif - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF8(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF8(itdir->path().string(), newuri); - } - } -#endif // defined(_WIN32) || defined(_WIN64) -} - -void ControllerClientImpl::_UploadDirectoryToController_UTF16(const std::wstring& copydir_utf16, const std::string& rawuri) -{ - BOOST_ASSERT(rawuri.size()>0 && copydir_utf16.size()>0); - - // if there's a trailing slash, have to get rid of it - std::string uri; - if( rawuri.at(rawuri.size()-1) == '/' ) { - if( copydir_utf16.at(copydir_utf16.size()-1) != s_wfilesep ) { - // append the copydir_utf16 name to rawuri - size_t nBaseFilenameStartIndex = copydir_utf16.find_last_of(s_wfilesep); - if( nBaseFilenameStartIndex == std::string::npos ) { - // there's no path? - nBaseFilenameStartIndex = 0; - } - else { - nBaseFilenameStartIndex++; - } - std::string name_utf8; - utf8::utf16to8(copydir_utf16.begin()+nBaseFilenameStartIndex, copydir_utf16.end(), std::back_inserter(name_utf8)); - uri = rawuri + EscapeString(name_utf8); - } - else { - // copydir also ends in a fileseparator, so remove the file separator from rawuri - uri = rawuri.substr(0, rawuri.size()-1); - } - } - else { - if (copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep) { - throw MUJIN_EXCEPTION_FORMAT("copydir '%s' cannot end in slash '%s'", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16)%s_filesep, MEC_InvalidArguments); - } - uri = rawuri; - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - - { - // make sure the directory is created - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "MKCOL"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, uri.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - if( http_code != 201 && http_code != 301 ) { - throw MUJIN_EXCEPTION_FORMAT("HTTP MKCOL failed for %s with HTTP status %d: %s", uri%http_code%_errormessage, MEC_HTTPServer); - } - } - - std::wstring sCopyDir_FS; - // remove the fileseparator if it exists - if( copydir_utf16.size() > 0 && copydir_utf16.at(copydir_utf16.size()-1) == s_wfilesep ) { - sCopyDir_FS = copydir_utf16.substr(0,copydir_utf16.size()-1); - } - else { - sCopyDir_FS = copydir_utf16; - } - std::stringstream ss; - ss << "uploading " << encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16) << " -> " << uri; - MUJIN_LOG_INFO(ss.str()); - -#if defined(_WIN32) || defined(_WIN64) - WIN32_FIND_DATAW ffd; - std::wstring searchstr = sCopyDir_FS + std::wstring(L"\\*"); - HANDLE hFind = FindFirstFileW(searchstr.c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) { - throw MUJIN_EXCEPTION_FORMAT("could not retrieve file data for %s", encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_Assert); - } - - do { - std::wstring filename = std::wstring(ffd.cFileName); - if( filename != L"." && filename != L".." ) { - std::string filename_utf8; - utf8::utf16to8(filename.begin(), filename.end(), std::back_inserter(filename_utf8)); - std::wstring newcopydir = str(boost::wformat(L"%s\\%s")%copydir_utf16%filename); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(filename_utf8)); - - if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { - _UploadDirectoryToController_UTF16(newcopydir, newuri); - } - else if( ffd.dwFileAttributes == 0 || ffd.dwFileAttributes == FILE_ATTRIBUTE_READONLY || ffd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL || ffd.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE ) { - _UploadFileToController_UTF16(newcopydir, newuri); - } - } - } while(FindNextFileW(hFind,&ffd) != 0); - - DWORD err = GetLastError(); - FindClose(hFind); - if( err != ERROR_NO_MORE_FILES ) { - throw MUJIN_EXCEPTION_FORMAT("system error 0x%x when recursing through %s", err%encoding::ConvertUTF16ToFileSystemEncoding(copydir_utf16), MEC_HTTPServer); - } - -#elif defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3 - boost::filesystem::path bfpcopydir(copydir_utf16); - for(boost::filesystem::directory_iterator itdir(bfpcopydir); itdir != boost::filesystem::directory_iterator(); ++itdir) { - std::wstring dirfilename_utf16 = itdir->path().filename().wstring(); - std::string dirfilename; - utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF16(itdir->path().wstring(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF16(itdir->path().wstring(), newuri); - } - } -#else - // boost filesystem v2 - boost::filesystem::wpath bfpcopydir(copydir_utf16); - for(boost::filesystem::wdirectory_iterator itdir(bfpcopydir); itdir != boost::filesystem::wdirectory_iterator(); ++itdir) { - std::wstring dirfilename_utf16 = itdir->path().filename(); - std::string dirfilename; - utf8::utf16to8(dirfilename_utf16.begin(), dirfilename_utf16.end(), std::back_inserter(dirfilename)); - std::string newuri = str(boost::format("%s/%s")%uri%EscapeString(dirfilename)); - if( boost::filesystem::is_directory(itdir->status()) ) { - _UploadDirectoryToController_UTF16(itdir->path().string(), newuri); - } - else if( boost::filesystem::is_regular_file(itdir->status()) ) { - _UploadFileToController_UTF16(itdir->path().string(), newuri); - } - } -#endif // defined(_WIN32) || defined(_WIN64) -} - -void ControllerClientImpl::_UploadFileToController_UTF8(const std::string& filename, const std::string& uri) -{ - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); - } - std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); - - std::string sFilename_FS = encoding::ConvertUTF8ToFileSystemEncoding(filename); - std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); - if(!fin.good()) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); - } - - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); -} - -void ControllerClientImpl::_UploadFileToController_UTF16(const std::wstring& filename, const std::string& uri) -{ - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( uri.size() < _basewebdavuri.size() || uri.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", uri, MEC_HTTPServer); - } - std::string filenameoncontroller = uri.substr(_basewebdavuri.size()); - - std::string sFilename_FS = encoding::ConvertUTF16ToFileSystemEncoding(filename); - std::vectorcontent; - std::ifstream fin(sFilename_FS.c_str(), std::ios::in | std::ios::binary); - if(!fin.good()) { - throw MUJIN_EXCEPTION_FORMAT("failed to open filename %s for uploading", sFilename_FS, MEC_InvalidArguments); - } - - MUJIN_LOG_DEBUG(str(boost::format("upload %s")%uri)) - _UploadFileToControllerViaForm(fin, filenameoncontroller, _baseuri + "fileupload"); -} - -void ControllerClientImpl::_UploadFileToControllerViaForm(std::istream& inputStream, const std::string& filename, const std::string& endpoint, double timeout) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - //timeout is default to 0 (never) - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - - std::streampos originalPos = inputStream.tellg(); - inputStream.seekg(0, std::ios::end); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to seek inputStream to get the length", MEC_InvalidArguments); - } - std::streampos contentLength = inputStream.tellg() - originalPos; - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to tell the length of inputStream", MEC_InvalidArguments); - } - inputStream.seekg(originalPos, std::ios::beg); - if(inputStream.fail()) { - throw MUJIN_EXCEPTION_FORMAT0("failed to rewind inputStream", MEC_InvalidArguments); - } - - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_READFUNCTION, NULL, _ReadIStreamCallback); - // prepare form - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - CURL_FORM_RELEASER(formpost); - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "files[]", - CURLFORM_FILENAME, filename.empty() ? "unused" : filename.c_str(), - CURLFORM_STREAM, &inputStream, -#if !CURL_AT_LEAST_VERSION(7,46,0) - // According to curl/lib/formdata.c, CURLFORM_CONTENTSLENGTH argument type is long. - // Also, as va_list is used in curl_formadd, the bit length needs to match exactly. - // streampos can be directly converted to streamoff, but it does not correspond on 32bit machines. - CURLFORM_CONTENTSLENGTH, (long)contentLength, -#else - // Actually we should use CURLFORM_CONTENTLEN, whose argument type is curl_off_t, which is 64bit. - // However, it was added in curl 7.46 and cannot be used in official Windows build. - CURLFORM_CONTENTLEN, (curl_off_t)contentLength, -#endif - CURLFORM_END); - if(!filename.empty()) { - curl_formadd(&formpost, &lastptr, - CURLFORM_COPYNAME, "filename", - CURLFORM_COPYCONTENTS, filename.c_str(), - CURLFORM_END); - } - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); - CURL_PERFORM(_curl); - // get http status - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // 204 is when it overwrites the file? - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); - } -} - -void ControllerClientImpl::_UploadDataToControllerViaForm(const void* data, size_t size, const std::string& filename, const std::string& endpoint, double timeout) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, endpoint.c_str()); - _buffer.clear(); - _buffer.str(""); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEFUNCTION, NULL, _WriteStringStreamCallback); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_WRITEDATA, NULL, &_buffer); - //timeout is default to 0 (never) - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); - - // prepare form - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; - CURL_FORM_RELEASER(formpost); - curl_formadd(&formpost, &lastptr, - CURLFORM_PTRNAME, "files[]", - CURLFORM_BUFFER, filename.empty() ? "unused" : filename.c_str(), - CURLFORM_BUFFERPTR, data, - CURLFORM_END); - if(!filename.empty()) { - curl_formadd(&formpost, &lastptr, - CURLFORM_PTRNAME, "filename", - CURLFORM_PTRCONTENTS, filename.c_str(), - CURLFORM_END); - } - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPPOST, NULL, formpost); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersmultipartformdata); - CURL_PERFORM(_curl); - // get http status - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - - // 204 is when it overwrites the file? - if( http_code != 200 ) { - throw MUJIN_EXCEPTION_FORMAT("upload of %s to %s failed with HTTP status %s", filename%endpoint%http_code, MEC_HTTPServer); - } -} - -void ControllerClientImpl::_DeleteFileOnController(const std::string& desturi) -{ - MUJIN_LOG_DEBUG(str(boost::format("delete %s")%desturi)) - - // the dest filename of the upload is determined by stripping the leading _basewebdavuri - if( desturi.size() < _basewebdavuri.size() || desturi.substr(0,_basewebdavuri.size()) != _basewebdavuri ) { - throw MUJIN_EXCEPTION_FORMAT("trying to upload a file outside of the webdav endpoint is not allowed: %s", desturi, MEC_HTTPServer); - } - std::string filename = desturi.substr(_basewebdavuri.size()); - - rapidjson::Document pt(rapidjson::kObjectType); - _CallPost(_baseuri+"file/delete/?filename="+filename, "", pt, pt.GetAllocator(), 200, 5.0); -} - -void ControllerClientImpl::_DeleteDirectoryOnController(const std::string& desturi) -{ - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_CUSTOMREQUEST, NULL, "DELETE"); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_HTTPHEADER, NULL, _httpheadersjson); - CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_URL, NULL, desturi.c_str()); - CURL_PERFORM(_curl); - long http_code = 0; - CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); - MUJIN_LOG_INFO("response code: " << http_code); -} - -size_t ControllerClientImpl::_ReadUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) -{ - // in real-world cases, this would probably get this data differently as this fread() stuff is exactly what the library already would do by default internally - size_t nread = fread(ptr, size, nmemb, (FILE*)stream); - //fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread); - return nread; -} - -size_t ControllerClientImpl::_ReadInMemoryUploadCallback(void *ptr, size_t size, size_t nmemb, void *stream) -{ - std::pair::const_iterator, size_t>* pstreamdata = static_cast::const_iterator, size_t>*>(stream); - size_t nBytesToRead = size*nmemb; - if( nBytesToRead > pstreamdata->second ) { - nBytesToRead = pstreamdata->second; - } - if( nBytesToRead > 0 ) { - std::copy(pstreamdata->first, pstreamdata->first+nBytesToRead, static_cast(ptr)); - pstreamdata->first += nBytesToRead; - pstreamdata->second -= nBytesToRead; - } - return nBytesToRead; -} - -void ControllerClientImpl::GetDebugInfos(std::vector& debuginfos, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - CallGet(str(boost::format("debug/?format=json&limit=0")), pt, 200, timeout); - rapidjson::Value& objects = pt["objects"]; - - debuginfos.resize(objects.Size()); - size_t iobj = 0; - for (rapidjson::Document::ValueIterator it = objects.Begin(); it != objects.End(); ++it) { - DebugResourcePtr debuginfo(new DebugResource(shared_from_this(), GetJsonValueByKey(*it, "pk"))); - - //LoadJsonValueByKey(*it, "datemodified", debuginfo->datemodified); - LoadJsonValueByKey(*it, "description", debuginfo->description); - //LoadJsonValueByKey(*it, "downloadUri", debuginfo->downloadUri); - LoadJsonValueByKey(*it, "name", debuginfo->name); - //LoadJsonValueByKey(*it, "resource_uri", debuginfo->resource_uri); - LoadJsonValueByKey(*it, "size", debuginfo->size); - - debuginfos.at(iobj++) = debuginfo; - } -} - -void ControllerClientImpl::ListFilesInController(std::vector& fileentries, const std::string &dirname, double timeout) -{ - rapidjson::Document pt(rapidjson::kObjectType); - _CallGet(_baseuri+"file/list/?dirname="+dirname, pt, pt.GetAllocator(), 200, timeout); - fileentries.resize(pt.MemberCount()); - size_t iobj = 0; - for (rapidjson::Document::MemberIterator it = pt.MemberBegin(); it != pt.MemberEnd(); ++it) { - FileEntry &fileentry = fileentries.at(iobj); - - fileentry.filename = it->name.GetString(); - LoadJsonValueByKey(it->value, "modified", fileentry.modified); - LoadJsonValueByKey(it->value, "size", fileentry.size); - - iobj++; - } -} - -} // end namespace mujinclient diff --git a/src/include/mujinwebstackclientcpp/mujincontrollerclient.h b/src/include/mujinwebstackclientcpp/mujincontrollerclient.h deleted file mode 100644 index 51c73c28..00000000 --- a/src/include/mujinwebstackclientcpp/mujincontrollerclient.h +++ /dev/null @@ -1,27 +0,0 @@ -/// \brief connecting to a controller's webstack -class MUJINCLIENT_API ControllerClientInfo : public mujinjson::JsonSerializable -{ -public: - virtual void Reset(); - - void LoadFromJson(const rapidjson::Value& rClientInfo) override; - void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; - void SaveToJson(rapidjson::Document& rClientInfo) const override; - - bool operator==(const ControllerClientInfo &rhs) const; - bool operator!=(const ControllerClientInfo &rhs) const { - return !operator==(rhs); - } - std::string GetURL(bool bIncludeNamePassword) const; - - inline bool IsEnabled() const { - return !host.empty(); - } - - std::string host; - uint16_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port - std::string username; - std::string password; - std::vector additionalHeaders; ///< expect each value to be in the format of "Header-Name: header-value" - std::string unixEndpoint; ///< unix socket endpoint for communicating with HTTP server over unix socket -}; diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 8fce2d0c..84729020 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -76,6 +76,35 @@ struct FileEntry typedef double Real; +/// \brief connecting to a controller's webstack +class MUJINWEBSTACKCLIENT_API WebstackClientInfo : public mujinjsonwebstack::JsonSerializable +{ +public: + static WebstackClientInfo FromUrl(const char* url); + + void Reset(); + + void LoadFromJson(const rapidjson::Value& rClientInfo) override; + void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; + + bool operator==(const WebstackClientInfo &rhs) const; + bool operator!=(const WebstackClientInfo &rhs) const { + return !operator==(rhs); + } + std::string GetURL(bool bIncludeNamePassword) const; + + inline bool IsEnabled() const { + return !host.empty(); + } + + std::string host; + uint16_t httpPort = 0; ///< Post to communicate with the webstack. If 0, then use the default port + std::string username; + std::string password; + std::vector additionalHeaders; ///< expect each value to be in the format of "Header-Name: header-value" + std::string unixEndpoint; ///< unix socket endpoint for communicating with HTTP server over unix socket +}; + /// \brief Creates on MUJIN Controller instance. /// /// Only one call can be made at a time. In order to make multiple calls simultaneously, create another instance. @@ -131,6 +160,8 @@ class MUJINWEBSTACKCLIENT_API WebstackClient /// \brief returns the URI used to setup the connection const std::string& GetBaseURI() const; + const WebstackClientInfo& GetClientInfo() const; + /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. /// /// \param serverport Specify proxy server to use. To specify port number in this string, append :[port] to the end of the host name. The proxy string may be prefixed with [protocol]:// since any such prefix will be ignored. The proxy's port number may optionally be specified with the separate option. If not specified, will default to using port 1080 for proxies. Setting to empty string will disable the proxy. @@ -341,14 +372,15 @@ class MUJINWEBSTACKCLIENT_API WebstackClient CURL *_curl; boost::mutex _mutex; std::stringstream _buffer; - std::string _baseuri, _baseapiuri, _basewebdavuri, _uri, _username; + std::string _baseuri, _baseapiuri, _basewebdavuri, _uri; + + WebstackClientInfo _clientInfo; curl_slist *_httpheadersjson; curl_slist *_httpheadersstl; curl_slist *_httpheadersmultipartformdata; std::string _charset, _language; std::string _csrfmiddlewaretoken; - std::vector _additionalHeaders; ///< list of "Header-Name: header-value" additional http headers rapidjson::Document _profile; ///< user profile and versioning std::string _errormessage; ///< set when an error occurs in libcurl diff --git a/src/mujincontrollerclient.cpp b/src/mujincontrollerclient.cpp deleted file mode 100644 index c8d1010c..00000000 --- a/src/mujincontrollerclient.cpp +++ /dev/null @@ -1,79 +0,0 @@ -void ControllerClientInfo::Reset() -{ - host.clear(); - httpPort = 0; - username.clear(); - password.clear(); - additionalHeaders.clear(); - unixEndpoint.clear(); -} - -void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) -{ - mujinjson::LoadJsonValueByKey(rClientInfo, "host", host); - mujinjson::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); - mujinjson::LoadJsonValueByKey(rClientInfo, "username", username); - mujinjson::LoadJsonValueByKey(rClientInfo, "password", password); - mujinjson::LoadJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders); - mujinjson::LoadJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint); -} - -void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const -{ - rClientInfo.SetObject(); - if( !host.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "host", host, alloc); - } - if( httpPort != 0 ) { - mujinjson::SetJsonValueByKey(rClientInfo, "httpPort", httpPort, alloc); - } - if( !username.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "username", username, alloc); - } - if( !password.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "password", password, alloc); - } - if( !additionalHeaders.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders, alloc); - } - if( !unixEndpoint.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint, alloc); - } -} - -void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const -{ - SaveToJson(rClientInfo, rClientInfo.GetAllocator()); -} - -bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const -{ - return host == rhs.host && - httpPort == rhs.httpPort && - username == rhs.username && - password == rhs.password && - additionalHeaders == rhs.additionalHeaders && - unixEndpoint == rhs.unixEndpoint; -} - -std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const -{ - std::string url; - if( host.empty() ) { - return url; - } - url += "http://"; - if( bIncludeNamePassword ) { - url += username; - url += ":"; - url += password; - url += "@"; - } - - url += host; - if( httpPort != 0 ) { - url += ":"; - url += std::to_string(httpPort); - } - return url; -} diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 757589d3..235976ad 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -95,16 +95,154 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } +/// \brief given a port string "80", fill ControllerClientInfo httpPort +void _ParseClientInfoPort(const char* port, size_t length, ControllerClientInfo& clientInfo) +{ + clientInfo.httpPort = 0; + for (; length > 0; ++port, --length) { + clientInfo.httpPort = clientInfo.httpPort * 10 + (*port - '0'); + } +} + } // end namespace + +WebstackClientInfo WebstackClientInfo::FromUrl(const char* url) +{ + WebstackClientInfo clientInfo; + const char* colonSlashSlash = strstr(url, "://"); + if (colonSlashSlash == nullptr) { + return clientInfo; + } + const char* hostname = colonSlashSlash + sizeof("://") - 1; + const char* at = strstr(hostname, "@"); // not found is ok + const char* slash = strstr(hostname, "/"); // not found is ok + if (at != nullptr && (slash == nullptr || at < slash)) { + // if the at is before the slash, i.e. for the username:password + const char* usernamePassword = hostname; + hostname = at + sizeof("@") - 1; + const char* colon = strstr(usernamePassword, ":"); // not found is ok + if (colon != nullptr) { + const char* password = colon + sizeof(":") - 1; + clientInfo.username = std::string(usernamePassword, colon - usernamePassword); + clientInfo.password = std::string(password, at - password); + } else { + clientInfo.username = std::string(usernamePassword, at - usernamePassword); + } + } + const char* port = strstr(hostname, ":"); // not found is ok + if (slash == nullptr) { + if (port == nullptr) { + // no port, no slash + clientInfo.host = hostname; + } else { + // has port, no slash + const char* portStart = port + sizeof(":") - 1; + _ParseClientInfoPort(portStart, strlen(portStart), clientInfo); + clientInfo.host = std::string(hostname, port - hostname); + } + } else { + if (port != nullptr && port < slash) { + // has port before slash + const char* portStart = port + sizeof(":") - 1; + _ParseClientInfoPort(portStart, slash - portStart, clientInfo); + clientInfo.host = std::string(hostname, port - hostname); + } else { + // no port, but has slash + clientInfo.host = std::string(hostname, slash - hostname); + } + } + return clientInfo; +} + +void ControllerClientInfo::Reset() +{ + host.clear(); + httpPort = 0; + username.clear(); + password.clear(); + additionalHeaders.clear(); + unixEndpoint.clear(); +} + +void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) +{ + mujinjson::LoadJsonValueByKey(rClientInfo, "host", host); + mujinjson::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); + mujinjson::LoadJsonValueByKey(rClientInfo, "username", username); + mujinjson::LoadJsonValueByKey(rClientInfo, "password", password); + mujinjson::LoadJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders); + mujinjson::LoadJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint); +} + +void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const +{ + rClientInfo.SetObject(); + if( !host.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "host", host, alloc); + } + if( httpPort != 0 ) { + mujinjson::SetJsonValueByKey(rClientInfo, "httpPort", httpPort, alloc); + } + if( !username.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "username", username, alloc); + } + if( !password.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "password", password, alloc); + } + if( !additionalHeaders.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders, alloc); + } + if( !unixEndpoint.empty() ) { + mujinjson::SetJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint, alloc); + } +} + +void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const +{ + SaveToJson(rClientInfo, rClientInfo.GetAllocator()); +} + +bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const +{ + return host == rhs.host && + httpPort == rhs.httpPort && + username == rhs.username && + password == rhs.password && + additionalHeaders == rhs.additionalHeaders && + unixEndpoint == rhs.unixEndpoint; +} + +std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const +{ + std::string url; + if( host.empty() ) { + return url; + } + url += "http://"; + if( bIncludeNamePassword ) { + url += username; + url += ":"; + url += password; + url += "@"; + } + + url += host; + if( httpPort != 0 ) { + url += ":"; + url += std::to_string(httpPort); + } + return url; +} + WebstackClient::WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); size_t usernameindex = 0; usernameindex = usernamepassword.find_first_of(':'); BOOST_ASSERT(usernameindex != std::string::npos ); - _username = usernamepassword.substr(0,usernameindex); - std::string password = usernamepassword.substr(usernameindex+1); + _clientInfo.username = usernamepassword.substr(0,usernameindex); + _clientInfo.password = usernamepassword.substr(usernameindex+1); _httpheadersjson = NULL; _httpheadersstl = NULL; @@ -118,10 +256,10 @@ WebstackClient::WebstackClient(const std::string& usernamepassword, const std::s // hack for now since webdav server and api server could be running on different ports if( boost::algorithm::ends_with(_baseuri, ":8000/") || (options&0x80000000) ) { // testing on localhost, however the webdav server is running on port 80... - _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%_username); + _basewebdavuri = str(boost::format("%s/u/%s/")%_baseuri.substr(0,_baseuri.size()-6)%_clientInfo.username); } else { - _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_username); + _basewebdavuri = str(boost::format("%su/%s/")%_baseuri%_clientInfo.username); } //CURLcode code = curl_global_init(CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32); @@ -275,7 +413,7 @@ void WebstackClient::SetUserAgent(const std::string& userAgent) void WebstackClient::SetAdditionalHeaders(const std::vector& additionalHeaders) { boost::mutex::scoped_lock lock(_mutex); - _additionalHeaders = additionalHeaders; + _clientInfo.additionalHeaders = additionalHeaders; _SetupHTTPHeadersJSON(); _SetupHTTPHeadersSTL(); _SetupHTTPHeadersMultipartFormData(); @@ -283,7 +421,7 @@ void WebstackClient::SetAdditionalHeaders(const std::vector& additi const std::string& WebstackClient::GetUserName() const { - return _username; + return _clientInfo.username; } const std::string& WebstackClient::GetBaseURI() const @@ -291,6 +429,11 @@ const std::string& WebstackClient::GetBaseURI() const return _baseuri; } +const WebstackClientInfo& WebstackClient::GetClientInfo() const +{ + return _clientInfo; +} + void WebstackClient::SetProxy(const std::string& serverport, const std::string& userpw) { // mutally exclusive with unix endpoint settings @@ -857,7 +1000,7 @@ void WebstackClient::_SetupHTTPHeadersJSON() _httpheadersjson = curl_slist_append(_httpheadersjson, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersjson = curl_slist_append(_httpheadersjson, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { + for (const std::string& additionalHeader : _clientInfo.additionalHeaders) { _httpheadersjson = curl_slist_append(_httpheadersjson, additionalHeader.c_str()); } } @@ -877,7 +1020,7 @@ void WebstackClient::_SetupHTTPHeadersSTL() _httpheadersstl = curl_slist_append(_httpheadersstl, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersstl = curl_slist_append(_httpheadersstl, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { + for (const std::string& additionalHeader : _clientInfo.additionalHeaders) { _httpheadersstl = curl_slist_append(_httpheadersstl, additionalHeader.c_str()); } } @@ -897,7 +1040,7 @@ void WebstackClient::_SetupHTTPHeadersMultipartFormData() _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Keep-Alive: 20"); // keep alive for 20s? // test on windows first //_httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, "Accept-Encoding: gzip, deflate"); - for (const std::string& additionalHeader : _additionalHeaders) { + for (const std::string& additionalHeader : _clientInfo.additionalHeaders) { _httpheadersmultipartformdata = curl_slist_append(_httpheadersmultipartformdata, additionalHeader.c_str()); } } From 5262368a47e10ac7c8562f7fdac41fda4be5d967 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 7 Aug 2023 12:08:58 +0900 Subject: [PATCH 469/477] Refactor createwebstackclient to use the webstackclientinfo --- src/createwebstackclient.cpp | 72 +++++++------------ .../mujinwebstackclientcpp/webstackclient.h | 1 + src/webstackclient.cpp | 6 +- 3 files changed, 29 insertions(+), 50 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index b1ab85d7..c7a257d4 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -5,6 +5,30 @@ MUJIN_LOGGER("mujin.mujinwebstackclientcpp.createwebstackclient"); namespace mujinwebstackclient { +namespace { + +// Versions of the below implemented in terms of the WebstackClientInfo, +// to avoid re-parsing the URL. + +bool IsWebstackLocal(const WebstackClientInfo& clientInfo) +{ + return IsHostnameLocal(clientInfo.host.c_str(), clientInfo.length()); +} + +const char* GetUnixEndpointForLocalWebstack(const WebstackClientInfo& clientInfo) +{ + if (IsWebstackLocal(clientInfo)) { + const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); + if (unixendpoint != nullptr && unixendpoint[0] != '\0') { + MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"")%unixendpoint%url)); + return unixendpoint; + } + } + return ""; +} + +} + /// \brief determine if hostname is local, if len is not given, then use strlen to determine string length bool IsHostnameLocal(const char* hostname, ssize_t len) { @@ -34,55 +58,13 @@ bool IsHostnameLocal(const char* hostname, ssize_t len) /// \brief determine if the url is pointing to local webstack bool IsWebstackLocal(const char* url) { - const char* colonSlashSlash = strstr(url, "://"); - if (colonSlashSlash == nullptr) { - return false; - } - const char* hostname = colonSlashSlash + sizeof("://") - 1; - const char* at = strstr(hostname, "@"); // not found is ok - const char* slash = strstr(hostname, "/"); // not found is ok - if (at != nullptr && (slash == nullptr || at < slash)) { - hostname = at + 1; - } - const char* port = strstr(hostname, ":"); // not found is ok - ssize_t len = -1; - if (slash == nullptr) { - if (port == nullptr) { - // no port, no slash - len = -1; // use the null-terminator - } else { - // has port, no slash - if (strcmp(port, ":80") != 0) { - return false; - } - len = port - hostname; - } - } else { - if (port != nullptr && port < slash) { - // has port before slash - if (strncmp(port, ":80", slash - port) != 0) { - return false; - } - len = port - hostname; - } else { - // no port, but has slash - len = slash - hostname; - } - } - return IsHostnameLocal(hostname, len); + return IsWebstackLocal(WebstackClientInfo::FromUrl(url)); } /// \brief determine the unix endpoint if webstack is local const char* GetUnixEndpointForLocalWebstack(const char* url) { - if (IsWebstackLocal(url)) { - const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); - if (unixendpoint != nullptr && unixendpoint[0] != '\0') { - MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"")%unixendpoint%url)); - return unixendpoint; - } - } - return ""; + return GetUnixEndpointForLocalWebstack(WebstackClientInfo::FromUrl(url)); } /// \brief Transparently diverge to private webstack if url is localhost @@ -95,7 +77,7 @@ mujinwebstackclient::WebstackClientPtr CreateWebstackClient( double timeout) { WebstackClientPtr pClient = WebstackClient::CreateWebstackClient(usernamepassword, url, proxyserverport, proxyuserpw, options, timeout); - std::string unixendpoint = GetUnixEndpointForLocalWebstack(url.c_str()); + std::string unixendpoint = GetUnixEndpointForLocalWebstack(pClient->GetClientInfo()); if (!unixendpoint.empty()) { pClient->SetUnixEndpoint(unixendpoint); } diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 84729020..fc551be4 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -80,6 +80,7 @@ typedef double Real; class MUJINWEBSTACKCLIENT_API WebstackClientInfo : public mujinjsonwebstack::JsonSerializable { public: + /// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse ControllerClientInfo static WebstackClientInfo FromUrl(const char* url); void Reset(); diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 235976ad..0c1ae612 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -238,11 +238,7 @@ std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const WebstackClient::WebstackClient(const std::string& usernamepassword, const std::string& baseuri, const std::string& proxyserverport, const std::string& proxyuserpw, int options, double timeout) { BOOST_ASSERT( !baseuri.empty() ); - size_t usernameindex = 0; - usernameindex = usernamepassword.find_first_of(':'); - BOOST_ASSERT(usernameindex != std::string::npos ); - _clientInfo.username = usernamepassword.substr(0,usernameindex); - _clientInfo.password = usernamepassword.substr(usernameindex+1); + _clientInfo = WebstackClientInfo::FromUrl(baseuri.c_str()); _httpheadersjson = NULL; _httpheadersstl = NULL; From 8a4f8b9cf1cee7efbd8fe192ef31265423b23382 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 7 Aug 2023 12:13:07 +0900 Subject: [PATCH 470/477] Fix build issues --- src/createwebstackclient.cpp | 4 +- .../mujinwebstackclientcpp/webstackclient.h | 2 +- src/webstackclient.cpp | 43 ++++++++----------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index c7a257d4..f095f4a4 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -12,7 +12,7 @@ namespace { bool IsWebstackLocal(const WebstackClientInfo& clientInfo) { - return IsHostnameLocal(clientInfo.host.c_str(), clientInfo.length()); + return IsHostnameLocal(clientInfo.host.c_str(), clientInfo.host.length()); } const char* GetUnixEndpointForLocalWebstack(const WebstackClientInfo& clientInfo) @@ -20,7 +20,7 @@ const char* GetUnixEndpointForLocalWebstack(const WebstackClientInfo& clientInfo if (IsWebstackLocal(clientInfo)) { const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); if (unixendpoint != nullptr && unixendpoint[0] != '\0') { - MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"")%unixendpoint%url)); + MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since host is \"%s\"")%unixendpoint%clientInfo.host)); return unixendpoint; } } diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index fc551be4..f79245f8 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -80,7 +80,7 @@ typedef double Real; class MUJINWEBSTACKCLIENT_API WebstackClientInfo : public mujinjsonwebstack::JsonSerializable { public: - /// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse ControllerClientInfo + /// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse WebstackClientInfo static WebstackClientInfo FromUrl(const char* url); void Reset(); diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 0c1ae612..c01b3051 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -95,8 +95,8 @@ std::wstring ParseWincapsWCNPath(const T& sourcefilename, const boost::function< return strWCNPath; } -/// \brief given a port string "80", fill ControllerClientInfo httpPort -void _ParseClientInfoPort(const char* port, size_t length, ControllerClientInfo& clientInfo) +/// \brief given a port string "80", fill WebstackClientInfo httpPort +void _ParseClientInfoPort(const char* port, size_t length, WebstackClientInfo& clientInfo) { clientInfo.httpPort = 0; for (; length > 0; ++port, --length) { @@ -155,7 +155,7 @@ WebstackClientInfo WebstackClientInfo::FromUrl(const char* url) return clientInfo; } -void ControllerClientInfo::Reset() +void WebstackClientInfo::Reset() { host.clear(); httpPort = 0; @@ -165,45 +165,40 @@ void ControllerClientInfo::Reset() unixEndpoint.clear(); } -void ControllerClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) +void WebstackClientInfo::LoadFromJson(const rapidjson::Value& rClientInfo) { - mujinjson::LoadJsonValueByKey(rClientInfo, "host", host); - mujinjson::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); - mujinjson::LoadJsonValueByKey(rClientInfo, "username", username); - mujinjson::LoadJsonValueByKey(rClientInfo, "password", password); - mujinjson::LoadJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders); - mujinjson::LoadJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "host", host); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "httpPort", httpPort); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "username", username); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "password", password); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders); + mujinjsonwebstack::LoadJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint); } -void ControllerClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const +void WebstackClientInfo::SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const { rClientInfo.SetObject(); if( !host.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "host", host, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "host", host, alloc); } if( httpPort != 0 ) { - mujinjson::SetJsonValueByKey(rClientInfo, "httpPort", httpPort, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "httpPort", httpPort, alloc); } if( !username.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "username", username, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "username", username, alloc); } if( !password.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "password", password, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "password", password, alloc); } if( !additionalHeaders.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "additionalHeaders", additionalHeaders, alloc); } if( !unixEndpoint.empty() ) { - mujinjson::SetJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint, alloc); + mujinjsonwebstack::SetJsonValueByKey(rClientInfo, "unixEndpoint", unixEndpoint, alloc); } } -void ControllerClientInfo::SaveToJson(rapidjson::Document& rClientInfo) const -{ - SaveToJson(rClientInfo, rClientInfo.GetAllocator()); -} - -bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const +bool WebstackClientInfo::operator==(const WebstackClientInfo &rhs) const { return host == rhs.host && httpPort == rhs.httpPort && @@ -213,7 +208,7 @@ bool ControllerClientInfo::operator==(const ControllerClientInfo &rhs) const unixEndpoint == rhs.unixEndpoint; } -std::string ControllerClientInfo::GetURL(bool bIncludeNamePassword) const +std::string WebstackClientInfo::GetURL(bool bIncludeNamePassword) const { std::string url; if( host.empty() ) { From 417a8f19a3108be43c840b88bae3dd89bb886040 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 7 Aug 2023 15:38:06 +0900 Subject: [PATCH 471/477] Let the vision manager's planning client info override the WebstackClientInfo's Reset method --- src/include/mujinwebstackclientcpp/webstackclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index f79245f8..3a0726f4 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -83,7 +83,7 @@ class MUJINWEBSTACKCLIENT_API WebstackClientInfo : public mujinjsonwebstack::Jso /// \brief given a url "http[s]://[username[:password]@]hostname[:port][/path]", parse WebstackClientInfo static WebstackClientInfo FromUrl(const char* url); - void Reset(); + virtual void Reset(); void LoadFromJson(const rapidjson::Value& rClientInfo) override; void SaveToJson(rapidjson::Value& rClientInfo, rapidjson::Document::AllocatorType& alloc) const override; From f16cd1629799c7c52815a1ff85edce98e9e5857c Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 8 Aug 2023 15:17:40 +0900 Subject: [PATCH 472/477] Fix mujinjson's exception definition. The idea is that if mujinjson::MujinJSONExceptionInternal (from controller common) is defined, we use that. The typedef is there to handle the discrpancy in the namespace. This is done so that you can catch any JSON exception in one catch. --- .../mujinwebstackclientcpp/mujinjson.h | 88 ++++++++++--------- .../mujinwebstackclientcpp/webstackclient.h | 4 + src/mujinjson.cpp | 16 ++-- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/include/mujinwebstackclientcpp/mujinjson.h b/src/include/mujinwebstackclientcpp/mujinjson.h index 5ba01a71..7893ec16 100644 --- a/src/include/mujinwebstackclientcpp/mujinjson.h +++ b/src/include/mujinwebstackclientcpp/mujinjson.h @@ -44,7 +44,7 @@ { \ if (!mujinjsonwebstack::LoadJsonValueByKey(rValue, key, param))) \ { \ - throw mujinjsonwebstack::MujinJSONException(boost::str(boost::format(("[%s, %u] assertmujinjsonwebstack::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ + throw mujinjsonwebstack::MujinJSONWebstackException(boost::str(boost::format(("[%s, %u] assertmujinjsonwebstack::LoadJsonValueByKey(%s, %s, %s))"))%__FILE__%__LINE__%# rValue%key%# param)); \ } \ } #endif // MUJINJSONWEBSTACK_LOAD_REQUIRED_JSON_VALUE_BY_KEY @@ -108,8 +108,10 @@ class MujinJSONException : public std::exception MujinJSONErrorCode _error; }; +typedef MujinJSONException MujinJSONWebstackException; + #else -using namespace mujinjson; +typedef mujinjson::MujinJSONException MujinJSONWebstackException; #endif template inline std::string GetJsonString(const T& t); @@ -175,7 +177,7 @@ inline void ParseJson(rapidjson::Document& d, const char* str, size_t length) { if (d.HasParseError()) { const std::string substr(str, length < 200 ? length : 200); - throw MujinJSONException(boost::str(boost::format("Json string is invalid (offset %u) %s data is '%s'.")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr)); + throw MujinJSONWebstackException(boost::str(boost::format("Json string is invalid (offset %u) %s data is '%s'.")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError())%substr)); } } @@ -190,7 +192,7 @@ inline void ParseJson(rapidjson::Document& d, std::istream& is) { d.GetAllocator().Clear(); d.ParseStream(isw); // parse float in full precision mode if (d.HasParseError()) { - throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError()))); + throw MujinJSONWebstackException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)d.GetErrorOffset())%GetParseError_En(d.GetParseError()))); } } @@ -235,7 +237,7 @@ template inline T LexicalCast(const S& v, const std::string& t catch (const boost::bad_lexical_cast& ex) { std::stringstream ss; ss << v; - throw MujinJSONException("Cannot convert \"" + ss.str() + "\" to type " + typeName); + throw MujinJSONWebstackException("Cannot convert \"" + ss.str() + "\" to type " + typeName); } } @@ -252,7 +254,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, std::string& t) { //TODO: add warnings on all usages of lexical_cast t = LexicalCast(v.GetInt64(), "String"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to String"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to String"); } } @@ -267,7 +269,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Int"); } } @@ -284,7 +286,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int8_t& t) { else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int8"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Int8"); } } @@ -296,7 +298,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint8_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt8"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to UInt8"); } } @@ -308,7 +310,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint16_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to UInt"); } } @@ -320,7 +322,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned int& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to UInt"); } } @@ -332,7 +334,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, unsigned long long& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to ULongLong"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to ULongLong"); } } @@ -344,7 +346,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, uint64_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to UInt64"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to UInt64"); } } @@ -356,7 +358,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, int64_t& t) { } else if (v.IsBool()) { t = v.GetBool() ? 1 : 0; } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Int64"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Int64"); } } @@ -366,7 +368,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, double& t) { } else if (v.IsString()) { t = LexicalCast(v.GetString(), "Double"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Double"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Double"); } } @@ -376,7 +378,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, float& t) { } else if (v.IsString()) { t = LexicalCast(v.GetString(), "Float"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Float"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Float"); } } @@ -386,7 +388,7 @@ inline void LoadJsonValue(const rapidjson::Value& v, bool& t) { else if (v.IsString()) { t = LexicalCast(v.GetString(), "Bool"); } else { - throw MujinJSONException("Cannot convert json type " + GetJsonString(v) + " to Bool"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonString(v) + " to Bool"); } } @@ -406,17 +408,17 @@ template inline void LoadJsonValue(const rapidjson::Valu LoadJsonValue(v[0], t.first); LoadJsonValue(v[1], t.second); } else { - throw MujinJSONException("List-based map has entry with size != 2"); + throw MujinJSONWebstackException("List-based map has entry with size != 2"); } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Pair"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonTypeName(v) + " to Pair"); } } template inline void LoadJsonValue(const rapidjson::Value& v, T (&p)[N]) { if (v.IsArray()) { if (v.GetArray().Size() != N) { - throw MujinJSONException("Json array size doesn't match"); + throw MujinJSONWebstackException("Json array size doesn't match"); } size_t i = 0; for (rapidjson::Value::ConstValueIterator it = v.Begin(); it != v.End(); ++it) { @@ -424,7 +426,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); } } @@ -438,14 +440,14 @@ template inline void LoadJsonValue(const rapidjson::Value i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Vector"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonTypeName(v) + " to Vector"); } } template inline void LoadJsonValue(const rapidjson::Value& v, std::array& t) { if (v.IsArray()) { if (v.GetArray().Size() != N) { - throw MujinJSONException( + throw MujinJSONWebstackException( (boost::format("Cannot convert json type " + GetJsonTypeName(v) + " to Array. " "Array length does not match (%d != %d)") % N % v.GetArray().Size()).str()); } @@ -455,7 +457,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, i++; } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonTypeName(v) + " to Array"); } } @@ -477,7 +479,7 @@ template inline void LoadJsonValue(const rapidjson::Value& v, std::map< t[std::string(it->name.GetString(), it->name.GetStringLength())] = value; // string can contain null character } } else { - throw MujinJSONException("Cannot convert json type " + GetJsonTypeName(v) + " to Map"); + throw MujinJSONWebstackException("Cannot convert json type " + GetJsonTypeName(v) + " to Map"); } } @@ -644,7 +646,7 @@ template inline void SetJsonValueByKey(rapidjson::Value& v, co //return true if key is present. Will return false if the key is not present or the member is Null template bool inline LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object."); + throw MujinJSONWebstackException("Cannot load value of non-object."); } rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); if( itMember != v.MemberEnd() ) { @@ -654,8 +656,8 @@ template bool inline LoadJsonValueByKey(const rapidjson::Value& v, cons LoadJsonValue(rMember, t); return true; } - catch (const MujinJSONException& ex) { - throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + catch (const MujinJSONWebstackException& ex) { + throw MujinJSONWebstackException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); } } } @@ -664,7 +666,7 @@ template bool inline LoadJsonValueByKey(const rapidjson::Value& v, cons } template inline void LoadJsonValueByKey(const rapidjson::Value& v, const char* key, T& t, const U& d) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object."); + throw MujinJSONWebstackException("Cannot load value of non-object."); } rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); @@ -672,8 +674,8 @@ template inline void LoadJsonValueByKey(const rapidjson::Value try { LoadJsonValue(itMember->value, t); } - catch (const MujinJSONException& ex) { - throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + catch (const MujinJSONWebstackException& ex) { + throw MujinJSONWebstackException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); } } else { @@ -701,7 +703,7 @@ template inline void LoadJsonValueByPath(const rapidjson::Valu //work the same as LoadJsonValueByKey, but the value is returned instead of being passed as reference template T GetJsonValueByKey(const rapidjson::Value& v, const char* key, const U& t) { if (!v.IsObject()) { - throw MujinJSONException("Cannot get value of non-object."); + throw MujinJSONWebstackException("Cannot get value of non-object."); } rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); @@ -712,8 +714,8 @@ template T GetJsonValueByKey(const rapidjson::Value& v, const try { LoadJsonValue(v[key], r); } - catch (const MujinJSONException& ex) { - throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + catch (const MujinJSONWebstackException& ex) { + throw MujinJSONWebstackException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); } return r; } @@ -722,7 +724,7 @@ template T GetJsonValueByKey(const rapidjson::Value& v, const } template inline T GetJsonValueByKey(const rapidjson::Value& v, const char* key) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object."); + throw MujinJSONWebstackException("Cannot load value of non-object."); } T r = T(); rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); @@ -732,8 +734,8 @@ template inline T GetJsonValueByKey(const rapidjson::Value& v, const ch try { LoadJsonValue(v[key], r); } - catch (const MujinJSONException& ex) { - throw MujinJSONException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); + catch (const MujinJSONWebstackException& ex) { + throw MujinJSONWebstackException("Got \"" + ex.message() + "\" while parsing the value of \"" + key + "\""); } } } @@ -747,7 +749,7 @@ inline std::string GetStringJsonValueByKey(const rapidjson::Value& v, const char /// \brief default value is returned when there is no key or value is null inline const char* GetCStringJsonValueByKey(const rapidjson::Value& v, const char* key, const char* pDefaultValue=nullptr) { if (!v.IsObject()) { - throw MujinJSONException("Cannot load value of non-object."); + throw MujinJSONWebstackException("Cannot load value of non-object."); } rapidjson::Value::ConstMemberIterator itMember = v.FindMember(key); if (itMember != v.MemberEnd() ) { @@ -757,7 +759,7 @@ inline const char* GetCStringJsonValueByKey(const rapidjson::Value& v, const cha return child.GetString(); } else { - throw MujinJSONException("In GetCStringJsonValueByKey, expecting a String, but got a different object type"); + throw MujinJSONWebstackException("In GetCStringJsonValueByKey, expecting a String, but got a different object type"); } } } @@ -818,7 +820,7 @@ template inline void SetJsonValueByPath(rapidjson::Document& d, const c template inline void SetJsonValueByKey(rapidjson::Value& v, const U& key, const T& t, rapidjson::Document::AllocatorType& alloc) { if (!v.IsObject()) { - throw MujinJSONException("Cannot set value for non-object."); + throw MujinJSONWebstackException("Cannot set value for non-object."); } if (v.HasMember(key)) { SaveJsonValue(v[key], t, alloc); @@ -846,7 +848,7 @@ inline void SetJsonValueByKey(rapidjson::Document& d, const std::string& key, co inline void ValidateJsonString(const std::string& str) { rapidjson::Document d; if (d.Parse(str.c_str()).HasParseError()) { - throw MujinJSONException("json string " + str + " is invalid." + GetParseError_En(d.GetParseError())); + throw MujinJSONWebstackException("json string " + str + " is invalid." + GetParseError_En(d.GetParseError())); } } @@ -866,10 +868,10 @@ template inline std::string GetJsonStringByKey(const U& key, c */ inline void UpdateJson(rapidjson::Document& a, const rapidjson::Value& b) { if (!a.IsObject()) { - throw MujinJSONException("json object should be a dict to be updated: " + GetJsonString(a)); + throw MujinJSONWebstackException("json object should be a dict to be updated: " + GetJsonString(a)); } if (!b.IsObject()) { - throw MujinJSONException("json object should be a dict to update another dict: " + GetJsonString(b)); + throw MujinJSONWebstackException("json object should be a dict to update another dict: " + GetJsonString(b)); } for (rapidjson::Value::ConstMemberIterator it = b.MemberBegin(); it != b.MemberEnd(); ++it) { SetJsonValueByKey(a, it->name.GetString(), it->value); diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 3a0726f4..3303af3c 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -161,6 +161,10 @@ class MUJINWEBSTACKCLIENT_API WebstackClient /// \brief returns the URI used to setup the connection const std::string& GetBaseURI() const; + std::string GetURIWithUsernamePassword() const { + return GetClientInfo().GetURL(true); + } + const WebstackClientInfo& GetClientInfo() const; /// \brief If necessary, changes the proxy to communicate to the controller server. Setting proxy disables previously set unix endpoint. diff --git a/src/mujinjson.cpp b/src/mujinjson.cpp index 3316e692..84e37d74 100644 --- a/src/mujinjson.cpp +++ b/src/mujinjson.cpp @@ -15,13 +15,13 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff const int fd = ::open(filename, O_RDONLY); if (fd < 0) { - throw MujinJSONException(boost::str(boost::format("Could not open Json file %s") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("Could not open Json file %s") % filename)); } struct stat fs; if (::fstat(fd, &fs) != 0) { ::close(fd); - throw MujinJSONException(boost::str(boost::format("Could not get file stats of Json file %s") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("Could not get file stats of Json file %s") % filename)); } if( fs.st_size == 0 ) { @@ -30,7 +30,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff size_t nBufferSize = nChunkSize; char* pbuffer = (char*)::malloc(nBufferSize); if( !pbuffer ) { - throw MujinJSONException("Could not allocate memory"); + throw MujinJSONWebstackException("Could not allocate memory"); } size_t nFileSize = 0; @@ -40,7 +40,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff nBufferSize += nChunkSize; pbuffer = (char*)::realloc(pbuffer, nBufferSize); if( !pbuffer ) { - throw MujinJSONException("Could not allocate memory"); + throw MujinJSONWebstackException("Could not allocate memory"); } nTotalToRead = nBufferSize - nFileSize; } @@ -51,7 +51,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff } ::close(fd); ::free(pbuffer); - throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); } if( count == 0 ) { break; // EOF @@ -63,7 +63,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff if( nFileSize == 0 ) { ::free(pbuffer); - throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("JSON file '%s' is empty") % filename)); } try { @@ -87,7 +87,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff continue; // retry if interrupted } ::close(fd); - throw MujinJSONException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("Could not read file data from Json file '%s'") % filename)); } if( count == 0 ) { break; // EOF @@ -97,7 +97,7 @@ void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buff ::close(fd); if( offset == 0 ) { - throw MujinJSONException(boost::str(boost::format("JSON file '%s' is empty") % filename)); + throw MujinJSONWebstackException(boost::str(boost::format("JSON file '%s' is empty") % filename)); } ParseJson(d, reinterpret_cast(buffer.data()), offset); From 00fca61f2f8fdba99651043459931e717c25e98d Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Mon, 14 Aug 2023 18:50:07 +0900 Subject: [PATCH 473/477] Update the client info when the unix endpoint is updated --- src/webstackclient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index c01b3051..9766c6ff 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -431,6 +431,7 @@ void WebstackClient::SetProxy(const std::string& serverport, const std::string& CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, serverport.c_str()); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, userpw.c_str()); + _clientInfo.unixEndpoint.clear(); } void WebstackClient::SetUnixEndpoint(const std::string& unixendpoint) @@ -439,6 +440,7 @@ void WebstackClient::SetUnixEndpoint(const std::string& unixendpoint) CURL_OPTION_SETTER(_curl, CURLOPT_PROXY, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_PROXYUSERPWD, NULL); CURL_OPTION_SETTER(_curl, CURLOPT_UNIX_SOCKET_PATH, unixendpoint.c_str()); + _clientInfo.unixEndpoint = unixendpoint; } void WebstackClient::RestartServer(double timeout) From 40ac36d72c6cf247e4480f9d6032320746d37da9 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 15 Aug 2023 10:13:23 +0900 Subject: [PATCH 474/477] Override the username and password from the baseuri with the parameter. Also add some logging because I'm losing my mind a little. --- src/createwebstackclient.cpp | 4 +++- src/webstackclient.cpp | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index f095f4a4..808a2694 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -20,10 +20,12 @@ const char* GetUnixEndpointForLocalWebstack(const WebstackClientInfo& clientInfo if (IsWebstackLocal(clientInfo)) { const char* unixendpoint = std::getenv("MUJIN_WEBSTACK_UNIX_ENDPOINT"); if (unixendpoint != nullptr && unixendpoint[0] != '\0') { - MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since host is \"%s\"")%unixendpoint%clientInfo.host)); + MUJIN_LOG_DEBUG(boost::str(boost::format("forcing webstack client to use unix endpoint \"%s\" since url is \"%s\"")%unixendpoint%clientInfo.GetURL(true))); return unixendpoint; } + MUJIN_LOG_DEBUG(boost::str(boost::format("No unix endpoint -- url is \"%s\"")%clientInfo.GetURL(true))); } + MUJIN_LOG_DEBUG(boost::str(boost::format("Not using unix endpoint since url is \"%s\"")%clientInfo.GetURL(true))); return ""; } diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index 9766c6ff..be1b9d54 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -104,6 +104,18 @@ void _ParseClientInfoPort(const char* port, size_t length, WebstackClientInfo& c } } +void _ParseUsernamePassword(const char* usernamePassword, const char* usernamePasswordEnd, WebstackClientInfo& clientInfo) +{ + const char* colon = strstr(usernamePassword, ":"); // not found is ok + if (colon != nullptr) { + const char* password = colon + sizeof(":") - 1; + clientInfo.username = std::string(usernamePassword, colon - usernamePassword); + clientInfo.password = std::string(password, at - password); + } else { + clientInfo.username = std::string(usernamePassword, at - usernamePassword); + } +} + } // end namespace @@ -121,14 +133,7 @@ WebstackClientInfo WebstackClientInfo::FromUrl(const char* url) // if the at is before the slash, i.e. for the username:password const char* usernamePassword = hostname; hostname = at + sizeof("@") - 1; - const char* colon = strstr(usernamePassword, ":"); // not found is ok - if (colon != nullptr) { - const char* password = colon + sizeof(":") - 1; - clientInfo.username = std::string(usernamePassword, colon - usernamePassword); - clientInfo.password = std::string(password, at - password); - } else { - clientInfo.username = std::string(usernamePassword, at - usernamePassword); - } + _ParseUsernamePassword(usernamePassword, at, clientInfo); } const char* port = strstr(hostname, ":"); // not found is ok if (slash == nullptr) { @@ -234,6 +239,10 @@ WebstackClient::WebstackClient(const std::string& usernamepassword, const std::s { BOOST_ASSERT( !baseuri.empty() ); _clientInfo = WebstackClientInfo::FromUrl(baseuri.c_str()); + if (!usernamepassword.empty()) { + const char* usernamePasswordPtr = usernamepassword.c_str(); + _ParseUsernamePassword(usernamePasswordPtr, usernamePasswordPtr + usernamepassword.length(), _clientInfo); + } _httpheadersjson = NULL; _httpheadersstl = NULL; From 32fe966211e85f971dc76aec6d86ca3cfdf1304a Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 15 Aug 2023 10:22:12 +0900 Subject: [PATCH 475/477] Fix name errors in _ParseUsernamePassword --- src/webstackclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index be1b9d54..a6ced177 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -110,9 +110,9 @@ void _ParseUsernamePassword(const char* usernamePassword, const char* usernamePa if (colon != nullptr) { const char* password = colon + sizeof(":") - 1; clientInfo.username = std::string(usernamePassword, colon - usernamePassword); - clientInfo.password = std::string(password, at - password); + clientInfo.password = std::string(password, usernamePasswordEnd - password); } else { - clientInfo.username = std::string(usernamePassword, at - usernamePassword); + clientInfo.username = std::string(usernamePassword, usernamePasswordEnd - usernamePassword); } } From 46e971954fdf3210ffd8a9a9c8e7e5fbca9252d0 Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Thu, 17 Aug 2023 18:20:43 +0900 Subject: [PATCH 476/477] Fix locality checking -- we need to be on port 80 or have no port for webstack to be local --- src/createwebstackclient.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/createwebstackclient.cpp b/src/createwebstackclient.cpp index 808a2694..56a9f952 100644 --- a/src/createwebstackclient.cpp +++ b/src/createwebstackclient.cpp @@ -12,6 +12,9 @@ namespace { bool IsWebstackLocal(const WebstackClientInfo& clientInfo) { + if (clientInfo.httpPort != 0 && clientInfo.httpPort != 80) { + return false; + } return IsHostnameLocal(clientInfo.host.c_str(), clientInfo.host.length()); } From da3ac74746f1f2fe017abef7ddc8a64f07ca29ae Mon Sep 17 00:00:00 2001 From: "heman.gandhi" Date: Tue, 22 Aug 2023 16:20:52 +0900 Subject: [PATCH 477/477] Apply https://git.mujin.co.jp/dev/controllerclientcpp/-/commit/9604b45c7dc334368c00250bf9b03068a6517f37 This makes it so getting JSON from HTTP GETs and POSTs do not clear the allocators of the caller-provided documents. --- .../mujinwebstackclientcpp/mujinjson.h | 25 +++++++++++++++++ .../mujinwebstackclientcpp/webstackclient.h | 4 +-- src/webstackclient.cpp | 28 +++++++++---------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/include/mujinwebstackclientcpp/mujinjson.h b/src/include/mujinwebstackclientcpp/mujinjson.h index 7893ec16..1c252406 100644 --- a/src/include/mujinwebstackclientcpp/mujinjson.h +++ b/src/include/mujinwebstackclientcpp/mujinjson.h @@ -166,6 +166,7 @@ inline void DumpJson(const rapidjson::Value& value, std::ostream& os, const unsi } } +/// \brief This clears the d's allocator! inline void ParseJson(rapidjson::Document& d, const char* str, size_t length) { // repeatedly calling Parse on the same rapidjson::Document will not release previsouly allocated memory, memory will accumulate until the object is destroyed // we use a new temporary Document to parse, and swap content with the original one, so that memory in original Document will be released when this function ends @@ -181,10 +182,12 @@ inline void ParseJson(rapidjson::Document& d, const char* str, size_t length) { } } +/// \brief This clears the d's allocator! inline void ParseJson(rapidjson::Document& d, const std::string& str) { ParseJson(d, str.c_str(), str.size()); } +/// \brief This clears the d's allocator! inline void ParseJson(rapidjson::Document& d, std::istream& is) { rapidjson::IStreamWrapper isw(is); // see note in: void ParseJson(rapidjson::Document& d, const std::string& str) @@ -196,6 +199,28 @@ inline void ParseJson(rapidjson::Document& d, std::istream& is) { } } +inline void ParseJson(rapidjson::Value& r, rapidjson::Document::AllocatorType& alloc, std::istream& is) +{ + rapidjson::IStreamWrapper isw(is); + rapidjson::GenericReader reader(&alloc); + //ClearStackOnExit scope(*this); + + size_t kDefaultStackCapacity = 1024; + rapidjson::Document rTemp(&alloc, kDefaultStackCapacity); // needed by Parse to be a document + rTemp.ParseStream(isw); // parse float in full precision mode + if (rTemp.HasParseError()) { + throw MujinJSONWebstackException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)rTemp.GetErrorOffset())%GetParseError_En(rTemp.GetParseError()))); + } + r.Swap(rTemp); + +// rapidjson::ParseResult parseResult = reader.template Parse(isw, rTemp); +// if( parseResult.IsError() ) { +// *stack_.template Pop(1) +// throw MujinJSONException(boost::str(boost::format("Json stream is invalid (offset %u) %s")%((unsigned)parseResult.Offset())%GetParseError_En(parseResult.Code()))); +// } +} + + template MUJINWEBSTACKCLIENT_API void ParseJsonFile(rapidjson::Document& d, const char* filename, Container& buffer); diff --git a/src/include/mujinwebstackclientcpp/webstackclient.h b/src/include/mujinwebstackclientcpp/webstackclient.h index 3303af3c..5939757d 100644 --- a/src/include/mujinwebstackclientcpp/webstackclient.h +++ b/src/include/mujinwebstackclientcpp/webstackclient.h @@ -332,12 +332,12 @@ class MUJINWEBSTACKCLIENT_API WebstackClient //@{ /// \param desturi expects the fully resolved URI to pass to curl - int _CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode=200, double timeout = 5.0); + int _CallGet(const std::string& desturi, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode=200, double timeout = 5.0); int _CallGet(const std::string& desturi, std::string& outputdata, int expectedhttpcode=200, double timeout = 5.0); int _CallGet(const std::string& desturi, std::vector& outputdata, int expectedhttpcode=200, double timeout = 5.0); int _CallGet(const std::string& desturi, std::ostream& outputStream, int expectedhttpcode=200, double timeout = 5.0); - int _CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode=201, double timeout = 5.0); + int _CallPost(const std::string& desturi, const std::string& data, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode=201, double timeout = 5.0); static int _WriteStringStreamCallback(char *data, size_t size, size_t nmemb, std::stringstream *writerData); static int _WriteVectorCallback(char *data, size_t size, size_t nmemb, std::vector *writerData); diff --git a/src/webstackclient.cpp b/src/webstackclient.cpp index a6ced177..566c795f 100644 --- a/src/webstackclient.cpp +++ b/src/webstackclient.cpp @@ -510,7 +510,7 @@ void WebstackClient::_ExecuteGraphQuery(const char* operationName, const char* q } _uri = _baseuri + "api/v2/graphql"; - _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, 200, timeout); + _CallPost(_uri, rRequestStringBuffer.GetString(), rResultDoc, rResultDoc.GetAllocator(), 200, timeout); } // parse response @@ -620,7 +620,7 @@ void WebstackClient::ModifySceneAddReferenceObjectPK(const std::string &scenepk, pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, 200, timeout); + _CallPost(_baseuri + "referenceobjectpks/add/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); } void WebstackClient::ModifySceneRemoveReferenceObjectPK(const std::string &scenepk, const std::string &referenceobjectpk, double timeout) @@ -637,7 +637,7 @@ void WebstackClient::ModifySceneRemoveReferenceObjectPK(const std::string &scene pt.AddMember("referenceobjectpk", value, pt.GetAllocator()); boost::mutex::scoped_lock lock(_mutex); - _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, 200, timeout); + _CallPost(_baseuri + "referenceobjectpks/remove/", DumpJson(pt), pt2, pt2.GetAllocator(), 200, timeout); } const std::string& WebstackClient::GetDefaultTaskType() @@ -697,10 +697,10 @@ int WebstackClient::CallGet(const std::string& relativeuri, rapidjson::Document& boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallGet(_uri, pt, expectedhttpcode, timeout); + return _CallGet(_uri, pt, pt.GetAllocator(), expectedhttpcode, timeout); } -int WebstackClient::_CallGet(const std::string& desturi, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int WebstackClient::_CallGet(const std::string& desturi, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) { MUJIN_LOG_INFO(str(boost::format("GET %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -715,11 +715,11 @@ int WebstackClient::_CallGet(const std::string& desturi, rapidjson::Document& pt long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { - mujinjsonwebstack::ParseJson(pt, _buffer.str()); + mujinjsonwebstack::ParseJson(rResult, alloc, _buffer); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); + std::string error_message = GetJsonValueByKey(rResult, "error_message"); + std::string traceback = GetJsonValueByKey(rResult, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP GET to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code; @@ -832,11 +832,11 @@ int WebstackClient::CallPost(const std::string& relativeuri, const std::string& boost::mutex::scoped_lock lock(_mutex); _uri = _baseapiuri; _uri += relativeuri; - return _CallPost(_uri, data, pt, expectedhttpcode, timeout); + return _CallPost(_uri, data, pt, pt.GetAllocator(), expectedhttpcode, timeout); } /// \brief expectedhttpcode is not 0, then will check with the returned http code and if not equal will throw an exception -int WebstackClient::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Document& pt, int expectedhttpcode, double timeout) +int WebstackClient::_CallPost(const std::string& desturi, const std::string& data, rapidjson::Value& rResult, rapidjson::Document::AllocatorType& alloc, int expectedhttpcode, double timeout) { MUJIN_LOG_VERBOSE(str(boost::format("POST %s")%desturi)); CURL_OPTION_SAVE_SETTER(_curl, CURLOPT_TIMEOUT_MS, 0L, (long)(timeout * 1000L)); @@ -853,13 +853,13 @@ int WebstackClient::_CallPost(const std::string& desturi, const std::string& dat long http_code = 0; CURL_INFO_GETTER(_curl, CURLINFO_RESPONSE_CODE, &http_code); if( _buffer.rdbuf()->in_avail() > 0 ) { - ParseJson(pt, _buffer.str()); + ParseJson(rResult, alloc, _buffer); } else { - pt.SetObject(); + rResult.SetObject(); } if( expectedhttpcode != 0 && http_code != expectedhttpcode ) { - std::string error_message = GetJsonValueByKey(pt, "error_message"); - std::string traceback = GetJsonValueByKey(pt, "traceback"); + std::string error_message = GetJsonValueByKey(rResult, "error_message"); + std::string traceback = GetJsonValueByKey(rResult, "traceback"); throw MUJIN_EXCEPTION_FORMAT("HTTP POST to '%s' returned HTTP status %s: %s", desturi%http_code%error_message, MEC_HTTPServer); } return http_code;