From 3462f602a0b3861bc3074e728d24bd131e36b333 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 29 Oct 2014 11:42:15 +0100 Subject: [PATCH] whisper polling, not finished --- libqethereum/QEthereum.cpp | 78 ++++++++++++-------- libqethereum/QEthereum.h | 1 + libweb3jsonrpc/WebThreeStubServer.cpp | 80 +++++++++++++++++++++ libweb3jsonrpc/WebThreeStubServer.h | 4 ++ libweb3jsonrpc/abstractwebthreestubserver.h | 21 ++++++ libweb3jsonrpc/spec.json | 6 +- test/webthreestubclient.h | 39 ++++++++++ 7 files changed, 200 insertions(+), 29 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a8f702e09..b5d40b4f2 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -35,17 +35,14 @@ QWebThree::~QWebThree() { } -void QWebThree::poll() +static QString toJsonRpcBatch(std::vector const& _watches, QString _method) { - if (m_watches.size() == 0) - return; - QJsonArray batch; - for (int w: m_watches) + for (int w: _watches) { QJsonObject res; res["jsonrpc"] = QString::fromStdString("2.0"); - res["method"] = QString::fromStdString("changed"); + res["method"] = _method; QJsonArray params; params.append(w); @@ -53,31 +50,38 @@ void QWebThree::poll() res["id"] = w; batch.append(res); } - - emit processData(QString::fromUtf8(QJsonDocument(batch).toJson()), "changed"); + + return QString::fromUtf8(QJsonDocument(batch).toJson()); +} + +void QWebThree::poll() +{ + if (m_watches.size() > 0) + { + QString batch = toJsonRpcBatch(m_watches, "changed"); + emit processData(batch, "changed"); + } + if (m_shhWatches.size() > 0) + { + QString batch = toJsonRpcBatch(m_shhWatches, "shhChanged"); + emit processData(batch, "shhChanged"); + } } void QWebThree::clearWatches() { - if (m_watches.size() == 0) - return; - - QJsonArray batch; - for (int w: m_watches) + if (m_watches.size() > 0) { - QJsonObject res; - res["jsonrpc"] = QString::fromStdString("2.0"); - res["method"] = QString::fromStdString("uninstallFilter"); - - QJsonArray params; - params.append(w); - res["params"] = params; - res["id"] = w; - batch.append(params); + QString batch = toJsonRpcBatch(m_watches, "uninstallFilter"); + m_watches.clear(); + emit processData(batch, "internal"); + } + if (m_shhWatches.size() > 0) + { + QString batch = toJsonRpcBatch(m_shhWatches, "shhUninstallFilter"); + m_shhWatches.clear(); + emit processData(batch, "internal"); } - - m_watches.clear(); - emit processData(QString::fromUtf8(QJsonDocument(batch).toJson()), "internal"); } void QWebThree::clientDieing() @@ -140,11 +144,29 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo) return; } + if (!_addInfo.compare("shhChanged")) + { + QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); + for (int i = 0; i < resultsArray.size(); i++) + { + QJsonObject elem = resultsArray[i].toObject(); + if (elem.contains("result")) + for (auto e: elem["result"].toArray()) + { + QJsonObject res; + res["_event"] = QString::fromStdString("messages"); + res["data"] = e; //TODO somehow send watch id? + response(QString::fromUtf8(QJsonDocument(res).toJson())); + } + } + } + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); - if (!_addInfo.compare("newFilter") || !_addInfo.compare("newFilterString")) - if (f.contains("result")) - m_watches.push_back(f["result"].toInt()); + if ((!_addInfo.compare("newFilter") || !_addInfo.compare("newFilterString")) && f.contains("result")) + m_watches.push_back(f["result"].toInt()); + if (!_addInfo.compare("shhNewFilter") && f.contains("result")) + m_shhWatches.push_back(f["result"].toInt()); response(formatOutput(f)); } diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 205b45209..ad5de71b7 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -50,6 +50,7 @@ signals: private: std::vector m_watches; + std::vector m_shhWatches; }; class QWebThreeConnector: public QObject, public jsonrpc::AbstractServerConnector diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 1f3634047..9b7237745 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -181,6 +181,48 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, return _m.seal(_from, bt, ttl, workToProve); } +static pair toWatch(Json::Value const& _json) +{ + shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); + Public to; + + if (!_json["to"].empty()) + to = jsToPublic(_json["to"].asString()); + + if (!_json["topic"].empty()) + { + if (_json["topic"].isString()) + bt.shift(asBytes(jsPadded(_json["topic"].asString(), 32))); + else if (_json["topic"].isArray()) + for (auto i: _json["topic"]) + { + if (i.isString()) + bt.shift(asBytes(jsPadded(i.asString(), 32))); + else + bt.shift(); + } + } + return make_pair(bt.toTopicMask(), to); +} + +static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) +{ + Json::Value res; + res["hash"] = toJS(_h); + + res["expiry"] = (int)_e.expiry(); + res["sent"] = (int)_e.sent(); + res["ttl"] = (int)_e.ttl(); + res["workProved"] = (int)_e.workProved(); + res["topic"] = toJS(_e.topic()); + + res["payload"] = toJS(_m.payload()); + res["from"] = toJS(_m.from()); + res["to"] = toJS(_m.to()); + return res; +} + + WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector const& _accounts): AbstractWebThreeStubServer(_conn), m_web3(_web3) @@ -509,6 +551,44 @@ bool WebThreeStubServer::setMining(bool const& _mining) return true; } +Json::Value WebThreeStubServer::shhChanged(int const& _id) +{ + Json::Value ret(Json::arrayValue); + auto pub = m_shhWatches[_id]; + if (!pub || m_ids.count(pub)) + for (h256 const& h: face()->checkWatch(_id)) + { + auto e = face()->envelope(h); + shh::Message m; + if (pub) + { + cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[pub]); + if (!m) + continue; + } + else + m = e.open(); + ret.append(toJson(h,e,m)); + } + + return ret; +} + +int WebThreeStubServer::shhNewFilter(Json::Value const& _json) +{ + auto w = toWatch(_json); + auto ret = face()->installWatch(w.first); + m_shhWatches.insert(make_pair(ret, w.second)); + return ret; +} + +bool WebThreeStubServer::shhUninstallFilter(int const& _id) +{ + face()->uninstallWatch(_id); + return true; +} + std::string WebThreeStubServer::stateAt(string const& _address, string const& _storage) { int block = 0; diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 0ea3eebf1..93d428fa0 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -89,6 +89,9 @@ public: virtual bool setDefaultBlock(int const& _block); virtual bool setListening(bool const& _listening); virtual bool setMining(bool const& _mining); + virtual Json::Value shhChanged(int const& _id); + virtual int shhNewFilter(Json::Value const& _json); + virtual bool shhUninstallFilter(int const& _id); virtual std::string stateAt(std::string const& _address, std::string const& _storage); virtual std::string transact(Json::Value const& _json); virtual Json::Value transactionByHash(std::string const& _hash, int const& _i); @@ -111,4 +114,5 @@ private: ldb::DB* m_db; std::map m_ids; + std::map m_shhWatches; }; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 5d305e47c..66b9ff77d 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -45,6 +45,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(new jsonrpc::Procedure("setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::setDefaultBlockI); this->bindAndAddMethod(new jsonrpc::Procedure("setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setListeningI); this->bindAndAddMethod(new jsonrpc::Procedure("setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setMiningI); + this->bindAndAddMethod(new jsonrpc::Procedure("shhChanged", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhChangedI); + this->bindAndAddMethod(new jsonrpc::Procedure("shhNewFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shhNewFilterI); + this->bindAndAddMethod(new jsonrpc::Procedure("shhUninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhUninstallFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::stateAtI); this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::transactI); this->bindAndAddMethod(new jsonrpc::Procedure("transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByHashI); @@ -215,6 +218,21 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServersetMining(request[0u].asBool()); } + inline virtual void shhChangedI(const Json::Value& request, Json::Value& response) + { + response = this->shhChanged(request[0u].asInt()); + } + + inline virtual void shhNewFilterI(const Json::Value& request, Json::Value& response) + { + response = this->shhNewFilter(request[0u]); + } + + inline virtual void shhUninstallFilterI(const Json::Value& request, Json::Value& response) + { + response = this->shhUninstallFilter(request[0u].asInt()); + } + inline virtual void stateAtI(const Json::Value& request, Json::Value& response) { response = this->stateAt(request[0u].asString(), request[1u].asString()); @@ -283,6 +301,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerclient->CallMethod("shhChanged",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + + int shhNewFilter(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + + Json::Value result = this->client->CallMethod("shhNewFilter",p); + if (result.isInt()) + return result.asInt(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + + bool shhUninstallFilter(const int& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + + Json::Value result = this->client->CallMethod("shhUninstallFilter",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + + } + std::string stateAt(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) { Json::Value p;