diff --git a/.gitmodules b/.gitmodules index f7f9e74a2..c4d514cea 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ +[submodule "supportlibs/restbed"] + path = supportlibs/restbed + url = https://github.com/Corvusoft/restbed.git [submodule "cmark"] path = supportlibs/cmark url = https://github.com/commonmark/cmark.git diff --git a/README.md b/README.md index c726983e5..3d98c2312 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Build Status | Platform | Build Status | | :------------- | :------------- | | GNU/Linux, MacOS, (via travis-ci) | [![Build Status](https://travis-ci.org/RetroShare/RetroShare.svg?branch=master)](https://travis-ci.org/RetroShare/RetroShare) | -| Windows, `MSys2` (via appveyor) | [![Build status](https://ci.appveyor.com/api/projects/status/fu7q0ye6pge53579?svg=true)](https://ci.appveyor.com/project/PhenomRetroShare/retroshare-59qxh) | +| Windows, `MSys2` (via appveyor) | [![Build status](https://ci.appveyor.com/api/projects/status/github/RetroShare/RetroShare?svg=true)](https://ci.appveyor.com/project/G10h4ck/retroshare-u4lmn) | Compilation on Windows ---------------------------- diff --git a/RetroShare.pro b/RetroShare.pro index 0b009cfd5..4197db2e0 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -23,6 +23,12 @@ TEMPLATE = subdirs SUBDIRS += openpgpsdk openpgpsdk.file = openpgpsdk/src/openpgpsdk.pro +rs_jsonapi { + SUBDIRS += jsonapi-generator + jsonapi-generator.file = jsonapi-generator/src/jsonapi-generator.pro + libretroshare.depends += jsonapi-generator +} + SUBDIRS += libbitdht libbitdht.file = libbitdht/src/libbitdht.pro libretroshare.depends = openpgpsdk libbitdht diff --git a/jsonapi-generator/README.adoc b/jsonapi-generator/README.adoc new file mode 100644 index 000000000..fe3566fa6 --- /dev/null +++ b/jsonapi-generator/README.adoc @@ -0,0 +1,313 @@ +RetroShare JSON API +=================== + +:Cxx: C++ + +== How to use RetroShare JSON API + +Look for methods marked with +@jsonapi+ doxygen custom command into ++libretroshare/src/retroshare+. The method path is composed by service instance +pointer name like +rsGxsChannels+ for +RsGxsChannels+, and the method name like ++createGroup+ and pass the input paramethers as a JSON object. + +.Service instance pointer in rsgxschannels.h +[source,cpp] +-------------------------------------------------------------------------------- +/** + * Pointer to global instance of RsGxsChannels service implementation + * @jsonapi{development} + */ +extern RsGxsChannels* rsGxsChannels; +-------------------------------------------------------------------------------- + +.Method declaration in rsgxschannels.h +[source,cpp] +-------------------------------------------------------------------------------- + /** + * @brief Request channel creation. + * The action is performed asyncronously, so it could fail in a subsequent + * phase even after returning true. + * @jsonapi{development} + * @param[out] token Storage for RsTokenService token to track request + * status. + * @param[in] group Channel data (name, description...) + * @return false on error, true otherwise + */ + virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0; +-------------------------------------------------------------------------------- + +.paramethers.json +[source,json] +-------------------------------------------------------------------------------- +{ + "group":{ + "mMeta":{ + "mGroupName":"JSON test group", + "mGroupFlags":4, + "mSignFlags":520 + }, + "mDescription":"JSON test group description" + }, + "caller_data":"Here can go any kind of JSON data (even objects) that the caller want to get back together with the response" +} +-------------------------------------------------------------------------------- + +.Calling the JSON API with curl on the terminal +[source,bash] +-------------------------------------------------------------------------------- +curl -H "Content-Type: application/json" --data @paramethers.json \ + http://127.0.0.1:9092/rsGxsChannels/createGroup +-------------------------------------------------------------------------------- + +.JSON API call result +[source,json] +-------------------------------------------------------------------------------- +{ + "caller_data": "Here can go any kind of JSON data (even objects) that the caller want to get back together with the response", + "retval": true, + "token": 3 +} +-------------------------------------------------------------------------------- + + +== Offer new RetroShare services through JSON API + +To offer a retroshare service through the JSON API, first of all one need find +the global pointer to the service instance and document it in doxygen syntax, +plus marking with the custom doxygen command +@jsonapi{RS_VERSION}+ where ++RS_VERSION+ is the retroshare version in which this service became available +with the current semantic (major changes to the service semantic, changes the +meaning of the service itself, so the version should be updated in the +documentation in that case). + +.Service instance pointer in rsgxschannels.h +[source,cpp] +-------------------------------------------------------------------------------- +/** + * Pointer to global instance of RsGxsChannels service implementation + * @jsonapi{development} + */ +extern RsGxsChannels* rsGxsChannels; +-------------------------------------------------------------------------------- + + +Once the service instance itself is known to the JSON API you need to document +in doxygen syntax and mark with the custom doxygen command ++@jsonapi{RS_VERSION}+ the methods of the service that you want to make +available through JSON API. + +.Offering RsGxsChannels::getChannelDownloadDirectory in rsgxschannels.h +[source,cpp] +-------------------------------------------------------------------------------- + /** + * Get download directory for the given channel + * @jsonapi{development} + * @param[in] channelId id of the channel + * @param[out] directory reference to string where to store the path + * @return false on error, true otherwise + */ + virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId, + std::string& directory ) = 0; +-------------------------------------------------------------------------------- + +For each paramether you must specify if it is used as input +@param[in]+ as +output +@param[out]+ or both +@param[inout]+. Paramethers and return value +types must be of a type supported by +RsTypeSerializer+ which already support +most basic types (+bool+, +std::string+...), +RsSerializable+ and containers of +them like +std::vector+. Paramethers passed by value and by +reference of those types are both supported, while passing by pointer is not +supported. If your paramether or return +class+/+struct+ type is not supported +yet by +RsTypeSerializer+ most convenient approach is to make it derive from ++RsSerializable+ and implement +serial_process+ method like I did with ++RsGxsChannelGroup+. + +.Deriving RsGxsChannelGroup from RsSerializable in rsgxschannels.h +[source,cpp] +-------------------------------------------------------------------------------- +struct RsGxsChannelGroup : RsSerializable +{ + RsGroupMetaData mMeta; + std::string mDescription; + RsGxsImage mImage; + + bool mAutoDownload; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mDescription); + RS_SERIAL_PROCESS(mImage); + RS_SERIAL_PROCESS(mAutoDownload); + } +}; +-------------------------------------------------------------------------------- + +You can do the same recursively for any member of your +struct+ that is not yet +supported by +RsTypeSerializer+. + +Some Retroshare {Cxx} API functions are asyncronous, historically RetroShare +didn't follow a policy on how to expose asyncronous API so differents services +and some times even differents method of the same service follow differents +asyncronous patterns, thus making automatic generation of JSON API wrappers for +those methods impractical. Instead of dealing with all those differents patterns +I have chosed to support only one new pattern taking advantage of modern {Cxx}11 +and restbed features. On the {Cxx}11 side lambdas and +std::function+s are used, +on the restbed side Server Side Events are used to send asyncronous results. + +Lets see an example so it will be much esier to understand. + +.RsGxsChannels::turtleSearchRequest asyncronous API +[source,cpp] +-------------------------------------------------------------------------------- + /** + * @brief Request remote channels search + * @jsonapi{development} + * @param[in] matchString string to look for in the search + * @param multiCallback function that will be called each time a search + * result is received + * @param[in] maxWait maximum wait time in seconds for search results + * @return false on error, true otherwise + */ + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& multiCallback, + std::time_t maxWait = 300 ) = 0; +-------------------------------------------------------------------------------- + ++RsGxsChannels::turtleSearchRequest(...)+ is an asyncronous method because it +send a channel search request on turtle network and then everytime a result is +received from the network +multiCallback+ is called and the result is passed as +parameter. To be supported by the automatic JSON API wrappers generator an +asyncronous method need a parameter of type +std::function+ called ++callback+ if the callback will be called only once or +multiCallback+ if the +callback is expected to be called more then once like in this case. +A second mandatory parameter is +maxWait+ of type +std::time_t+ it indicates the +maximum amount of time in seconds for which the caller is willing to wait for +results, in case the timeout is reached the callback will not be called anymore. + +[IMPORTANT] +================================================================================ ++callback+ and +multiCallback+ parameters documentation must *not* specify ++[in]+, +[out]+, +[inout]+, in Doxygen documentation as this would fool the +automatic wrapper generator, and ultimately break the compilation. +================================================================================ + +.RsFiles::turtleSearchRequest asyncronous JSON API usage example +[source,bash] +-------------------------------------------------------------------------------- +$ cat turtle_search.json +{ + "matchString":"linux" +} +$ curl --data @turtle_search.json http://127.0.0.1:9092/rsFiles/turtleSearchRequest +data: {"retval":true} + +data: {"results":[{"size":157631,"hash":"69709b4d01025584a8def5cd78ebbd1a3cf3fd05","name":"kill_bill_linux_1024x768.jpg"},{"size":192560,"hash":"000000000000000000009a93e5be8486c496f46c","name":"coffee_box_linux2.jpg"},{"size":455087,"hash":"9a93e5be8486c496f46c00000000000000000000","name":"Linux.png"},{"size":182004,"hash":"e8845280912ebf3779e400000000000000000000","name":"Linux_2_6.png"}]} + +data: {"results":[{"size":668,"hash":"e8845280912ebf3779e400000000000000000000","name":"linux.png"},{"size":70,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.txt.sha1sum"},{"size":3076767744,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.iso"},{"size":2780872,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.bin"},{"size":917504,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.lzma"},{"size":2278404096,"hash":"e8845280912ebf3779e400000000000000000000","name":"gentoo-linux-livedvd-amd64-multilib-20160704.iso"},{"size":151770333,"hash":"e8845280912ebf3779e400000000000000000000","name":"flashtool-0.9.23.0-linux.tar.7z"},{"size":2847372,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.elf"},{"size":1310720,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.gz"},{"size":987809,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux-lzma.elf"}]} + +-------------------------------------------------------------------------------- + +== A bit of history + +=== First writings about this + +The previous attempt of exposing a RetroShare JSON API is called +libresapi+ and +unfortunatley it requires a bunch of boilerplate code when we want to expose +something present in the {Cxx} API in the JSON API. + +As an example here you can see the libresapi that exposes part of the retroshare +chat {Cxx} API and lot of boilerplate code just to convert {Cxx} objects to JSON + +https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L44 + +To avoid the {Cxx} to JSON and back conversion boilerplate code I have worked out +an extension to our {Cxx} serialization code so it is capable to serialize and +deserialize to JSON you can see it in this pull request + +https://github.com/RetroShare/RetroShare/pull/1155 + +So first step toward having a good API is to take advantage of the fact that RS +is now capable of converting C++ objects from and to JSON. + +The current API is accessible via HTTP and unix socket, there is no +authentication in both of them, so anyone having access to the HTTP server or to +the unix socket can access the API without extra restrictions. +Expecially for the HTTP API this is a big risk because also if the http server +listen on 127.0.0.1 every application on the machine (even rogue javascript +running on your web browser) can access that and for example on android it is +not safe at all (because of that I implemented the unix socket access so at +least in android API was reasonably safe) because of this. + +A second step to improve the API would be to implement some kind of API +authentication mechanism (it would be nice that the mechanism is handled at API +level and not at transport level so we can use it for any API trasport not just +HTTP for example) + +The HTTP server used by libresapi is libmicrohttpd server that is very minimal, +it doesn't provide HTTPS nor modern HTTP goodies, like server notifications, +websockets etc. because the lack of support we have a token polling mechanism in +libresapi to avoid polling for every thing but it is still ugly, so if we can +completely get rid of polling in the API that would be really nice. +I have done a crawl to look for a replacement and briefly looked at + +- https://www.gnu.org/software/libmicrohttpd/ +- http://wolkykim.github.io/libasyncd/ +- https://github.com/corvusoft/restbed +- https://code.facebook.com/posts/1503205539947302/introducing-proxygen-facebook-s-c-http-framework/ +- https://github.com/cmouse/yahttp + +taking in account a few metrics like modern HTTP goodies support, license, +platform support, external dependencies and documentation it seemed to me that +restbed is the more appropriate. + +Another source of boilerplate code into libresapi is the mapping between JSON +API requests and C++ API methods as an example you can look at this + +https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L158 + +and this + +https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ApiServer.cpp#L253 + +The abstract logic of this thing is, when libreasapi get a request like ++/chat/initiate_distant_chat+ then call ++ChatHandler::handleInitiateDistantChatConnexion+ which in turn is just a +wrapper of +RsMsgs::initiateDistantChatConnexion+ all this process is basically +implemented as boilerplate code and would be unnecessary in a smarter design of +the API because almost all the information needed is already present in the +C++ API +libretroshare/src/retroshare+. + +So a third step to improve the JSON API would be to remove this source of +boilerplate code by automatizing the mapping between C++ and JSON API call. + +This may result a little tricky as language parsing or other adevanced things +may be required. + +Hope this dive is useful for you + +Cheers + +G10h4ck + +=== Second writings about this + +I have been investigating a bit more about: +[verse, G10h4ck] +________________________________________________________________________________ +So a third step to improve the JSON API would be to remove this source of +boilerplate code by automatizing the mapping between C++ and JSON API call +________________________________________________________________________________ + +After spending some hours investigating this topic the most reasonable approach +seems to: + +1. Properly document headers in +libretroshare/src/retroshare/+ in doxygen syntax +specifying wihich params are input and/or output (doxygen sysntax for this is ++@param[in/out/inout]+) this will be the API documentation too. + +2. At compile time use doxygen to generate XML description of the headers and use +the XML to generate the JSON api server stub. +http://www.stack.nl/~dimitri/doxygen/manual/customize.html#xmlgenerator + +3. Enjoy diff --git a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl new file mode 100644 index 000000000..8dd03a505 --- /dev/null +++ b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl @@ -0,0 +1,73 @@ +/* + * RetroShare JSON API + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +registerHandler("$%apiPath%$", + [$%captureVars%$](const std::shared_ptr session) +{ + const std::multimap headers + { + { "Connection", "keep-alive" }, + { "Content-Type", "text/event-stream" } + }; + session->yield(rb::OK, headers); + + size_t reqSize = session->get_request()->get_header("Content-Length", 0); + session->fetch( reqSize, [$%captureVars%$]( + const std::shared_ptr session, + const rb::Bytes& body ) + { + RsGenericSerializer::SerializeContext cReq( + nullptr, 0, + RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ); + RsJson& jReq(cReq.mJson); + jReq.Parse(reinterpret_cast(body.data()), body.size()); + + RsGenericSerializer::SerializeContext cAns; + RsJson& jAns(cAns.mJson); + + // if caller specified caller_data put it back in the answhere + const char kcd[] = "caller_data"; + if(jReq.HasMember(kcd)) + jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + +$%paramsDeclaration%$ + +$%inputParamsDeserialization%$ + + $%callbackName%$ = [session]($%callbackParams%$) + { +$%callbackParamsSerialization%$ + + std::stringstream message; + message << "data: " << compactJSON << ctx.mJson << "\n\n"; + session->yield(message.str()); + $%sessionEarlyClose%$ + }; + +$%functionCall%$ + +$%outputParamsSerialization%$ + + // return them to the API caller + std::stringstream message; + message << "data: " << compactJSON << cAns.mJson << "\n\n"; + session->yield(message.str()); + $%sessionDelayedClose%$ + } ); +}); + diff --git a/jsonapi-generator/src/jsonapi-generator-doxygen.conf b/jsonapi-generator/src/jsonapi-generator-doxygen.conf new file mode 100644 index 000000000..d7fbafebb --- /dev/null +++ b/jsonapi-generator/src/jsonapi-generator-doxygen.conf @@ -0,0 +1,229 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "libretroshare" + +ALIASES += jsonapi{1}="\xmlonly\endxmlonly" + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +#INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = NO + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = YES + + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + diff --git a/jsonapi-generator/src/jsonapi-generator.cpp b/jsonapi-generator/src/jsonapi-generator.cpp new file mode 100644 index 000000000..4977f850f --- /dev/null +++ b/jsonapi-generator/src/jsonapi-generator.cpp @@ -0,0 +1,364 @@ +/* + * RetroShare JSON API + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct MethodParam +{ + MethodParam() : + in(false), out(false), isMultiCallback(false), isSingleCallback(false){} + + QString type; + QString name; + QString defval; + bool in; + bool out; + bool isMultiCallback; + bool isSingleCallback; +}; + +int main(int argc, char *argv[]) +{ + if(argc != 3) + qFatal("Usage: jsonapi-generator SOURCE_PATH OUTPUT_PATH"); + + QString sourcePath(argv[1]); + QString outputPath(argv[2]); + QString doxPrefix(outputPath+"/xml/"); + + QString wrappersDefFilePath(outputPath + "/jsonapi-wrappers.inl"); + QFile wrappersDefFile(wrappersDefFilePath); + wrappersDefFile.remove(); + if(!wrappersDefFile.open(QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text)) + qFatal(QString("Can't open: " + wrappersDefFilePath).toLatin1().data()); + + QString cppApiIncludesFilePath(outputPath + "/jsonapi-includes.inl"); + QFile cppApiIncludesFile(cppApiIncludesFilePath); + cppApiIncludesFile.remove(); + if(!cppApiIncludesFile.open(QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text)) + qFatal(QString("Can't open: " + cppApiIncludesFilePath).toLatin1().data()); + QSet cppApiIncludesSet; + + QDirIterator it(doxPrefix, QStringList() << "*8h.xml", QDir::Files); + while(it.hasNext()) + { + QDomDocument hDoc; + QString hFilePath(it.next()); + QString parseError; int line, column; + QFile hFile(hFilePath); + if (!hFile.open(QIODevice::ReadOnly) || + !hDoc.setContent(&hFile, &parseError, &line, &column)) + { + qWarning() << "Error parsing:" << hFilePath + << parseError << line << column; + continue; + } + + QFileInfo hfi(hFile); + QString headerFileName(hfi.fileName()); + headerFileName.replace(QString("_8h.xml"), QString(".h")); + + QDomNodeList sectiondefs = hDoc.elementsByTagName("sectiondef"); + for(int j = 0; j < sectiondefs.size(); ++j) + { + QDomElement sectDef = sectiondefs.item(j).toElement(); + + if( sectDef.attributes().namedItem("kind").nodeValue() != "var" + || sectDef.elementsByTagName("jsonapi").isEmpty() ) + continue; + + QString instanceName = + sectDef.elementsByTagName("name").item(0).toElement().text(); + QString typeName = + sectDef.elementsByTagName("ref").item(0).toElement().text(); + QString typeFilePath(doxPrefix); + typeFilePath += sectDef.elementsByTagName("ref").item(0) + .attributes().namedItem("refid").nodeValue(); + typeFilePath += ".xml"; + + QDomDocument typeDoc; + QFile typeFile(typeFilePath); + if ( !typeFile.open(QIODevice::ReadOnly) || + !typeDoc.setContent(&typeFile, &parseError, &line, &column) ) + { + qWarning() << "Error parsing:" << typeFilePath + << parseError << line << column; + continue; + } + + QDomNodeList members = typeDoc.elementsByTagName("member"); + for (int i = 0; i < members.size(); ++i) + { + QDomNode member = members.item(i); + QString refid(member.attributes().namedItem("refid").nodeValue()); + QString methodName(member.firstChildElement("name").toElement().text()); + QString wrapperName(instanceName+methodName+"Wrapper"); + QString defFilePath(doxPrefix + refid.split('_')[0] + ".xml"); + + qDebug() << "Looking for" << typeName << methodName << "into" + << typeFilePath; + + QDomDocument defDoc; + QFile defFile(defFilePath); + if ( !defFile.open(QIODevice::ReadOnly) || + !defDoc.setContent(&defFile, &parseError, &line, &column) ) + { + qWarning() << "Error parsing:" << defFilePath + << parseError << line << column; + continue; + } + + QDomElement memberdef; + QDomNodeList memberdefs = defDoc.elementsByTagName("memberdef"); + for (int k = 0; k < memberdefs.size(); ++k) + { + QDomElement tmpMBD = memberdefs.item(k).toElement(); + QString tmpId = tmpMBD.attributes().namedItem("id").nodeValue(); + QString tmpKind = tmpMBD.attributes().namedItem("kind").nodeValue(); + bool hasJsonApi = !tmpMBD.elementsByTagName("jsonapi").isEmpty(); + if( tmpId == refid && tmpKind == "function" && hasJsonApi ) + { + memberdef = tmpMBD; + break; + } + } + + if(memberdef.isNull()) continue; + + QString apiPath("/" + instanceName + "/" + methodName); + QString retvalType = memberdef.firstChildElement("type").text(); + QMap paramsMap; + QStringList orderedParamNames; + bool hasInput = false; + bool hasOutput = false; + bool hasSingleCallback = false; + bool hasMultiCallback = false; + QString callbackName; + QString callbackParams; + + QDomNodeList params = memberdef.elementsByTagName("param"); + for (int k = 0; k < params.size(); ++k) + { + QDomElement tmpPE = params.item(k).toElement(); + MethodParam tmpParam; + QString& pName(tmpParam.name); + QString& pType(tmpParam.type); + pName = tmpPE.firstChildElement("declname").text(); + QDomElement tmpDefval = tmpPE.firstChildElement("defval"); + if(!tmpDefval.isNull()) tmpParam.defval = tmpDefval.text(); + QDomElement tmpType = tmpPE.firstChildElement("type"); + pType = tmpType.text(); + if(pType.startsWith("const ")) pType.remove(0,6); + if(pType.startsWith("std::function")) + { + if(pType.endsWith('&')) pType.chop(1); + if(pName.startsWith("multiCallback")) + { + tmpParam.isMultiCallback = true; + hasMultiCallback = true; + } + else if(pName.startsWith("callback")) + { + tmpParam.isSingleCallback = true; + hasSingleCallback = true; + } + callbackName = pName; + callbackParams = pType; + } + else + { + pType.replace(QString("&"), QString()); + pType.replace(QString(" "), QString()); + } + paramsMap.insert(tmpParam.name, tmpParam); + orderedParamNames.push_back(tmpParam.name); + } + + QDomNodeList parameternames = memberdef.elementsByTagName("parametername"); + for (int k = 0; k < parameternames.size(); ++k) + { + QDomElement tmpPN = parameternames.item(k).toElement(); + MethodParam& tmpParam = paramsMap[tmpPN.text()]; + QString tmpD = tmpPN.attributes().namedItem("direction").nodeValue(); + if(tmpD.contains("in")) + { + tmpParam.in = true; + hasInput = true; + } + if(tmpD.contains("out")) + { + tmpParam.out = true; + hasOutput = true; + } + } + + QString functionCall("\t\t"); + if(retvalType != "void") + { + functionCall += retvalType + " retval = "; + hasOutput = true; + } + functionCall += instanceName + "->" + methodName + "("; + functionCall += orderedParamNames.join(", ") + ");\n"; + + qDebug() << instanceName << apiPath << retvalType << typeName + << methodName; + for (const QString& pn : orderedParamNames) + { + const MethodParam& mp(paramsMap[pn]); + qDebug() << "\t" << mp.type << mp.name << mp.in << mp.out; + } + + QString inputParamsDeserialization; + if(hasInput) + { + inputParamsDeserialization += + "\t\t{\n" + "\t\t\tRsGenericSerializer::SerializeContext& ctx(cReq);\n" + "\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON);\n"; + } + + QString outputParamsSerialization; + if(hasOutput) + { + outputParamsSerialization += + "\t\t{\n" + "\t\t\tRsGenericSerializer::SerializeContext& ctx(cAns);\n" + "\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON);\n"; + } + + QString paramsDeclaration; + for (const QString& pn : orderedParamNames) + { + const MethodParam& mp(paramsMap[pn]); + paramsDeclaration += "\t\t" + mp.type + " " + mp.name; + if(!mp.defval.isEmpty()) + paramsDeclaration += "(" + mp.defval + ")"; + paramsDeclaration += ";\n"; + if(mp.in) + inputParamsDeserialization += "\t\t\tRS_SERIAL_PROCESS(" + + mp.name + ");\n"; + if(mp.out) + outputParamsSerialization += "\t\t\tRS_SERIAL_PROCESS(" + + mp.name + ");\n"; + } + + if(hasInput) inputParamsDeserialization += "\t\t}\n"; + if(retvalType != "void") + outputParamsSerialization += + "\t\t\tRS_SERIAL_PROCESS(retval);\n"; + if(hasOutput) outputParamsSerialization += "\t\t}\n"; + + QString captureVars; + + QString sessionEarlyClose; + if(hasSingleCallback) + sessionEarlyClose = "session->close();"; + + QString sessionDelayedClose; + if(hasMultiCallback) + { + sessionDelayedClose = "mService.schedule( [session](){session->close();}, std::chrono::seconds(maxWait+120) );"; + captureVars = "this"; + } + + QString callbackParamsSerialization; + + if(hasSingleCallback || hasMultiCallback || + ((callbackParams.indexOf('(')+2) < callbackParams.indexOf(')'))) + { + QString& cbs(callbackParamsSerialization); + + callbackParams = callbackParams.split('(')[1]; + callbackParams = callbackParams.split(')')[0]; + + cbs += "\t\t\tRsGenericSerializer::SerializeContext ctx;\n"; + + for (QString cbPar : callbackParams.split(',')) + { + bool isConst(cbPar.startsWith("const ")); + QChar pSep(' '); + bool isRef(cbPar.contains('&')); + if(isRef) pSep = '&'; + int sepIndex = cbPar.lastIndexOf(pSep)+1; + QString cpt(cbPar.mid(0, sepIndex)); + cpt.remove(0,6); + QString cpn(cbPar.mid(sepIndex)); + + cbs += "\t\t\tRsTypeSerializer::serial_process("; + cbs += "RsGenericSerializer::TO_JSON, ctx, "; + if(isConst) + { + cbs += "const_cast<"; + cbs += cpt; + cbs += ">("; + } + cbs += cpn; + if(isConst) cbs += ")"; + cbs += ", \""; + cbs += cpn; + cbs += "\" );\n"; + } + } + + QMap substitutionsMap; + substitutionsMap.insert("paramsDeclaration", paramsDeclaration); + substitutionsMap.insert("inputParamsDeserialization", inputParamsDeserialization); + substitutionsMap.insert("outputParamsSerialization", outputParamsSerialization); + substitutionsMap.insert("wrapperName", wrapperName); + substitutionsMap.insert("headerFileName", headerFileName); + substitutionsMap.insert("functionCall", functionCall); + substitutionsMap.insert("apiPath", apiPath); + substitutionsMap.insert("sessionEarlyClose", sessionEarlyClose); + substitutionsMap.insert("sessionDelayedClose", sessionDelayedClose); + substitutionsMap.insert("captureVars", captureVars); + substitutionsMap.insert("callbackName", callbackName); + substitutionsMap.insert("callbackParams", callbackParams); + substitutionsMap.insert("callbackParamsSerialization", callbackParamsSerialization); + + QString templFilePath(sourcePath); + if(hasMultiCallback || hasSingleCallback) + templFilePath.append("/async-method-wrapper-template.cpp.tmpl"); + else templFilePath.append("/method-wrapper-template.cpp.tmpl"); + + QFile templFile(templFilePath); + templFile.open(QIODevice::ReadOnly); + QString wrapperDef(templFile.readAll()); + + QMap::iterator it; + for ( it = substitutionsMap.begin(); + it != substitutionsMap.end(); ++it ) + wrapperDef.replace(QString("$%"+it.key()+"%$"), QString(it.value()), Qt::CaseSensitive); + + wrappersDefFile.write(wrapperDef.toLocal8Bit()); + + cppApiIncludesSet.insert("#include \"retroshare/" + headerFileName + "\"\n"); + } + } + } + + for(const QString& incl : cppApiIncludesSet) + cppApiIncludesFile.write(incl.toLocal8Bit()); + + return 0; +} diff --git a/jsonapi-generator/src/jsonapi-generator.pro b/jsonapi-generator/src/jsonapi-generator.pro new file mode 100644 index 000000000..c36eeea1d --- /dev/null +++ b/jsonapi-generator/src/jsonapi-generator.pro @@ -0,0 +1,6 @@ +TARGET = jsonapi-generator + +QT *= core xml +QT -= gui + +SOURCES += jsonapi-generator.cpp diff --git a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl new file mode 100644 index 000000000..f9be77d76 --- /dev/null +++ b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl @@ -0,0 +1,64 @@ +/* + * RetroShare JSON API + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +registerHandler("$%apiPath%$", + [$%captureVars%$](const std::shared_ptr session) +{ + size_t reqSize = session->get_request()->get_header("Content-Length", 0); + session->fetch( reqSize, []( + const std::shared_ptr session, + const rb::Bytes& body ) + { + RsGenericSerializer::SerializeContext cReq( + nullptr, 0, + RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ); + RsJson& jReq(cReq.mJson); + jReq.Parse(reinterpret_cast(body.data()), body.size()); + + RsGenericSerializer::SerializeContext cAns; + RsJson& jAns(cAns.mJson); + + // if caller specified caller_data put it back in the answhere + const char kcd[] = "caller_data"; + if(jReq.HasMember(kcd)) + jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + +$%paramsDeclaration%$ + + // deserialize input parameters from JSON +$%inputParamsDeserialization%$ + + // call retroshare C++ API +$%functionCall%$ + + // serialize out parameters and return value to JSON +$%outputParamsSerialization%$ + + // return them to the API caller + std::stringstream ss; + ss << jAns; + std::string&& ans(ss.str()); + const std::multimap headers + { + { "Content-Type", "text/json" }, + { "Content-Length", std::to_string(ans.length()) } + }; + session->close(rb::OK, ans, headers); + } ); +}); + diff --git a/libresapi/src/api/ChannelsHandler.cpp b/libresapi/src/api/ChannelsHandler.cpp index ddd679bf9..01000f7d0 100644 --- a/libresapi/src/api/ChannelsHandler.cpp +++ b/libresapi/src/api/ChannelsHandler.cpp @@ -75,12 +75,12 @@ void ChannelsHandler::handleListChannels(Request& /*req*/, Response& resp) tChannels.requestGroupInfo(token, RS_DEPRECATED_TOKREQ_ANSTYPE, opts); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); std::list grps; - if( tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE + if( tChannels.requestStatus(token) == RsTokenService::COMPLETE && mChannels.getGroupSummary(token, grps) ) { for( RsGroupMetaData& grp : grps ) @@ -140,12 +140,12 @@ void ChannelsHandler::handleGetChannelInfo(Request& req, Response& resp) opts, groupIds ); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); std::vector grps; - if( tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE + if( tChannels.requestStatus(token) == RsTokenService::COMPLETE && mChannels.getGroupData(token, grps) ) { for( RsGxsChannelGroup& grp : grps ) @@ -214,14 +214,14 @@ void ChannelsHandler::handleGetChannelContent(Request& req, Response& resp) } time_t start = time(NULL); - while((mChannels.getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mChannels.getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mChannels.getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mChannels.getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); std::vector posts; std::vector comments; if( mChannels.getTokenService()->requestStatus(token) == - RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE && + RsTokenService::COMPLETE && mChannels.getPostData(token, posts, comments) ) { for( std::vector::iterator vit = posts.begin(); @@ -290,11 +290,11 @@ void ChannelsHandler::handleToggleSubscription(Request& req, Response& resp) RsTokenService& tChannels = *mChannels.getTokenService(); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); - if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(tChannels.requestStatus(token) == RsTokenService::COMPLETE) resp.setOk(); else resp.setFail("Unknown GXS error!"); } @@ -357,11 +357,11 @@ void ChannelsHandler::handleCreateChannel(Request& req, Response& resp) RsTokenService& tChannels = *mChannels.getTokenService(); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); - if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(tChannels.requestStatus(token) == RsTokenService::COMPLETE) resp.setOk(); else resp.setFail("Unknown GXS error!"); } @@ -440,11 +440,11 @@ void ChannelsHandler::handleTogglePostRead(Request& req, Response& resp) RsTokenService& tChannels = *mChannels.getTokenService(); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); - if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(tChannels.requestStatus(token) == RsTokenService::COMPLETE) resp.setOk(); else resp.setFail("Unknown GXS error!"); } @@ -526,11 +526,11 @@ void ChannelsHandler::handleCreatePost(Request &req, Response &resp) RsTokenService& tChannels = *mChannels.getTokenService(); time_t start = time(NULL); - while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((tChannels.requestStatus(token) != RsTokenService::COMPLETE) + &&(tChannels.requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000); - if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(tChannels.requestStatus(token) == RsTokenService::COMPLETE) resp.setOk(); else resp.setFail("Unknown GXS error!"); } diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp index fcfe3d942..4180eb023 100644 --- a/libresapi/src/api/ForumHandler.cpp +++ b/libresapi/src/api/ForumHandler.cpp @@ -59,8 +59,8 @@ void ForumHandler::handleWildcard(Request &req, Response &resp) mRsGxsForums->getTokenService()->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); time_t start = time(NULL); - while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10))) ) { @@ -71,7 +71,7 @@ void ForumHandler::handleWildcard(Request &req, Response &resp) #endif } - if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::COMPLETE) { std::vector grps; ok &= mRsGxsForums->getMsgData(token, grps); @@ -107,8 +107,8 @@ void ForumHandler::handleWildcard(Request &req, Response &resp) mRsGxsForums->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); time_t start = time(NULL); - while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10))) ) { @@ -118,7 +118,7 @@ void ForumHandler::handleWildcard(Request &req, Response &resp) usleep(500*1000) ; #endif } - if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::COMPLETE) { std::vector grps; ok &= mRsGxsForums->getGroupData(token, grps); diff --git a/libresapi/src/api/GxsResponseTask.cpp b/libresapi/src/api/GxsResponseTask.cpp index d1622b798..036a1f60a 100644 --- a/libresapi/src/api/GxsResponseTask.cpp +++ b/libresapi/src/api/GxsResponseTask.cpp @@ -42,11 +42,11 @@ bool GxsResponseTask::doWork(Request &req, Response &resp) for(std::vector::iterator vit = mWaitingTokens.begin(); vit != mWaitingTokens.end(); ++vit) { uint8_t status = mTokenService->requestStatus(*vit); - if(status != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(status != RsTokenService::COMPLETE) { ready = false; } - if(status == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + if(status == RsTokenService::FAILED) { std::cerr << "GxsResponseTask::doWork() Error: token failed. aborting." << std::endl; resp.setFail("GxsResponseTask::doWork() Error: token failed."); diff --git a/libresapi/src/api/IdentityHandler.cpp b/libresapi/src/api/IdentityHandler.cpp index 854dfdb59..9e7228759 100644 --- a/libresapi/src/api/IdentityHandler.cpp +++ b/libresapi/src/api/IdentityHandler.cpp @@ -223,15 +223,15 @@ void IdentityHandler::handleWildcard(Request & /*req*/, Response &resp) time_t timeout = time(NULL)+10; uint8_t rStatus = mRsIdentity->getTokenService()->requestStatus(token); - while( rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE && - rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED && + while( rStatus != RsTokenService::COMPLETE && + rStatus != RsTokenService::FAILED && time(NULL) < timeout ) { usleep(50*1000); rStatus = mRsIdentity->getTokenService()->requestStatus(token); } - if(rStatus == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(rStatus == RsTokenService::COMPLETE) { std::vector grps; ok &= mRsIdentity->getGroupData(token, grps); @@ -280,15 +280,15 @@ void IdentityHandler::handleNotOwnIdsRequest(Request & /*req*/, Response &resp) time_t timeout = time(NULL)+10; uint8_t rStatus = mRsIdentity->getTokenService()->requestStatus(token); - while( rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE && - rStatus != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED && + while( rStatus != RsTokenService::COMPLETE && + rStatus != RsTokenService::FAILED && time(NULL) < timeout ) { usleep(50*1000); rStatus = mRsIdentity->getTokenService()->requestStatus(token); } - if(rStatus == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(rStatus == RsTokenService::COMPLETE) { std::vector grps; ok &= mRsIdentity->getGroupData(token, grps); @@ -330,8 +330,8 @@ void IdentityHandler::handleOwnIdsRequest(Request & /*req*/, Response &resp) mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); time_t start = time(NULL); - while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10))) ) { @@ -342,7 +342,7 @@ void IdentityHandler::handleOwnIdsRequest(Request & /*req*/, Response &resp) #endif } - if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if(mRsIdentity->getTokenService()->requestStatus(token) == RsTokenService::COMPLETE) { std::vector grps; ok &= mRsIdentity->getGroupData(token, grps); @@ -413,8 +413,8 @@ void IdentityHandler::handleGetIdentityDetails(Request& req, Response& resp) mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); time_t start = time(NULL); - while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10))) ) { @@ -548,8 +548,8 @@ void IdentityHandler::handleSetAvatar(Request& req, Response& resp) mRsIdentity->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); time_t start = time(NULL); - while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) - &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + while((mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::COMPLETE) + &&(mRsIdentity->getTokenService()->requestStatus(token) != RsTokenService::FAILED) &&((time(NULL) < (start+10))) ) { diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index b07846411..ba728f9a5 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -110,7 +110,7 @@ libresapihttpserver { QMAKE_EXTRA_COMPILERS += create_webfiles_html create_webfiles_js create_webfiles_css } - win32 { + appveyor { DEFINES *= WINDOWS_SYS INCLUDEPATH += . $$INC_DIR @@ -126,6 +126,19 @@ libresapihttpserver { system($$MAKE_SRC\\init.bat .) } + win32 { + DEFINES *= WINDOWS_SYS + INCLUDEPATH += . $$INC_DIR + + PRO_PATH=$$shell_path($$_PRO_FILE_PWD_) + MAKE_SRC=$$shell_path($$PRO_PATH/webui-src/make-src) + + QMAKE_POST_LINK=$$MAKE_SRC/build.sh $$PRO_PATH + + # create dummy files + system($$MAKE_SRC/init.sh .) + } + linux { CONFIG += link_pkgconfig PKGCONFIG *= libmicrohttpd diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index d517a0114..182964446 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -71,7 +71,8 @@ ftServer::ftServer(p3PeerMgr *pm, p3ServiceControl *sc) mPeerMgr(pm), mServiceCtrl(sc), mFileDatabase(NULL), mFtController(NULL), mFtExtra(NULL), - mFtDataplex(NULL), mFtSearch(NULL), srvMutex("ftServer") + mFtDataplex(NULL), mFtSearch(NULL), srvMutex("ftServer"), + mSearchCallbacksMapMutex("ftServer callbacks map") { addSerialType(new RsFileTransferSerialiser()) ; } @@ -425,7 +426,7 @@ void ftServer::requestDirUpdate(void *ref) } /* Directory Handling */ -bool ftServer::setDownloadDirectory(std::string path) +bool ftServer::setDownloadDirectory(const std::string& path) { return mFtController->setDownloadDirectory(path); } @@ -435,7 +436,7 @@ std::string ftServer::getDownloadDirectory() return mFtController->getDownloadDirectory(); } -bool ftServer::setPartialsDirectory(std::string path) +bool ftServer::setPartialsDirectory(const std::string& path) { return mFtController->setPartialsDirectory(path); } @@ -1630,6 +1631,7 @@ int ftServer::tick() mFtDataplex->deleteUnusedServers() ; mFtDataplex->handlePendingCrcRequests() ; mFtDataplex->dispatchReceivedChunkCheckSum() ; + cleanTimedOutSearches(); } return moreToTick; @@ -1820,6 +1822,24 @@ int ftServer::handleIncoming() ********************************** *********************************/ +void ftServer::receiveSearchResult(RsTurtleFTSearchResultItem *item) +{ + bool hasCallback = false; + + { + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto cbpt = mSearchCallbacksMap.find(item->request_id); + if(cbpt != mSearchCallbacksMap.end()) + { + hasCallback = true; + cbpt->second.first(item->result); + } + } // end RS_STACK_MUTEX(mSearchCallbacksMapMutex); + + if(!hasCallback) + RsServer::notify()->notifyTurtleSearchResult(item->PeerId(),item->request_id, item->result ); +} + /***************************** CONFIG ****************************/ bool ftServer::addConfiguration(p3ConfigMgr *cfgmgr) @@ -1832,6 +1852,42 @@ bool ftServer::addConfiguration(p3ConfigMgr *cfgmgr) return true; } +bool ftServer::turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait ) +{ + if(matchString.empty()) + { + std::cerr << __PRETTY_FUNCTION__ << " match string can't be empty!" + << std::endl; + return false; + } + + TurtleRequestId sId = turtleSearch(matchString); + + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + mSearchCallbacksMap.emplace( + sId, + std::make_pair( + multiCallback, + std::chrono::system_clock::now() + + std::chrono::seconds(maxWait) ) ); + + return true; +} + +void ftServer::cleanTimedOutSearches() +{ + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto now = std::chrono::system_clock::now(); + for( auto cbpt = mSearchCallbacksMap.begin(); + cbpt != mSearchCallbacksMap.end(); ) + if(cbpt->second.second <= now) + cbpt = mSearchCallbacksMap.erase(cbpt); + else ++cbpt; +} + // Offensive content file filtering int ftServer::banFile(const RsFileHash& real_file_hash, const std::string& filename, uint64_t file_size) @@ -1851,3 +1907,5 @@ bool ftServer::isHashBanned(const RsFileHash& hash) { return mFileDatabase->isFileBanned(hash); } + + diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 8e420092f..c15c991fc 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include "ft/ftdata.h" #include "turtle/turtleclientservice.h" @@ -96,7 +98,7 @@ public: uint16_t serviceId() const { return RS_SERVICE_TYPE_FILE_TRANSFER ; } virtual bool handleTunnelRequest(const RsFileHash& hash,const RsPeerId& peer_id) ; virtual void receiveTurtleData(const RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ; - //virtual void receiveSearchResult(RsTurtleSearchResultItem *item);// TODO + virtual void receiveSearchResult(RsTurtleFTSearchResultItem *item); virtual RsItem *create_item(uint16_t service,uint8_t item_type) const ; virtual RsServiceSerializer *serializer() { return this ; } @@ -143,6 +145,12 @@ public: virtual void setFilePermDirectDL(uint32_t perm) ; virtual uint32_t filePermDirectDL() ; + /// @see RsFiles + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait = 300 ); + virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ; virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ; @@ -210,8 +218,8 @@ public: * Directory Handling ***/ virtual void requestDirUpdate(void *ref) ; // triggers the update of the given reference. Used when browsing. - virtual bool setDownloadDirectory(std::string path); - virtual bool setPartialsDirectory(std::string path); + virtual bool setDownloadDirectory(const std::string& path); + virtual bool setPartialsDirectory(const std::string& path); virtual std::string getDownloadDirectory(); virtual std::string getPartialsDirectory(); @@ -319,6 +327,18 @@ private: std::map mEncryptedHashes ; // This map is such that sha1(it->second) = it->first std::map mEncryptedPeerIds ; // This map holds the hash to be used with each peer id std::map > mUploadLimitMap ; + + /** Store search callbacks with timeout*/ + std::map< + TurtleRequestId, + std::pair< + std::function& results)>, + std::chrono::system_clock::time_point > + > mSearchCallbacksMap; + RsMutex mSearchCallbacksMapMutex; + + /// Cleanup mSearchCallbacksMap + void cleanTimedOutSearches(); }; diff --git a/libretroshare/src/gxs/gxstokenqueue.cc b/libretroshare/src/gxs/gxstokenqueue.cc index 568daf88a..c5ebf87fd 100644 --- a/libretroshare/src/gxs/gxstokenqueue.cc +++ b/libretroshare/src/gxs/gxstokenqueue.cc @@ -55,7 +55,7 @@ void GxsTokenQueue::checkRequests() uint32_t token = it->mToken; uint32_t status = mGenExchange->getTokenService()->requestStatus(token); - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status == RsTokenService::COMPLETE) { toload.push_back(*it); it = mQueue.erase(it); @@ -67,7 +67,7 @@ void GxsTokenQueue::checkRequests() #endif ++it; } - else if (status == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + else if (status == RsTokenService::FAILED) { // maybe we should do alternative callback? std::cerr << "GxsTokenQueue::checkRequests() ERROR Request Failed: " << token; diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 3927e6f61..3d1c0fc6a 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1999,7 +1999,7 @@ void RsGenExchange::processMsgMetaChanges() if(ok) { - mDataAccess->updatePublicRequestStatus(token, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE); + mDataAccess->updatePublicRequestStatus(token, RsTokenService::COMPLETE); if (changed) { msgIds[m.msgId.first].insert(m.msgId.second); @@ -2007,7 +2007,7 @@ void RsGenExchange::processMsgMetaChanges() } else { - mDataAccess->updatePublicRequestStatus(token, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + mDataAccess->updatePublicRequestStatus(token, RsTokenService::FAILED); } { @@ -2053,11 +2053,11 @@ void RsGenExchange::processGrpMetaChanges() if(ok) { - mDataAccess->updatePublicRequestStatus(token, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE); + mDataAccess->updatePublicRequestStatus(token, RsTokenService::COMPLETE); grpChanged.push_back(g.grpId); }else { - mDataAccess->updatePublicRequestStatus(token, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + mDataAccess->updatePublicRequestStatus(token, RsTokenService::FAILED); } { @@ -2290,7 +2290,7 @@ void RsGenExchange::publishMsgs() // add to published to allow acknowledgement mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(grpId, msgId))); - mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE); + mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::COMPLETE); } else @@ -2300,7 +2300,7 @@ void RsGenExchange::publishMsgs() if(!tryLater) mDataAccess->updatePublicRequestStatus(mit->first, - RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + RsTokenService::FAILED); std::cerr << "RsGenExchange::publishMsgs() failed to publish msg " << std::endl; } @@ -2377,7 +2377,7 @@ void RsGenExchange::processGroupUpdatePublish() if(mit == grpMeta.end() || mit->second == NULL) { std::cerr << "Error! could not find meta of old group to update!" << std::endl; - mDataAccess->updatePublicRequestStatus(gup.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + mDataAccess->updatePublicRequestStatus(gup.mToken, RsTokenService::FAILED); delete gup.grpItem; continue; } @@ -2405,7 +2405,7 @@ void RsGenExchange::processGroupUpdatePublish() std::cerr << "(EE) publish group fails because RS cannot find the private publish and author keys" << std::endl; delete gup.grpItem; - mDataAccess->updatePublicRequestStatus(gup.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + mDataAccess->updatePublicRequestStatus(gup.mToken, RsTokenService::FAILED); } } @@ -2426,7 +2426,7 @@ void RsGenExchange::processRoutingClues() void RsGenExchange::processGroupDelete() { - RS_STACK_MUTEX(mGenMtx) ; + RS_STACK_MUTEX(mGenMtx); // get keys for group delete publish typedef std::pair GrpNote; @@ -2447,8 +2447,9 @@ void RsGenExchange::processGroupDelete() for(; mit != toNotify.end(); ++mit) { GrpNote& note = mit->second; - uint8_t status = note.first ? RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE - : RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; + RsTokenService::GxsRequestStatus status = + note.first ? RsTokenService::COMPLETE + : RsTokenService::FAILED; mGrpNotify.insert(std::make_pair(mit->first, note.second)); mDataAccess->updatePublicRequestStatus(mit->first, status); @@ -2756,8 +2757,9 @@ void RsGenExchange::publishGrps() for(; mit != toNotify.end(); ++mit) { GrpNote& note = mit->second; - uint8_t status = note.first ? RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE - : RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; + RsTokenService::GxsRequestStatus status = + note.first ? RsTokenService::COMPLETE + : RsTokenService::FAILED; mGrpNotify.insert(std::make_pair(mit->first, note.second)); mDataAccess->updatePublicRequestStatus(mit->first, status); @@ -2793,7 +2795,8 @@ uint32_t RsGenExchange::generatePublicToken() return mDataAccess->generatePublicToken(); } -bool RsGenExchange::updatePublicRequestStatus(const uint32_t &token, const uint32_t &status) +bool RsGenExchange::updatePublicRequestStatus( + uint32_t token, RsTokenService::GxsRequestStatus status ) { return mDataAccess->updatePublicRequestStatus(token, status); } diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index e4dd074eb..336eeb4fe 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -479,7 +479,8 @@ public: * @param status * @return false if token could not be found, true if token disposed of */ - bool updatePublicRequestStatus(const uint32_t &token, const uint32_t &status); + bool updatePublicRequestStatus( + uint32_t token, RsTokenService::GxsRequestStatus status); /*! * This gets rid of a publicly issued token diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index c9e826482..b0219ecb2 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -26,15 +26,6 @@ #include "rsgxsdataaccess.h" #include "retroshare/rsgxsflags.h" -// TODO CLEANUP: This should be an enum defined in rstokenservice.h - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_FAILED = 0; - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_PENDING = 1; - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_PARTIAL = 2; - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE = 3; - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE = 4; - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_DONE = 5; // ONCE ALL DATA RETRIEVED. - const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_CANCELLED = 6; - /*********** * #define DATA_DEBUG 1 **********/ @@ -314,22 +305,22 @@ void RsGxsDataAccess::storeRequest(GxsRequest* req) { RsStackMutex stack(mDataMutex); /****** LOCKED *****/ - req->status = GXS_REQUEST_V2_STATUS_PENDING; + req->status = PENDING; req->reqTime = time(NULL); mRequests[req->token] = req; return; } -uint32_t RsGxsDataAccess::requestStatus(uint32_t token) +RsTokenService::GxsRequestStatus RsGxsDataAccess::requestStatus(uint32_t token) { - uint32_t status; + RsTokenService::GxsRequestStatus status; uint32_t reqtype; uint32_t anstype; time_t ts; { - RsStackMutex stack(mDataMutex); + RS_STACK_MUTEX(mDataMutex); // first check public tokens if(mPublicToken.find(token) != mPublicToken.end()) @@ -337,7 +328,7 @@ uint32_t RsGxsDataAccess::requestStatus(uint32_t token) } if (!checkRequestStatus(token, status, reqtype, anstype, ts)) - return RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; + return RsTokenService::FAILED; return status; } @@ -352,7 +343,7 @@ bool RsGxsDataAccess::cancelRequest(const uint32_t& token) return false; } - req->status = GXS_REQUEST_V2_STATUS_CANCELLED; + req->status = CANCELLED; return true; } @@ -388,7 +379,7 @@ bool RsGxsDataAccess::getGroupSummary(const uint32_t& token, std::liststatus == GXS_REQUEST_V2_STATUS_COMPLETE) + else if(req->status == COMPLETE) { GroupMetaReq* gmreq = dynamic_cast(req); @@ -396,7 +387,7 @@ bool RsGxsDataAccess::getGroupSummary(const uint32_t& token, std::listmGroupMetaData; gmreq->mGroupMetaData.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else { @@ -427,7 +418,7 @@ bool RsGxsDataAccess::getGroupData(const uint32_t& token, std::list& << "data" << std::endl; return false; } - else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE) + else if(req->status == COMPLETE) { GroupDataReq* gmreq = dynamic_cast(req); GroupSerializedDataReq* gsreq = dynamic_cast(req); @@ -437,13 +428,13 @@ bool RsGxsDataAccess::getGroupData(const uint32_t& token, std::list& grpData.swap(gsreq->mGroupData); gsreq->mGroupData.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else if(gmreq) { grpData.swap(gmreq->mGroupData); gmreq->mGroupData.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else { @@ -472,7 +463,7 @@ bool RsGxsDataAccess::getMsgData(const uint32_t& token, NxsMsgDataResult& msgDat std::cerr << "RsGxsDataAccess::getMsgData() Unable to retrieve group data" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ MsgDataReq* mdreq = dynamic_cast(req); @@ -480,7 +471,7 @@ bool RsGxsDataAccess::getMsgData(const uint32_t& token, NxsMsgDataResult& msgDat { msgData.swap(mdreq->mMsgData); mdreq->mMsgData.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else { @@ -506,7 +497,7 @@ bool RsGxsDataAccess::getMsgRelatedData(const uint32_t &token, NxsMsgRelatedData std::cerr << "RsGxsDataAccess::getMsgRelatedData() Unable to retrieve group data" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ MsgRelatedInfoReq* mrireq = dynamic_cast(req); @@ -517,7 +508,7 @@ bool RsGxsDataAccess::getMsgRelatedData(const uint32_t &token, NxsMsgRelatedData { msgData.swap(mrireq->mMsgDataResult); mrireq->mMsgDataResult.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else { @@ -543,7 +534,7 @@ bool RsGxsDataAccess::getMsgSummary(const uint32_t& token, GxsMsgMetaResult& msg std::cerr << "RsGxsDataAccess::getMsgSummary() Unable to retrieve group data" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ MsgMetaReq* mmreq = dynamic_cast(req); @@ -551,7 +542,7 @@ bool RsGxsDataAccess::getMsgSummary(const uint32_t& token, GxsMsgMetaResult& msg { msgInfo.swap(mmreq->mMsgMetaData); mmreq->mMsgMetaData.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else @@ -580,7 +571,7 @@ bool RsGxsDataAccess::getMsgRelatedSummary(const uint32_t &token, MsgRelatedMeta std::cerr << "RsGxsDataAccess::getMsgRelatedSummary() Unable to retrieve message summary" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_META) return false; @@ -591,7 +582,7 @@ bool RsGxsDataAccess::getMsgRelatedSummary(const uint32_t &token, MsgRelatedMeta { msgMeta.swap(mrireq->mMsgMetaResult); mrireq->mMsgMetaResult.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else { @@ -619,7 +610,7 @@ bool RsGxsDataAccess::getMsgRelatedList(const uint32_t &token, MsgRelatedIdResul std::cerr << "RsGxsDataAccess::getMsgRelatedList() Unable to retrieve message data" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_IDS) return false; @@ -630,7 +621,7 @@ bool RsGxsDataAccess::getMsgRelatedList(const uint32_t &token, MsgRelatedIdResul { msgIds.swap(mrireq->mMsgIdResult); mrireq->mMsgIdResult.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else{ std::cerr << "RsGxsDataAccess::getMsgRelatedList() Req found, failed caste" << std::endl; @@ -656,7 +647,7 @@ bool RsGxsDataAccess::getMsgList(const uint32_t& token, GxsMsgIdResult& msgIds) std::cerr << "RsGxsDataAccess::getMsgList() Unable to retrieve msg Ids" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ MsgIdReq* mireq = dynamic_cast(req); @@ -664,7 +655,7 @@ bool RsGxsDataAccess::getMsgList(const uint32_t& token, GxsMsgIdResult& msgIds) { msgIds.swap(mireq->mMsgIdResult); mireq->mMsgIdResult.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else{ std::cerr << "RsGxsDataAccess::getMsgList() Req found, failed caste" << std::endl; @@ -689,7 +680,7 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::liststatus == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ GroupIdReq* gireq = dynamic_cast(req); @@ -697,7 +688,7 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::listmGroupIdResult); gireq->mGroupIdResult.clear(); - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); }else{ std::cerr << "RsGxsDataAccess::getGroupList() Req found, failed caste" << std::endl; @@ -739,21 +730,21 @@ void RsGxsDataAccess::processRequests() switch (req->status) { - case GXS_REQUEST_V2_STATUS_PENDING: + case PENDING: // process request later break; - case GXS_REQUEST_V2_STATUS_PARTIAL: + case PARTIAL: // should not happen - req->status = GXS_REQUEST_V2_STATUS_COMPLETE; + req->status = COMPLETE; break; - case GXS_REQUEST_V2_STATUS_DONE: + case DONE: #ifdef DATA_DEBUG std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " << req->token; std::cerr << std::endl; #endif toClear.push_back(req->token); break; - case GXS_REQUEST_V2_STATUS_CANCELLED: + case CANCELLED: #ifdef DATA_DEBUG std::cerr << "RsGxsDataAccess::processrequests() Clearing Cancelled Request Token: " << req->token; std::cerr << std::endl; @@ -791,10 +782,10 @@ void RsGxsDataAccess::processRequests() for (it = mRequests.begin(); it != mRequests.end(); ++it) { GxsRequest* reqCheck = it->second; - if (reqCheck->status == GXS_REQUEST_V2_STATUS_PENDING) + if (reqCheck->status == PENDING) { req = reqCheck; - req->status = GXS_REQUEST_V2_STATUS_PARTIAL; + req->status = PARTIAL; break; } } @@ -874,9 +865,9 @@ void RsGxsDataAccess::processRequests() { RsStackMutex stack(mDataMutex); /******* LOCKED *******/ - if (req->status == GXS_REQUEST_V2_STATUS_PARTIAL) + if (req->status == PARTIAL) { - req->status = ok ? GXS_REQUEST_V2_STATUS_COMPLETE : GXS_REQUEST_V2_STATUS_FAILED; + req->status = ok ? COMPLETE : FAILED; } } // END OF MUTEX. } @@ -892,14 +883,14 @@ bool RsGxsDataAccess::getGroupStatistic(const uint32_t &token, GxsGroupStatistic std::cerr << "RsGxsDataAccess::getGroupStatistic() Unable to retrieve grp stats" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ GroupStatisticRequest* gsreq = dynamic_cast(req); if(gsreq) { grpStatistic = gsreq->mGroupStatistic; - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else{ std::cerr << "RsGxsDataAccess::getGroupStatistic() Req found, failed caste" << std::endl; @@ -923,14 +914,14 @@ bool RsGxsDataAccess::getServiceStatistic(const uint32_t &token, GxsServiceStati std::cerr << "RsGxsDataAccess::getServiceStatistic() Unable to retrieve service stats" << std::endl; return false; - }else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){ + }else if(req->status == COMPLETE){ ServiceStatisticRequest* ssreq = dynamic_cast(req); if(ssreq) { servStatistic = ssreq->mServiceStatistic; - locked_updateRequestStatus(token, GXS_REQUEST_V2_STATUS_DONE); + locked_updateRequestStatus(token, DONE); } else{ std::cerr << "RsGxsDataAccess::getServiceStatistic() Req found, failed caste" << std::endl; @@ -1767,15 +1758,15 @@ void RsGxsDataAccess::filterGrpList(std::list &grpIds, const RsTok } -bool RsGxsDataAccess::checkRequestStatus(const uint32_t& token, - uint32_t& status, uint32_t& reqtype, uint32_t& anstype, time_t& ts) +bool RsGxsDataAccess::checkRequestStatus( + uint32_t token, GxsRequestStatus& status, uint32_t& reqtype, + uint32_t& anstype, time_t& ts ) { - - RsStackMutex stack(mDataMutex); + RS_STACK_MUTEX(mDataMutex); GxsRequest* req = locked_retrieveRequest(token); - if (req == NULL || req->status == GXS_REQUEST_V2_STATUS_CANCELLED) + if (req == NULL || req->status == CANCELLED) return false; anstype = req->ansType; @@ -1845,70 +1836,52 @@ void RsGxsDataAccess::tokenList(std::list& tokens) } } -bool RsGxsDataAccess::locked_updateRequestStatus(const uint32_t& token, - const uint32_t& status) +bool RsGxsDataAccess::locked_updateRequestStatus( + uint32_t token, RsTokenService::GxsRequestStatus status ) { - GxsRequest* req = locked_retrieveRequest(token); - if(req) - req->status = status; - else - return false; + if(req) req->status = status; + else return false; return true; } uint32_t RsGxsDataAccess::generatePublicToken() { - uint32_t token; generateToken(token); - { - RsStackMutex stack(mDataMutex); - mPublicToken[token] = RsTokenService::GXS_REQUEST_V2_STATUS_PENDING; - } + { + RS_STACK_MUTEX(mDataMutex); + mPublicToken[token] = RsTokenService::PENDING; + } return token; } -bool RsGxsDataAccess::updatePublicRequestStatus(const uint32_t& token, - const uint32_t& status) +bool RsGxsDataAccess::updatePublicRequestStatus( + uint32_t token, RsTokenService::GxsRequestStatus status ) { - RsStackMutex stack(mDataMutex); - std::map::iterator mit = mPublicToken.find(token); - - if(mit != mPublicToken.end()) - { - mit->second = status; - } - else - { - return false; - } - + RS_STACK_MUTEX(mDataMutex); + std::map::iterator mit = + mPublicToken.find(token); + if(mit != mPublicToken.end()) mit->second = status; + else return false; return true; } -bool RsGxsDataAccess::disposeOfPublicToken(const uint32_t& token) +bool RsGxsDataAccess::disposeOfPublicToken(uint32_t token) { - RsStackMutex stack(mDataMutex); - std::map::iterator mit = mPublicToken.find(token); - - if(mit != mPublicToken.end()) - { - mPublicToken.erase(mit); - } - else - { - return false; - } - + RS_STACK_MUTEX(mDataMutex); + std::map::iterator mit = + mPublicToken.find(token); + if(mit != mPublicToken.end()) mPublicToken.erase(mit); + else return false; return true; } diff --git a/libretroshare/src/gxs/rsgxsdataaccess.h b/libretroshare/src/gxs/rsgxsdataaccess.h index 754c3078b..df79c1e95 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.h +++ b/libretroshare/src/gxs/rsgxsdataaccess.h @@ -44,6 +44,8 @@ public: * deprecated and should be removed as soon as possible as it is cause of * many confusions, instead use const RsTokReqOptions::mReqType &opts to * specify the kind of data you are interested in. + * Most of the methods use const uint32_t &token as param type change it to + * uint32_t */ /*! @@ -117,7 +119,7 @@ public: /* Poll */ - uint32_t requestStatus(const uint32_t token); + GxsRequestStatus requestStatus(const uint32_t token); /* Cancel Request */ bool cancelRequest(const uint32_t &token); @@ -300,7 +302,7 @@ private: * @param status the status to set * @return */ - bool locked_updateRequestStatus(const uint32_t &token, const uint32_t &status); + bool locked_updateRequestStatus(uint32_t token, GxsRequestStatus status); /*! * Use to query the status and other values of a given token @@ -311,7 +313,8 @@ private: * @param ts time stamp * @return false if token does not exist, true otherwise */ - bool checkRequestStatus(const uint32_t &token, uint32_t &status, uint32_t &reqtype, uint32_t &anstype, time_t &ts); + bool checkRequestStatus( uint32_t token, GxsRequestStatus &status, + uint32_t &reqtype, uint32_t &anstype, time_t &ts); // special ones for testing (not in final design) /*! @@ -341,14 +344,14 @@ public: * @param status * @return false if token could not be found, true if token disposed of */ - bool updatePublicRequestStatus(const uint32_t &token, const uint32_t &status); + bool updatePublicRequestStatus(uint32_t token, GxsRequestStatus status); /*! * This gets rid of a publicly issued token * @param token * @return false if token could not found, true if token disposed of */ - bool disposeOfPublicToken(const uint32_t &token); + bool disposeOfPublicToken(uint32_t token); private: @@ -488,7 +491,7 @@ private: RsMutex mDataMutex; /* protecting below */ uint32_t mNextToken; - std::map mPublicToken; + std::map mPublicToken; std::map mRequests; diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index cb8af6064..df19a900d 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -5181,43 +5181,51 @@ bool RsGxsNetService::clearDistantSearchResults(const TurtleRequestId& id) } void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req, const std::list& group_infos) { - RS_STACK_MUTEX(mNxsMutex) ; + std::set groupsToNotifyResults; - RsGxsGrpMetaTemporaryMap grpMeta; - std::map& search_results_map(mDistantSearchResults[req]) ; + { + RS_STACK_MUTEX(mNxsMutex); - for(auto it(group_infos.begin());it!=group_infos.end();++it) - if(search_results_map.find((*it).mGroupId) == search_results_map.end()) - grpMeta[(*it).mGroupId] = NULL; + RsGxsGrpMetaTemporaryMap grpMeta; + std::map& + search_results_map(mDistantSearchResults[req]); - mDataStore->retrieveGxsGrpMetaData(grpMeta); + for(auto it(group_infos.begin());it!=group_infos.end();++it) + if(search_results_map.find((*it).mGroupId) == search_results_map.end()) + grpMeta[(*it).mGroupId] = NULL; - std::list filtered_results ; + mDataStore->retrieveGxsGrpMetaData(grpMeta); - // only keep groups that are not locally known, and groups that are not already in the mDistantSearchResults structure + // only keep groups that are not locally known, and groups that are not already in the mDistantSearchResults structure - for(auto it(group_infos.begin());it!=group_infos.end();++it) - if(grpMeta[(*it).mGroupId] == NULL) - { - filtered_results.push_back(*it) ; + for(auto it(group_infos.begin());it!=group_infos.end();++it) + if(grpMeta[(*it).mGroupId] == NULL) + { + const RsGxsGroupId& grpId((*it).mGroupId); - auto it2 = search_results_map.find((*it).mGroupId) ; + groupsToNotifyResults.insert(grpId); - if(it2 != search_results_map.end()) - { - // update existing data + auto it2 = search_results_map.find(grpId); - it2->second.mPopularity++ ; - it2->second.mNumberOfMessages = std::max(it2->second.mNumberOfMessages,(*it).mNumberOfMessages) ; - } - else - { - search_results_map[(*it).mGroupId] = *it; - search_results_map[(*it).mGroupId].mPopularity = 1; // number of results so far - } + if(it2 != search_results_map.end()) + { + // update existing data - mObserver->receiveDistantSearchResults(req,(*it).mGroupId) ; - } + it2->second.mPopularity++; + it2->second.mNumberOfMessages = std::max( + it2->second.mNumberOfMessages, + (*it).mNumberOfMessages ); + } + else + { + search_results_map[grpId] = *it; + search_results_map[grpId].mPopularity = 1; // number of results so far + } + } + } // end RS_STACK_MUTEX(mNxsMutex); + + for(const RsGxsGroupId& grpId : groupsToNotifyResults) + mObserver->receiveDistantSearchResults(req, grpId); } void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req,const unsigned char *encrypted_group_data,uint32_t encrypted_group_data_len) diff --git a/libretroshare/src/gxs/rsgxsrequesttypes.h b/libretroshare/src/gxs/rsgxsrequesttypes.h index aa485edbb..7af50b135 100644 --- a/libretroshare/src/gxs/rsgxsrequesttypes.h +++ b/libretroshare/src/gxs/rsgxsrequesttypes.h @@ -28,7 +28,9 @@ struct GxsRequest { - GxsRequest() : token(0), reqTime(0), ansType(0), reqType(0), status(0) {} + GxsRequest() : + token(0), reqTime(0), ansType(0), reqType(0), + status(RsTokenService::FAILED) {} virtual ~GxsRequest() {} uint32_t token; @@ -38,7 +40,7 @@ struct GxsRequest uint32_t reqType; RsTokReqOptions Options; - uint32_t status; + RsTokenService::GxsRequestStatus status; }; class GroupMetaReq : public GxsRequest diff --git a/libretroshare/src/gxstrans/p3gxstrans.h b/libretroshare/src/gxstrans/p3gxstrans.h index 2b5abdead..3b0aca003 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.h +++ b/libretroshare/src/gxstrans/p3gxstrans.h @@ -89,7 +89,7 @@ struct MsgSizeCount * @see GxsTransClient::receiveGxsTransMail(...), * @see GxsTransClient::notifyGxsTransSendStatus(...). */ -class p3GxsTrans : public RsGenExchange, public GxsTokenQueue, public p3Config, public RsGxsTrans +struct p3GxsTrans : RsGenExchange, GxsTokenQueue, p3Config, RsGxsTrans { public: p3GxsTrans( RsGeneralDataService* gds, RsNetworkExchangeService* nes, @@ -98,17 +98,16 @@ public: RS_SERVICE_TYPE_GXS_TRANS, &identities, AuthenPolicy()), GxsTokenQueue(this), - RsGxsTrans(this), - mIdService(identities), + RsGxsTrans(static_cast(*this)), + // always check 30 secs after start) + mLastMsgCleanup(time(NULL) - MAX_DELAY_BETWEEN_CLEANUPS + 30), + mIdService(identities), mServClientsMutex("p3GxsTrans client services map mutex"), mOutgoingMutex("p3GxsTrans outgoing queue map mutex"), mIngoingMutex("p3GxsTrans ingoing queue map mutex"), + mCleanupThread(nullptr), mPerUserStatsMutex("p3GxsTrans user stats mutex"), - mDataMutex("p3GxsTrans data mutex") - { - mLastMsgCleanup = time(NULL) - MAX_DELAY_BETWEEN_CLEANUPS + 30; // always check 30 secs after start - mCleanupThread = NULL ; - } + mDataMutex("p3GxsTrans data mutex") {} virtual ~p3GxsTrans(); diff --git a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc index a86625f0f..c43e4baae 100644 --- a/libretroshare/src/gxstunnel/rsgxstunnelitems.cc +++ b/libretroshare/src/gxstunnel/rsgxstunnelitems.cc @@ -19,7 +19,6 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#pragma once #include #include diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp new file mode 100644 index 000000000..255fd0548 --- /dev/null +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -0,0 +1,145 @@ +/* + * RetroShare JSON API + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "jsonapi.h" + +#include +#include +#include +#include + +#include "util/rsjson.h" +#include "retroshare/rsfiles.h" +#include "util/radix64.h" + +// Generated at compile time +#include "jsonapi-includes.inl" + +JsonApiServer::JsonApiServer( + uint16_t port, const std::function shutdownCallback) : + mPort(port), mShutdownCallback(shutdownCallback) +{ + registerHandler("/jsonApiServer/shutdown", + [this](const std::shared_ptr) + { + shutdown(); + }); + + registerHandler("/rsFiles/getFileData", + [](const std::shared_ptr session) + { + size_t reqSize = session->get_request()->get_header("Content-Length", 0); + session->fetch( reqSize, []( + const std::shared_ptr session, + const rb::Bytes& body ) + { + RsGenericSerializer::SerializeContext cReq( + nullptr, 0, + RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ); + RsJson& jReq(cReq.mJson); + jReq.Parse(reinterpret_cast(body.data()), body.size()); + + RsGenericSerializer::SerializeContext cAns; + RsJson& jAns(cAns.mJson); + + // if caller specified caller_data put it back in the answhere + const char kcd[] = "caller_data"; + if(jReq.HasMember(kcd)) + jAns.AddMember(kcd, jReq[kcd], jAns.GetAllocator()); + + RsFileHash hash; + uint64_t offset; + uint32_t requested_size; + bool retval = false; + std::string errorMessage; + std::string base64data; + + // deserialize input parameters from JSON + { + RsGenericSerializer::SerializeContext& ctx(cReq); + RsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON); + RS_SERIAL_PROCESS(hash); + RS_SERIAL_PROCESS(offset); + RS_SERIAL_PROCESS(requested_size); + } + + if(requested_size > 10485760) + errorMessage = "requested_size is too big! Better less then 1M"; + else + { + std::vector buffer(requested_size); + + // call retroshare C++ API + retval = rsFiles->getFileData( + hash, offset, requested_size, buffer.data()); + + Radix64::encode(buffer.data(), requested_size, base64data); + } + + // serialize out parameters and return value to JSON + { + RsGenericSerializer::SerializeContext& ctx(cAns); + RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON); + RS_SERIAL_PROCESS(retval); + RS_SERIAL_PROCESS(requested_size); + RS_SERIAL_PROCESS(base64data); + if(!errorMessage.empty()) RS_SERIAL_PROCESS(errorMessage); + } + + // return them to the API caller + std::stringstream ss; + ss << jAns; + std::string&& ans(ss.str()); + const std::multimap headers + { + { "Content-Type", "text/json" }, + { "Content-Length", std::to_string(ans.length()) } + }; + session->close(rb::OK, ans, headers); + } ); + }); + +// Generated at compile time +#include "jsonapi-wrappers.inl" +} + +void JsonApiServer::run() +{ + std::shared_ptr settings(new rb::Settings); + settings->set_port(mPort); +// settings->set_default_header("Connection", "close"); + settings->set_default_header("Cache-Control", "no-cache"); + mService.start(settings); +} + +void JsonApiServer::registerHandler( + const std::string& path, + const std::function)>& handler) +{ + std::shared_ptr resource(new rb::Resource); + resource->set_path(path); + resource->set_method_handler("GET", handler); + resource->set_method_handler("POST", handler); + mService.publish(resource); +} + +void JsonApiServer::shutdown(int exitCode) +{ + mService.stop(); + mShutdownCallback(exitCode); +} diff --git a/libretroshare/src/jsonapi/jsonapi.h b/libretroshare/src/jsonapi/jsonapi.h new file mode 100644 index 000000000..f06f7e459 --- /dev/null +++ b/libretroshare/src/jsonapi/jsonapi.h @@ -0,0 +1,73 @@ +/* + * RetroShare JSON API + * Copyright (C) 2018 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "util/rsthreads.h" + +namespace rb = restbed; + + +/** + * Simple usage + * \code{.cpp} + * JsonApiServer jas(9092); + * jas.start("JsonApiServer"); + * \endcode + */ +struct JsonApiServer : RsSingleJobThread +{ + JsonApiServer( + uint16_t port, + const std::function shutdownCallback = [](int){} ); + + /// @see RsSingleJobThread + virtual void run(); + + /** + * @param[in] path Path itno which publish the API call + * @param[in] handler function which will be called to handle the requested + * path, the function must be declared like: + * \code{.cpp} + * void functionName(const shared_ptr session) + * \endcode + */ + void registerHandler( + const std::string& path, + const std::function)>& handler ); + + /** + * @brief Shutdown the JSON API server and call shutdownCallback + * @jsonapi{development} + * Beware that this method shout down only the JSON API server instance not + * the whole RetroShare instance, this behaviour can be altered via + * shutdownCallback paramether of @see JsonApiServer::JsonApiServer + * This method is made available also via JSON API with path + * /jsonApiServer/shutdown + * @param exitCode just passed down to the shutdownCallback + */ + void shutdown(int exitCode = 0); + +private: + uint16_t mPort; + rb::Service mService; + const std::function mShutdownCallback; +}; + diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 6a9d538e5..68bf97161 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -776,10 +776,12 @@ SOURCES += gxstunnel/p3gxstunnel.cc \ # new serialization code HEADERS += serialiser/rsserializable.h \ serialiser/rsserializer.h \ - serialiser/rstypeserializer.h + serialiser/rstypeserializer.h \ + util/rsjson.h SOURCES += serialiser/rsserializer.cc \ - serialiser/rstypeserializer.cc + serialiser/rstypeserializer.cc \ + util/rsjson.cc # Identity Service HEADERS += retroshare/rsidentity.h \ @@ -867,11 +869,64 @@ rs_gxs_trans { SOURCES += gxstrans/p3gxstransitems.cc gxstrans/p3gxstrans.cc } +rs_jsonapi { + JSONAPI_GENERATOR_SRC=$$system_path($$clean_path($${RS_SRC_PATH}/jsonapi-generator/src/)) + JSONAPI_GENERATOR_OUT=$$system_path($$clean_path($${RS_BUILD_PATH}/jsonapi-generator/src/)) + JSONAPI_GENERATOR_EXE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-generator)) + DOXIGEN_INPUT_DIRECTORY=$$system_path($$clean_path($${PWD})) + DOXIGEN_CONFIG_SRC=$$system_path($$clean_path($${RS_SRC_PATH}/jsonapi-generator/src/jsonapi-generator-doxygen.conf)) + DOXIGEN_CONFIG_OUT=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-generator-doxygen.conf)) + WRAPPERS_INCL_FILE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-includes.inl)) + WRAPPERS_REG_FILE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-wrappers.inl)) + + restbed.target = $$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/librestbed.a)) + restbed.commands = \ + cd $${RS_SRC_PATH};\ + git submodule update --init --recommend-shallow supportlibs/restbed;\ + cd $${RESTBED_SRC_PATH};\ + git submodule update --init --recommend-shallow dependency/asio;\ + git submodule update --init --recommend-shallow dependency/catch;\ + git submodule update --init --recommend-shallow dependency/kashmir;\ + mkdir -p $${RESTBED_BUILD_PATH}; cd $${RESTBED_BUILD_PATH};\ + cmake -DBUILD_SSL=OFF -DCMAKE_INSTALL_PREFIX=. -B. -H$${RESTBED_SRC_PATH};\ + make; make install + QMAKE_EXTRA_TARGETS += restbed + libretroshare.depends += restbed + PRE_TARGETDEPS *= $${restbed.target} + + PRE_TARGETDEPS *= $${JSONAPI_GENERATOR_EXE} + INCLUDEPATH *= $${JSONAPI_GENERATOR_OUT} + GENERATED_HEADERS += $${WRAPPERS_INCL_FILE} + + jsonwrappersincl.target = $${WRAPPERS_INCL_FILE} + jsonwrappersincl.commands = \ + cp $${DOXIGEN_CONFIG_SRC} $${DOXIGEN_CONFIG_OUT}; \ + echo OUTPUT_DIRECTORY=$${JSONAPI_GENERATOR_OUT} >> $${DOXIGEN_CONFIG_OUT};\ + echo INPUT=$${DOXIGEN_INPUT_DIRECTORY} >> $${DOXIGEN_CONFIG_OUT}; \ + doxygen $${DOXIGEN_CONFIG_OUT}; \ + $${JSONAPI_GENERATOR_EXE} $${JSONAPI_GENERATOR_SRC} $${JSONAPI_GENERATOR_OUT}; + QMAKE_EXTRA_TARGETS += jsonwrappersincl + libretroshare.depends += jsonwrappersincl + PRE_TARGETDEPS *= $${WRAPPERS_INCL_FILE} + + jsonwrappersreg.target = $${WRAPPERS_REG_FILE} + jsonwrappersreg.commands = touch $${WRAPPERS_REG_FILE} + jsonwrappersreg.depends = jsonwrappersincl + QMAKE_EXTRA_TARGETS += jsonwrappersreg + libretroshare.depends += jsonwrappersreg + PRE_TARGETDEPS *= $${WRAPPERS_REG_FILE} + + # Force recalculation of libretroshare dependencies see https://stackoverflow.com/a/47884045 + QMAKE_EXTRA_TARGETS += libretroshare + + HEADERS += jsonapi/jsonapi.h + SOURCES += jsonapi/jsonapi.cpp +} + rs_deep_search { HEADERS += deep_search/deep_search.h } - ########################################################################################################### # OLD CONFIG OPTIONS. # Not used much - but might be useful one day. diff --git a/libretroshare/src/plugins/dlfcn_win32.cc b/libretroshare/src/plugins/dlfcn_win32.cc index 83404e965..b669cfa54 100644 --- a/libretroshare/src/plugins/dlfcn_win32.cc +++ b/libretroshare/src/plugins/dlfcn_win32.cc @@ -19,7 +19,6 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#pragma once #ifdef WINDOWS_SYS diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index 2da8275c3..318397b2c 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -95,7 +95,11 @@ std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char return password ; } -void AuthGPG::init(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file) +void AuthGPG::init( + const std::string& path_to_public_keyring, + const std::string& path_to_secret_keyring, + const std::string& path_to_trustdb, + const std::string& pgp_lock_file) { if(_instance != NULL) { @@ -103,8 +107,11 @@ void AuthGPG::init(const std::string& path_to_public_keyring,const std::string& std::cerr << "AuthGPG::init() called twice!" << std::endl ; } - PGPHandler::setPassphraseCallback(pgp_pwd_callback) ; - _instance = new AuthGPG(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file) ; +// if(cb) PGPHandler::setPassphraseCallback(cb);else + PGPHandler::setPassphraseCallback(pgp_pwd_callback); + _instance = new AuthGPG( path_to_public_keyring, + path_to_secret_keyring, + path_to_trustdb, pgp_lock_file ); } void AuthGPG::exit() diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index 588148e86..bc01b1cd0 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -82,8 +82,8 @@ public: class AuthGPGService { public: - AuthGPGService() {}; - ~AuthGPGService() {}; + AuthGPGService() {} + ~AuthGPGService() {} virtual AuthGPGOperation *getGPGOperation() = 0; virtual void setGPGOperation(AuthGPGOperation *operation) = 0; @@ -91,12 +91,11 @@ public: class AuthGPG: public p3Config, public RsTickingThread, public PGPHandler { - public: - - static void init( const std::string& path_to_pubring, - const std::string& path_to_secring, - const std::string& path_to_trustdb, - const std::string& pgp_lock_file); +public: + static void init(const std::string& path_to_pubring, + const std::string& path_to_secring, + const std::string& path_to_trustdb, + const std::string& pgp_lock_file); static void exit(); static AuthGPG *getAuthGPG() { return _instance ; } diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index e516bea27..9a312683f 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -19,18 +19,25 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_FILES_GUI_INTERFACE_H -#define RS_FILES_GUI_INTERFACE_H +#pragma once #include #include #include +#include +#include #include "rstypes.h" +#include "serialiser/rsserializable.h" #include "rsturtle.h" class RsFiles; -extern RsFiles *rsFiles; + +/** + * Pointer to global instance of RsFiles service implementation + * @jsonapi{development} + */ +extern RsFiles* rsFiles; namespace RsRegularExpression { class Expression; } @@ -104,7 +111,7 @@ const TransferRequestFlags RS_FILE_REQ_NO_SEARCH ( 0x02000000 ); // di const uint32_t RS_FILE_EXTRA_DELETE = 0x0010; -struct SharedDirInfo +struct SharedDirInfo : RsSerializable { static bool sameLists(const std::list& l1,const std::list& l2) { @@ -118,10 +125,22 @@ struct SharedDirInfo return it1 == l1.end() && it2 == l2.end() ; } - std::string filename ; - std::string virtualname ; - FileStorageFlags shareflags ; // combnation of DIR_FLAGS_ANONYMOUS_DOWNLOAD | DIR_FLAGS_BROWSABLE | ... - std::list parent_groups ; + std::string filename; + std::string virtualname; + + /// combnation of DIR_FLAGS_ANONYMOUS_DOWNLOAD | DIR_FLAGS_BROWSABLE | ... + FileStorageFlags shareflags; + std::list parent_groups; + + /// @see RsSerializable::serial_process + virtual void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) + { + RS_SERIAL_PROCESS(filename); + RS_SERIAL_PROCESS(virtualname); + RS_SERIAL_PROCESS(shareflags); + RS_SERIAL_PROCESS(parent_groups); + } }; struct SharedDirStats @@ -177,38 +196,128 @@ public: RsFiles() {} virtual ~RsFiles() {} - /** - * Provides file data for the gui: media streaming or rpc clients. - * It may return unverified chunks. This allows streaming without having to wait for hashes or completion of the file. - * This function returns an unspecified amount of bytes. Either as much data as available or a sensible maximum. Expect a block size of around 1MiB. - * To get more data, call this function repeatedly with different offsets. - * Returns false in case - * - the files is not available on the local node - * - not downloading - * - the requested data was not downloaded yet - * - end of file was reached - * @param hash hash of a file. The file has to be available on this node or it has to be in downloading state. - * @param offset where the desired block starts - * @param requested_size size of pre-allocated data. Will be updated by the function. - * @param data pre-allocated memory chunk of size 'requested_size' by the client - */ - virtual bool getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& requested_size,uint8_t *data)=0; + /** + * Provides file data for the gui, media streaming or rpc clients. + * It may return unverified chunks. This allows streaming without having to + * wait for hashes or completion of the file. + * This function returns an unspecified amount of bytes. Either as much data + * as available or a sensible maximum. Expect a block size of around 1MiB. + * To get more data, call this function repeatedly with different offsets. + * + * jsonapi{development} + * note the missing @ the wrapper for this is written manually not + * autogenerated @see JsonApiServer. + * + * @param[in] hash hash of the file. The file has to be available on this node + * or it has to be in downloading state. + * @param[in] offset where the desired block starts + * @param[inout] requested_size size of pre-allocated data. Will be updated + * by the function. + * @param data pre-allocated memory chunk of size 'requested_size' by the + * client + * @return Returns false in case + * - the files is not available on the local node + * - not downloading + * - the requested data was not downloaded yet + * - end of file was reached + */ + virtual bool getFileData( const RsFileHash& hash, uint64_t offset, + uint32_t& requested_size, uint8_t* data ) = 0; - /*** - * Control of Downloads. - ***/ + /** + * @brief Check if we already have a file + * @jsonapi{development} + * @param[in] hash file identifier + * @param[out] info storage for the possibly found file information + * @return true if the file is already present, false otherwise + */ + virtual bool alreadyHaveFile(const RsFileHash& hash, FileInfo &info) = 0; + + /** + * @brief Initiate downloading of a file + * @jsonapi{development} + * @param[in] fileName + * @param[in] hash + * @param[in] size + * @param[in] destPath in not empty specify a destination path + * @param[in] flags you usually want RS_FILE_REQ_ANONYMOUS_ROUTING + * @param[in] srcIds eventually specify known sources + * @return false if we already have the file, true otherwhise + */ + virtual bool FileRequest( + const std::string& fileName, const RsFileHash& hash, uint64_t size, + const std::string& destPath, TransferRequestFlags flags, + const std::list& srcIds ) = 0; + + /** + * @brief Cancel file downloading + * @jsonapi{development} + * @param[in] hash + * @return false if the file is not in the download queue, true otherwhise + */ + virtual bool FileCancel(const RsFileHash& hash) = 0; + + /** + * @brief Set destination directory for given file + * @jsonapi{development} + * @param[in] hash file identifier + * @param[in] newPath + * @return false if some error occurred, true otherwise + */ + virtual bool setDestinationDirectory( + const RsFileHash& hash, const std::string& newPath ) = 0; + + /** + * @brief Set name for dowloaded file + * @jsonapi{development} + * @param[in] hash file identifier + * @param[in] newName + * @return false if some error occurred, true otherwise + */ + virtual bool setDestinationName( + const RsFileHash& hash, const std::string& newName ) = 0; + + /** + * @brief Set chunk strategy for file, useful to set streaming mode to be + * able of see video or other media preview while it is still downloading + * @jsonapi{development} + * @param[in] hash file identifier + * @param[in] newStrategy + * @return false if some error occurred, true otherwise + */ + virtual bool setChunkStrategy( + const RsFileHash& hash, + FileChunksInfo::ChunkStrategy newStrategy ) = 0; + + /** + * @brief Set default chunk strategy + * @jsonapi{development} + * @param[in] strategy + */ + virtual void setDefaultChunkStrategy( + FileChunksInfo::ChunkStrategy strategy ) = 0; + + /** + * @brief Get default chunk strategy + * @jsonapi{development} + * @return current default chunck strategy + */ + virtual FileChunksInfo::ChunkStrategy defaultChunkStrategy() = 0; + + /** + * @brief Get free disk space limit + * @jsonapi{development} + * @return current current minimum free space on disk in MB + */ + virtual uint32_t freeDiskSpaceLimit() const = 0; + + /** + * @brief Set minimum free disk space limit + * @jsonapi{development} + * @param[in] minimumFreeMB minimum free space in MB + */ + virtual void setFreeDiskSpaceLimit(uint32_t minimumFreeMB) = 0; - virtual bool alreadyHaveFile(const RsFileHash& hash, FileInfo &info) = 0; - /// Returns false is we already have the file. Otherwise, initiates the dl and returns true. - virtual bool FileRequest(const std::string& fname, const RsFileHash& hash, uint64_t size, const std::string& dest, TransferRequestFlags flags, const std::list& srcIds) = 0; - virtual bool FileCancel(const RsFileHash& hash) = 0; - virtual bool setDestinationDirectory(const RsFileHash& hash,const std::string& new_path) = 0; - virtual bool setDestinationName(const RsFileHash& hash,const std::string& new_name) = 0; - virtual bool setChunkStrategy(const RsFileHash& hash,FileChunksInfo::ChunkStrategy) = 0; - virtual void setDefaultChunkStrategy(FileChunksInfo::ChunkStrategy) = 0; - virtual FileChunksInfo::ChunkStrategy defaultChunkStrategy() = 0; - virtual uint32_t freeDiskSpaceLimit() const =0; - virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) =0; virtual bool FileControl(const RsFileHash& hash, uint32_t flags) = 0; virtual bool FileClearCompleted() = 0; virtual void setDefaultEncryptionPolicy(uint32_t policy)=0; // RS_FILE_CTRL_ENCRYPTION_POLICY_STRICT/PERMISSIVE @@ -217,8 +326,24 @@ public: virtual uint32_t getMaxUploadSlotsPerFriend()=0; virtual void setFilePermDirectDL(uint32_t perm)=0; virtual uint32_t filePermDirectDL()=0; - virtual TurtleRequestId turtleSearch(const std::string& string_to_match) =0; - virtual TurtleRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) =0; + + /** + * @brief Request remote files search + * @jsonapi{development} + * @param[in] matchString string to look for in the search + * @param multiCallback function that will be called each time a search + * result is received + * @param[in] maxWait maximum wait time in seconds for search results + * @return false on error, true otherwise + */ + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& results)>& multiCallback, + std::time_t maxWait = 300 ) = 0; + + virtual TurtleRequestId turtleSearch(const std::string& string_to_match) = 0; + virtual TurtleRequestId turtleSearch( + const RsRegularExpression::LinearizedExpression& expr) = 0; /*** * Control of Downloads Priority. @@ -229,21 +354,56 @@ public: virtual bool changeDownloadSpeed(const RsFileHash& hash, int speed) = 0; virtual bool getDownloadSpeed(const RsFileHash& hash, int & speed) = 0; virtual bool clearDownload(const RsFileHash& hash) = 0; -// virtual void getDwlDetails(std::list & details) = 0; - /*** - * Download / Upload Details. - ***/ - virtual void FileDownloads(std::list &hashs) = 0; - virtual bool FileUploads(std::list &hashs) = 0; - virtual bool FileDetails(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) = 0; + /** + * @brief Get incoming files list + * @jsonapi{development} + * @param[out] hashs storage for files identifiers list + */ + virtual void FileDownloads(std::list& hashs) = 0; + + /** + * @brief Get outgoing files list + * @jsonapi{development} + * @param[out] hashs storage for files identifiers list + * @return false if some error occurred, true otherwise + */ + virtual bool FileUploads(std::list& hashs) = 0; + + /** + * @brief Get file details + * @jsonapi{development} + * @param[in] hash file identifier + * @param[in] hintflags filtering hint (RS_FILE_HINTS_EXTRA|...|RS_FILE_HINTS_LOCAL) + * @param[out] info storage for file information + * @return true if file found, false otherwise + */ + virtual bool FileDetails( + const RsFileHash &hash, FileSearchFlags hintflags, FileInfo& info ) = 0; + virtual bool isEncryptedSource(const RsPeerId& virtual_peer_id) =0; - /// Gives chunk details about the downloaded file with given hash. - virtual bool FileDownloadChunksDetails(const RsFileHash& hash,FileChunksInfo& info) = 0 ; + /** + * @brief Get chunk details about the downloaded file with given hash. + * @jsonapi{development} + * @param[in] hash file identifier + * @param[out] info storage for file information + * @return true if file found, false otherwise + */ + virtual bool FileDownloadChunksDetails( + const RsFileHash& hash, FileChunksInfo& info) = 0; - /// details about the upload with given hash - virtual bool FileUploadChunksDetails(const RsFileHash& hash,const RsPeerId& peer_id,CompressedChunkMap& map) = 0 ; + /** + * @brief Get details about the upload with given hash + * @jsonapi{development} + * @param[in] hash file identifier + * @param[in] peer_id peer identifier + * @param[out] map storage for chunk info + * @return true if file found, false otherwise + */ + virtual bool FileUploadChunksDetails( + const RsFileHash& hash, const RsPeerId& peer_id, + CompressedChunkMap& map ) = 0; /*** * Extra List Access @@ -289,16 +449,76 @@ public: ***/ virtual void requestDirUpdate(void *ref) =0 ; // triggers the update of the given reference. Used when browsing. - virtual bool setDownloadDirectory(std::string path) = 0; - virtual bool setPartialsDirectory(std::string path) = 0; - virtual std::string getDownloadDirectory() = 0; - virtual std::string getPartialsDirectory() = 0; + /** + * @brief Set default complete downloads directory + * @jsonapi{development} + * @param[in] path directory path + * @return false if something failed, true otherwhise + */ + virtual bool setDownloadDirectory(const std::string& path) = 0; - virtual bool getSharedDirectories(std::list& dirs) = 0; - virtual bool setSharedDirectories(const std::list& dirs) = 0; - virtual bool addSharedDirectory(const SharedDirInfo& dir) = 0; - virtual bool updateShareFlags(const SharedDirInfo& dir) = 0; // updates the flags. The directory should already exist ! - virtual bool removeSharedDirectory(std::string dir) = 0; + /** + * @brief Set partial downloads directory + * @jsonapi{development} + * @param[in] path directory path + * @return false if something failed, true otherwhise + */ + virtual bool setPartialsDirectory(const std::string& path) = 0; + + /** + * @brief Get default complete downloads directory + * @jsonapi{development} + * @return default completed downloads directory path + */ + virtual std::string getDownloadDirectory() = 0; + + /** + * @brief Get partial downloads directory + * @jsonapi{development} + * @return partials downloads directory path + */ + virtual std::string getPartialsDirectory() = 0; + + /** + * @brief Get list of current shared directories + * @jsonapi{development} + * @param[out] dirs storage for the list of share directories + * @return false if something failed, true otherwhise + */ + virtual bool getSharedDirectories(std::list& dirs) = 0; + + /** + * @brief Set shared directories + * @jsonapi{development} + * @param[in] dirs list of shared directories with share options + * @return false if something failed, true otherwhise + */ + virtual bool setSharedDirectories(const std::list& dirs) = 0; + + /** + * @brief Add shared directory + * @jsonapi{development} + * @param[in] dir directory to share with sharing options + * @return false if something failed, true otherwhise + */ + virtual bool addSharedDirectory(const SharedDirInfo& dir) = 0; + + /** + * @brief Updates shared directory sharing flags. + * The directory should be already shared! + * @jsonapi{development} + * @param[in] dir Shared directory with updated sharing options + * @return false if something failed, true otherwhise + */ + virtual bool updateShareFlags(const SharedDirInfo& dir) = 0; + + /** + * @brief Remove directory from shared list + * @jsonapi{development} + * @param[in] dir Path of the directory to remove from shared list + * @return false if something failed, true otherwhise + */ + virtual bool removeSharedDirectory(std::string dir) = 0; virtual bool getIgnoreLists(std::list& ignored_prefixes, std::list& ignored_suffixes,uint32_t& flags) =0; virtual void setIgnoreLists(const std::list& ignored_prefixes, const std::list& ignored_suffixes,uint32_t flags) =0; @@ -320,8 +540,4 @@ public: virtual bool ignoreDuplicates() = 0; virtual void setIgnoreDuplicates(bool ignore) = 0; - }; - - -#endif diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 665963fe4..383ebc7df 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -1,9 +1,11 @@ +#pragma once /******************************************************************************* * libretroshare/src/retroshare: rsgxschannels.h * * * * libretroshare: retroshare core library * * * * Copyright 2012-2012 by Robert Fernie * + * Copyright (C) 2018 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,44 +21,56 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RETROSHARE_GXS_CHANNEL_GUI_INTERFACE_H -#define RETROSHARE_GXS_CHANNEL_GUI_INTERFACE_H #include #include #include +#include #include "retroshare/rstokenservice.h" #include "retroshare/rsgxsifacehelper.h" #include "retroshare/rsgxscommon.h" +#include "serialiser/rsserializable.h" #include "retroshare/rsturtle.h" -/* The Main Interface Class - for information about your Peers */ class RsGxsChannels; -extern RsGxsChannels *rsGxsChannels; +/** + * Pointer to global instance of RsGxsChannels service implementation + * @jsonapi{development} + */ +extern RsGxsChannels* rsGxsChannels; // These should be in rsgxscommon.h - -class RsGxsChannelGroup +struct RsGxsChannelGroup : RsSerializable { - public: RsGroupMetaData mMeta; std::string mDescription; RsGxsImage mImage; bool mAutoDownload; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mDescription); + RS_SERIAL_PROCESS(mImage); + RS_SERIAL_PROCESS(mAutoDownload); + } }; -class RsGxsChannelPost +std::ostream &operator<<(std::ostream& out, const RsGxsChannelGroup& group); + + +struct RsGxsChannelPost : RsSerializable { -public: RsGxsChannelPost() : mCount(0), mSize(0) {} -public: RsMsgMetaData mMeta; - std::set mOlderVersions ; + std::set mOlderVersions; std::string mMsg; // UTF8 encoded. std::list mFiles; @@ -64,26 +78,217 @@ public: uint64_t mSize; // auto calced. RsGxsImage mThumbnail; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mOlderVersions); + + RS_SERIAL_PROCESS(mMsg); + RS_SERIAL_PROCESS(mFiles); + RS_SERIAL_PROCESS(mCount); + RS_SERIAL_PROCESS(mSize); + RS_SERIAL_PROCESS(mThumbnail); + } }; +std::ostream &operator<<(std::ostream& out, const RsGxsChannelPost& post); -std::ostream &operator<<(std::ostream &out, const RsGxsChannelGroup &group); -std::ostream &operator<<(std::ostream &out, const RsGxsChannelPost &post); class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService { public: - explicit RsGxsChannels(RsGxsIface *gxs) - :RsGxsIfaceHelper(gxs) {} + explicit RsGxsChannels(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsChannels() {} - /* Specific Service Data */ + /** + * @brief Get channels summaries list. Blocking API. + * @jsonapi{development} + * @param[out] channels list where to store the channels + * @return false if something failed, true otherwhise + */ + virtual bool getChannelsSummaries(std::list& channels) = 0; + + /** + * @brief Get channels information (description, thumbnail...). + * Blocking API. + * @jsonapi{development} + * @param[in] chanIds ids of the channels of which to get the informations + * @param[out] channelsInfo storage for the channels informations + * @return false if something failed, true otherwhise + */ + virtual bool getChannelsInfo( + const std::list& chanIds, + std::vector& channelsInfo ) = 0; + + /** + * @brief Get content of specified channels. Blocking API + * @jsonapi{development} + * @param[in] chanIds id of the channels of which the content is requested + * @param[out] posts storage for the posts + * @param[out] comments storage for the comments + * @return false if something failed, true otherwhise + */ + virtual bool getChannelsContent( + const std::list& chanIds, + std::vector& posts, + std::vector& comments ) = 0; + + /* Specific Service Data + * TODO: change the orrible const uint32_t &token to uint32_t token + * TODO: create a new typedef for token so code is easier to read + */ + virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts) = 0; virtual bool getPostData(const uint32_t &token, std::vector &posts) = 0; - ////////////////////////////////////////////////////////////////////////////// + /** + * @brief toggle message read status + * @jsonapi{development} + * @param[out] token GXS token queue token + * @param[in] msgId + * @param[in] read + */ + virtual void setMessageReadStatus( + uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0; + + /** + * @brief Enable or disable auto-download for given channel + * @jsonapi{development} + * @param[in] groupId channel id + * @param[in] enable true to enable, false to disable + * @return false if something failed, true otherwhise + */ + virtual bool setChannelAutoDownload( + const RsGxsGroupId &groupId, bool enable) = 0; + + /** + * @brief Get auto-download option value for given channel + * @jsonapi{development} + * @param[in] groupId channel id + * @param[in] enabled storage for the auto-download option value + * @return false if something failed, true otherwhise + */ + virtual bool getChannelAutoDownload( + const RsGxsGroupId &groupId, bool& enabled) = 0; + + /** + * @brief Set download directory for the given channel + * @jsonapi{development} + * @param[in] channelId id of the channel + * @param[in] directory path + * @return false on error, true otherwise + */ + virtual bool setChannelDownloadDirectory( + const RsGxsGroupId& channelId, const std::string& directory) = 0; + + /** + * @brief Get download directory for the given channel + * @jsonapi{development} + * @param[in] channelId id of the channel + * @param[out] directory reference to string where to store the path + * @return false on error, true otherwise + */ + virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId, + std::string& directory ) = 0; + + /** + * @brief Share channel publishing key + * This can be used to authorize other peers to post on the channel + * @jsonapi{development} + * param[in] groupId Channel id + * param[in] peers peers to which share the key + * @return false on error, true otherwise + */ + virtual bool groupShareKeys( + const RsGxsGroupId& groupId, const std::set& peers ) = 0; + + /** + * @brief Request subscription to a group. + * The action is performed asyncronously, so it could fail in a subsequent + * phase even after returning true. + * @jsonapi{development} + * @param[out] token Storage for RsTokenService token to track request + * status. + * @param[in] groupId Channel id + * @param[in] subscribe + * @return false on error, true otherwise + */ + virtual bool subscribeToGroup( uint32_t& token, const RsGxsGroupId &groupId, + bool subscribe ) = 0; + + /** + * @brief Request channel creation. + * The action is performed asyncronously, so it could fail in a subsequent + * phase even after returning true. + * @jsonapi{development} + * @param[out] token Storage for RsTokenService token to track request + * status. + * @param[in] group Channel data (name, description...) + * @return false on error, true otherwise + */ + virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0; + + /** + * @brief Request post creation. + * The action is performed asyncronously, so it could fail in a subsequent + * phase even after returning true. + * @jsonapi{development} + * @param[out] token Storage for RsTokenService token to track request + * status. + * @param[in] post + * @return false on error, true otherwise + */ + virtual bool createPost(uint32_t& token, RsGxsChannelPost& post) = 0; + + /** + * @brief Request channel change. + * The action is performed asyncronously, so it could fail in a subsequent + * phase even after returning true. + * @jsonapi{development} + * @param[out] token Storage for RsTokenService token to track request + * status. + * @param[in] group Channel data (name, description...) with modifications + * @return false on error, true otherwise + */ + virtual bool updateGroup(uint32_t& token, RsGxsChannelGroup& group) = 0; + + /** + * @brief Share extra file + * Can be used to share extra file attached to a channel post + * @jsonapi{development} + * @param[in] path file path + * @return false on error, true otherwise + */ + virtual bool ExtraFileHash(const std::string& path) = 0; + + /** + * @brief Remove extra file from shared files + * @jsonapi{development} + * @param[in] hash hash of the file to remove + * @return false on error, true otherwise + */ + virtual bool ExtraFileRemove(const RsFileHash& hash) = 0; + + /** + * @brief Request remote channels search + * @jsonapi{development} + * @param[in] matchString string to look for in the search + * @param multiCallback function that will be called each time a search + * result is received + * @param[in] maxWait maximum wait time in seconds for search results + * @return false on error, true otherwise + */ + virtual bool turtleSearchRequest( + const std::string& matchString, + const std::function& multiCallback, + std::time_t maxWait = 300 ) = 0; + + ////////////////////////////////////////////////////////////////////////////// /// Distant synchronisation methods /// ////////////////////////////////////////////////////////////////////////////// /// @@ -94,29 +299,4 @@ public: virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0; ////////////////////////////////////////////////////////////////////////////// - virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read) = 0; - - virtual bool setChannelAutoDownload(const RsGxsGroupId &groupId, bool enabled) = 0; - virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled) = 0; - - virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory)=0; - virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory)=0; - - virtual bool groupShareKeys(const RsGxsGroupId &groupId, std::set& peers)=0; - - // Overloaded subscribe fn. - virtual bool subscribeToGroup(uint32_t &token, const RsGxsGroupId &groupId, bool subscribe) = 0; - - virtual bool createGroup(uint32_t &token, RsGxsChannelGroup &group) = 0; - virtual bool createPost(uint32_t &token, RsGxsChannelPost &post) = 0; - - virtual bool updateGroup(uint32_t &token, RsGxsChannelGroup &group) = 0; - - // File Interface - virtual bool ExtraFileHash(const std::string &path, std::string filename) = 0; - virtual bool ExtraFileRemove(const RsFileHash &hash) = 0; }; - - - -#endif diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 5ebb671d2..f01e92ef3 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -122,8 +122,8 @@ class RsGxsCircles: public RsGxsIfaceHelper { public: - RsGxsCircles(RsGxsIface *gxs) :RsGxsIfaceHelper(gxs) { return; } - virtual ~RsGxsCircles() { return; } + RsGxsCircles(RsGxsIface& gxs) :RsGxsIfaceHelper(gxs) {} + virtual ~RsGxsCircles() {} /* External Interface (Cached stuff) */ virtual bool getCircleDetails(const RsGxsCircleId &id, RsGxsCircleDetails &details) = 0; diff --git a/libretroshare/src/retroshare/rsgxscommon.h b/libretroshare/src/retroshare/rsgxscommon.h index b1579e406..57b17ed35 100644 --- a/libretroshare/src/retroshare/rsgxscommon.h +++ b/libretroshare/src/retroshare/rsgxscommon.h @@ -31,37 +31,55 @@ #include #include "rsgxsifacetypes.h" +#include "serialiser/rsserializable.h" -class RsGxsFile +struct RsGxsFile : RsSerializable { - public: RsGxsFile(); std::string mName; RsFileHash mHash; uint64_t mSize; - //std::string mPath; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mName); + RS_SERIAL_PROCESS(mHash); + RS_SERIAL_PROCESS(mSize); + } }; -class RsGxsImage +struct RsGxsImage : RsSerializable { - public: - RsGxsImage(); + RsGxsImage(); ~RsGxsImage(); - RsGxsImage(const RsGxsImage& a); // TEMP use copy constructor and duplicate memory. -RsGxsImage &operator=(const RsGxsImage &a); // Need this as well? -//NB: Must make sure that we always use methods - to be consistent about malloc/free for this data. -static uint8_t *allocate(uint32_t size); -static void release(void *data); + /// Use copy constructor and duplicate memory. + RsGxsImage(const RsGxsImage& a); + + RsGxsImage &operator=(const RsGxsImage &a); // Need this as well? + + /** NB: Must make sure that we always use methods - to be consistent about + * malloc/free for this data. */ + static uint8_t *allocate(uint32_t size); + static void release(void *data); void take(uint8_t *data, uint32_t size); // Copies Pointer. void copy(uint8_t *data, uint32_t size); // Allocates and Copies. void clear(); // Frees. void shallowClear(); // Clears Pointer. - uint8_t *mData; uint32_t mSize; + uint8_t* mData; + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RsTypeSerializer::TlvMemBlock_proxy b(mData, mSize); + RsTypeSerializer::serial_process(j, ctx, b, "mData"); + } }; @@ -84,17 +102,23 @@ namespace GXS_SERV { -class RsGxsVote +struct RsGxsVote : RsSerializable { - public: RsGxsVote(); RsMsgMetaData mMeta; uint32_t mVoteType; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mVoteType); + } }; -class RsGxsComment +struct RsGxsComment : RsSerializable { - public: RsGxsComment(); RsMsgMetaData mMeta; std::string mComment; @@ -109,6 +133,19 @@ class RsGxsComment // This is filled in if detailed Comment Data is called. std::list mVotes; + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mComment); + RS_SERIAL_PROCESS(mUpVotes); + RS_SERIAL_PROCESS(mDownVotes); + RS_SERIAL_PROCESS(mScore); + RS_SERIAL_PROCESS(mOwnVote); + RS_SERIAL_PROCESS(mVotes); + } + const std::ostream &print(std::ostream &out, std::string indent = "", std::string varName = "") const { out << indent << varName << " of RsGxsComment Values ###################" << std::endl; mMeta.print(out, indent + " ", "mMeta"); diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 9d0296e4b..e93a137a3 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -59,8 +59,7 @@ class RsGxsForums: public RsGxsIfaceHelper { public: - explicit RsGxsForums(RsGxsIface *gxs) - :RsGxsIfaceHelper(gxs) {} + explicit RsGxsForums(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsForums() {} /* Specific Service Data */ diff --git a/libretroshare/src/retroshare/rsgxsiface.h b/libretroshare/src/retroshare/rsgxsiface.h index b85f3fbce..7fbf4b691 100644 --- a/libretroshare/src/retroshare/rsgxsiface.h +++ b/libretroshare/src/retroshare/rsgxsiface.h @@ -32,6 +32,7 @@ #include "gxs/rsgxsdata.h" #include "retroshare/rsgxsifacetypes.h" #include "util/rsdeprecate.h" +#include "serialiser/rsserializable.h" /*! * This structure is used to transport group summary information when a GXS @@ -76,9 +77,8 @@ struct RsGxsGroupSummary : RsSerializable /*! * Stores ids of changed gxs groups and messages. It is used to notify the GUI about changes. */ -class RsGxsChanges +struct RsGxsChanges { -public: RsGxsChanges(): mService(0){} RsTokenService *mService; std::map > mMsgs; @@ -91,13 +91,9 @@ public: /*! * All implementations must offer thread safety */ -class RsGxsIface +struct RsGxsIface { -public: - - virtual ~RsGxsIface(){}; - -public: + virtual ~RsGxsIface() {} /*! * Gxs services should call this for automatic handling of diff --git a/libretroshare/src/retroshare/rsgxsifacehelper.h b/libretroshare/src/retroshare/rsgxsifacehelper.h index fbe12570e..5a8c2d5fd 100644 --- a/libretroshare/src/retroshare/rsgxsifacehelper.h +++ b/libretroshare/src/retroshare/rsgxsifacehelper.h @@ -7,6 +7,7 @@ * RetroShare GXS. Convenience interface implementation * * Copyright 2012 by Christopher Evi-Parker + * Copyright (C) 2018 Gioacchino Mazzurco * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,29 +27,30 @@ * */ +#include +#include + #include "retroshare/rsgxsiface.h" #include "retroshare/rsreputations.h" #include "rsgxsflags.h" +#include "util/rsdeprecate.h" /*! - * The simple idea of this class is to implement the simple interface functions - * of gen exchange. - * This class provides convenience implementations of: - * - Handle msg and group changes (client class must pass changes sent by RsGenExchange to it) - * - subscription to groups - * - retrieval of msgs and group ids and meta info + * This class only make method of internal members visible tu upper level to + * offer a more friendly API. + * This is just a workaround to awkward GXS API design, do not take it as an + * example for your coding. + * To properly fix the API design many changes with the implied chain reactions + * are necessary, so at this point this workaround seems acceptable. */ -class RsGxsIfaceHelper +struct RsGxsIfaceHelper { -public: - - /*! - * - * @param gxs handle to RsGenExchange instance of service (Usually the service class itself) - */ - RsGxsIfaceHelper(RsGxsIface* gxs) - : mGxs(gxs) - {} + /*! + * @param gxs handle to RsGenExchange instance of service (Usually the + * service class itself) + */ + RsGxsIfaceHelper(RsGxsIface& gxs) : + mGxs(gxs), mTokenService(*gxs.getTokenService()) {} ~RsGxsIfaceHelper(){} @@ -59,15 +61,7 @@ public: */ void receiveChanges(std::vector &changes) { - mGxs->receiveChanges(changes); - } - - /*! - * @return handle to token service for this GXS service - */ - RsTokenService* getTokenService() - { - return mGxs->getTokenService(); + mGxs.receiveChanges(changes); } /* Generic Lists */ @@ -81,7 +75,7 @@ public: bool getGroupList(const uint32_t &token, std::list &groupIds) { - return mGxs->getGroupList(token, groupIds); + return mGxs.getGroupList(token, groupIds); } /*! @@ -93,7 +87,7 @@ public: bool getMsgList(const uint32_t &token, GxsMsgIdResult& msgIds) { - return mGxs->getMsgList(token, msgIds); + return mGxs.getMsgList(token, msgIds); } /*! @@ -104,7 +98,7 @@ public: */ bool getMsgRelatedList(const uint32_t &token, MsgRelatedIdResult &msgIds) { - return mGxs->getMsgRelatedList(token, msgIds); + return mGxs.getMsgRelatedList(token, msgIds); } /*! @@ -115,7 +109,7 @@ public: bool getGroupSummary(const uint32_t &token, std::list &groupInfo) { - return mGxs->getGroupMeta(token, groupInfo); + return mGxs.getGroupMeta(token, groupInfo); } /*! @@ -126,7 +120,7 @@ public: bool getMsgSummary(const uint32_t &token, GxsMsgMetaMap &msgInfo) { - return mGxs->getMsgMeta(token, msgInfo); + return mGxs.getMsgMeta(token, msgInfo); } /*! @@ -136,7 +130,7 @@ public: */ bool getMsgRelatedSummary(const uint32_t &token, GxsMsgRelatedMetaMap &msgInfo) { - return mGxs->getMsgRelatedMeta(token, msgInfo); + return mGxs.getMsgRelatedMeta(token, msgInfo); } /*! @@ -147,7 +141,7 @@ public: */ bool subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe) { - return mGxs->subscribeToGroup(token, grpId, subscribe); + return mGxs.subscribeToGroup(token, grpId, subscribe); } /*! @@ -159,7 +153,7 @@ public: */ bool acknowledgeMsg(const uint32_t& token, std::pair& msgId) { - return mGxs->acknowledgeTokenMsg(token, msgId); + return mGxs.acknowledgeTokenMsg(token, msgId); } /*! @@ -171,7 +165,7 @@ public: */ bool acknowledgeGrp(const uint32_t& token, RsGxsGroupId& grpId) { - return mGxs->acknowledgeTokenGrp(token, grpId); + return mGxs.acknowledgeTokenGrp(token, grpId); } /*! @@ -182,7 +176,7 @@ public: */ bool getServiceStatistic(const uint32_t& token, GxsServiceStatistic& stats) { - return mGxs->getServiceStatistic(token, stats); + return mGxs.getServiceStatistic(token, stats); } /*! @@ -193,7 +187,7 @@ public: */ bool getGroupStatistic(const uint32_t& token, GxsGroupStatistic& stats) { - return mGxs->getGroupStatistic(token, stats); + return mGxs.getGroupStatistic(token, stats); } /*! @@ -206,7 +200,7 @@ public: */ void setGroupReputationCutOff(uint32_t& token, const RsGxsGroupId& grpId, int CutOff) { - return mGxs->setGroupReputationCutOff(token, grpId, CutOff); + return mGxs.setGroupReputationCutOff(token, grpId, CutOff); } /*! @@ -214,36 +208,111 @@ public: */ uint32_t getDefaultStoragePeriod() { - return mGxs->getDefaultStoragePeriod(); + return mGxs.getDefaultStoragePeriod(); } uint32_t getStoragePeriod(const RsGxsGroupId& grpId) { - return mGxs->getStoragePeriod(grpId); + return mGxs.getStoragePeriod(grpId); } void setStoragePeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) { - mGxs->setStoragePeriod(grpId,age_in_secs); + mGxs.setStoragePeriod(grpId,age_in_secs); } uint32_t getDefaultSyncPeriod() { - return mGxs->getDefaultSyncPeriod(); + return mGxs.getDefaultSyncPeriod(); } uint32_t getSyncPeriod(const RsGxsGroupId& grpId) { - return mGxs->getSyncPeriod(grpId); + return mGxs.getSyncPeriod(grpId); } void setSyncPeriod(const RsGxsGroupId& grpId,uint32_t age_in_secs) { - mGxs->setSyncPeriod(grpId,age_in_secs); + mGxs.setSyncPeriod(grpId,age_in_secs); } RsReputations::ReputationLevel minReputationForForwardingMessages(uint32_t group_sign_flags,uint32_t identity_flags) { - return mGxs->minReputationForForwardingMessages(group_sign_flags,identity_flags); + return mGxs.minReputationForForwardingMessages(group_sign_flags,identity_flags); } -private: - RsGxsIface* mGxs; + /// @see RsTokenService::requestGroupInfo + bool requestGroupInfo( uint32_t& token, const RsTokReqOptions& opts, + const std::list &groupIds ) + { return mTokenService.requestGroupInfo(token, 0, opts, groupIds); } + + /// @see RsTokenService::requestGroupInfo + bool requestGroupInfo(uint32_t& token, const RsTokReqOptions& opts) + { return mTokenService.requestGroupInfo(token, 0, opts); } + + /// @see RsTokenService::requestMsgInfo + bool requestMsgInfo( uint32_t& token, + const RsTokReqOptions& opts, const GxsMsgReq& msgIds ) + { return mTokenService.requestMsgInfo(token, 0, opts, msgIds); } + + /// @see RsTokenService::requestMsgInfo + bool requestMsgInfo( + uint32_t& token, const RsTokReqOptions& opts, + const std::list& grpIds ) + { return mTokenService.requestMsgInfo(token, 0, opts, grpIds); } + + /// @see RsTokenService::requestMsgRelatedInfo + bool requestMsgRelatedInfo( + uint32_t& token, const RsTokReqOptions& opts, + const std::vector& msgIds ) + { return mTokenService.requestMsgRelatedInfo(token, 0, opts, msgIds); } + + /** + * @jsonapi{development} + * @param[in] token + */ + RsTokenService::GxsRequestStatus requestStatus(uint32_t token) + { return mTokenService.requestStatus(token); } + + /// @see RsTokenService::requestServiceStatistic + void requestServiceStatistic(uint32_t& token) + { mTokenService.requestServiceStatistic(token); } + + /// @see RsTokenService::requestGroupStatistic + void requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) + { mTokenService.requestGroupStatistic(token, grpId); } + + /// @see RsTokenService::cancelRequest + bool cancelRequest(uint32_t token) + { return mTokenService.cancelRequest(token); } + + /** + * @deprecated + * Token service methods are already exposed by this helper, so you should + * not need to get token service pointer directly anymore. + */ + RS_DEPRECATED RsTokenService* getTokenService() { return &mTokenService; } + +protected: + /** + * Block caller while request is being processed. + * Useful for blocking API implementation. + * @param[in] token token associated to the request caller is waiting for + * @param[in] maxWait maximum waiting time in milliseconds + */ + RsTokenService::GxsRequestStatus waitToken( + uint32_t token, + std::chrono::milliseconds maxWait = std::chrono::milliseconds(500) ) + { + auto timeout = std::chrono::steady_clock::now() + maxWait; + auto st = requestStatus(token); + while( !(st == RsTokenService::FAILED || st >= RsTokenService::COMPLETE) + && std::chrono::steady_clock::now() < timeout ) + { + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + st = requestStatus(token); + } + return st; + } + +private: + RsGxsIface& mGxs; + RsTokenService& mTokenService; }; #endif // RSGXSIFACEIMPL_H diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index 627513630..8c90cb3b2 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -119,7 +119,7 @@ struct RsGroupMetaData : RsSerializable -struct RsMsgMetaData +struct RsMsgMetaData : RsSerializable { RsMsgMetaData() : mPublishTs(0), mMsgFlags(0), mMsgStatus(0), mChildTs(0) {} @@ -150,6 +150,24 @@ struct RsMsgMetaData time_t mChildTs; std::string mServiceString; // Service Specific Free-Form extra storage. + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mGroupId); + RS_SERIAL_PROCESS(mMsgId); + RS_SERIAL_PROCESS(mThreadId); + RS_SERIAL_PROCESS(mParentId); + RS_SERIAL_PROCESS(mOrigMsgId); + RS_SERIAL_PROCESS(mAuthorId); + RS_SERIAL_PROCESS(mMsgName); + RS_SERIAL_PROCESS(mPublishTs); + RS_SERIAL_PROCESS(mMsgFlags); + RS_SERIAL_PROCESS(mMsgStatus); + RS_SERIAL_PROCESS(mChildTs); + RS_SERIAL_PROCESS(mServiceString); + } + const std::ostream &print(std::ostream &out, std::string indent = "", std::string varName = "") const { out << indent << varName << " of RsMsgMetaData Values ###################" << std::endl diff --git a/libretroshare/src/retroshare/rsgxstrans.h b/libretroshare/src/retroshare/rsgxstrans.h index b78191d97..bee1e11ec 100644 --- a/libretroshare/src/retroshare/rsgxstrans.h +++ b/libretroshare/src/retroshare/rsgxstrans.h @@ -91,7 +91,7 @@ public: std::vector outgoing_records; }; - RsGxsTrans(RsGxsIface *gxs) : RsGxsIfaceHelper(gxs) {} + RsGxsTrans(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsTrans() {} diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 610df360f..687d3d3a5 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -339,7 +339,7 @@ struct RsIdentityDetails : RsSerializable struct RsIdentity : RsGxsIfaceHelper { - explicit RsIdentity(RsGxsIface *gxs): RsGxsIfaceHelper(gxs) {} + explicit RsIdentity(RsGxsIface& gxs): RsGxsIfaceHelper(gxs) {} virtual ~RsIdentity() {} /********************************************************************************************/ diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index db0e8fab8..c99978aea 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -43,80 +43,89 @@ #include #include +struct RsLoginHelper; + +/** + * Pointer to global instance of RsLoginHelper + * @jsonapi{development} + */ +extern RsLoginHelper* rsLoginHelper; + /*! * Initialisation Class (not publicly disclosed to RsIFace) */ class RsInit { - public: - /* reorganised RsInit system */ +public: + enum LoadCertificateStatus : uint8_t + { + OK, /// Everything go as expected, no error occurred + ERR_ALREADY_RUNNING, /// Another istance is running already + ERR_CANT_ACQUIRE_LOCK, /// Another istance is already running? + ERR_UNKOWN /// Unkown error, maybe password is wrong? + }; - /*! - * PreLogin - * Call before init retroshare, initialises rsinitconfig's public attributes - */ - static void InitRsConfig() ; + /* reorganised RsInit system */ - /*! - * Should be called to load up ssl cert and private key, and intialises gpg - * this must be called before accessing rsserver (e.g. ::startupretroshare) - * @param argc passed from executable - * @param argv commandline arguments passed to executable - * @param strictCheck set to true if you want rs to continue executing if invalid argument passed and vice versa - * @return RS_INIT_... - */ - static int InitRetroShare(int argc, char **argv, bool strictCheck=true); + /*! + * PreLogin + * Call before init retroshare, initialises rsinitconfig's public attributes + */ + static void InitRsConfig(); - static bool isPortable(); - static bool isWindowsXP(); - static bool collectEntropy(uint32_t bytes) ; + /*! + * Should be called to load up ssl cert and private key, and intialises gpg + * this must be called before accessing rsserver (e.g. ::startupretroshare) + * @param argc passed from executable + * @param argv commandline arguments passed to executable + * @param strictCheck set to true if you want rs to continue executing if + * invalid argument passed and vice versa + * @return RS_INIT_... + */ + static int InitRetroShare(int argc, char **argv, bool strictCheck=true); - /*! - * Setup Hidden Location; - */ - static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob); + static bool isPortable(); + static bool isWindowsXP(); + static bool collectEntropy(uint32_t bytes) ; - static bool LoadPassword(const std::string& passwd) ; + /* + * Setup Hidden Location; + */ + static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob); - /*! + static bool LoadPassword(const std::string& passwd) ; + /* + * Final Certificate load. This can be called if: + * a) InitRetroshare() returns RS_INIT_HAVE_ACCOUNT -> autoLoad/password Set. + * b) or LoadPassword() + * + * This uses the preferredId from RsAccounts. + * This wrapper also locks the profile before finalising the login + */ + static LoadCertificateStatus LockAndLoadCertificates( + bool autoLoginNT, std::string& lockFilePath ); - * Final Certificate load. This can be called if: - * a) InitRetroshare() returns RS_INIT_HAVE_ACCOUNT -> autoLoad/password Set. - * b) or LoadPassword() - * - * This uses the preferredId from RsAccounts. - * This wrapper also locks the profile before finalising the login - */ - static int LockAndLoadCertificates(bool autoLoginNT, std::string& lockFilePath); + // Post Login Options + static bool getStartMinimised(); - /*! - * Post Login Options - */ + static int getSslPwdLen(); + static bool getAutoLogin(); + static void setAutoLogin(bool autoLogin); + static bool RsClearAutoLogin() ; - static bool getStartMinimised(); +private: + /** @brief Lock profile directory + * param[in] accountDir account directory to lock + * param[out] lockFilePath path of the created lock-file + */ + static LoadCertificateStatus LockConfigDirectory( + const std::string& accountDir, std::string& lockFilePath); - static int getSslPwdLen(); - static bool getAutoLogin(); - static void setAutoLogin(bool autoLogin); - static bool RsClearAutoLogin() ; - - private: - -#if 0 - /* Auto Login */ - static bool RsStoreAutoLogin() ; - static bool RsTryAutoLogin() ; -#endif - -// THESE CAN BE REMOVED FROM THE CLASS TOO. - /* Lock/unlock profile directory */ - static int LockConfigDirectory(const std::string& accountDir, std::string& lockFilePath); - static void UnlockConfigDirectory(); - - /* The true LoadCertificates() method */ - static int LoadCertificates(bool autoLoginNT) ; + /// @brief Unlock profile directory + static void UnlockConfigDirectory(); + static int LoadCertificates(bool autoLoginNT); }; @@ -170,7 +179,11 @@ public: static bool GetAccountDetails(const RsPeerId &id, RsPgpId &gpgId, std::string &gpgName, std::string &gpgEmail, std::string &location); - static bool createNewAccount(const RsPgpId& pgp_id, const std::string& org, const std::string& loc, const std::string& country, bool ishiddenloc,bool is_auto_tor, const std::string& passwd, RsPeerId &sslId, std::string &errString); + static bool createNewAccount( + const RsPgpId& pgp_id, const std::string& org, + const std::string& loc, const std::string& country, + bool ishiddenloc, bool is_auto_tor, const std::string& passwd, + RsPeerId &sslId, std::string &errString ); static void storeSelectedAccount() ; @@ -198,6 +211,63 @@ private: }; +/** + * This helper class have been implemented because there was not reasonable way + * to login in the API that could be exposed via JSON API + */ +struct RsLoginHelper +{ + /** + * @brief Normal way to attempt login + * @jsonapi{development} + * @param[in] account Id of the account to which attempt login + * @param[in] password Password for the given account + * @return RsInit::OK if login attempt success, error code otherwhise + */ + RsInit::LoadCertificateStatus attemptLogin( + const RsPeerId& account, const std::string& password ); + struct Location : RsSerializable + { + RsPeerId mLocationId; + RsPgpId mPgpId; + std::string mLocationName; + std::string mPpgName; + + /// @see RsSerializable::serial_process + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ); + }; + + /** + * @brief Get locations and associated information + * @jsonapi{development} + * @param[out] locations storage for the retrived locations + */ + void getLocations(std::vector& locations); + + /** + * @brief Creates a new RetroShare location, and log in once is created + * @jsonapi{development} + * @param[inout] location provide input information to generate the location + * and storage to output the data of the generated location + * @param[in] password to protect and unlock the associated PGP key + * @param[in] makeHidden pass true to create an hidden location. UNTESTED! + * @param[in] makeAutoTor pass true to create an automatically configured + * Tor hidden location. UNTESTED! + * @param[out] errorMessage if some error occurred human readable error + * message + * @return true if success, false otherwise + */ + bool createLocation( RsLoginHelper::Location& location, + const std::string& password, bool makeHidden, + bool makeAutoTor, std::string& errorMessage ); + + /** + * @brief Close RetroShare session + * @jsonapi{development} + */ + void closeSession(); +}; #endif diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 340606bb8..a459a489c 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -92,7 +92,7 @@ const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_PGP_SIGNED ( 0x00000010 ) ; // requi typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; -typedef std::string ChatLobbyNickName ; +typedef std::string ChatLobbyNickName ; typedef uint64_t MessageId ; @@ -279,7 +279,7 @@ struct DistantChatPeerInfo // Identifier for an chat endpoint like // neighbour peer, distant peer, chatlobby, broadcast -class ChatId +class ChatId : RsSerializable { public: ChatId(); @@ -310,17 +310,28 @@ public: // this defines from which peer the status string came from RsPeerId broadcast_status_peer_id; private: - enum Type { TYPE_NOT_SET, - TYPE_PRIVATE, // private chat with directly connected friend, peer_id is valid - TYPE_PRIVATE_DISTANT, // private chat with distant peer, gxs_id is valid - TYPE_LOBBY, // chat lobby id, lobby_id is valid - TYPE_BROADCAST // message to/from all connected peers - }; + enum Type : uint8_t + { TYPE_NOT_SET, + TYPE_PRIVATE, // private chat with directly connected friend, peer_id is valid + TYPE_PRIVATE_DISTANT, // private chat with distant peer, gxs_id is valid + TYPE_LOBBY, // chat lobby id, lobby_id is valid + TYPE_BROADCAST // message to/from all connected peers + }; Type type; RsPeerId peer_id; DistantChatPeerId distant_chat_id; ChatLobbyId lobby_id; + + // RsSerializable interface +public: + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { + RS_SERIAL_PROCESS(broadcast_status_peer_id); + RS_SERIAL_PROCESS(type); + RS_SERIAL_PROCESS(peer_id); + RS_SERIAL_PROCESS(distant_chat_id); + RS_SERIAL_PROCESS(lobby_id); + } }; class ChatMessage @@ -340,49 +351,90 @@ public: //bool system_message; }; -class ChatLobbyInvite +class ChatLobbyInvite : RsSerializable { - public: - ChatLobbyId lobby_id ; - RsPeerId peer_id ; - std::string lobby_name ; - std::string lobby_topic ; - ChatLobbyFlags lobby_flags ; +public: + ChatLobbyId lobby_id ; + RsPeerId peer_id ; + std::string lobby_name ; + std::string lobby_topic ; + ChatLobbyFlags lobby_flags ; + + // RsSerializable interface +public: + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { + RS_SERIAL_PROCESS(lobby_id); + RS_SERIAL_PROCESS(peer_id); + RS_SERIAL_PROCESS(lobby_name); + RS_SERIAL_PROCESS(lobby_topic); + RS_SERIAL_PROCESS(lobby_flags); + } }; -class VisibleChatLobbyRecord +class VisibleChatLobbyRecord : RsSerializable { public: VisibleChatLobbyRecord(): lobby_id(0), total_number_of_peers(0), last_report_time(0){} - ChatLobbyId lobby_id ; // unique id of the lobby - std::string lobby_name ; // name to use for this lobby - std::string lobby_topic ; // topic to use for this lobby - std::set participating_friends ; // list of direct friend who participate. + ChatLobbyId lobby_id ; // unique id of the lobby + std::string lobby_name ; // name to use for this lobby + std::string lobby_topic ; // topic to use for this lobby + std::set participating_friends ; // list of direct friend who participate. - uint32_t total_number_of_peers ; // total number of particpating peers. Might not be - time_t last_report_time ; // last time the lobby was reported. - ChatLobbyFlags lobby_flags ; // see RS_CHAT_LOBBY_PRIVACY_LEVEL_PUBLIC / RS_CHAT_LOBBY_PRIVACY_LEVEL_PRIVATE + uint32_t total_number_of_peers ; // total number of particpating peers. Might not be + time_t last_report_time ; // last time the lobby was reported. + ChatLobbyFlags lobby_flags ; // see RS_CHAT_LOBBY_PRIVACY_LEVEL_PUBLIC / RS_CHAT_LOBBY_PRIVACY_LEVEL_PRIVATE + + // RsSerializable interface +public: + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { + RS_SERIAL_PROCESS(lobby_id); + RS_SERIAL_PROCESS(lobby_name); + RS_SERIAL_PROCESS(lobby_topic); + RS_SERIAL_PROCESS(participating_friends); + + RS_SERIAL_PROCESS(total_number_of_peers); + RS_SERIAL_PROCESS(last_report_time); + RS_SERIAL_PROCESS(lobby_flags); + } }; -class ChatLobbyInfo +class ChatLobbyInfo : RsSerializable { - public: - ChatLobbyId lobby_id ; // unique id of the lobby - std::string lobby_name ; // name to use for this lobby - std::string lobby_topic ; // topic to use for this lobby - std::set participating_friends ; // list of direct friend who participate. Used to broadcast sent messages. - RsGxsId gxs_id ; // ID to sign messages +public: + ChatLobbyId lobby_id ; // unique id of the lobby + std::string lobby_name ; // name to use for this lobby + std::string lobby_topic ; // topic to use for this lobby + std::set participating_friends ; // list of direct friend who participate. Used to broadcast sent messages. + RsGxsId gxs_id ; // ID to sign messages - ChatLobbyFlags lobby_flags ; // see RS_CHAT_LOBBY_PRIVACY_LEVEL_PUBLIC / RS_CHAT_LOBBY_PRIVACY_LEVEL_PRIVATE - std::map gxs_ids ; // list of non direct friend who participate. Used to display only. - time_t last_activity ; // last recorded activity. Useful for removing dead lobbies. + ChatLobbyFlags lobby_flags ; // see RS_CHAT_LOBBY_PRIVACY_LEVEL_PUBLIC / RS_CHAT_LOBBY_PRIVACY_LEVEL_PRIVATE + std::map gxs_ids ; // list of non direct friend who participate. Used to display only. + time_t last_activity ; // last recorded activity. Useful for removing dead lobbies. + + // RsSerializable interface +public: + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { + RS_SERIAL_PROCESS(lobby_id); + RS_SERIAL_PROCESS(lobby_name); + RS_SERIAL_PROCESS(lobby_topic); + RS_SERIAL_PROCESS(participating_friends); + RS_SERIAL_PROCESS(gxs_id); + + RS_SERIAL_PROCESS(lobby_flags); + RS_SERIAL_PROCESS(gxs_ids); + RS_SERIAL_PROCESS(last_activity); + } }; std::ostream &operator<<(std::ostream &out, const Rs::Msgs::MessageInfo &info); class RsMsgs; +/** + * @brief Pointer to retroshare's message service + * @jsonapi{development} + */ extern RsMsgs *rsMsgs; class RsMsgs @@ -438,15 +490,59 @@ virtual bool resetMessageStandardTagTypes(Rs::Msgs::MsgTagType& tags) = 0; // sendChat for broadcast, private, lobby and private distant chat // note: for lobby chat, you first have to subscribe to a lobby // for private distant chat, it is reqired to have an active distant chat session -virtual bool sendChat(ChatId id, std::string msg) = 0; -virtual uint32_t getMaxMessageSecuritySize(int type) = 0; -virtual void sendStatusString(const ChatId& id,const std::string& status_string) = 0; -virtual void clearChatLobby(const ChatId& id) = 0; + /** + * @brief sendChat send a chat message to a given id + * @jsonapi{development} + * @param[in] id id to send the message + * @param[in] msg message to send + * @return true on success + */ + virtual bool sendChat(ChatId id, std::string msg) = 0; -virtual void setCustomStateString(const std::string& status_string) = 0 ; -virtual std::string getCustomStateString() = 0 ; -virtual std::string getCustomStateString(const RsPeerId& peer_id) = 0 ; + /** + * @brief getMaxMessageSecuritySize get the maximum size of a chta message + * @jsonapi{development} + * @param[in] type chat type + * @return maximum size or zero for infinite + */ + virtual uint32_t getMaxMessageSecuritySize(int type) = 0; + + /** + * @brief sendStatusString send a status string + * @jsonapi{development} + * @param[in] id chat id to send the status string to + * @param[in] status_string status string + */ + virtual void sendStatusString(const ChatId &id, const std::string &status_string) = 0; + + /** + * @brief clearChatLobby clear a chat lobby + * @jsonapi{development} + * @param[in] id chat lobby id to clear + */ + virtual void clearChatLobby(const ChatId &id) = 0; + + /** + * @brief setCustomStateString set your custom status message + * @jsonapi{development} + * @param[in] status_string status message + */ + virtual void setCustomStateString(const std::string &status_string) = 0; + + /** + * @brief getCustomStateString get your custom status message + * @return status message + */ + virtual std::string getCustomStateString() = 0; + + /** + * @brief getCustomStateString get the custom status message from a peer + * @jsonapi{development} + * @param[in] peer_id peer id to the peer you want to get the status message from + * @return status message + */ + virtual std::string getCustomStateString(const RsPeerId &peer_id) = 0; // get avatar data for peer pid virtual void getAvatarData(const RsPeerId& pid,unsigned char *& data,int& size) = 0 ; @@ -454,29 +550,139 @@ virtual void getAvatarData(const RsPeerId& pid,unsigned char *& data,int& size) virtual void setOwnAvatarData(const unsigned char *data,int size) = 0 ; virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ; -/****************************************/ -/* Chat lobbies */ -/****************************************/ + /****************************************/ + /* Chat lobbies */ + /****************************************/ + /** + * @brief joinVisibleChatLobby join a lobby that is visible + * @jsonapi{development} + * @param[in] lobby_id lobby to join to + * @param[in] own_id chat id to use + * @return true on success + */ + virtual bool joinVisibleChatLobby(const ChatLobbyId &lobby_id, const RsGxsId &own_id) = 0 ; -virtual bool joinVisibleChatLobby(const ChatLobbyId& lobby_id,const RsGxsId& own_id) = 0 ; -/// get ids of subscribed lobbies -virtual void getChatLobbyList(std::list& cl_list) = 0; -/// get lobby info of a subscribed chat lobby. Returns true if lobby id is valid. -virtual bool getChatLobbyInfo(const ChatLobbyId& id,ChatLobbyInfo& info) = 0 ; -/// get info about all lobbies, subscribed and unsubscribed -virtual void getListOfNearbyChatLobbies(std::vector& public_lobbies) = 0 ; -virtual void invitePeerToLobby(const ChatLobbyId& lobby_id,const RsPeerId& peer_id) = 0; -virtual bool acceptLobbyInvite(const ChatLobbyId& id,const RsGxsId& identity) = 0 ; -virtual void denyLobbyInvite(const ChatLobbyId& id) = 0 ; -virtual void getPendingChatLobbyInvites(std::list& invites) = 0; -virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) = 0; -virtual bool setIdentityForChatLobby(const ChatLobbyId& lobby_id,const RsGxsId& nick) = 0; -virtual bool getIdentityForChatLobby(const ChatLobbyId& lobby_id,RsGxsId& nick) = 0 ; -virtual bool setDefaultIdentityForChatLobby(const RsGxsId& nick) = 0; -virtual void getDefaultIdentityForChatLobby(RsGxsId& id) = 0 ; -virtual void setLobbyAutoSubscribe(const ChatLobbyId& lobby_id, const bool autoSubscribe) = 0 ; -virtual bool getLobbyAutoSubscribe(const ChatLobbyId& lobby_id) = 0 ; -virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId& lobby_identity,const std::string& lobby_topic,const std::set& invited_friends,ChatLobbyFlags lobby_privacy_type) = 0 ; + /** + * @brief getChatLobbyList get ids of subscribed lobbies + * @jsonapi{development} + * @param[out] cl_list lobby list + */ + virtual void getChatLobbyList(std::list &cl_list) = 0; + + /** + * @brief getChatLobbyInfo get lobby info of a subscribed chat lobby. Returns true if lobby id is valid. + * @jsonapi{development} + * @param[in] id id to get infos from + * @param[out] info lobby infos + * @return true on success + */ + virtual bool getChatLobbyInfo(const ChatLobbyId &id, ChatLobbyInfo &info) = 0 ; + + /** + * @brief getListOfNearbyChatLobbies get info about all lobbies, subscribed and unsubscribed + * @jsonapi{development} + * @param[out] public_lobbies list of all visible lobbies + */ + virtual void getListOfNearbyChatLobbies(std::vector &public_lobbies) = 0 ; + + /** + * @brief invitePeerToLobby invite a peer to join a lobby + * @jsonapi{development} + * @param[in] lobby_id lobby it to invite into + * @param[in] peer_id peer to invite + */ + virtual void invitePeerToLobby(const ChatLobbyId &lobby_id, const RsPeerId &peer_id) = 0; + + /** + * @brief acceptLobbyInvite accept a chat invite + * @jsonapi{development} + * @param[in] id chat lobby id you were invited into and you want to join + * @param[in] identity chat identity to use + * @return true on success + */ + virtual bool acceptLobbyInvite(const ChatLobbyId &id, const RsGxsId &identity) = 0 ; + + /** + * @brief denyLobbyInvite deny a chat lobby invite + * @jsonapi{development} + * @param[in] id chat lobby id you were invited into + */ + virtual void denyLobbyInvite(const ChatLobbyId &id) = 0 ; + + /** + * @brief getPendingChatLobbyInvites get a list of all pending chat lobby invites + * @jsonapi{development} + * @param[out] invites list of all pending chat lobby invites + */ + virtual void getPendingChatLobbyInvites(std::list &invites) = 0; + + /** + * @brief unsubscribeChatLobby leave a chat lobby + * @jsonapi{development} + * @param[in] lobby_id lobby to leave + */ + virtual void unsubscribeChatLobby(const ChatLobbyId &lobby_id) = 0; + + /** + * @brief setIdentityForChatLobby set the chat identit + * @jsonapi{development} + * @param[in] lobby_id lobby to change the chat idnetity for + * @param[in] nick new chat identity + * @return true on success + */ + virtual bool setIdentityForChatLobby(const ChatLobbyId &lobby_id, const RsGxsId &nick) = 0; + + /** + * @brief getIdentityForChatLobby + * @jsonapi{development} + * @param[in] lobby_id lobby to get the chat id from + * @param[out] nick chat identity + * @return true on success + */ + virtual bool getIdentityForChatLobby(const ChatLobbyId &lobby_id, RsGxsId &nick) = 0 ; + + /** + * @brief setDefaultIdentityForChatLobby set the default identity used for chat lobbies + * @jsonapi{development} + * @param[in] nick chat identitiy to use + * @return true on success + */ + virtual bool setDefaultIdentityForChatLobby(const RsGxsId &nick) = 0; + + /** + * @brief getDefaultIdentityForChatLobby get the default identity used for chat lobbies + * @jsonapi{development} + * @param[out] id chat identitiy to use + */ + virtual void getDefaultIdentityForChatLobby(RsGxsId &id) = 0 ; + + /** + * @brief setLobbyAutoSubscribe enable or disable auto subscribe for a chat lobby + * @jsonapi{development} + * @param[in] lobby_id lobby to auto (un)subscribe + * @param[in] autoSubscribe set value for auto subscribe + */ + virtual void setLobbyAutoSubscribe(const ChatLobbyId &lobby_id, const bool autoSubscribe) = 0 ; + + /** + * @brief getLobbyAutoSubscribe get current value of auto subscribe + * @jsonapi{development} + * @param[in] lobby_id lobby to get value from + * @return wether lobby has auto subscribe enabled or disabled + */ + virtual bool getLobbyAutoSubscribe(const ChatLobbyId &lobby_id) = 0 ; + + /** + * @brief createChatLobby create a new chat lobby + * @jsonapi{development} + * @param[in] lobby_name lobby name + * @param[in] lobby_identity chat id to use for new lobby + * @param[in] lobby_topic lobby toppic + * @param[in] invited_friends list of friends to invite + * @param[in] lobby_privacy_type flag for new chat lobby + * @return chat id of new lobby + */ + virtual ChatLobbyId createChatLobby(const std::string &lobby_name, const RsGxsId &lobby_identity, const std::string &lobby_topic, const std::set &invited_friends, ChatLobbyFlags lobby_privacy_type) = 0 ; /****************************************/ /* Distant chat */ diff --git a/libretroshare/src/retroshare/rsnotify.h b/libretroshare/src/retroshare/rsnotify.h index 6c916e034..a418cb958 100644 --- a/libretroshare/src/retroshare/rsnotify.h +++ b/libretroshare/src/retroshare/rsnotify.h @@ -181,7 +181,7 @@ class RsFeedItem // This mechanism can be used in plugins, new services, etc. // -class NotifyClient ; +class NotifyClient; class RsNotify { @@ -208,42 +208,41 @@ class RsNotify class NotifyClient { - public: - NotifyClient() {} - virtual ~NotifyClient() {} +public: + NotifyClient() {} + virtual ~NotifyClient() {} - virtual void notifyListPreChange (int /* list */, int /* type */) {} - virtual void notifyListChange (int /* list */, int /* type */) {} - virtual void notifyErrorMsg (int /* list */, int /* sev */, std::string /* msg */) {} - virtual void notifyChatMessage (const ChatMessage& /* msg */) {} - virtual void notifyChatStatus (const ChatId& /* chat_id */, const std::string& /* status_string */) {} - virtual void notifyChatCleared (const ChatId& /* chat_id */) {} - virtual void notifyChatLobbyEvent (uint64_t /* lobby id */, uint32_t /* event type */ ,const RsGxsId& /* nickname */,const std::string& /* any string */) {} - virtual void notifyChatLobbyTimeShift (int /* time_shift*/) {} - virtual void notifyCustomState (const std::string& /* peer_id */, const std::string& /* status_string */) {} - virtual void notifyHashingInfo (uint32_t /* type */, const std::string& /* fileinfo */) {} - virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list& /* files */) {} + virtual void notifyListPreChange (int /* list */, int /* type */) {} + virtual void notifyListChange (int /* list */, int /* type */) {} + virtual void notifyErrorMsg (int /* list */, int /* sev */, std::string /* msg */) {} + virtual void notifyChatMessage (const ChatMessage& /* msg */) {} + virtual void notifyChatStatus (const ChatId& /* chat_id */, const std::string& /* status_string */) {} + virtual void notifyChatCleared (const ChatId& /* chat_id */) {} + virtual void notifyChatLobbyEvent (uint64_t /* lobby id */, uint32_t /* event type */ ,const RsGxsId& /* nickname */,const std::string& /* any string */) {} + virtual void notifyChatLobbyTimeShift (int /* time_shift*/) {} + virtual void notifyCustomState (const std::string& /* peer_id */, const std::string& /* status_string */) {} + virtual void notifyHashingInfo (uint32_t /* type */, const std::string& /* fileinfo */) {} + virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list& /* files */) {} #warning MISSING CODE HERE - // virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list& /* groups */) {} - virtual void notifyPeerHasNewAvatar (std::string /* peer_id */) {} - virtual void notifyOwnAvatarChanged () {} - virtual void notifyOwnStatusMessageChanged () {} - virtual void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) {} - virtual void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) {} - virtual void notifyGxsChange (const RsGxsChanges& /* changes */) {} - virtual void notifyConnectionWithoutCert () {} + // virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list& /* groups */) {} + virtual void notifyPeerHasNewAvatar (std::string /* peer_id */) {} + virtual void notifyOwnAvatarChanged () {} + virtual void notifyOwnStatusMessageChanged () {} + virtual void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) {} + virtual void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) {} + virtual void notifyGxsChange (const RsGxsChanges& /* changes */) {} + virtual void notifyConnectionWithoutCert () {} - /* one or more peers has changed the states */ - virtual void notifyPeerStatusChangedSummary () {} - virtual void notifyDiscInfoChanged () {} + /* one or more peers has changed the states */ + virtual void notifyPeerStatusChangedSummary () {} + virtual void notifyDiscInfoChanged () {} - virtual bool askForDeferredSelfSignature (const void * /* data */, const uint32_t /* len */, unsigned char * /* sign */, unsigned int * /* signlen */,int& signature_result , std::string /*reason = ""*/) { signature_result = false ;return true; } - virtual void notifyDownloadComplete (const std::string& /* fileHash */) {} - virtual void notifyDownloadCompleteCount (uint32_t /* count */) {} - virtual void notifyHistoryChanged (uint32_t /* msgId */, int /* type */) {} - - virtual bool askForPassword (const std::string& /* title */, const std::string& /* key_details */, bool /* prev_is_bad */, std::string& /* password */,bool& /* cancelled */ ) { return false ;} - virtual bool askForPluginConfirmation (const std::string& /* plugin_filename */, const std::string& /* plugin_file_hash */,bool /* first_time */) { return false ;} + virtual bool askForDeferredSelfSignature (const void * /* data */, const uint32_t /* len */, unsigned char * /* sign */, unsigned int * /* signlen */,int& signature_result , std::string /*reason = ""*/) { signature_result = false ;return true; } + virtual void notifyDownloadComplete (const std::string& /* fileHash */) {} + virtual void notifyDownloadCompleteCount (uint32_t /* count */) {} + virtual void notifyHistoryChanged (uint32_t /* msgId */, int /* type */) {} + virtual bool askForPassword (const std::string& /* title */, const std::string& /* key_details */, bool /* prev_is_bad */, std::string& /* password */,bool& /* cancelled */ ) { return false ;} + virtual bool askForPluginConfirmation (const std::string& /* plugin_filename */, const std::string& /* plugin_file_hash */,bool /* first_time */) { return false ;} }; #endif diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index 01fb7ba8d..a77a5c4b3 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -293,16 +293,25 @@ public: std::string cipher_version; }; -class RsGroupInfo +class RsGroupInfo : RsSerializable { public: - RsGroupInfo(); + RsGroupInfo(); - RsNodeGroupId id; - std::string name; - uint32_t flag; + RsNodeGroupId id; + std::string name; + uint32_t flag; - std::set peerIds; + std::set peerIds; + + // RsSerializable interface +public: + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { + RS_SERIAL_PROCESS(id); + RS_SERIAL_PROCESS(name); + RS_SERIAL_PROCESS(flag); + RS_SERIAL_PROCESS(peerIds); + } }; std::ostream &operator<<(std::ostream &out, const RsPeerDetails &detail); diff --git a/libretroshare/src/retroshare/rsposted.h b/libretroshare/src/retroshare/rsposted.h index eb089383c..12d729d7a 100644 --- a/libretroshare/src/retroshare/rsposted.h +++ b/libretroshare/src/retroshare/rsposted.h @@ -74,7 +74,7 @@ class RsPosted : public RsGxsIfaceHelper, public RsGxsCommentService //static const uint32_t FLAG_MSGTYPE_POST; //static const uint32_t FLAG_MSGTYPE_MASK; - explicit RsPosted(RsGxsIface* gxs) : RsGxsIfaceHelper(gxs) {} + explicit RsPosted(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsPosted() {} /* Specific Service Data */ diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index f4e51fe80..90c0694e6 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -119,19 +119,19 @@ class RsTokenService public: - // TODO CLEANUP: This should be an enum - static const uint8_t GXS_REQUEST_V2_STATUS_FAILED; - static const uint8_t GXS_REQUEST_V2_STATUS_PENDING; - static const uint8_t GXS_REQUEST_V2_STATUS_PARTIAL; - static const uint8_t GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE; - static const uint8_t GXS_REQUEST_V2_STATUS_COMPLETE; - static const uint8_t GXS_REQUEST_V2_STATUS_DONE; // ONCE ALL DATA RETRIEVED. - static const uint8_t GXS_REQUEST_V2_STATUS_CANCELLED; + enum GxsRequestStatus : uint8_t + { + FAILED, + PENDING, + PARTIAL, + COMPLETE, + DONE, /// Once all data has been retrived + CANCELLED + }; -public: - RsTokenService() { return; } - virtual ~RsTokenService() { return; } + RsTokenService() {} + virtual ~RsTokenService() {} /* Data Requests */ @@ -195,7 +195,7 @@ public: * @param token value of token to check status for * @return the current status of request */ - virtual uint32_t requestStatus(const uint32_t token) = 0; + virtual GxsRequestStatus requestStatus(const uint32_t token) = 0; /*! * This request statistics on amount of data held @@ -216,19 +216,14 @@ public: */ virtual void requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) = 0; - - /* Cancel Request */ - - /*! - * If this function returns false, it may be that the request has completed - * already. Useful for very expensive request. This is a blocking operation - * @param token the token of the request to cancel - * @return false if unusuccessful in cancelling request, true if successful - */ - virtual bool cancelRequest(const uint32_t &token) = 0; - - - + /*! + * @brief Cancel Request + * If this function returns false, it may be that the request has completed + * already. Useful for very expensive request. + * @param token the token of the request to cancel + * @return false if unusuccessful in cancelling request, true if successful + */ + virtual bool cancelRequest(const uint32_t &token) = 0; }; #endif // RSTOKENSERVICE_H diff --git a/libretroshare/src/retroshare/rsturtle.h b/libretroshare/src/retroshare/rsturtle.h index 91cc75adc..6f5ac469c 100644 --- a/libretroshare/src/retroshare/rsturtle.h +++ b/libretroshare/src/retroshare/rsturtle.h @@ -29,24 +29,42 @@ #include "serialiser/rstlvbinary.h" #include "retroshare/rstypes.h" #include "retroshare/rsgxsifacetypes.h" +#include "serialiser/rsserializable.h" namespace RsRegularExpression { class LinearizedExpression ; } class RsTurtleClientService ; class RsTurtle; -extern RsTurtle *rsTurtle ; + +/** + * Pointer to global instance of RsTurtle service implementation + */ +extern RsTurtle* rsTurtle; typedef uint32_t TurtleRequestId ; typedef RsPeerId TurtleVirtualPeerId; -// This is the structure used to send back results of the turtle search -// to the notifyBase class, or send info to the GUI. - -struct TurtleFileInfo +/** + * This is the structure used to send back results of the turtle search, + * to other peers, to the notifyBase class, to the search caller or to the GUI. + */ +struct TurtleFileInfo : RsSerializable { - RsFileHash hash ; - std::string name ; - uint64_t size ; + uint64_t size; /// File size + RsFileHash hash; /// File hash + std::string name; /// File name + + /// @see RsSerializable::serial_process + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(size); + RS_SERIAL_PROCESS(hash); + + // Use String TLV serial process for retrocompatibility + RsTypeSerializer::serial_process( + j, ctx, TLV_TYPE_STR_NAME, name, "name" ); + } }; struct TurtleTunnelRequestDisplayInfo @@ -90,7 +108,7 @@ class TurtleTrafficStatisticsInfo // class RsTurtle { - public: +public: RsTurtle() {} virtual ~RsTurtle() {} @@ -106,7 +124,9 @@ class RsTurtle // the request id, which will be further used by the gui to store results // as they come back. // - virtual TurtleRequestId turtleSearch(unsigned char *search_bin_data,uint32_t search_bin_data_len,RsTurtleClientService *client_service) =0; + virtual TurtleRequestId turtleSearch( + unsigned char *search_bin_data, uint32_t search_bin_data_len, + RsTurtleClientService* client_service ) = 0; // Initiates tunnel handling for the given file hash. tunnels. Launches // an exception if an error occurs during the initialization process. The diff --git a/libretroshare/src/retroshare/rstypes.h b/libretroshare/src/retroshare/rstypes.h index 443f2e2b3..b1b35748c 100644 --- a/libretroshare/src/retroshare/rstypes.h +++ b/libretroshare/src/retroshare/rstypes.h @@ -65,15 +65,25 @@ const uint32_t RS_CONFIG_DIRECTORY = 0x0002 ; const uint32_t RS_PGP_DIRECTORY = 0x0003 ; const uint32_t RS_DIRECTORY_COUNT = 0x0004 ; -class TransferInfo +struct TransferInfo : RsSerializable { - public: - /**** Need Some of these Fields ****/ - RsPeerId peerId; - std::string name; /* if has alternative name? */ - double tfRate; /* kbytes */ - int status; /* FT_STATE_... */ - uint64_t transfered ; // used when no chunkmap data is available + /**** Need Some of these Fields ****/ + RsPeerId peerId; + std::string name; /* if has alternative name? */ + double tfRate; /* kbytes */ + int status; /* FT_STATE_... */ + uint64_t transfered ; // used when no chunkmap data is available + + /// @see RsSerializable + void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) + { + RS_SERIAL_PROCESS(peerId); + RS_SERIAL_PROCESS(name); + RS_SERIAL_PROCESS(tfRate); + RS_SERIAL_PROCESS(status); + RS_SERIAL_PROCESS(transfered); + } }; enum QueueMove { QUEUE_TOP = 0x00, @@ -82,9 +92,11 @@ enum QueueMove { QUEUE_TOP = 0x00, QUEUE_BOTTOM = 0x03 }; -enum DwlSpeed { SPEED_LOW = 0x00, - SPEED_NORMAL = 0x01, - SPEED_HIGH = 0x02 +enum DwlSpeed : uint8_t +{ + SPEED_LOW = 0x00, + SPEED_NORMAL = 0x01, + SPEED_HIGH = 0x02 }; @@ -171,54 +183,76 @@ const FileStorageFlags DIR_FLAGS_PERMISSIONS_MASK ( DIR_FLAGS_ANONYMOUS_DOW const FileStorageFlags DIR_FLAGS_LOCAL ( 0x1000 ); const FileStorageFlags DIR_FLAGS_REMOTE ( 0x2000 ); -class FileInfo +struct FileInfo : RsSerializable { - /* old BaseInfo Entries */ - public: + FileInfo(): + mId(0), searchId(0), size(0), avail(0), rank(0), age(0), + queue_position(0), transfered(0), tfRate(0), downloadStatus(0), + priority(SPEED_NORMAL), lastTS(0) {} - FileInfo() : mId(0), searchId(0), size(0), avail(0), rank(0), age(0), queue_position(0), - transfered(0), tfRate(0), downloadStatus(0), priority(SPEED_NORMAL), lastTS(0){} -// RsCertId id; /* key for matching everything */ + /// Combination of the four RS_DIR_FLAGS_*. Updated when the file is a local stored file. + FileStorageFlags storage_permission_flags; - FileStorageFlags storage_permission_flags; // Combination of the four RS_DIR_FLAGS_*. Updated when the file is a local stored file. - TransferRequestFlags transfer_info_flags ; // various flags from RS_FILE_HINTS_* + /// various flags from RS_FILE_HINTS_* + TransferRequestFlags transfer_info_flags; - /* allow this to be tweaked by the GUI Model */ - mutable unsigned int mId; /* (GUI) Model Id -> unique number */ + /** allow this to be tweaked by the GUI Model + * (GUI) Model Id -> unique number + */ + mutable unsigned int mId; - /* Old FileInfo Entries */ - public: - static const int kRsFiStatusNone = 0; - static const int kRsFiStatusStall = 1; - static const int kRsFiStatusProgress = 2; - static const int kRsFiStatusDone = 2; + /// 0 if none + int searchId; - /* FileInfo(); */ + std::string path; + std::string fname; + RsFileHash hash; + std::string ext; - int searchId; /* 0 if none */ - std::string path; - std::string fname; - RsFileHash hash; - std::string ext; + uint64_t size; + uint64_t avail; /// how much we have - uint64_t size; - uint64_t avail; /* how much we have */ + double rank; + int age; + uint32_t queue_position; - double rank; - int age; - uint32_t queue_position ; + /* Transfer Stuff */ + uint64_t transfered; + double tfRate; /// in kbytes + uint32_t downloadStatus; /// FT_STATE_DOWNLOADING & co. See rstypes.h + std::vector peers; - /* Transfer Stuff */ - uint64_t transfered; - double tfRate; /* in kbytes */ - uint32_t downloadStatus; // FT_STATE_DOWNLOADING & co. See rstypes.h - std::vector peers; + DwlSpeed priority; + time_t lastTS; - DwlSpeed priority ; - time_t lastTS; - - std::list parent_groups ; + std::list parent_groups; + + /// @see RsSerializable + void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) + { + RS_SERIAL_PROCESS(storage_permission_flags); + RS_SERIAL_PROCESS(transfer_info_flags); + RS_SERIAL_PROCESS(mId); + RS_SERIAL_PROCESS(searchId); + RS_SERIAL_PROCESS(path); + RS_SERIAL_PROCESS(fname); + RS_SERIAL_PROCESS(hash); + RS_SERIAL_PROCESS(ext); + RS_SERIAL_PROCESS(size); + RS_SERIAL_PROCESS(avail); + RS_SERIAL_PROCESS(rank); + RS_SERIAL_PROCESS(age); + RS_SERIAL_PROCESS(queue_position); + RS_SERIAL_PROCESS(transfered); + RS_SERIAL_PROCESS(tfRate); + RS_SERIAL_PROCESS(downloadStatus); + RS_SERIAL_PROCESS(peers); + RS_SERIAL_PROCESS(priority); + RS_SERIAL_PROCESS(lastTS); + RS_SERIAL_PROCESS(parent_groups); + } }; std::ostream &operator<<(std::ostream &out, const FileInfo& info); @@ -268,36 +302,58 @@ class FileDetail class CompressedChunkMap ; -class FileChunksInfo +struct FileChunksInfo : RsSerializable { - public: - enum ChunkState { CHUNK_CHECKING=3, CHUNK_DONE=2, CHUNK_ACTIVE=1, CHUNK_OUTSTANDING=0 } ; - enum ChunkStrategy { CHUNK_STRATEGY_STREAMING, CHUNK_STRATEGY_RANDOM, CHUNK_STRATEGY_PROGRESSIVE } ; + enum ChunkState : uint8_t + { + CHUNK_OUTSTANDING = 0, + CHUNK_ACTIVE = 1, + CHUNK_DONE = 2, + CHUNK_CHECKING = 3 + }; - struct SliceInfo - { - uint32_t start ; - uint32_t size ; - RsPeerId peer_id ; - }; + enum ChunkStrategy : uint8_t + { + CHUNK_STRATEGY_STREAMING, + CHUNK_STRATEGY_RANDOM, + CHUNK_STRATEGY_PROGRESSIVE + }; - uint64_t file_size ; // real size of the file - uint32_t chunk_size ; // size of chunks - uint32_t strategy ; + struct SliceInfo + { + uint32_t start; + uint32_t size; + RsPeerId peer_id; + }; - // dl state of chunks. Only the last chunk may have size < chunk_size - std::vector chunks ; + uint64_t file_size; /// real size of the file + uint32_t chunk_size; /// size of chunks + ChunkStrategy strategy; - // For each source peer, gives the compressed bit map of have/don't have sate - std::map compressed_peer_availability_maps ; + /// dl state of chunks. Only the last chunk may have size < chunk_size + std::vector chunks; - // For each chunk (by chunk number), gives the completion of the chunk. - // - std::vector > active_chunks ; + /// For each source peer, gives the compressed bit map of have/don't have sate + std::map compressed_peer_availability_maps; - // The list of pending requests, chunk per chunk (by chunk id) - // - std::map > pending_slices ; + /// For each chunk (by chunk number), gives the completion of the chunk. + std::vector > active_chunks; + + /// The list of pending requests, chunk per chunk (by chunk id) + std::map > pending_slices; + + /// @see RsSerializable + void serial_process(RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) + { + RS_SERIAL_PROCESS(file_size); + RS_SERIAL_PROCESS(chunk_size); + RS_SERIAL_PROCESS(strategy); + RS_SERIAL_PROCESS(chunks); + RS_SERIAL_PROCESS(compressed_peer_availability_maps); + RS_SERIAL_PROCESS(active_chunks); + //RS_SERIAL_PROCESS(pending_slices); + } }; class CompressedChunkMap : public RsSerializable diff --git a/libretroshare/src/retroshare/rswiki.h b/libretroshare/src/retroshare/rswiki.h index ab3bcfd85..feb7dead2 100644 --- a/libretroshare/src/retroshare/rswiki.h +++ b/libretroshare/src/retroshare/rswiki.h @@ -111,10 +111,10 @@ std::ostream &operator<<(std::ostream &out, const RsWikiComment &comment); class RsWiki: public RsGxsIfaceHelper { - public: +public: - RsWiki(RsGxsIface *gxs): RsGxsIfaceHelper(gxs) { return; } -virtual ~RsWiki() { return; } + RsWiki(RsGxsIface& gxs): RsGxsIfaceHelper(gxs) {} + virtual ~RsWiki() {} /* Specific Service Data */ virtual bool getCollections(const uint32_t &token, std::vector &collections) = 0; diff --git a/libretroshare/src/retroshare/rswire.h b/libretroshare/src/retroshare/rswire.h index 6052c7291..580d3f279 100644 --- a/libretroshare/src/retroshare/rswire.h +++ b/libretroshare/src/retroshare/rswire.h @@ -104,7 +104,7 @@ class RsWire: public RsGxsIfaceHelper { public: - explicit RsWire(RsGxsIface *gxs): RsGxsIfaceHelper(gxs) {} + explicit RsWire(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsWire() {} /* Specific Service Data */ diff --git a/libretroshare/src/rsitems/rsitem.h b/libretroshare/src/rsitems/rsitem.h index c7cdccf5b..d8495ab58 100644 --- a/libretroshare/src/rsitems/rsitem.h +++ b/libretroshare/src/rsitems/rsitem.h @@ -77,7 +77,7 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable inline uint8_t priority_level() const { return _priority_level ;} inline void setPriorityLevel(uint8_t l) { _priority_level = l ;} - /** + /* * TODO: This default implementation should be removed and childs structs * implement ::serial_process(...) as soon as all the codebase is ported to * the new serialization system diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index f6120e788..c989d0bca 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -1410,7 +1410,10 @@ bool RsAccounts::GetAccountDetails(const RsPeerId &id, return rsAccounts->getCurrentAccountDetails(id, pgpId, pgpName, pgpEmail, location); } -bool RsAccounts::createNewAccount(const RsPgpId& pgp_id, const std::string& org, const std::string& loc, const std::string& country, bool ishiddenloc, bool isautotor, const std::string& passwd, RsPeerId &sslId, std::string &errString) +bool RsAccounts::createNewAccount( + const RsPgpId& pgp_id, const std::string& org, const std::string& loc, + const std::string& country, bool ishiddenloc, bool isautotor, + const std::string& passwd, RsPeerId &sslId, std::string &errString ) { return rsAccounts->GenerateSSLCertificate(pgp_id, org, loc, country, ishiddenloc, isautotor, passwd, sslId, errString); } diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index c7a112f42..3a76fd79a 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -101,7 +101,9 @@ RsDht *rsDht = NULL ; //std::map > RsInit::unsupported_keys ; -class RsInitConfig +RsLoginHelper* rsLoginHelper; + +class RsInitConfig { public: @@ -431,7 +433,9 @@ int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */) AuthSSL::AuthSSLInit(); AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL, ""); - int error_code ; + rsLoginHelper = new RsLoginHelper; + + int error_code ; if(!RsAccounts::init(opt_base_dir,error_code)) return error_code ; @@ -485,12 +489,21 @@ int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */) * 1 : Another instance already has the lock * 2 : Unexpected error */ -int RsInit::LockConfigDirectory(const std::string& accountDir, std::string& lockFilePath) +RsInit::LoadCertificateStatus RsInit::LockConfigDirectory( + const std::string& accountDir, std::string& lockFilePath ) { const std::string lockFile = accountDir + "/" + "lock"; lockFilePath = lockFile; - return RsDirUtil::createLockFile(lockFile,rsInitConfig->lockHandle) ; + int rt = RsDirUtil::createLockFile(lockFile,rsInitConfig->lockHandle); + + switch (rt) + { + case 0: return RsInit::OK; + case 1: return RsInit::ERR_ALREADY_RUNNING; + case 2: return RsInit::ERR_CANT_ACQUIRE_LOCK; + default: return RsInit::ERR_UNKOWN; + } } /* @@ -522,38 +535,30 @@ bool RsInit::LoadPassword(const std::string& inPwd) return true; } - -/** - * Locks the profile directory and tries to finalize the login procedure - * - * Return value: - * 0 : success - * 1 : another instance is already running - * 2 : unexpected error while locking - * 3 : unexpected error while loading certificates - */ -int RsInit::LockAndLoadCertificates(bool autoLoginNT, std::string& lockFilePath) +RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates( + bool autoLoginNT, std::string& lockFilePath ) { try { if (!RsAccounts::lockPreferredAccount()) - throw 3; // invalid PreferredAccount. + throw RsInit::ERR_UNKOWN; // invalid PreferredAccount. // Logic that used to be external to RsInit... RsPeerId accountId; if (!RsAccounts::GetPreferredAccountId(accountId)) - throw 3; // invalid PreferredAccount; + throw RsInit::ERR_UNKOWN; // invalid PreferredAccount; RsPgpId pgpId; std::string pgpName, pgpEmail, location; if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location)) - throw 3; // invalid PreferredAccount; + throw RsInit::ERR_UNKOWN; // invalid PreferredAccount; if(0 == AuthGPG::getAuthGPG() -> GPGInit(pgpId)) - throw 3; // PGP Error. + throw RsInit::ERR_UNKOWN; // PGP Error. - int retVal = LockConfigDirectory(RsAccounts::AccountDirectory(), lockFilePath); + LoadCertificateStatus retVal = + LockConfigDirectory(RsAccounts::AccountDirectory(), lockFilePath); if(retVal > 0) throw retVal ; @@ -561,12 +566,12 @@ int RsInit::LockAndLoadCertificates(bool autoLoginNT, std::string& lockFilePath if(LoadCertificates(autoLoginNT) != 1) { UnlockConfigDirectory(); - throw 3; + throw RsInit::ERR_UNKOWN; } - return 0; + return RsInit::OK; } - catch(int retVal) + catch(LoadCertificateStatus retVal) { RsAccounts::unlockPreferredAccount(); return retVal ; @@ -1929,3 +1934,89 @@ int RsServer::StartupRetroShare() return 1; } +RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin( + const RsPeerId& account, const std::string& password) +{ + if(!rsNotify->cachePgpPassphrase(password)) return RsInit::ERR_UNKOWN; + if(!rsNotify->setDisableAskPassword(true)) return RsInit::ERR_UNKOWN; + if(!RsAccounts::SelectAccount(account)) return RsInit::ERR_UNKOWN; + std::string _ignore_lockFilePath; + RsInit::LoadCertificateStatus ret = + RsInit::LockAndLoadCertificates(false, _ignore_lockFilePath); + if(!rsNotify->setDisableAskPassword(false)) return RsInit::ERR_UNKOWN; + if(!rsNotify->clearPgpPassphrase()) return RsInit::ERR_UNKOWN; + if(ret != RsInit::OK) return ret; + if(RsControl::instance()->StartupRetroShare() == 1) return RsInit::OK; + return RsInit::ERR_UNKOWN; +} + +void RsLoginHelper::getLocations(std::vector& store) +{ + std::list locIds; + RsAccounts::GetAccountIds(locIds); + store.clear(); + + for(const RsPeerId& locId : locIds ) + { + Location l; l.mLocationId = locId; + std::string discardPgpMail; + RsAccounts::GetAccountDetails( locId, l.mPgpId, l.mPpgName, + discardPgpMail, l.mLocationName ); + store.push_back(l); + } +} + +bool RsLoginHelper::createLocation( + RsLoginHelper::Location& l, const std::string& password, + bool makeHidden, bool makeAutoTor, std::string& errorMessage ) +{ + if(l.mLocationName.empty()) + { + errorMessage = "Location name is needed"; + return false; + } + + if(l.mPgpId.isNull() && l.mPpgName.empty()) + { + errorMessage = "Either PGP name or PGP id is needed"; + return false; + } + + if(l.mPgpId.isNull() && !RsAccounts::GeneratePGPCertificate( + l.mPpgName, "", password, l.mPgpId, 4096, errorMessage) ) + { + errorMessage = "Failure creating PGP key: " + errorMessage; + return false; + } + + std::string sslPassword = + RSRandom::random_alphaNumericString(RsInit::getSslPwdLen()); + + if(!rsNotify->cachePgpPassphrase(password)) return false; + if(!rsNotify->setDisableAskPassword(true)) return false; + + bool ret = RsAccounts::createNewAccount( + l.mPgpId, "", l.mLocationName, "", makeHidden, makeAutoTor, + sslPassword, l.mLocationId, errorMessage ); + + ret = ret && RsInit::LoadPassword(sslPassword); + ret = ret && RsInit::OK == attemptLogin(l.mLocationId, password); + + rsNotify->setDisableAskPassword(false); + return ret; +} + +void RsLoginHelper::closeSession() +{ + RsControl::instance()->rsGlobalShutDown(); +} + +void RsLoginHelper::Location::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ + RS_SERIAL_PROCESS(mLocationId); + RS_SERIAL_PROCESS(mPgpId); + RS_SERIAL_PROCESS(mLocationName); + RS_SERIAL_PROCESS(mPpgName); +} diff --git a/libretroshare/src/serialiser/rsbaseserial.cc b/libretroshare/src/serialiser/rsbaseserial.cc index a5b84518f..65528c801 100644 --- a/libretroshare/src/serialiser/rsbaseserial.cc +++ b/libretroshare/src/serialiser/rsbaseserial.cc @@ -244,9 +244,10 @@ bool getRawString(const void *data, uint32_t size, uint32_t *offset, std::string } /* check there is space for string */ - if(len > size || size-len < *offset) // better than if(size < *offset + len) because it avoids integer overflow + if(len > size || size-len < *offset) // better than if(size < *offset + len) because it avoids integer overflow { - std::cerr << "getRawString() not enough size" << std::endl; + std::cerr << "getRawString() not enough size" << std::endl; + print_stacktrace(); return false; } uint8_t *buf = &(((uint8_t *) data)[*offset]); diff --git a/libretroshare/src/serialiser/rsserializer.cc b/libretroshare/src/serialiser/rsserializer.cc index 4a07da014..c1385fddf 100644 --- a/libretroshare/src/serialiser/rsserializer.cc +++ b/libretroshare/src/serialiser/rsserializer.cc @@ -26,11 +26,13 @@ #include "util/rsprint.h" #include "serialiser/rsserializer.h" #include "serialiser/rstypeserializer.h" +#include "util/stacktrace.h" const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_NONE ( 0x0000 ); const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_CONFIG ( 0x0001 ); const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE ( 0x0002 ); const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER ( 0x0004 ); +const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ( 0x0008 ); RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size) { @@ -240,3 +242,31 @@ RsItem *RsRawSerialiser::deserialise(void *data, uint32_t *pktsize) return item; } + +RsGenericSerializer::SerializeContext::SerializeContext( + uint8_t* data, uint32_t size, SerializationFlags flags, + RsJson::AllocatorType* allocator ) : + mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags), + mJson(rapidjson::kObjectType, allocator) +{ + if(data) + { + if(size == 0) + { + std::cerr << __PRETTY_FUNCTION__ << " data passed without " + << "size! This make no sense report to developers!" + << std::endl; + print_stacktrace(); + } + + if(flags & SERIALIZATION_FLAG_YIELDING) + { + std::cerr << __PRETTY_FUNCTION__ << " Attempt to create a " + << "binary serialization context with " + << "SERIALIZATION_FLAG_YIELDING! " + << "This make no sense report to developers!" + << std::endl; + print_stacktrace(); + } + } +} diff --git a/libretroshare/src/serialiser/rsserializer.h b/libretroshare/src/serialiser/rsserializer.h index 0ddc2aadc..40ccc35e9 100644 --- a/libretroshare/src/serialiser/rsserializer.h +++ b/libretroshare/src/serialiser/rsserializer.h @@ -151,20 +151,14 @@ #include #include #include -#ifdef HAS_RAPIDJSON -#include -#else -#include -#endif // HAS_RAPIDJSON #include "retroshare/rsflags.h" #include "serialiser/rsserial.h" #include "util/rsdeprecate.h" +#include "util/rsjson.h" struct RsItem; -#define SERIALIZE_ERROR() std::cerr << __PRETTY_FUNCTION__ << " : " - // This is the base class for serializers. class RsSerialType @@ -198,8 +192,6 @@ class RsRawSerialiser: public RsSerialType virtual RsItem * deserialise(void *data, uint32_t *size); }; -typedef rapidjson::Document RsJson; - /// Top class for all services and config serializers. struct RsGenericSerializer : RsSerialType { @@ -226,11 +218,9 @@ struct RsGenericSerializer : RsSerialType /** Allow shared allocator usage to avoid costly JSON deepcopy for * nested RsSerializable */ SerializeContext( - uint8_t *data, uint32_t size, + uint8_t* data = nullptr, uint32_t size = 0, SerializationFlags flags = SERIALIZATION_FLAG_NONE, - RsJson::AllocatorType* allocator = nullptr) : - mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags), - mJson(rapidjson::kObjectType, allocator) {} + RsJson::AllocatorType* allocator = nullptr); RS_DEPRECATED SerializeContext( uint8_t *data, uint32_t size, SerializationFormat format, @@ -261,6 +251,12 @@ struct RsGenericSerializer : RsSerialType static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE; // 0x0002 static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER; // 0x0004 + /** Used for JSON deserialization in JSON API, it causes the deserialization + * to continue even if some field is missing (or incorrect), this way the + * API is more user friendly as some methods need just part of the structs + * they take as parameters. */ + static const SerializationFlags SERIALIZATION_FLAG_YIELDING; // 0x0008 + /** * The following functions overload RsSerialType. * They *should not* need to be further overloaded. diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 4378c7473..f620f7af0 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -25,7 +25,7 @@ #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvkeys.h" #include "serialiser/rsserializable.h" - +#include "util/radix64.h" #include "util/rsprint.h" #include @@ -42,7 +42,8 @@ //static const uint32_t MAX_SERIALIZED_ARRAY_SIZE = 500 ; static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. -#define SAFE_GET_JSON_V() \ +#ifdef RSSERIAL_DEBUG +# define SAFE_GET_JSON_V() \ const char* mName = memberName.c_str(); \ bool ret = jDoc.HasMember(mName); \ if(!ret) \ @@ -50,10 +51,16 @@ static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName \ << "\" not found in JSON:" << std::endl \ << jDoc << std::endl << std::endl; \ - print_stacktrace(); \ return false; \ } \ rapidjson::Value& v = jDoc[mName] +#else // ifdef RSSERIAL_DEBUG +# define SAFE_GET_JSON_V() \ + const char* mName = memberName.c_str(); \ + bool ret = jDoc.HasMember(mName); \ + if(!ret) return false; \ + rapidjson::Value& v = jDoc[mName] +#endif // ifdef RSSERIAL_DEBUG //============================================================================// @@ -162,23 +169,23 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const bool & } template<> void RsTypeSerializer::print_data(const std::string& n, const int32_t& V) { - std::cerr << " [int32_t ] " << n << ": " << V << std::endl; + std::cerr << " [int32_t ] " << n << ": " << std::to_string(V) << std::endl; } template<> void RsTypeSerializer::print_data(const std::string& n, const uint8_t & V) { - std::cerr << " [uint8_t ] " << n << ": " << V << std::endl; + std::cerr << " [uint8_t ] " << n << ": " << std::to_string(V) << std::endl; } template<> void RsTypeSerializer::print_data(const std::string& n, const uint16_t& V) { - std::cerr << " [uint16_t ] " << n << ": " << V << std::endl; + std::cerr << " [uint16_t ] " << n << ": " << std::to_string(V) << std::endl; } template<> void RsTypeSerializer::print_data(const std::string& n, const uint32_t& V) { - std::cerr << " [uint32_t ] " << n << ": " << V << std::endl; + std::cerr << " [uint32_t ] " << n << ": " << std::to_string(V) << std::endl; } template<> void RsTypeSerializer::print_data(const std::string& n, const uint64_t& V) { - std::cerr << " [uint64_t ] " << n << ": " << V << std::endl; + std::cerr << " [uint64_t ] " << n << ": " << std::to_string(V) << std::endl; } template<> void RsTypeSerializer::print_data(const std::string& n, const time_t& V) { @@ -328,6 +335,49 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName, return ret; } +template<> /*static*/ +uint32_t RsTypeSerializer::serial_size(const double&) +{ + std::cerr << "Binary [de]serialization not implemented yet for double" + << std::endl; + print_stacktrace(); + return 0; +} + +template<> /*static*/ +bool RsTypeSerializer::serialize(uint8_t[], uint32_t, uint32_t&, const double&) +{ + std::cerr << "Binary [de]serialization not implemented yet for double" + << std::endl; + print_stacktrace(); + return false; +} + +template<> /*static*/ +bool RsTypeSerializer::deserialize(const uint8_t[], uint32_t, uint32_t&, double&) +{ + std::cerr << "Binary [de]serialization not implemented yet for double" + << std::endl; + print_stacktrace(); + return false; +} + +template<> /*static*/ +void RsTypeSerializer::print_data(const std::string& n, const double& V) +{ std::cerr << " [double ] " << n << ": " << V << std::endl; } + +SIMPLE_TO_JSON_DEF(double) + +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + double& member, RsJson& jDoc ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsDouble(); + if(ret) member = v.GetDouble(); + return ret; +} + //============================================================================// // std::string // @@ -596,9 +646,12 @@ bool RsTypeSerializer::to_JSON( rapidjson::Value key; key.SetString(memberName.c_str(), memberName.length(), allocator); + std::string encodedValue; + Radix64::encode( reinterpret_cast(member.first), + member.second, encodedValue ); + rapidjson::Value value; - const char* tName = typeid(member).name(); - value.SetString(tName, allocator); + value.SetString(encodedValue.data(), allocator); jDoc.AddMember(key, value, allocator); @@ -606,20 +659,27 @@ bool RsTypeSerializer::to_JSON( } template<> /*static*/ -bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/, - RsTypeSerializer::TlvMemBlock_proxy&, - RsJson& /*jDoc*/) -{ return true; } - - -//============================================================================// -// RsJson std:ostream support // -//============================================================================// - -std::ostream &operator<<(std::ostream &out, const RsJson &jDoc) +bool RsTypeSerializer::from_JSON( const std::string& memberName, + RsTypeSerializer::TlvMemBlock_proxy& member, + RsJson& jDoc) { - rapidjson::StringBuffer buffer; buffer.Clear(); - rapidjson::PrettyWriter writer(buffer); - jDoc.Accept(writer); - return out << buffer.GetString(); + SAFE_GET_JSON_V(); + ret = ret && v.IsString(); + if(ret) + { + std::string encodedValue = v.GetString(); + std::vector decodedValue = Radix64::decode(encodedValue); + member.second = decodedValue.size(); + + if(member.second == 0) + { + member.first = nullptr; + return ret; + } + + member.first = rs_malloc(member.second); + ret = ret && member.first && + memcpy(member.first, decodedValue.data(), member.second); + } + return ret; } diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index 371df6f12..fc13d42e4 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -31,18 +31,14 @@ #include "serialiser/rsserializer.h" #include "serialiser/rsserializable.h" +#include "util/rsjson.h" -#ifdef HAS_RAPIDJSON -#include -#else -#include -#endif // HAS_RAPIDJSON #include // for typeid #include #include -/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} +/* INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} * Can't use a template function because T is needed for const_cast */ #define RsTypeSerializer_PRIVATE_TO_JSON_ARRAY() do \ { \ @@ -58,9 +54,7 @@ { \ /* Use same allocator to avoid deep copy */\ RsGenericSerializer::SerializeContext elCtx(\ - nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\ - RsGenericSerializer::SERIALIZATION_FLAG_NONE,\ - &allocator );\ + nullptr, 0, ctx.mFlags, &allocator );\ \ /* If el is const the default serial_process template is matched */ \ /* also when specialization is necessary so the compilation break */ \ @@ -78,7 +72,7 @@ ctx.mJson.AddMember(arrKey, arr, allocator);\ } while (false) -/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} +/* INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set} * Can't use a template function because std::{vector,list,set} has different * name for insert/push_back function */ @@ -86,7 +80,7 @@ {\ using namespace rapidjson;\ \ - bool& ok(ctx.mOk);\ + bool ok = ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING;\ Document& jDoc(ctx.mJson);\ Document::AllocatorType& allocator = jDoc.GetAllocator();\ \ @@ -100,23 +94,28 @@ {\ for (auto&& arrEl : jDoc[arrKey].GetArray())\ {\ + Value arrKeyT;\ + arrKeyT.SetString(memberName.c_str(), memberName.length());\ +\ RsGenericSerializer::SerializeContext elCtx(\ - nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\ - RsGenericSerializer::SERIALIZATION_FLAG_NONE,\ - &allocator );\ - elCtx.mJson.AddMember(arrKey, arrEl, allocator);\ + nullptr, 0, ctx.mFlags, &allocator );\ + elCtx.mJson.AddMember(arrKeyT, arrEl, allocator);\ \ T el;\ serial_process(j, elCtx, el, memberName); \ ok = ok && elCtx.mOk;\ -\ + ctx.mOk &= ok;\ if(ok) v.INSERT_FUN(el);\ else break;\ }\ }\ + else\ + {\ + ctx.mOk = false;\ + }\ +\ } while(false) -std::ostream &operator<<(std::ostream &out, const RsJson &jDoc); struct RsTypeSerializer { @@ -134,8 +133,8 @@ struct RsTypeSerializer template typename std::enable_if::value || !(std::is_base_of::value || std::is_enum::value || std::is_base_of::value)>::type static /*void*/ serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx, - T& member, const std::string& member_name) + RsGenericSerializer::SerializeContext& ctx, + T& member, const std::string& member_name ) { switch(j) { @@ -157,7 +156,8 @@ struct RsTypeSerializer ctx.mOk = ctx.mOk && to_JSON(member_name, member, ctx.mJson); break; case RsGenericSerializer::FROM_JSON: - ctx.mOk = ctx.mOk && from_JSON(member_name, member, ctx.mJson); + ctx.mOk &= (ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING) + && from_JSON(member_name, member, ctx.mJson); break; default: std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: " @@ -195,8 +195,9 @@ struct RsTypeSerializer to_JSON(member_name, type_id, member, ctx.mJson); break; case RsGenericSerializer::FROM_JSON: - ctx.mOk = ctx.mOk && - from_JSON(member_name, type_id, member, ctx.mJson); + ctx.mOk &= + (ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING) + && from_JSON(member_name, type_id, member, ctx.mJson); break; default: std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: " @@ -288,15 +289,11 @@ struct RsTypeSerializer { // Use same allocator to avoid deep copy RsGenericSerializer::SerializeContext kCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE, - &allocator ); + nullptr, 0, ctx.mFlags, &allocator ); serial_process(j, kCtx, const_cast(kv.first), "key"); RsGenericSerializer::SerializeContext vCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE, - &allocator ); + nullptr, 0, ctx.mFlags, &allocator ); serial_process(j, vCtx, const_cast(kv.second), "value"); if(kCtx.mOk && vCtx.mOk) @@ -317,7 +314,7 @@ struct RsTypeSerializer { using namespace rapidjson; - bool& ok(ctx.mOk); + bool ok = ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING; Document& jDoc(ctx.mJson); Document::AllocatorType& allocator = jDoc.GetAllocator(); @@ -337,9 +334,7 @@ struct RsTypeSerializer if (!ok) break; RsGenericSerializer::SerializeContext kCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE, - &allocator ); + nullptr, 0, ctx.mFlags, &allocator ); if(ok) kCtx.mJson.AddMember("key", kvEl["key"], allocator); @@ -347,9 +342,7 @@ struct RsTypeSerializer ok = ok && (serial_process(j, kCtx, key, "key"), kCtx.mOk); RsGenericSerializer::SerializeContext vCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE, - &allocator ); + nullptr, 0, ctx.mFlags, &allocator ); if(ok) vCtx.mJson.AddMember("value", kvEl["value"], allocator); @@ -357,14 +350,102 @@ struct RsTypeSerializer ok = ok && ( serial_process(j, vCtx, value, "value"), vCtx.mOk ); + ctx.mOk &= ok; if(ok) v.insert(std::pair(key,value)); else break; } } + else + { + ctx.mOk = false; + } + break; + } + default: + std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: " + << static_cast::type>(j) + << std::endl; + exit(EINVAL); + } + } + + /// std::pair + template + static void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx, + std::pair& p, + const std::string& memberName ) + { + switch(j) + { + case RsGenericSerializer::SIZE_ESTIMATE: // fallthrough + case RsGenericSerializer::DESERIALIZE: // fallthrough + case RsGenericSerializer::SERIALIZE: // fallthrough + case RsGenericSerializer::PRINT: + serial_process(j, ctx, p.first, "pair::first"); + serial_process(j, ctx, p.second, "pair::second"); + break; + case RsGenericSerializer::TO_JSON: + { + RsJson& jDoc(ctx.mJson); + RsJson::AllocatorType& allocator = jDoc.GetAllocator(); + + // Reuse allocator to avoid deep copy later + RsGenericSerializer::SerializeContext lCtx( + nullptr, 0, ctx.mFlags, &allocator ); + + serial_process(j, ctx, p.first, "first"); + serial_process(j, ctx, p.second, "second"); + + rapidjson::Value key; + key.SetString(memberName.c_str(), memberName.length(), allocator); + + /* Because the passed allocator is reused it doesn't go out of scope + * and there is no need of deep copy and we can take advantage of + * the much faster rapidjson move semantic */ + jDoc.AddMember(key, lCtx.mJson, allocator); + + ctx.mOk = ctx.mOk && lCtx.mOk; + break; + } + case RsGenericSerializer::FROM_JSON: + { + RsJson& jDoc(ctx.mJson); + const char* mName = memberName.c_str(); + bool hasMember = jDoc.HasMember(mName); + bool yielding = ctx.mFlags & + RsGenericSerializer::SERIALIZATION_FLAG_YIELDING; + + if(!hasMember) + { + if(!yielding) + { + std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" not found in JSON:" << std::endl + << jDoc << std::endl << std::endl; + print_stacktrace(); + } + ctx.mOk = false; + break; + } + + rapidjson::Value& v = jDoc[mName]; + + RsGenericSerializer::SerializeContext lCtx(nullptr, 0, ctx.mFlags); + lCtx.mJson.SetObject() = v; // Beware of move semantic!! + + serial_process(j, ctx, p.first, "first"); + serial_process(j, ctx, p.second, "second"); + ctx.mOk &= lCtx.mOk; break; } - default: break; + default: + std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: " + << static_cast::type>(j) + << std::endl; + exit(EINVAL); + break; } } @@ -404,10 +485,12 @@ struct RsTypeSerializer case RsGenericSerializer::PRINT: { if(v.empty()) - std::cerr << " Empty array"<< std::endl; - else - std::cerr << " Array of " << v.size() << " elements:" + std::cerr << " Empty vector \"" << memberName << "\"" << std::endl; + else + std::cerr << " Vector of " << v.size() << " elements: \"" + << memberName << "\"" << std::endl; + for(uint32_t i=0;i(f); break; } @@ -624,9 +715,7 @@ struct RsTypeSerializer // Reuse allocator to avoid deep copy later RsGenericSerializer::SerializeContext lCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE, - &allocator ); + nullptr, 0, ctx.mFlags, &allocator ); member.serial_process(j, lCtx); @@ -643,28 +732,32 @@ struct RsTypeSerializer } case RsGenericSerializer::FROM_JSON: { - rapidjson::Document& jDoc(ctx.mJson); + RsJson& jDoc(ctx.mJson); const char* mName = memberName.c_str(); - ctx.mOk = ctx.mOk && jDoc.HasMember(mName); + bool hasMember = jDoc.HasMember(mName); + bool yielding = ctx.mFlags & + RsGenericSerializer::SERIALIZATION_FLAG_YIELDING; - if(!ctx.mOk) + if(!hasMember) { - std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName - << "\" not found in JSON:" << std::endl - << jDoc << std::endl << std::endl; - print_stacktrace(); + if(!yielding) + { + std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" not found in JSON:" << std::endl + << jDoc << std::endl << std::endl; + print_stacktrace(); + } + ctx.mOk = false; break; } rapidjson::Value& v = jDoc[mName]; - RsGenericSerializer::SerializeContext lCtx( - nullptr, 0, RsGenericSerializer::FORMAT_BINARY, - RsGenericSerializer::SERIALIZATION_FLAG_NONE ); + RsGenericSerializer::SerializeContext lCtx(nullptr, 0, ctx.mFlags); lCtx.mJson.SetObject() = v; // Beware of move semantic!! member.serial_process(j, lCtx); - ctx.mOk = ctx.mOk && lCtx.mOk; + ctx.mOk &= lCtx.mOk; break; } diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 1c7cf1058..386fe4ee0 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -64,8 +64,13 @@ RsGxsChannels *rsGxsChannels = NULL; /******************* Startup / Tick ******************************************/ /********************************************************************************/ -p3GxsChannels::p3GxsChannels(RsGeneralDataService *gds, RsNetworkExchangeService *nes, RsGixs* gixs) - : RsGenExchange(gds, nes, new RsGxsChannelSerialiser(), RS_SERVICE_GXS_TYPE_CHANNELS, gixs, channelsAuthenPolicy()), RsGxsChannels(this), GxsTokenQueue(this) +p3GxsChannels::p3GxsChannels( + RsGeneralDataService *gds, RsNetworkExchangeService *nes, + RsGixs* gixs ) : + RsGenExchange( gds, nes, new RsGxsChannelSerialiser(), + RS_SERVICE_GXS_TYPE_CHANNELS, gixs, channelsAuthenPolicy() ), + RsGxsChannels(static_cast(*this)), GxsTokenQueue(this), + mSearchCallbacksMapMutex("GXS channels search") { // For Dummy Msgs. mGenActive = false; @@ -347,8 +352,6 @@ static time_t last_dummy_tick = 0; GxsTokenQueue::checkRequests(); mCommentService->comment_tick(); - - return; } bool p3GxsChannels::getGroupData(const uint32_t &token, std::vector &groups) @@ -392,10 +395,11 @@ bool p3GxsChannels::getGroupData(const uint32_t &token, std::vector& peers) +bool p3GxsChannels::groupShareKeys( + const RsGxsGroupId &groupId, const std::set& peers ) { - RsGenExchange::shareGroupPublishKey(groupId,peers) ; - return true ; + RsGenExchange::shareGroupPublishKey(groupId,peers); + return true; } @@ -992,6 +996,50 @@ void p3GxsChannels::handleResponse(uint32_t token, uint32_t req_type) } } +//////////////////////////////////////////////////////////////////////////////// +/// Blocking API implementation begin +//////////////////////////////////////////////////////////////////////////////// + +bool p3GxsChannels::getChannelsSummaries( + std::list& channels ) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_META; + if( !requestGroupInfo(token, opts) + || waitToken(token) != RsTokenService::COMPLETE ) return false; + return getGroupSummary(token, channels); +} + +bool p3GxsChannels::getChannelsInfo( + const std::list& chanIds, + std::vector& channelsInfo ) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + if( !requestGroupInfo(token, opts, chanIds) + || waitToken(token) != RsTokenService::COMPLETE ) return false; + return getGroupData(token, channelsInfo); +} + +bool p3GxsChannels::getChannelsContent( + const std::list& chanIds, + std::vector& posts, + std::vector& comments ) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + if( !requestMsgInfo(token, opts, chanIds) + || waitToken(token) != RsTokenService::COMPLETE ) return false; + return getPostData(token, posts, comments); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Blocking API implementation end +//////////////////////////////////////////////////////////////////////////////// + /********************************************************************************************/ /********************************************************************************************/ @@ -1234,17 +1282,10 @@ bool p3GxsChannels::createPost(uint32_t &token, RsGxsChannelPost &msg) /********************************************************************************************/ /********************************************************************************************/ -bool p3GxsChannels::ExtraFileHash(const std::string &path, std::string filename) +bool p3GxsChannels::ExtraFileHash(const std::string& path) { - /* extract filename */ - filename = RsDirUtil::getTopDir(path); - - TransferRequestFlags flags = RS_FILE_REQ_ANONYMOUS_ROUTING; - if(!rsFiles->ExtraFileHash(path, GXSCHANNEL_STOREPERIOD, flags)) - return false; - - return true; + return rsFiles->ExtraFileHash(path, GXSCHANNEL_STOREPERIOD, flags); } @@ -1312,14 +1353,14 @@ void p3GxsChannels::dummy_tick() #endif uint32_t status = RsGenExchange::getTokenService()->requestStatus(mGenToken); - if (status != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status != RsTokenService::COMPLETE) { #ifdef GXSCHANNELS_DEBUG std::cerr << "p3GxsChannels::dummy_tick() Status: " << status; std::cerr << std::endl; #endif - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + if (status == RsTokenService::FAILED) { #ifdef GXSCHANNELS_DEBUG std::cerr << "p3GxsChannels::dummy_tick() generateDummyMsgs() FAILED"; @@ -1518,6 +1559,8 @@ void p3GxsChannels::dummy_tick() } } + + cleanTimedOutSearches(); } @@ -1733,4 +1776,60 @@ bool p3GxsChannels::retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChann return false ; } +bool p3GxsChannels::turtleSearchRequest( + const std::string& matchString, + const std::function& multiCallback, + std::time_t maxWait ) +{ + if(matchString.empty()) + { + std::cerr << __PRETTY_FUNCTION__ << " match string can't be empty!" + << std::endl; + return false; + } + TurtleRequestId sId = turtleSearchRequest(matchString); + + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + mSearchCallbacksMap.emplace( + sId, + std::make_pair( + multiCallback, + std::chrono::system_clock::now() + + std::chrono::seconds(maxWait) ) ); + + return true; +} + +void p3GxsChannels::receiveDistantSearchResults( + TurtleRequestId id, const RsGxsGroupId& grpId ) +{ + std::cerr << __PRETTY_FUNCTION__ << "(" << id << ", " << grpId << ")" + << std::endl; + + RsGenExchange::receiveDistantSearchResults(id, grpId); + RsGxsGroupSummary gs; + gs.mGroupId = grpId; + netService()->retrieveDistantGroupSummary(grpId, gs); + + { + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto cbpt = mSearchCallbacksMap.find(id); + if(cbpt != mSearchCallbacksMap.end()) + cbpt->second.first(gs); + } // end RS_STACK_MUTEX(mSearchCallbacksMapMutex); +} + +void p3GxsChannels::cleanTimedOutSearches() +{ + RS_STACK_MUTEX(mSearchCallbacksMapMutex); + auto now = std::chrono::system_clock::now(); + for( auto cbpt = mSearchCallbacksMap.begin(); + cbpt != mSearchCallbacksMap.end(); ) + if(cbpt->second.second <= now) + { + clearDistantSearchResults(cbpt->first); + cbpt = mSearchCallbacksMap.erase(cbpt); + } + else ++cbpt; +} diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index 94d4a5332..4f24f88b9 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -54,14 +54,14 @@ class p3GxsChannels: public RsGenExchange, public RsGxsChannels, public GxsTokenQueue, public p3Config, public RsTickEvent /* only needed for testing - remove after */ { - public: +public: + p3GxsChannels( RsGeneralDataService* gds, RsNetworkExchangeService* nes, + RsGixs* gixs ); + virtual RsServiceInfo getServiceInfo(); - p3GxsChannels(RsGeneralDataService* gds, RsNetworkExchangeService* nes, RsGixs* gixs); -virtual RsServiceInfo getServiceInfo(); + virtual void service_tick(); -virtual void service_tick(); - - protected: +protected: virtual RsSerialiser* setupSerialiser(); // @see p3Config::setupSerialiser() @@ -82,7 +82,7 @@ virtual void notifyChanges(std::vector& changes); // Overloaded from RsTickEvent. virtual void handle_event(uint32_t event_type, const std::string &elabel); - public: +public: virtual bool getGroupData(const uint32_t &token, std::vector &groups); virtual bool getPostData(const uint32_t &token, std::vector &posts, std::vector &cmts); @@ -96,7 +96,8 @@ virtual bool getPostData(const uint32_t &token, std::vector &p //virtual bool setGroupSubscribeFlags(const std::string &groupId, uint32_t subscribeFlags, uint32_t subscribeMask); //virtual bool groupRestoreKeys(const std::string &groupId); - virtual bool groupShareKeys(const RsGxsGroupId &groupId, std::set& peers) ; + virtual bool groupShareKeys( + const RsGxsGroupId &groupId, const std::set& peers); virtual bool createGroup(uint32_t &token, RsGxsChannelGroup &group); virtual bool createPost(uint32_t &token, RsGxsChannelPost &post); @@ -109,6 +110,18 @@ virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled); virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory); virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory); + /// @see RsGxsChannels::turtleSearchRequest + virtual bool turtleSearchRequest(const std::string& matchString, + const std::function& multiCallback, + std::time_t maxWait = 300 ); + + /** + * Receive results from turtle search @see RsGenExchange @see RsNxsObserver + * @see p3turtle::handleSearchResult + */ + void receiveDistantSearchResults( TurtleRequestId id, + const RsGxsGroupId& grpId ); + /* Comment service - Provide RsGxsCommentService - redirect to p3GxsCommentService */ virtual bool getCommentData(uint32_t token, std::vector &msgs) { return mCommentService->getGxsCommentData(token, msgs); } @@ -151,15 +164,30 @@ virtual void setMessageProcessedStatus(uint32_t& token, const RsGxsGrpMsgIdPair& virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read); // File Interface -virtual bool ExtraFileHash(const std::string &path, std::string filename); + virtual bool ExtraFileHash(const std::string& path); virtual bool ExtraFileRemove(const RsFileHash &hash); - protected: + /// Implementation of @see RsGxsChannels::getChannelsSummaries + virtual bool getChannelsSummaries(std::list& channels); + + /// Implementation of @see RsGxsChannels::getChannelsInfo + virtual bool getChannelsInfo( + const std::list& chanIds, + std::vector& channelsInfo ); + + /// Implementation of @see RsGxsChannels::getChannelContent + virtual bool getChannelsContent( + const std::list& chanIds, + std::vector& posts, + std::vector& comments ); + +protected: // Overloaded from GxsTokenQueue for Request callbacks. -virtual void handleResponse(uint32_t token, uint32_t req_type); + virtual void handleResponse(uint32_t token, uint32_t req_type); - private: + +private: static uint32_t channelsAuthenPolicy(); @@ -220,8 +248,20 @@ bool generateGroup(uint32_t &token, std::string groupName); std::vector mGenRefs; RsGxsMessageId mGenThreadId; - p3GxsCommentService *mCommentService; + p3GxsCommentService *mCommentService; std::map mKnownChannels; + + /** Store search callbacks with timeout*/ + std::map< + TurtleRequestId, + std::pair< + std::function, + std::chrono::system_clock::time_point > + > mSearchCallbacksMap; + RsMutex mSearchCallbacksMapMutex; + + /// Cleanup mSearchCallbacksMap + void cleanTimedOutSearches(); }; #endif diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 00eeb353d..10e6f3628 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -107,16 +107,16 @@ RsGxsCircles *rsGxsCircles = NULL; /******************* Startup / Tick ******************************************/ /********************************************************************************/ -p3GxsCircles::p3GxsCircles(RsGeneralDataService *gds, RsNetworkExchangeService *nes, - p3IdService *identities, PgpAuxUtils *pgpUtils) - : RsGxsCircleExchange(gds, nes, new RsGxsCircleSerialiser(), - RS_SERVICE_GXS_TYPE_GXSCIRCLE, identities, circleAuthenPolicy()), - RsGxsCircles(this), GxsTokenQueue(this), RsTickEvent(), - mIdentities(identities), - mPgpUtils(pgpUtils), - mCircleMtx("p3GxsCircles"), - mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache") - +p3GxsCircles::p3GxsCircles( + RsGeneralDataService *gds, RsNetworkExchangeService *nes, + p3IdService *identities, PgpAuxUtils *pgpUtils) : + RsGxsCircleExchange( + gds, nes, new RsGxsCircleSerialiser(), RS_SERVICE_GXS_TYPE_GXSCIRCLE, + identities, circleAuthenPolicy() ), + RsGxsCircles(static_cast(*this)), GxsTokenQueue(this), + RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils), + mCircleMtx("p3GxsCircles"), + mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache" ) { // Kick off Cache Testing, + Others. //RsTickEvent::schedule_in(CIRCLE_EVENT_CACHETEST, CACHETEST_PERIOD); @@ -1653,8 +1653,8 @@ void p3GxsCircles::checkDummyIdData() // check the token. uint32_t status = rsIdentity->getTokenService()->requestStatus(mDummyIdToken); - if ( (RsTokenService::GXS_REQUEST_V2_STATUS_FAILED == status) || - (RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE == status) ) + if ( (RsTokenService::FAILED == status) || + (RsTokenService::COMPLETE == status) ) { std::vector ids; if (!rsIdentity->getGroupData(mDummyIdToken, ids)) diff --git a/libretroshare/src/services/p3gxscommon.cc b/libretroshare/src/services/p3gxscommon.cc index 27be679e4..28d94e28c 100644 --- a/libretroshare/src/services/p3gxscommon.cc +++ b/libretroshare/src/services/p3gxscommon.cc @@ -552,24 +552,22 @@ void p3GxsCommentService::load_PendingVoteParent(const uint32_t &token) pit = mPendingVotes.find(parentId); if (pit == mPendingVotes.end()) { - std::cerr << "p3GxsCommentService::load_PendingVoteParent() ERROR Finding Pending Vote"; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ + << " ERROR Finding Pending Vote" << std::endl; continue; } RsGxsVote vote = pit->second.mVote; if (meta.mMsgStatus & GXS_SERV::GXS_MSG_STATUS_VOTE_MASK) { - std::cerr << "p3GxsCommentService::load_PendingVoteParent() ERROR Already Voted"; - std::cerr << std::endl; - std::cerr << "mGroupId: " << meta.mGroupId; - std::cerr << std::endl; - std::cerr << "mMsgId: " << meta.mMsgId; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " ERROR Already Voted" + << std::endl + << "mGroupId: " << meta.mGroupId << std::endl + << "mMsgId: " << meta.mMsgId << std::endl; pit->second.mStatus = VoteHolder::VOTE_ERROR; - uint32_t status = RsTokenService::GXS_REQUEST_V2_STATUS_FAILED; - mExchange->updatePublicRequestStatus(pit->second.mReqToken, status); + mExchange->updatePublicRequestStatus( + pit->second.mReqToken, RsTokenService::FAILED ); continue; } @@ -613,8 +611,8 @@ void p3GxsCommentService::completeInternalVote(uint32_t &token) { if (it->second.mVoteToken == token) { - - uint32_t status = mExchange->getTokenService()->requestStatus(token); + RsTokenService::GxsRequestStatus status = + mExchange->getTokenService()->requestStatus(token); mExchange->updatePublicRequestStatus(it->second.mReqToken, status); #ifdef DEBUG_GXSCOMMON diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index e222f1743..1a348b61c 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -51,7 +51,8 @@ p3GxsForums::p3GxsForums( RsGeneralDataService *gds, RsNetworkExchangeService *nes, RsGixs* gixs ) : RsGenExchange( gds, nes, new RsGxsForumSerialiser(), RS_SERVICE_GXS_TYPE_FORUMS, gixs, forumsAuthenPolicy()), - RsGxsForums(this), mGenToken(0), mGenActive(false), mGenCount(0) + RsGxsForums(static_cast(*this)), mGenToken(0), + mGenActive(false), mGenCount(0) { // Test Data disabled in Repo. //RsTickEvent::schedule_in(FORUM_TESTEVENT_DUMMYDATA, DUMMYDATA_PERIOD); @@ -486,12 +487,12 @@ void p3GxsForums::dummy_tick() std::cerr << std::endl; uint32_t status = RsGenExchange::getTokenService()->requestStatus(mGenToken); - if (status != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status != RsTokenService::COMPLETE) { std::cerr << "p3GxsForums::dummy_tick() Status: " << status; std::cerr << std::endl; - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + if (status == RsTokenService::FAILED) { std::cerr << "p3GxsForums::dummy_tick() generateDummyMsgs() FAILED"; std::cerr << std::endl; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index d44122d8f..a4d5fb844 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -152,12 +152,14 @@ RsIdentity *rsIdentity = NULL; /******************* Startup / Tick ******************************************/ /********************************************************************************/ -p3IdService::p3IdService(RsGeneralDataService *gds, RsNetworkExchangeService *nes, PgpAuxUtils *pgpUtils) - : RsGxsIdExchange(gds, nes, new RsGxsIdSerialiser(), RS_SERVICE_GXS_TYPE_GXSID, idAuthenPolicy()), - RsIdentity(this), GxsTokenQueue(this), RsTickEvent(), - mKeyCache(GXSID_MAX_CACHE_SIZE, "GxsIdKeyCache"), - mIdMtx("p3IdService"), mNes(nes), - mPgpUtils(pgpUtils) +p3IdService::p3IdService( + RsGeneralDataService *gds, RsNetworkExchangeService *nes, + PgpAuxUtils *pgpUtils ) : + RsGxsIdExchange( gds, nes, new RsGxsIdSerialiser(), + RS_SERVICE_GXS_TYPE_GXSID, idAuthenPolicy() ), + RsIdentity(static_cast(*this)), GxsTokenQueue(this), + RsTickEvent(), mKeyCache(GXSID_MAX_CACHE_SIZE, "GxsIdKeyCache"), + mIdMtx("p3IdService"), mNes(nes), mPgpUtils(pgpUtils) { mBgSchedule_Mode = 0; mBgSchedule_Active = false; @@ -1532,7 +1534,7 @@ bool p3IdService::opinion_handlerequest(uint32_t token) std::cerr << "p3IdService::opinion_handlerequest() ERROR getGroupMeta()"; std::cerr << std::endl; - updatePublicRequestStatus(req.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + updatePublicRequestStatus(req.mToken, RsTokenService::FAILED); return false; } @@ -1542,7 +1544,7 @@ bool p3IdService::opinion_handlerequest(uint32_t token) std::cerr << std::endl; // error. - updatePublicRequestStatus(req.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + updatePublicRequestStatus(req.mToken, RsTokenService::FAILED); return false; } RsGroupMetaData &meta = *(groups.begin()); @@ -1553,7 +1555,7 @@ bool p3IdService::opinion_handlerequest(uint32_t token) std::cerr << std::endl; // error. - updatePublicRequestStatus(req.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED); + updatePublicRequestStatus(req.mToken, RsTokenService::FAILED); return false; } @@ -1588,7 +1590,7 @@ bool p3IdService::opinion_handlerequest(uint32_t token) setGroupServiceString(dummyToken, meta.mGroupId, serviceString); cache_update_if_cached(RsGxsId(meta.mGroupId), serviceString); - updatePublicRequestStatus(req.mToken, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE); + updatePublicRequestStatus(req.mToken, RsTokenService::COMPLETE); return true; } diff --git a/libretroshare/src/services/p3posted.cc b/libretroshare/src/services/p3posted.cc index c83a6f241..4d5cced66 100644 --- a/libretroshare/src/services/p3posted.cc +++ b/libretroshare/src/services/p3posted.cc @@ -36,13 +36,12 @@ RsPosted *rsPosted = NULL; /******************* Startup / Tick ******************************************/ /********************************************************************************/ -p3Posted::p3Posted(RsGeneralDataService *gds, RsNetworkExchangeService *nes, RsGixs* gixs) - :p3PostBase(gds, nes, gixs, new RsGxsPostedSerialiser(), RS_SERVICE_GXS_TYPE_POSTED), - RsPosted(this) -{ - return; -} - +p3Posted::p3Posted( + RsGeneralDataService *gds, RsNetworkExchangeService *nes, + RsGixs* gixs ) : + p3PostBase( gds, nes, gixs, new RsGxsPostedSerialiser(), + RS_SERVICE_GXS_TYPE_POSTED ), + RsPosted(static_cast(*this)) {} const std::string GXS_POSTED_APP_NAME = "gxsposted"; const uint16_t GXS_POSTED_APP_MAJOR_VERSION = 1; diff --git a/libretroshare/src/services/p3wiki.cc b/libretroshare/src/services/p3wiki.cc index 0d7a2a450..26c33881a 100644 --- a/libretroshare/src/services/p3wiki.cc +++ b/libretroshare/src/services/p3wiki.cc @@ -534,7 +534,7 @@ void p3Wiki::dummyTick() uint32_t status = RsGenExchange::getTokenService()->requestStatus(mAboutToken); - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status == RsTokenService::COMPLETE) { std::cerr << "p3Wiki::dummyTick() AboutActive, Lines: " << mAboutLines; std::cerr << std::endl; @@ -601,7 +601,7 @@ void p3Wiki::dummyTick() uint32_t status = RsGenExchange::getTokenService()->requestStatus(mImprovToken); - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status == RsTokenService::COMPLETE) { std::cerr << "p3Wiki::dummyTick() ImprovActive, Lines: " << mImprovLines; std::cerr << std::endl; @@ -669,7 +669,7 @@ void p3Wiki::dummyTick() uint32_t status = RsGenExchange::getTokenService()->requestStatus(mMarkdownToken); - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + if (status == RsTokenService::COMPLETE) { std::cerr << "p3Wiki::dummyTick() MarkdownActive, Lines: " << mMarkdownLines; std::cerr << std::endl; diff --git a/libretroshare/src/turtle/p3turtle.cc b/libretroshare/src/turtle/p3turtle.cc index 112363ea9..90274d02d 100644 --- a/libretroshare/src/turtle/p3turtle.cc +++ b/libretroshare/src/turtle/p3turtle.cc @@ -928,7 +928,6 @@ void p3turtle::handleSearchRequest(RsTurtleSearchRequestItem *item) for(auto it(search_results.begin());it!=search_results.end();++it) { (*it)->request_id = item->request_id ; - (*it)->depth = 0 ; (*it)->PeerId(item->PeerId()) ; sendItem(*it) ; @@ -1133,7 +1132,7 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item) std::list > results_to_notify_off_mutex ; { - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mTurtleMtx); // Find who actually sent the corresponding request. // std::map::iterator it = _search_requests_origins.find(item->request_id) ; @@ -1195,11 +1194,10 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item) // of the files found can be further reached by a tunnel. fwd_item->PeerId(it->second.origin) ; - fwd_item->depth = 0 ; // obfuscate the depth for non immediate friends. Result will always be 0. This effectively removes the information. sendItem(fwd_item) ; } - } + } // mTurtleMtx end // now we notify clients off-mutex. @@ -1212,7 +1210,16 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item) if(ftsr!=NULL) { - RsServer::notify()->notifyTurtleSearchResult(ftsr->request_id,ftsr->result) ; + ftServer *client = dynamic_cast((*it).second) ; + + if(!client) + { + std::cerr << "(EE) received turtle FT search result but the service is not a ftServer!!" << std::endl; + continue; + } + //RsServer::notify()->notifyTurtleSearchResult(ftsr->request_id,ftsr->result) ; + + client->receiveSearchResult(ftsr); continue ; } diff --git a/libretroshare/src/turtle/rsturtleitem.cc b/libretroshare/src/turtle/rsturtleitem.cc index 3c51f7c29..6e3feee52 100644 --- a/libretroshare/src/turtle/rsturtleitem.cc +++ b/libretroshare/src/turtle/rsturtleitem.cc @@ -193,13 +193,20 @@ RS_TYPE_SERIALIZER_FROM_JSON_NOT_IMPLEMENTED_DEF(RsRegularExpression::Linearized void RsTurtleFTSearchResultItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,request_id,"request_id") ; - RsTypeSerializer::serial_process(j,ctx,depth ,"depth") ; + + // This depth was previously a member of SearchResult parent class that was set to be always 0. It's removed, but we have to stay backward compatible. + uint16_t depth_retrocompat_unused_placeholder = 0 ; + RsTypeSerializer::serial_process(j,ctx,depth_retrocompat_unused_placeholder,"depth") ; + RsTypeSerializer::serial_process (j,ctx,result ,"result") ; } void RsTurtleGenericSearchResultItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,request_id,"request_id") ; - RsTypeSerializer::serial_process(j,ctx,depth ,"depth") ; + + // This depth was previously a member of SearchResult parent class that was set to be always 0. It's removed, but we have to stay backward compatible. + uint16_t depth_retrocompat_unused_placeholder = 0 ; + RsTypeSerializer::serial_process(j,ctx,depth_retrocompat_unused_placeholder,"depth") ; RsTypeSerializer::TlvMemBlock_proxy prox(result_data,result_data_len) ; RsTypeSerializer::serial_process(j,ctx,prox,"search_data") ; @@ -212,59 +219,9 @@ RsTurtleSearchResultItem *RsTurtleGenericSearchResultItem::duplicate() const memcpy(sr->result_data,result_data,result_data_len) ; sr->result_data_len = result_data_len ; sr->request_id = request_id ; - sr->depth = depth ; return sr ; } -template<> uint32_t RsTypeSerializer::serial_size(const TurtleFileInfo& i) -{ - uint32_t s = 0 ; - - s += 8 ; // size - s += i.hash.SIZE_IN_BYTES ; - s += GetTlvStringSize(i.name) ; - - return s; -} - -template<> bool RsTypeSerializer::deserialize(const uint8_t data[],uint32_t size,uint32_t& offset,TurtleFileInfo& i) -{ - uint32_t saved_offset = offset ; - bool ok = true ; - - ok &= getRawUInt64(data, size, &offset, &i.size); // file size - ok &= i.hash.deserialise(data, size, offset); // file hash - ok &= GetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // file name - - if(!ok) - offset = saved_offset ; - - return ok; -} - -template<> bool RsTypeSerializer::serialize(uint8_t data[],uint32_t size,uint32_t& offset,const TurtleFileInfo& i) -{ - uint32_t saved_offset = offset ; - bool ok = true ; - - ok &= setRawUInt64(data, size, &offset, i.size); // file size - ok &= i.hash.serialise(data, size, offset); // file hash - ok &= SetTlvString(data, size, &offset, TLV_TYPE_STR_NAME, i.name); // file name - - if(!ok) - offset = saved_offset ; - - return ok; -} - -template<> void RsTypeSerializer::print_data(const std::string& n, const TurtleFileInfo& i) -{ - std::cerr << " [FileInfo ] " << n << " size=" << i.size << " hash=" << i.hash << ", name=" << i.name << std::endl; -} - -RS_TYPE_SERIALIZER_TO_JSON_NOT_IMPLEMENTED_DEF(TurtleFileInfo) -RS_TYPE_SERIALIZER_FROM_JSON_NOT_IMPLEMENTED_DEF(TurtleFileInfo) - void RsTurtleOpenTunnelItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process (j,ctx,file_hash ,"file_hash") ; diff --git a/libretroshare/src/turtle/rsturtleitem.h b/libretroshare/src/turtle/rsturtleitem.h index 9643089b8..1f4893087 100644 --- a/libretroshare/src/turtle/rsturtleitem.h +++ b/libretroshare/src/turtle/rsturtleitem.h @@ -191,12 +191,9 @@ class RsTurtleGenericSearchRequestItem: public RsTurtleSearchRequestItem class RsTurtleSearchResultItem: public RsTurtleItem { public: - RsTurtleSearchResultItem(uint8_t subtype) : RsTurtleItem(subtype), request_id(0), depth(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_SEARCH_RESULT) ;} + RsTurtleSearchResultItem(uint8_t subtype) : RsTurtleItem(subtype), request_id(0) { setPriorityLevel(QOS_PRIORITY_RS_TURTLE_SEARCH_RESULT) ;} TurtleSearchRequestId request_id ; // Randomly generated request id. - uint16_t depth ; // The depth of a search result is obfuscated in this way: - // If the actual depth is 1, this field will be 1. - // If the actual depth is > 1, this field is a larger arbitrary integer. virtual uint32_t count() const =0; virtual void pop() =0; diff --git a/libretroshare/src/use_libretroshare.pri b/libretroshare/src/use_libretroshare.pri index d613a2aa3..abc18fff0 100644 --- a/libretroshare/src/use_libretroshare.pri +++ b/libretroshare/src/use_libretroshare.pri @@ -47,6 +47,18 @@ sLibs = mLibs = $$RS_SQL_LIB ssl crypto $$RS_THREAD_LIB $$RS_UPNP_LIB dLibs = +rs_jsonapi { + RS_SRC_PATH=$$system_path($$clean_path($${PWD}/../../)) + RS_BUILD_PATH=$$system_path($$clean_path($${OUT_PWD}/../../)) + RESTBED_SRC_PATH=$$system_path($$clean_path($${RS_SRC_PATH}/supportlibs/restbed)) + RESTBED_BUILD_PATH=$$system_path($$clean_path($${RS_BUILD_PATH}/supportlibs/restbed)) + + INCLUDEPATH *= $$system_path($$clean_path($${RESTBED_BUILD_PATH}/include/)) + QMAKE_LIBDIR *= $$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/)) + # Using sLibs would fail as librestbed.a is generated at compile-time + LIBS *= -L$$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/)) -lrestbed +} + linux-* { mLibs += dl } diff --git a/libretroshare/src/util/rsdebug.cc b/libretroshare/src/util/rsdebug.cc index aade16282..434b06363 100644 --- a/libretroshare/src/util/rsdebug.cc +++ b/libretroshare/src/util/rsdebug.cc @@ -142,11 +142,12 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg if(info->lvl == RsLog::None) return; - RsStackMutex stack(logMtx); /******** LOCKED ****************/ - bool process = info->lvl == RsLog::Default ? (lvl <= defaultLevel) : lvl <= info->lvl; - if(process) + if(!process) + return; + { + RsStackMutex stack(logMtx); /******** LOCKED ****************/ time_t t = time(NULL); if (debugMode == RS_DEBUG_LOGCRASH) @@ -179,6 +180,9 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg fprintf(ofd, "(%s Z: %s, lvl: %u): %s \n", timestr2.c_str(), info->name.c_str(), (unsigned int)info->lvl, msg.c_str()); fflush(ofd); + + fprintf(stdout, "(%s Z: %s, lvl: %u): %s \n", + timestr2.c_str(), info->name.c_str(), (unsigned int)info->lvl, msg.c_str()); lineCount++; } } diff --git a/libretroshare/src/util/rsjson.cc b/libretroshare/src/util/rsjson.cc new file mode 100644 index 000000000..37f6282e4 --- /dev/null +++ b/libretroshare/src/util/rsjson.cc @@ -0,0 +1,68 @@ +/******************************************************************************* + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2018 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include "util/rsjson.h" + +#ifdef HAS_RAPIDJSON +# include +# include +# include +#else +# include +# include +# include +#endif // HAS_RAPIDJSON + + +inline int getJsonManipulatorStatePosition() +{ + static int p = std::ios_base::xalloc(); + return p; +} + +std::ostream& compactJSON(std::ostream &out) +{ + out.iword(getJsonManipulatorStatePosition()) = 1; + return out; +} + +std::ostream& prettyJSON(std::ostream &out) +{ + out.iword(getJsonManipulatorStatePosition()) = 0; + return out; +} + +std::ostream& operator<<(std::ostream &out, const RsJson &jDoc) +{ + rapidjson::StringBuffer buffer; buffer.Clear(); + if(out.iword(getJsonManipulatorStatePosition())) + { + rapidjson::Writer writer(buffer); + jDoc.Accept(writer); + } + else + { + rapidjson::PrettyWriter writer(buffer); + jDoc.Accept(writer); + } + + return out << buffer.GetString(); +} diff --git a/libretroshare/src/util/rsjson.h b/libretroshare/src/util/rsjson.h new file mode 100644 index 000000000..c52584b7e --- /dev/null +++ b/libretroshare/src/util/rsjson.h @@ -0,0 +1,56 @@ +/******************************************************************************* + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2018 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include + +#ifdef HAS_RAPIDJSON +# include +#else +# include +#endif // HAS_RAPIDJSON + +/** + * Use this type for JSON documents representations in RetroShare code + */ +typedef rapidjson::Document RsJson; + +/** + * Print out RsJson to a stream, use std::stringstream to get the string + * @param[out] out output stream + * @param[in] jDoc JSON document to print + * @return same output stream passed as out parameter + */ +std::ostream &operator<<(std::ostream &out, const RsJson &jDoc); + +/** + * Stream manipulator to print RsJson in compact format + * @param[out] out output stream + * @return same output stream passed as out parameter + */ +std::ostream& compactJSON(std::ostream &out); + +/** + * Stream manipulator to print RsJson in human readable format + * @param[out] out output stream + * @return same output stream passed as out parameter + */ +std::ostream& prettyJSON(std::ostream &out); diff --git a/plugins/FeedReader/services/p3FeedReader.cc b/plugins/FeedReader/services/p3FeedReader.cc index 256a1e285..b964e0a74 100644 --- a/plugins/FeedReader/services/p3FeedReader.cc +++ b/plugins/FeedReader/services/p3FeedReader.cc @@ -2229,11 +2229,11 @@ bool p3FeedReader::waitForToken(uint32_t token) while (!mStopped) { uint32_t status = service->requestStatus(token); - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) { + if (status == RsTokenService::FAILED) { break; } - if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) { + if (status == RsTokenService::COMPLETE) { return true; } diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index 4c36916e7..83381975c 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -30,6 +30,22 @@ #include "api/ApiServerLocal.h" #include "api/RsControlModule.h" +#ifdef RS_JSONAPI +# include "jsonapi/jsonapi.h" +# include "retroshare/rsiface.h" + +JsonApiServer jas(9092, [](int ec) +{ + RsControl::instance()->rsGlobalShutDown(); + QCoreApplication::exit(ec); +}); + +void exitGracefully(int ec) { jas.shutdown(ec); } + +#else // ifdef RS_JSONAPI +void exitGracefully(int ec) { QCoreApplication::exit(ec); } +#endif // ifdef RS_JSONAPI + using namespace resource_api; int main(int argc, char *argv[]) @@ -40,12 +56,13 @@ int main(int argc, char *argv[]) QCoreApplication app(argc, argv); - signal(SIGINT, &QCoreApplication::exit); - signal(SIGTERM, &QCoreApplication::exit); + signal(SIGINT, exitGracefully); + signal(SIGTERM, exitGracefully); #ifdef SIGBREAK - signal(SIGBREAK, &QCoreApplication::exit); -#endif // def SIGBREAK + signal(SIGBREAK, exitGracefully); +#endif // ifdef SIGBREAK +#ifdef LIBRESAPI_LOCAL_SERVER ApiServer api; RsControlModule ctrl_mod(argc, argv, api.getStateTokenServer(), &api, true); api.addResourceHandler( @@ -53,7 +70,6 @@ int main(int argc, char *argv[]) dynamic_cast(&ctrl_mod), &resource_api::RsControlModule::handleRequest); - QString sockPath = QDir::homePath() + "/.retroshare"; sockPath.append("/libresapi.sock"); qDebug() << "Listening on:" << sockPath; @@ -64,9 +80,16 @@ int main(int argc, char *argv[]) QTimer shouldExitTimer; shouldExitTimer.setTimerType(Qt::VeryCoarseTimer); shouldExitTimer.setInterval(1000); - QObject::connect( &shouldExitTimer, &QTimer::timeout, [&](){ - if(ctrl_mod.processShouldExit()) app.quit(); } ); + QObject::connect( &shouldExitTimer, &QTimer::timeout, [&]() + { if(ctrl_mod.processShouldExit()) exitGracefully(0); } ); shouldExitTimer.start(); +#else +# error retroshare-android-service need CONFIG+=libresapilocalserver to build +#endif + +#ifdef RS_JSONAPI + jas.start(); +#endif return app.exec(); } diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp index b4470ac5c..6d8105531 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp @@ -31,6 +31,7 @@ #include "gui/RetroShareLink.h" #include "util/HandleRichText.h" #include "util/misc.h" +#include "util/rsdir.h" #include @@ -449,11 +450,10 @@ void CreateGxsChannelMsg::addAttachment(const std::string &path) } FileInfo fInfo; - std::string filename; + std::string filename = RsDirUtil::getTopDir(path); uint64_t size = 0; RsFileHash hash ; - - rsGxsChannels->ExtraFileHash(path, filename); + rsGxsChannels->ExtraFileHash(path); // Only path and filename are valid. // Destroyed when fileFrame (this subfileitem) is destroyed diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp index 7e9217a82..774394bcf 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp @@ -112,11 +112,11 @@ void GxsForumsFillThread::run() service->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds); /* wait for the answer */ - uint32_t requestStatus = RsTokenService::GXS_REQUEST_V2_STATUS_PENDING; + uint32_t requestStatus = RsTokenService::PENDING; while (!wasStopped()) { requestStatus = service->requestStatus(token); - if (requestStatus == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED || - requestStatus == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) { + if (requestStatus == RsTokenService::FAILED || + requestStatus == RsTokenService::COMPLETE) { break; } msleep(100); @@ -132,7 +132,7 @@ void GxsForumsFillThread::run() return; } - if (requestStatus == RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) { + if (requestStatus == RsTokenService::FAILED) { //#TODO return; } diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index a7885922c..b2ffd555b 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -191,7 +191,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) std::cerr << std::endl; #endif - connect(ui.discComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); connect(ui.netModeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); connect(ui.localAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); @@ -231,6 +230,10 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) QObject::connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode())); QObject::connect(ui.serverCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode())); + + // when the network menu is opened and the hidden service tab is already selected updateOutProxyIndicator() won't be called and thus resulting in wrong proxy indicators. + if (ui.tabWidget->currentIndex() == TAB_HIDDEN_SERVICE) + updateOutProxyIndicator(); } void ServerPage::saveAndTestInProxy() diff --git a/retroshare-gui/src/gui/settings/WebuiPage.cpp b/retroshare-gui/src/gui/settings/WebuiPage.cpp index aea611312..1d2dd6013 100644 --- a/retroshare-gui/src/gui/settings/WebuiPage.cpp +++ b/retroshare-gui/src/gui/settings/WebuiPage.cpp @@ -22,6 +22,9 @@ resource_api::ApiServerMHD* WebuiPage::apiServerMHD = 0; resource_api::ApiServerLocal* WebuiPage::apiServerLocal = 0; #endif resource_api::RsControlModule* WebuiPage::controlModule = 0; +#ifdef RS_JSONAPI +JsonApiServer* WebuiPage::jsonApiServer = nullptr; +#endif WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) { @@ -105,6 +108,11 @@ QString WebuiPage::helpText() const // TODO: LIBRESAPI_LOCAL_SERVER Move in appropriate place #ifdef LIBRESAPI_LOCAL_SERVER apiServerLocal = new resource_api::ApiServerLocal(apiServer, resource_api::ApiServerLocal::serverPath()); +#endif +#ifdef RS_JSONAPI + // Use same port of libresapi + 2 + jsonApiServer = new JsonApiServer(Settings->getWebinterfacePort() + 2); + jsonApiServer->start("WebuiPage::jsonApiServer"); #endif return ok; } @@ -126,6 +134,10 @@ QString WebuiPage::helpText() const delete controlModule; controlModule = 0; } +#ifdef RS_JSONAPI + delete jsonApiServer; + jsonApiServer = nullptr; +#endif } /*static*/ void WebuiPage::showWebui() diff --git a/retroshare-gui/src/gui/settings/WebuiPage.h b/retroshare-gui/src/gui/settings/WebuiPage.h index 66af0327b..78961c98d 100644 --- a/retroshare-gui/src/gui/settings/WebuiPage.h +++ b/retroshare-gui/src/gui/settings/WebuiPage.h @@ -3,6 +3,10 @@ #include #include "ui_WebuiPage.h" +#ifdef RS_JSONAPI +# include "jsonapi/jsonapi.h" +#endif + namespace resource_api{ class ApiServer; class ApiServerMHD; @@ -55,4 +59,7 @@ private: static resource_api::ApiServerLocal* apiServerLocal; #endif static resource_api::RsControlModule* controlModule; +#ifdef RS_JSONAPI + static JsonApiServer* jsonApiServer; +#endif }; diff --git a/retroshare-gui/src/util/TokenQueue.cpp b/retroshare-gui/src/util/TokenQueue.cpp index 3fa5e7ced..2fc453aa7 100644 --- a/retroshare-gui/src/util/TokenQueue.cpp +++ b/retroshare-gui/src/util/TokenQueue.cpp @@ -164,8 +164,8 @@ bool TokenQueue::checkForRequest(uint32_t token) { /* check token */ uint32_t status = mService->requestStatus(token); - return ( (RsTokenService::GXS_REQUEST_V2_STATUS_FAILED == status) || - (RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE == status) ); + return ( (RsTokenService::FAILED == status) || + (RsTokenService::COMPLETE == status) ); } bool TokenQueue::activeRequestExist(const uint32_t& userType) const diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index 65d8c6168..527c480df 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -48,6 +48,11 @@ #include "TerminalApiClient.h" #endif +#ifdef RS_JSONAPI +# include +# include "jsonapi/jsonapi.h" +#endif // RS_JSONAPI + /* Basic instructions for running libretroshare as background thread. * ******************************************************************* * * This allows your program to communicate with authenticated peers. @@ -60,6 +65,32 @@ int main(int argc, char **argv) { +#ifdef RS_JSONAPI + JsonApiServer* jsonApiServer = nullptr; + uint16_t jsonApiPort = 0; + + { + argstream jsonApiArgs(argc, argv); + jsonApiArgs >> parameter( + "jsonApiPort", jsonApiPort, "jsonApiPort", + "Enable JSON API on the specified port", false ); + jsonApiArgs >> help('h', "help", "Display this Help"); + + if (jsonApiArgs.helpRequested()) + std::cerr << jsonApiArgs.usage() << std::endl; + } + + if(jsonApiPort) + { + jsonApiServer = new JsonApiServer( jsonApiPort, [](int /*ec*/) + { + std::raise(SIGTERM); + } ); + + jsonApiServer->start("JSON API Server"); + } +#endif // RS_JSONAPI + #ifdef ENABLE_WEBUI std::string docroot = resource_api::getDefaultDocroot(); diff --git a/retroshare.pri b/retroshare.pri index 5f54fd123..f622bed80 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -134,6 +134,11 @@ rs_macos10.9:CONFIG -= rs_macos10.11 rs_macos10.10:CONFIG -= rs_macos10.11 rs_macos10.12:CONFIG -= rs_macos10.11 +# To enable JSON API append the following assignation to qmake command line +# "CONFIG+=rs_jsonapi" +CONFIG *= no_rs_jsonapi +rs_jsonapi:CONFIG -= no_rs_jsonapi + # To disable deep search append the following assignation to qmake command line CONFIG+=no_rs_deep_search CONFIG *= rs_deep_search @@ -181,7 +186,7 @@ rs_v07_changes { } ################################################################################ -## RetroShare qmake functions goes here as all the rest may use them ########### +## RetroShare qmake functions goes here as all the rest may use them. ########## ################################################################################ ## Qt versions older the 5 are not supported anymore, check if the user is @@ -298,7 +303,12 @@ no_sqlcipher { rs_autologin { DEFINES *= RS_AUTOLOGIN - warning("You have enabled RetroShare auto-login, this is discouraged. The usage of auto-login on some linux distributions may allow someone having access to your session to steal the SSL keys of your node location and therefore compromise your security") + RS_AUTOLOGIN_WARNING_MSG = \ + You have enabled RetroShare auto-login, this is discouraged. The usage \ + of auto-login on some linux distributions may allow someone having \ + access to your session to steal the SSL keys of your node location and \ + therefore compromise your security + warning("$${RS_AUTOLOGIN_WARNING_MSG}") } rs_onlyhiddennode { @@ -338,6 +348,10 @@ rs_chatserver { DEFINES *= RS_CHATSERVER } +rs_jsonapi { + DEFINES *= RS_JSONAPI +} + rs_deep_search { DEFINES *= RS_DEEP_SEARCH diff --git a/supportlibs/restbed b/supportlibs/restbed new file mode 160000 index 000000000..c27c6726d --- /dev/null +++ b/supportlibs/restbed @@ -0,0 +1 @@ +Subproject commit c27c6726d28c42e2e1b7537ba63eeb23e944789d diff --git a/tests/unittests/libretroshare/gxs/gen_exchange/genexchangetester.cc b/tests/unittests/libretroshare/gxs/gen_exchange/genexchangetester.cc index 6fb4cae2a..9d000d443 100644 --- a/tests/unittests/libretroshare/gxs/gen_exchange/genexchangetester.cc +++ b/tests/unittests/libretroshare/gxs/gen_exchange/genexchangetester.cc @@ -42,7 +42,7 @@ void GenExchangeTest::pollForToken(uint32_t token, const RsTokReqOptions &opts, Sleep((int) (timeDelta * 1000)); #endif - if((RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE == mTokenService->requestStatus(token))) + if((RsTokenService::COMPLETE == mTokenService->requestStatus(token))) { switch(opts.mReqType) { @@ -81,7 +81,7 @@ void GenExchangeTest::pollForToken(uint32_t token, const RsTokReqOptions &opts, } break; } - else if(RsTokenService::GXS_REQUEST_V2_STATUS_FAILED == mTokenService->requestStatus(token)) + else if(RsTokenService::FAILED == mTokenService->requestStatus(token)) { mTokenService->cancelRequest(token); break; @@ -108,12 +108,12 @@ bool GenExchangeTest::pollForMsgAcknowledgement(uint32_t token, Sleep((int) (timeDelta * 1000)); #endif - if((RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE == mTokenService->requestStatus(token))) + if((RsTokenService::COMPLETE == mTokenService->requestStatus(token))) { mTestService->acknowledgeTokenMsg(token, msgId); return true; } - else if(RsTokenService::GXS_REQUEST_V2_STATUS_FAILED == mTokenService->requestStatus(token)) + else if(RsTokenService::FAILED == mTokenService->requestStatus(token)) { mTokenService->cancelRequest(token); return false; @@ -146,12 +146,12 @@ bool GenExchangeTest::pollForGrpAcknowledgement(uint32_t token, Sleep((int) (timeDelta * 1000)); #endif - if((RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE == mTokenService->requestStatus(token))) + if((RsTokenService::COMPLETE == mTokenService->requestStatus(token))) { mTestService->acknowledgeTokenGrp(token, grpId); return true; } - else if(RsTokenService::GXS_REQUEST_V2_STATUS_FAILED == mTokenService->requestStatus(token)) + else if(RsTokenService::FAILED == mTokenService->requestStatus(token)) { mTokenService->cancelRequest(token); return false; diff --git a/tests/unittests/libretroshare/services/gxs/GxsPeerNode.cc b/tests/unittests/libretroshare/services/gxs/GxsPeerNode.cc index 5e8439af8..3be7cd392 100644 --- a/tests/unittests/libretroshare/services/gxs/GxsPeerNode.cc +++ b/tests/unittests/libretroshare/services/gxs/GxsPeerNode.cc @@ -242,7 +242,7 @@ bool GxsPeerNode::createIdentity(const std::string &name, return false; } - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -316,7 +316,7 @@ bool GxsPeerNode::createCircle(const std::string &name, uint32_t token; mGxsCircles->createGroup(token, grp1) ; - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -371,7 +371,7 @@ bool GxsPeerNode::createGroup(const std::string &name, return false; } - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -402,7 +402,7 @@ bool GxsPeerNode::createMsg(const std::string &msgstr, return false; } - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -430,7 +430,7 @@ bool GxsPeerNode::subscribeToGroup(const RsGxsGroupId &groupId, bool subscribe) return false; } - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -453,7 +453,7 @@ bool GxsPeerNode::getGroups(std::vector &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -475,7 +475,7 @@ bool GxsPeerNode::getGroupList(std::list &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_LIST, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -500,7 +500,7 @@ bool GxsPeerNode::getMsgList(const RsGxsGroupId &id, std::list & grpIds.push_back(id); tokenService->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_LIST, opts, grpIds); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -533,7 +533,7 @@ bool GxsPeerNode::getIdentities(std::vector &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -553,7 +553,7 @@ bool GxsPeerNode::getIdentitiesList(std::list &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_LIST, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -575,7 +575,7 @@ bool GxsPeerNode::getCircles(std::vector &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); @@ -595,7 +595,7 @@ bool GxsPeerNode::getCirclesList(std::list &groups) uint32_t token; tokenService->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_LIST, opts); - while(tokenService->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token) != RsTokenService::COMPLETE) { tick(); sleep(1); diff --git a/tests/unittests/libretroshare/services/gxs/nxsbasic_test.cc b/tests/unittests/libretroshare/services/gxs/nxsbasic_test.cc index 078eba249..9c4069c80 100644 --- a/tests/unittests/libretroshare/services/gxs/nxsbasic_test.cc +++ b/tests/unittests/libretroshare/services/gxs/nxsbasic_test.cc @@ -118,14 +118,14 @@ TEST(libretroshare_services, DISABLED_GXS_nxs_basic2) uint32_t token2; ASSERT_TRUE(testService->submitTestGroup(token1, grp1)); - while(tokenService->requestStatus(token1) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token1) != RsTokenService::COMPLETE) { tester.tick(); sleep(1); } ASSERT_TRUE(testService->submitTestGroup(token2, grp2)); - while(tokenService->requestStatus(token2) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + while(tokenService->requestStatus(token2) != RsTokenService::COMPLETE) { tester.tick(); sleep(1);