Merge pull request #1289 from G10h4ck/jsonapi

Implement automatic JSON API generation
This commit is contained in:
csoler 2018-08-28 19:11:08 +02:00 committed by GitHub
commit c294971633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 3813 additions and 962 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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<std::string>+. 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<void (const RsGxsGroupSummary& result)>& 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<void (...)>+ 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

View File

@ -0,0 +1,73 @@
/*
* RetroShare JSON API
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
registerHandler("$%apiPath%$",
[$%captureVars%$](const std::shared_ptr<rb::Session> session)
{
const std::multimap<std::string, std::string> 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<rb::Session> session,
const rb::Bytes& body )
{
RsGenericSerializer::SerializeContext cReq(
nullptr, 0,
RsGenericSerializer::SERIALIZATION_FLAG_YIELDING );
RsJson& jReq(cReq.mJson);
jReq.Parse(reinterpret_cast<const char*>(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%$
} );
});

View File

@ -0,0 +1,229 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libretroshare"
ALIASES += jsonapi{1}="\xmlonly<jsonapi minversion=\"\1\"/>\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

View File

@ -0,0 +1,364 @@
/*
* RetroShare JSON API
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QCoreApplication>
#include <QDebug>
#include <QtXml>
#include <QDirIterator>
#include <QFileInfo>
#include <iterator>
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<QString> 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<QString,MethodParam> 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<QString,QString> 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<QString,QString>::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;
}

View File

@ -0,0 +1,6 @@
TARGET = jsonapi-generator
QT *= core xml
QT -= gui
SOURCES += jsonapi-generator.cpp

View File

@ -0,0 +1,64 @@
/*
* RetroShare JSON API
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
registerHandler("$%apiPath%$",
[$%captureVars%$](const std::shared_ptr<rb::Session> session)
{
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
RsGenericSerializer::SerializeContext cReq(
nullptr, 0,
RsGenericSerializer::SERIALIZATION_FLAG_YIELDING );
RsJson& jReq(cReq.mJson);
jReq.Parse(reinterpret_cast<const char*>(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<std::string, std::string> headers
{
{ "Content-Type", "text/json" },
{ "Content-Length", std::to_string(ans.length()) }
};
session->close(rb::OK, ans, headers);
} );
});

View File

@ -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<RsGroupMetaData> 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<RsGxsChannelGroup> 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<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
if( mChannels.getTokenService()->requestStatus(token) ==
RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE &&
RsTokenService::COMPLETE &&
mChannels.getPostData(token, posts, comments) )
{
for( std::vector<RsGxsChannelPost>::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!");
}

View File

@ -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<RsGxsForumMsg> 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<RsGxsForumGroup> grps;
ok &= mRsGxsForums->getGroupData(token, grps);

View File

@ -42,11 +42,11 @@ bool GxsResponseTask::doWork(Request &req, Response &resp)
for(std::vector<uint32_t>::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.");

View File

@ -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<RsGxsIdGroup> 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<RsGxsIdGroup> 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<RsGxsIdGroup> 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)))
)
{

View File

@ -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;
@ -1822,9 +1824,21 @@ int ftServer::handleIncoming()
void ftServer::receiveSearchResult(RsTurtleFTSearchResultItem *item)
{
// @Gio: add your thing here
bool hasCallback = false;
RsServer::notify()->notifyTurtleSearchResult(item->request_id,item->result) ;
{
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->request_id, item->result );
}
/***************************** CONFIG ****************************/
@ -1839,3 +1853,38 @@ bool ftServer::addConfiguration(p3ConfigMgr *cfgmgr)
return true;
}
bool ftServer::turtleSearchRequest(
const std::string& matchString,
const std::function<void (const std::list<TurtleFileInfo>& 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;
}

View File

@ -39,6 +39,8 @@
#include <map>
#include <list>
#include <iostream>
#include <functional>
#include <chrono>
#include "ft/ftdata.h"
#include "turtle/turtleclientservice.h"
@ -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<void (const std::list<TurtleFileInfo>& results)>& multiCallback,
std::time_t maxWait = 300 );
virtual TurtleSearchRequestId turtleSearch(const std::string& string_to_match) ;
virtual TurtleSearchRequestId turtleSearch(const RsRegularExpression::LinearizedExpression& expr) ;
@ -205,8 +213,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();
@ -313,6 +321,18 @@ private:
std::map<RsFileHash,RsFileHash> mEncryptedHashes ; // This map is such that sha1(it->second) = it->first
std::map<RsPeerId,RsFileHash> mEncryptedPeerIds ; // This map holds the hash to be used with each peer id
std::map<RsPeerId,std::map<RsFileHash,time_t> > mUploadLimitMap ;
/** Store search callbacks with timeout*/
std::map<
TurtleRequestId,
std::pair<
std::function<void (const std::list<TurtleFileInfo>& results)>,
std::chrono::system_clock::time_point >
> mSearchCallbacksMap;
RsMutex mSearchCallbacksMapMutex;
/// Cleanup mSearchCallbacksMap
void cleanTimedOutSearches();
};

View File

@ -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;

View File

@ -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<bool, RsGxsGroupId> 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);
}

View File

@ -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

View File

@ -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::list<const RsG
<< "group summary" << std::endl;
return false;
}
else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE)
else if(req->status == COMPLETE)
{
GroupMetaReq* gmreq = dynamic_cast<GroupMetaReq*>(req);
@ -396,7 +387,7 @@ bool RsGxsDataAccess::getGroupSummary(const uint32_t& token, std::list<const RsG
{
groupInfo = gmreq->mGroupMetaData;
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<RsNxsGrp*>&
<< "data" << std::endl;
return false;
}
else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE)
else if(req->status == COMPLETE)
{
GroupDataReq* gmreq = dynamic_cast<GroupDataReq*>(req);
GroupSerializedDataReq* gsreq = dynamic_cast<GroupSerializedDataReq*>(req);
@ -437,13 +428,13 @@ bool RsGxsDataAccess::getGroupData(const uint32_t& token, std::list<RsNxsGrp*>&
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<MsgDataReq*>(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<MsgRelatedInfoReq*>(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<MsgMetaReq*>(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<MsgIdReq*>(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::list<RsGxsGroupId
std::cerr << "RsGxsDataAccess::getGroupList() Unable to retrieve group Ids,"
"\nRequest does not exist" << std::endl;
return false;
}else if(req->status == GXS_REQUEST_V2_STATUS_COMPLETE){
}else if(req->status == COMPLETE){
GroupIdReq* gireq = dynamic_cast<GroupIdReq*>(req);
@ -697,7 +688,7 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::list<RsGxsGroupId
{
groupIds.swap(gireq->mGroupIdResult);
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<GroupStatisticRequest*>(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<ServiceStatisticRequest*>(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<RsGxsGroupId> &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,29 +1836,25 @@ void RsGxsDataAccess::tokenList(std::list<uint32_t>& 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;
@ -1875,40 +1862,26 @@ uint32_t RsGxsDataAccess::generatePublicToken()
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<uint32_t, uint32_t>::iterator mit = mPublicToken.find(token);
if(mit != mPublicToken.end())
{
mit->second = status;
}
else
{
return false;
}
RS_STACK_MUTEX(mDataMutex);
std::map<uint32_t, RsTokenService::GxsRequestStatus>::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<uint32_t, uint32_t>::iterator mit = mPublicToken.find(token);
if(mit != mPublicToken.end())
{
mPublicToken.erase(mit);
}
else
{
return false;
}
RS_STACK_MUTEX(mDataMutex);
std::map<uint32_t, RsTokenService::GxsRequestStatus>::iterator mit =
mPublicToken.find(token);
if(mit != mPublicToken.end()) mPublicToken.erase(mit);
else return false;
return true;
}

View File

@ -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<uint32_t, uint32_t> mPublicToken;
std::map<uint32_t, GxsRequestStatus> mPublicToken;
std::map<uint32_t, GxsRequest*> mRequests;

View File

@ -5181,10 +5181,14 @@ bool RsGxsNetService::clearDistantSearchResults(const TurtleRequestId& id)
}
void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req, const std::list<RsGxsGroupSummary>& group_infos)
{
RS_STACK_MUTEX(mNxsMutex) ;
std::set<RsGxsGroupId> groupsToNotifyResults;
{
RS_STACK_MUTEX(mNxsMutex);
RsGxsGrpMetaTemporaryMap grpMeta;
std::map<RsGxsGroupId,RsGxsGroupSummary>& search_results_map(mDistantSearchResults[req]) ;
std::map<RsGxsGroupId,RsGxsGroupSummary>&
search_results_map(mDistantSearchResults[req]);
for(auto it(group_infos.begin());it!=group_infos.end();++it)
if(search_results_map.find((*it).mGroupId) == search_results_map.end())
@ -5192,32 +5196,36 @@ void RsGxsNetService::receiveTurtleSearchResults(TurtleRequestId req, const std:
mDataStore->retrieveGxsGrpMetaData(grpMeta);
std::list<RsGxsGroupSummary> filtered_results ;
// 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) ;
const RsGxsGroupId& grpId((*it).mGroupId);
auto it2 = search_results_map.find((*it).mGroupId) ;
groupsToNotifyResults.insert(grpId);
auto it2 = search_results_map.find(grpId);
if(it2 != search_results_map.end())
{
// update existing data
it2->second.mPopularity++ ;
it2->second.mNumberOfMessages = std::max(it2->second.mNumberOfMessages,(*it).mNumberOfMessages) ;
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
search_results_map[grpId] = *it;
search_results_map[grpId].mPopularity = 1; // number of results so far
}
}
} // end RS_STACK_MUTEX(mNxsMutex);
mObserver->receiveDistantSearchResults(req,(*it).mGroupId) ;
}
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)

View File

@ -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

View File

@ -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),
RsGxsTrans(static_cast<RsGxsIface&>(*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();

View File

@ -19,7 +19,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdexcept>
#include <time.h>

View File

@ -0,0 +1,145 @@
/*
* RetroShare JSON API
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "jsonapi.h"
#include <sstream>
#include <memory>
#include <restbed>
#include <vector>
#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<void(int)> shutdownCallback) :
mPort(port), mShutdownCallback(shutdownCallback)
{
registerHandler("/jsonApiServer/shutdown",
[this](const std::shared_ptr<rb::Session>)
{
shutdown();
});
registerHandler("/rsFiles/getFileData",
[](const std::shared_ptr<rb::Session> session)
{
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
RsGenericSerializer::SerializeContext cReq(
nullptr, 0,
RsGenericSerializer::SERIALIZATION_FLAG_YIELDING );
RsJson& jReq(cReq.mJson);
jReq.Parse(reinterpret_cast<const char*>(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<uint8_t> 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<std::string, std::string> 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<rb::Settings> 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<void (const std::shared_ptr<restbed::Session>)>& handler)
{
std::shared_ptr<restbed::Resource> 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);
}

View File

@ -0,0 +1,73 @@
/*
* RetroShare JSON API
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <memory>
#include <restbed>
#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<void(int)> 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<restbed::Session> session)
* \endcode
*/
void registerHandler(
const std::string& path,
const std::function<void(const std::shared_ptr<rb::Session>)>& 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<void(int)> mShutdownCallback;
};

View File

@ -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.

View File

@ -19,7 +19,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#ifdef WINDOWS_SYS

View File

@ -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()

View File

@ -82,8 +82,8 @@ public:
class AuthGPGService
{
public:
AuthGPGService() {};
~AuthGPGService() {};
AuthGPGService() {}
~AuthGPGService() {}
virtual AuthGPGOperation *getGPGOperation() = 0;
virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
@ -91,9 +91,8 @@ public:
class AuthGPG: public p3Config, public RsTickingThread, public PGPHandler
{
public:
static void init( const std::string& path_to_pubring,
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);

View File

@ -19,18 +19,25 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef RS_FILES_GUI_INTERFACE_H
#define RS_FILES_GUI_INTERFACE_H
#pragma once
#include <list>
#include <iostream>
#include <string>
#include <functional>
#include <chrono>
#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<RsNodeGroupId>& l1,const std::list<RsNodeGroupId>& 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<RsNodeGroupId> parent_groups ;
std::string filename;
std::string virtualname;
/// combnation of DIR_FLAGS_ANONYMOUS_DOWNLOAD | DIR_FLAGS_BROWSABLE | ...
FileStorageFlags shareflags;
std::list<RsNodeGroupId> 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
@ -169,37 +188,127 @@ public:
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.
* 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
*
* 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
* @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;
/***
* Control of Downloads.
***/
virtual bool getFileData( const RsFileHash& hash, uint64_t offset,
uint32_t& requested_size, uint8_t* data ) = 0;
/**
* @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;
/// 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<RsPeerId>& srcIds) = 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<RsPeerId>& 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;
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;
/**
* @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;
virtual uint32_t freeDiskSpaceLimit() const =0;
virtual void setFreeDiskSpaceLimit(uint32_t size_in_mb) =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 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
@ -208,8 +317,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<void (const std::list<TurtleFileInfo>& 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.
@ -220,21 +345,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<DwlDetails> & details) = 0;
/***
* Download / Upload Details.
***/
virtual void FileDownloads(std::list<RsFileHash> &hashs) = 0;
virtual bool FileUploads(std::list<RsFileHash> &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<RsFileHash>& 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<RsFileHash>& 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
@ -275,15 +435,75 @@ 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;
/**
* @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;
/**
* @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<SharedDirInfo>& 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<SharedDirInfo>& 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;
virtual bool updateShareFlags(const SharedDirInfo& dir) = 0; // updates the flags. The directory should already exist !
/**
* @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<std::string>& ignored_prefixes, std::list<std::string>& ignored_suffixes,uint32_t& flags) =0;
@ -306,8 +526,4 @@ public:
virtual bool ignoreDuplicates() = 0;
virtual void setIgnoreDuplicates(bool ignore) = 0;
};
#endif

View File

@ -1,9 +1,11 @@
#pragma once
/*******************************************************************************
* libretroshare/src/retroshare: rsgxschannels.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2012-2012 by Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef RETROSHARE_GXS_CHANNEL_GUI_INTERFACE_H
#define RETROSHARE_GXS_CHANNEL_GUI_INTERFACE_H
#include <inttypes.h>
#include <string>
#include <list>
#include <functional>
#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<RsGxsMessageId> mOlderVersions ;
std::set<RsGxsMessageId> mOlderVersions;
std::string mMsg; // UTF8 encoded.
std::list<RsGxsFile> mFiles;
@ -64,25 +78,216 @@ 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<RsGroupMetaData>& 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<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelGroup>& 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<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& 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<RsGxsChannelGroup> &groups) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts, std::vector<RsGxsComment> &cmts) = 0;
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &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<RsPeerId>& 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<void (const RsGxsGroupSummary& result)>& 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<RsPeerId>& 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

View File

@ -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;

View File

@ -31,37 +31,55 @@
#include <list>
#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(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<RsGxsVote> 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");

View File

@ -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 */

View File

@ -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<RsGxsGroupId, std::set<RsGxsMessageId> > 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

View File

@ -7,6 +7,7 @@
* RetroShare GXS. Convenience interface implementation
*
* Copyright 2012 by Christopher Evi-Parker
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
*
* 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 <chrono>
#include <thread>
#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)
* @param gxs handle to RsGenExchange instance of service (Usually the
* service class itself)
*/
RsGxsIfaceHelper(RsGxsIface* gxs)
: mGxs(gxs)
{}
RsGxsIfaceHelper(RsGxsIface& gxs) :
mGxs(gxs), mTokenService(*gxs.getTokenService()) {}
~RsGxsIfaceHelper(){}
@ -59,15 +61,7 @@ public:
*/
void receiveChanges(std::vector<RsGxsNotify *> &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<RsGxsGroupId> &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<RsGroupMetaData> &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<RsGxsGroupId, RsGxsMessageId>& 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<RsGxsGroupId> &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<RsGxsGroupId>& grpIds )
{ return mTokenService.requestMsgInfo(token, 0, opts, grpIds); }
/// @see RsTokenService::requestMsgRelatedInfo
bool requestMsgRelatedInfo(
uint32_t& token, const RsTokReqOptions& opts,
const std::vector<RsGxsGrpMsgIdPair>& 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

View File

@ -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

View File

@ -91,7 +91,7 @@ public:
std::vector<RsGxsTransOutgoingRecord> outgoing_records;
};
RsGxsTrans(RsGxsIface *gxs) : RsGxsIfaceHelper(gxs) {}
RsGxsTrans(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {}
virtual ~RsGxsTrans() {}

View File

@ -339,7 +339,7 @@ struct RsIdentityDetails : RsSerializable
struct RsIdentity : RsGxsIfaceHelper
{
explicit RsIdentity(RsGxsIface *gxs): RsGxsIfaceHelper(gxs) {}
explicit RsIdentity(RsGxsIface& gxs): RsGxsIfaceHelper(gxs) {}
virtual ~RsIdentity() {}
/********************************************************************************************/

View File

@ -43,26 +43,43 @@
#include <vector>
#include <retroshare/rstypes.h>
struct RsLoginHelper;
/**
* Pointer to global instance of RsLoginHelper
* @jsonapi{development}
*/
extern RsLoginHelper* rsLoginHelper;
/*!
* Initialisation Class (not publicly disclosed to RsIFace)
*/
class RsInit
{
public:
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?
};
/* reorganised RsInit system */
/*!
* PreLogin
* Call before init retroshare, initialises rsinitconfig's public attributes
*/
static void InitRsConfig() ;
static void InitRsConfig();
/*!
* 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
* @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);
@ -71,16 +88,14 @@ class RsInit
static bool isWindowsXP();
static bool collectEntropy(uint32_t bytes) ;
/*!
/*
* 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()
@ -88,12 +103,10 @@ class RsInit
* 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 LoadCertificateStatus LockAndLoadCertificates(
bool autoLoginNT, std::string& lockFilePath );
// Post Login Options
static bool getStartMinimised();
static int getSslPwdLen();
@ -101,22 +114,18 @@ class RsInit
static void setAutoLogin(bool autoLogin);
static bool RsClearAutoLogin() ;
private:
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);
#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);
/// @brief Unlock profile directory
static void UnlockConfigDirectory();
/* The true LoadCertificates() method */
static int LoadCertificates(bool autoLoginNT) ;
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<RsLoginHelper::Location>& 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

View File

@ -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,7 +310,8 @@ public:
// this defines from which peer the status string came from
RsPeerId broadcast_status_peer_id;
private:
enum Type { TYPE_NOT_SET,
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
@ -321,6 +322,16 @@ private:
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,17 +351,27 @@ public:
//bool system_message;
};
class ChatLobbyInvite
class ChatLobbyInvite : RsSerializable
{
public:
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){}
@ -363,12 +384,25 @@ public:
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:
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
@ -376,13 +410,31 @@ class ChatLobbyInfo
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<RsGxsId,time_t> gxs_ids ; // list of non direct friend who participate. Used to display only.
std::map<RsGxsId, time_t> 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<ChatLobbyId>& 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<VisibleChatLobbyRecord>& 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<ChatLobbyInvite>& 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<RsPeerId>& 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<ChatLobbyId> &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<VisibleChatLobbyRecord> &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<ChatLobbyInvite> &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<RsPeerId> &invited_friends, ChatLobbyFlags lobby_privacy_type) = 0 ;
/****************************************/
/* Distant chat */

View File

@ -181,7 +181,7 @@ class RsFeedItem
// This mechanism can be used in plugins, new services, etc.
//
class NotifyClient ;
class NotifyClient;
class RsNotify
{
@ -208,7 +208,7 @@ class RsNotify
class NotifyClient
{
public:
public:
NotifyClient() {}
virtual ~NotifyClient() {}
@ -244,6 +244,5 @@ class NotifyClient
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

View File

@ -293,7 +293,7 @@ public:
std::string cipher_version;
};
class RsGroupInfo
class RsGroupInfo : RsSerializable
{
public:
RsGroupInfo();
@ -303,6 +303,15 @@ public:
uint32_t flag;
std::set<RsPgpId> 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);

View File

@ -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 */

View File

@ -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 */
/*!
* @brief 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
* 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

View File

@ -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

View File

@ -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
/// @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,7 +92,9 @@ enum QueueMove { QUEUE_TOP = 0x00,
QUEUE_BOTTOM = 0x03
};
enum DwlSpeed { SPEED_LOW = 0x00,
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(); */
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 avail; /// how much we have
double rank;
int age;
uint32_t queue_position ;
uint32_t queue_position;
/* Transfer Stuff */
uint64_t transfered;
double tfRate; /* in kbytes */
uint32_t downloadStatus; // FT_STATE_DOWNLOADING & co. See rstypes.h
double tfRate; /// in kbytes
uint32_t downloadStatus; /// FT_STATE_DOWNLOADING & co. See rstypes.h
std::vector<TransferInfo> peers;
DwlSpeed priority ;
DwlSpeed priority;
time_t lastTS;
std::list<RsNodeGroupId> parent_groups ;
std::list<RsNodeGroupId> 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
};
enum ChunkStrategy : uint8_t
{
CHUNK_STRATEGY_STREAMING,
CHUNK_STRATEGY_RANDOM,
CHUNK_STRATEGY_PROGRESSIVE
};
struct SliceInfo
{
uint32_t start ;
uint32_t size ;
RsPeerId peer_id ;
uint32_t start;
uint32_t size;
RsPeerId peer_id;
};
uint64_t file_size ; // real size of the file
uint32_t chunk_size ; // size of chunks
uint32_t strategy ;
uint64_t file_size; /// real size of the file
uint32_t chunk_size; /// size of chunks
ChunkStrategy strategy;
// dl state of chunks. Only the last chunk may have size < chunk_size
std::vector<ChunkState> chunks ;
/// dl state of chunks. Only the last chunk may have size < chunk_size
std::vector<ChunkState> chunks;
// For each source peer, gives the compressed bit map of have/don't have sate
std::map<RsPeerId, CompressedChunkMap> compressed_peer_availability_maps ;
/// For each source peer, gives the compressed bit map of have/don't have sate
std::map<RsPeerId, CompressedChunkMap> compressed_peer_availability_maps;
// For each chunk (by chunk number), gives the completion of the chunk.
//
std::vector<std::pair<uint32_t,uint32_t> > active_chunks ;
/// For each chunk (by chunk number), gives the completion of the chunk.
std::vector<std::pair<uint32_t,uint32_t> > active_chunks;
// The list of pending requests, chunk per chunk (by chunk id)
//
std::map<uint32_t, std::vector<SliceInfo> > pending_slices ;
/// The list of pending requests, chunk per chunk (by chunk id)
std::map<uint32_t, std::vector<SliceInfo> > 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

View File

@ -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<RsWikiCollection> &collections) = 0;

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -101,6 +101,8 @@ RsDht *rsDht = NULL ;
//std::map<std::string,std::vector<std::string> > RsInit::unsupported_keys ;
RsLoginHelper* rsLoginHelper;
class RsInitConfig
{
public:
@ -431,6 +433,8 @@ int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */)
AuthSSL::AuthSSLInit();
AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL, "");
rsLoginHelper = new RsLoginHelper;
int error_code ;
if(!RsAccounts::init(opt_base_dir,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<RsLoginHelper::Location>& store)
{
std::list<RsPeerId> 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);
}

View File

@ -247,6 +247,7 @@ bool getRawString(const void *data, uint32_t size, uint32_t *offset, std::string
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;
print_stacktrace();
return false;
}
uint8_t *buf = &(((uint8_t *) data)[*offset]);

View File

@ -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();
}
}
}

View File

@ -151,20 +151,14 @@
#include <string.h>
#include <iostream>
#include <string>
#ifdef HAS_RAPIDJSON
#include <rapidjson/document.h>
#else
#include <rapid_json/document.h>
#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.

View File

@ -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 <iomanip>
@ -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<uint8_t*>(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<rapidjson::StringBuffer> 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<uint8_t> 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;
}

View File

@ -31,18 +31,14 @@
#include "serialiser/rsserializer.h"
#include "serialiser/rsserializable.h"
#include "util/rsjson.h"
#ifdef HAS_RAPIDJSON
#include <rapidjson/document.h>
#else
#include <rapid_json/document.h>
#endif // HAS_RAPIDJSON
#include <typeinfo> // for typeid
#include <type_traits>
#include <errno.h>
/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
/* INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
* 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}<T>
/* INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
* Can't use a template function because std::{vector,list,set}<T> 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
{
@ -135,7 +134,7 @@ struct RsTypeSerializer
typename std::enable_if<std::is_same<RsTlvItem,T>::value || !(std::is_base_of<RsSerializable,T>::value || std::is_enum<T>::value || std::is_base_of<RsTlvItem,T>::value)>::type
static /*void*/ serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx,
T& member, const std::string& member_name)
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<T>(j, kCtx, const_cast<T&>(kv.first), "key");
RsGenericSerializer::SerializeContext vCtx(
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
&allocator );
nullptr, 0, ctx.mFlags, &allocator );
serial_process<U>(j, vCtx, const_cast<U&>(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<T,U>(key,value));
else break;
}
}
else
{
ctx.mOk = false;
}
break;
}
default:
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
<< std::endl;
exit(EINVAL);
}
}
/// std::pair<T,U>
template<typename T, typename U>
static void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx,
std::pair<T,U>& 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<std::underlying_type<decltype(j)>::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<v.size();++i)
{
std::cerr << " " ;
@ -466,9 +549,12 @@ struct RsTypeSerializer
}
case RsGenericSerializer::PRINT:
{
if(v.empty()) std::cerr << " Empty set"<< std::endl;
else std::cerr << " Set of " << v.size() << " elements:"
if(v.empty())
std::cerr << " Empty set \"" << memberName << "\""
<< std::endl;
else
std::cerr << " Set of " << v.size() << " elements: \""
<< memberName << "\"" << std::endl;
break;
}
case RsGenericSerializer::TO_JSON:
@ -519,9 +605,12 @@ struct RsTypeSerializer
}
case RsGenericSerializer::PRINT:
{
if(v.empty()) std::cerr << " Empty list"<< std::endl;
else std::cerr << " List of " << v.size() << " elements:"
if(v.empty())
std::cerr << " Empty list \"" << memberName << "\""
<< std::endl;
else
std::cerr << " List of " << v.size() << " elements: \""
<< memberName << "\"" << std::endl;
break;
}
case RsGenericSerializer::TO_JSON:
@ -567,7 +656,9 @@ struct RsTypeSerializer
case RsGenericSerializer::FROM_JSON:
{
uint32_t f;
ctx.mOk = from_JSON(memberName, f, ctx.mJson);
ctx.mOk &=
(ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
&& from_JSON(memberName, f, ctx.mJson);
v = t_RsFlags32<N>(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)
{
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;
}

View File

@ -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<RsGxsIface&>(*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<RsGxsChannelGroup> &groups)
@ -392,10 +395,11 @@ bool p3GxsChannels::getGroupData(const uint32_t &token, std::vector<RsGxsChannel
return ok;
}
bool p3GxsChannels::groupShareKeys(const RsGxsGroupId &groupId, std::set<RsPeerId>& peers)
bool p3GxsChannels::groupShareKeys(
const RsGxsGroupId &groupId, const std::set<RsPeerId>& 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<RsGroupMetaData>& 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<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelGroup>& 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<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& 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<void (const RsGxsGroupSummary&)>& 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;
}

View File

@ -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<RsGxsNotify*>& 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<RsGxsChannelGroup> &groups);
virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &posts, std::vector<RsGxsComment> &cmts);
@ -96,7 +96,8 @@ virtual bool getPostData(const uint32_t &token, std::vector<RsGxsChannelPost> &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<RsPeerId>& peers) ;
virtual bool groupShareKeys(
const RsGxsGroupId &groupId, const std::set<RsPeerId>& 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<void (const RsGxsGroupSummary&)>& 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<RsGxsComment> &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<RsGroupMetaData>& channels);
/// Implementation of @see RsGxsChannels::getChannelsInfo
virtual bool getChannelsInfo(
const std::list<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelGroup>& channelsInfo );
/// Implementation of @see RsGxsChannels::getChannelContent
virtual bool getChannelsContent(
const std::list<RsGxsGroupId>& chanIds,
std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& 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();
@ -222,6 +250,18 @@ bool generateGroup(uint32_t &token, std::string groupName);
p3GxsCommentService *mCommentService;
std::map<RsGxsGroupId,time_t> mKnownChannels;
/** Store search callbacks with timeout*/
std::map<
TurtleRequestId,
std::pair<
std::function<void (const RsGxsGroupSummary&)>,
std::chrono::system_clock::time_point >
> mSearchCallbacksMap;
RsMutex mSearchCallbacksMapMutex;
/// Cleanup mSearchCallbacksMap
void cleanTimedOutSearches();
};
#endif

View File

@ -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),
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<RsGxsIface&>(*this)), GxsTokenQueue(this),
RsTickEvent(), mIdentities(identities), mPgpUtils(pgpUtils),
mCircleMtx("p3GxsCircles"),
mCircleCache(DEFAULT_MEM_CACHE_SIZE, "GxsCircleCache")
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<RsGxsIdGroup> ids;
if (!rsIdentity->getGroupData(mDummyIdToken, ids))

View File

@ -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

View File

@ -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<RsGxsIface&>(*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;

View File

@ -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<RsGxsIface&>(*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;
}

View File

@ -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<RsGxsIface&>(*this)) {}
const std::string GXS_POSTED_APP_NAME = "gxsposted";
const uint16_t GXS_POSTED_APP_MAJOR_VERSION = 1;

View File

@ -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;

View File

@ -1111,7 +1111,7 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item)
std::list<std::pair<RsTurtleSearchResultItem*,RsTurtleClientService*> > results_to_notify_off_mutex ;
{
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
RS_STACK_MUTEX(mTurtleMtx);
// Find who actually sent the corresponding request.
//
std::map<TurtleRequestId,TurtleSearchRequestInfo>::iterator it = _search_requests_origins.find(item->request_id) ;
@ -1176,7 +1176,7 @@ void p3turtle::handleSearchResult(RsTurtleSearchResultItem *item)
sendItem(fwd_item) ;
}
}
} // mTurtleMtx end
// now we notify clients off-mutex.

View File

@ -222,55 +222,6 @@ RsTurtleSearchResultItem *RsTurtleGenericSearchResultItem::duplicate() const
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") ;

View File

@ -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
}

View File

@ -0,0 +1,68 @@
/*******************************************************************************
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "util/rsjson.h"
#ifdef HAS_RAPIDJSON
# include <rapidjson/writer.h>
# include <rapidjson/stringbuffer.h>
# include <rapidjson/prettywriter.h>
#else
# include <rapid_json/writer.h>
# include <rapid_json/stringbuffer.h>
# include <rapid_json/prettywriter.h>
#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<rapidjson::StringBuffer> writer(buffer);
jDoc.Accept(writer);
}
else
{
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
jDoc.Accept(writer);
}
return out << buffer.GetString();
}

View File

@ -0,0 +1,56 @@
/*******************************************************************************
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <iostream>
#ifdef HAS_RAPIDJSON
# include <rapidjson/document.h>
#else
# include <rapid_json/document.h>
#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);

View File

@ -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;
}

View File

@ -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<resource_api::ResourceRouter*>(&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();
}

View File

@ -31,6 +31,7 @@
#include "gui/RetroShareLink.h"
#include "util/HandleRichText.h"
#include "util/misc.h"
#include "util/rsdir.h"
#include <retroshare/rsfiles.h>
@ -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

View File

@ -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;
}

View File

@ -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()

View File

@ -3,6 +3,10 @@
#include <retroshare-gui/configpage.h>
#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
};

View File

@ -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

View File

@ -48,6 +48,11 @@
#include "TerminalApiClient.h"
#endif
#ifdef RS_JSONAPI
# include <csignal>
# 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();

View File

@ -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

1
supportlibs/restbed Submodule

@ -0,0 +1 @@
Subproject commit c27c6726d28c42e2e1b7537ba63eeb23e944789d

View File

@ -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;

View File

@ -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<RsTestGroup> &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<RsGxsGroupId> &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<RsGxsMessageId> &
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<RsGxsIdGroup> &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<RsGxsGroupId> &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<RsGxsCircleGroup> &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<RsGxsGroupId> &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);

View File

@ -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);