rippled
Loading...
Searching...
No Matches
Unsubscribe.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2014 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/misc/NetworkOPs.h>
21#include <xrpld/rpc/Context.h>
22#include <xrpld/rpc/Role.h>
23#include <xrpld/rpc/detail/RPCHelpers.h>
24
25#include <xrpl/basics/Log.h>
26#include <xrpl/protocol/ErrorCodes.h>
27#include <xrpl/protocol/RPCErr.h>
28#include <xrpl/protocol/jss.h>
29
30namespace ripple {
31
34{
35 InfoSub::pointer ispSub;
37 bool removeUrl{false};
38
39 if (!context.infoSub && !context.params.isMember(jss::url))
40 {
41 // Must be a JSON-RPC call.
43 }
44
45 if (context.params.isMember(jss::url))
46 {
47 if (context.role != Role::ADMIN)
49
50 std::string strUrl = context.params[jss::url].asString();
51 ispSub = context.netOps.findRpcSub(strUrl);
52 if (!ispSub)
53 return jvResult;
54 removeUrl = true;
55 }
56 else
57 {
58 ispSub = context.infoSub;
59 }
60
61 if (context.params.isMember(jss::streams))
62 {
63 if (!context.params[jss::streams].isArray())
65
66 for (auto& it : context.params[jss::streams])
67 {
68 if (!it.isString())
70
71 std::string streamName = it.asString();
72 if (streamName == "server")
73 {
74 context.netOps.unsubServer(ispSub->getSeq());
75 }
76 else if (streamName == "ledger")
77 {
78 context.netOps.unsubLedger(ispSub->getSeq());
79 }
80 else if (streamName == "manifests")
81 {
82 context.netOps.unsubManifests(ispSub->getSeq());
83 }
84 else if (streamName == "transactions")
85 {
86 context.netOps.unsubTransactions(ispSub->getSeq());
87 }
88 else if (
89 streamName == "transactions_proposed" ||
90 streamName == "rt_transactions") // DEPRECATED
91 {
92 context.netOps.unsubRTTransactions(ispSub->getSeq());
93 }
94 else if (streamName == "validations")
95 {
96 context.netOps.unsubValidations(ispSub->getSeq());
97 }
98 else if (streamName == "peer_status")
99 {
100 context.netOps.unsubPeerStatus(ispSub->getSeq());
101 }
102 else if (streamName == "consensus")
103 {
104 context.netOps.unsubConsensus(ispSub->getSeq());
105 }
106 else
107 {
109 }
110 }
111 }
112
113 auto accountsProposed = context.params.isMember(jss::accounts_proposed)
114 ? jss::accounts_proposed
115 : jss::rt_accounts; // DEPRECATED
116 if (context.params.isMember(accountsProposed))
117 {
118 if (!context.params[accountsProposed].isArray())
120
121 auto ids = RPC::parseAccountIds(context.params[accountsProposed]);
122 if (ids.empty())
124 context.netOps.unsubAccount(ispSub, ids, true);
125 }
126
127 if (context.params.isMember(jss::accounts))
128 {
129 if (!context.params[jss::accounts].isArray())
131
132 auto ids = RPC::parseAccountIds(context.params[jss::accounts]);
133 if (ids.empty())
135 context.netOps.unsubAccount(ispSub, ids, false);
136 }
137
138 if (context.params.isMember(jss::account_history_tx_stream))
139 {
140 auto const& req = context.params[jss::account_history_tx_stream];
141 if (!req.isMember(jss::account) || !req[jss::account].isString())
143
144 auto const id = parseBase58<AccountID>(req[jss::account].asString());
145 if (!id)
147
148 bool stopHistoryOnly = false;
149 if (req.isMember(jss::stop_history_tx_only))
150 {
151 if (!req[jss::stop_history_tx_only].isBool())
153 stopHistoryOnly = req[jss::stop_history_tx_only].asBool();
154 }
155 context.netOps.unsubAccountHistory(ispSub, *id, stopHistoryOnly);
156
157 JLOG(context.j.debug())
158 << "doUnsubscribe: account_history_tx_stream: " << toBase58(*id)
159 << " stopHistoryOnly=" << (stopHistoryOnly ? "true" : "false");
160 }
161
162 if (context.params.isMember(jss::books))
163 {
164 if (!context.params[jss::books].isArray())
166
167 for (auto& jv : context.params[jss::books])
168 {
169 if (!jv.isObject() || !jv.isMember(jss::taker_pays) ||
170 !jv.isMember(jss::taker_gets) ||
171 !jv[jss::taker_pays].isObjectOrNull() ||
172 !jv[jss::taker_gets].isObjectOrNull())
173 {
175 }
176
177 Json::Value taker_pays = jv[jss::taker_pays];
178 Json::Value taker_gets = jv[jss::taker_gets];
179
180 Book book;
181
182 // Parse mandatory currency.
183 if (!taker_pays.isMember(jss::currency) ||
185 book.in.currency, taker_pays[jss::currency].asString()))
186 {
187 JLOG(context.j.info()) << "Bad taker_pays currency.";
189 }
190 // Parse optional issuer.
191 else if (
192 ((taker_pays.isMember(jss::issuer)) &&
193 (!taker_pays[jss::issuer].isString() ||
194 !to_issuer(
195 book.in.account, taker_pays[jss::issuer].asString())))
196 // Don't allow illegal issuers.
197 || !isConsistent(book.in) || noAccount() == book.in.account)
198 {
199 JLOG(context.j.info()) << "Bad taker_pays issuer.";
200
202 }
203
204 // Parse mandatory currency.
205 if (!taker_gets.isMember(jss::currency) ||
207 book.out.currency, taker_gets[jss::currency].asString()))
208 {
209 JLOG(context.j.info()) << "Bad taker_gets currency.";
210
212 }
213 // Parse optional issuer.
214 else if (
215 ((taker_gets.isMember(jss::issuer)) &&
216 (!taker_gets[jss::issuer].isString() ||
217 !to_issuer(
218 book.out.account, taker_gets[jss::issuer].asString())))
219 // Don't allow illegal issuers.
220 || !isConsistent(book.out) || noAccount() == book.out.account)
221 {
222 JLOG(context.j.info()) << "Bad taker_gets issuer.";
223
225 }
226
227 if (book.in == book.out)
228 {
229 JLOG(context.j.info()) << "taker_gets same as taker_pays.";
230 return rpcError(rpcBAD_MARKET);
231 }
232
233 if (jv.isMember(jss::domain))
234 {
235 uint256 domain;
236 if (!jv[jss::domain].isString() ||
237 !domain.parseHex(jv[jss::domain].asString()))
238 {
240 }
241 else
242 {
243 book.domain = domain;
244 }
245 }
246
247 context.netOps.unsubBook(ispSub->getSeq(), book);
248
249 // both_sides is deprecated.
250 if ((jv.isMember(jss::both) && jv[jss::both].asBool()) ||
251 (jv.isMember(jss::both_sides) && jv[jss::both_sides].asBool()))
252 {
253 context.netOps.unsubBook(ispSub->getSeq(), reversed(book));
254 }
255 }
256 }
257
258 if (removeUrl)
259 {
260 context.netOps.tryRemoveRpcSub(context.params[jss::url].asString());
261 }
262
263 return jvResult;
264}
265
266} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
bool isArray() const
bool isString() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
Stream debug() const
Definition Journal.h:328
Stream info() const
Definition Journal.h:334
Specifies an order book.
Definition Book.h:36
Issue in
Definition Book.h:38
Issue out
Definition Book.h:39
std::optional< uint256 > domain
Definition Book.h:40
virtual bool unsubBook(std::uint64_t uListener, Book const &)=0
virtual bool unsubValidations(std::uint64_t uListener)=0
virtual bool unsubServer(std::uint64_t uListener)=0
virtual bool unsubPeerStatus(std::uint64_t uListener)=0
virtual bool tryRemoveRpcSub(std::string const &strUrl)=0
virtual bool unsubConsensus(std::uint64_t uListener)=0
virtual bool unsubLedger(std::uint64_t uListener)=0
virtual pointer findRpcSub(std::string const &strUrl)=0
virtual bool unsubTransactions(std::uint64_t uListener)=0
virtual void unsubAccount(ref isplistener, hash_set< AccountID > const &vnaAccountIDs, bool realTime)=0
virtual bool unsubManifests(std::uint64_t uListener)=0
virtual void unsubAccountHistory(ref ispListener, AccountID const &account, bool historyOnly)=0
unsubscribe an account's transactions
virtual bool unsubRTTransactions(std::uint64_t uListener)=0
std::uint64_t getSeq()
Definition InfoSub.cpp:74
AccountID account
Definition Issue.h:36
Currency currency
Definition Issue.h:35
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
hash_set< AccountID > parseAccountIds(Json::Value const &jvArray)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
AccountID const & noAccount()
A placeholder for empty accounts.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Json::Value doUnsubscribe(RPC::JsonContext &)
bool isConsistent(Book const &book)
Definition Book.cpp:29
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
@ rpcACT_MALFORMED
Definition ErrorCodes.h:90
@ rpcBAD_MARKET
Definition ErrorCodes.h:97
@ rpcDOMAIN_MALFORMED
Definition ErrorCodes.h:158
@ rpcDST_ISR_MALFORMED
Definition ErrorCodes.h:108
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
@ rpcSTREAM_MALFORMED
Definition ErrorCodes.h:126
@ rpcSRC_ISR_MALFORMED
Definition ErrorCodes.h:125
@ rpcDST_AMT_MALFORMED
Definition ErrorCodes.h:106
@ rpcSRC_CUR_MALFORMED
Definition ErrorCodes.h:124
@ rpcNO_PERMISSION
Definition ErrorCodes.h:53
Book reversed(Book const &book)
Definition Book.cpp:49
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:84
InfoSub::pointer infoSub
Definition Context.h:48
beast::Journal const j
Definition Context.h:40
NetworkOPs & netOps
Definition Context.h:43