Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTStorage.cpp
Go to the documentation of this file.
1 /************************************************************
2 *
3 * OTStorage.cpp
4 *
5 */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "stdafx.hpp"
134 
135 #include "OTStorage.hpp"
136 #include "crypto/OTASCIIArmor.hpp"
137 #include "util/OTDataFolder.hpp"
138 #include "OTLog.hpp"
139 #include "util/OTPaths.hpp"
140 #include "OTPayload.hpp"
141 #include "OTStoragePB.hpp"
142 
143 #include <fstream>
144 #include <typeinfo>
145 
146 /*
147  // We want to store EXISTING OT OBJECTS (Usually signed contracts)
148  // These have an EXISTING OT path, such as "inbox/acct_id".
149  // These files are always in the form of a STRING.
150  // The easiest way for me to store/retrieve those strings is:
151 
152 
153  using namespace OTDB;
154 
155  bool bSuccessStore = StoreString(strContents, strFolder, strFilename);
156  bool bSuccessQuery = QueryString(strRetrieved, strFolder, strFilename);
157 
158 
159  // Internal to the above functions, the default Packing/Buffer is
160  // used, and the default Storage type is used. But what if I want to
161  // CHOOSE the storage and packing? Perhaps the default (filesystem) is not
162  // good enough for me, and I prefer a key/value DB.
163 
164  // Storage.
165  // Before creating my OWN storage, let's try using the default storage object
166  // itself, instead of asking the API to use it for me:
167 
168  OTDB::Storage * pStorage = OTDB::GetDefaultStorage();
169  OT_ASSERT(nullptr!=pStorage);
170 
171  bool bSuccessStore = pStorage->StoreString(strContents, strFolder,
172  strFilename);
173  bool bSuccessQuery = pStorage->QueryString(strRetrieved, strFolder,
174  strFilename);
175 
176 
177  // So if I wanted to create my OWN instance of storage, instead of using the
178  // default one, it would be similar:
179 
180  OTDB::Storage * pStorage = OTDB::CreateStorageContext(STORE_FILESYSTEM,
181  PACK_MESSAGE_PACK);
182  OT_ASSERT(nullptr!=pStorage);
183 
184  bool bSuccessInit = pStorage->Init("/path/to/data_folder", "wallet.xml");
185 
186  if (bSuccessInit)
187  {
188  bool bSuccessStore = pStorage->StoreString(strContents, strFolder,
189  strFilename);
190  bool bSuccessQuery = pStorage->QueryString(strRetrieved, strFolder,
191  strFilename);
192  }
193 
194 
195  // Creating like above is also how the default storage context gets
196  instantiated
197  // (internally) when you first start storing and querying.
198 
199  // But Storage needs to be SET UP -- whether a database connection initiated,
200  // or files loaded, or sub-directories created, or a Tor connection or
201  whatever.
202  // Therefore, there is an Init() call, which may have different parameters for
203  // each storage type. That way, all subclasses might use it differently, and
204  // the parameters are easily thrown into a config file later.
205 
206 
207  // What if it was a CouchDB database, instead of the filesystem?
208  // And using Google's Protocol Buffers for packing, isntead of MsgPack?
209  // (Note: OT doesn't actually support CouchDB yet.) But it would look like:
210 
211  Storage * pStorage =
212  CreateStorageContext(STORE_COUCHDB, PACK_PROTOCOL_BUFFERS);
213  OT_ASSERT(nullptr!=pStorage);
214 
215  // This time, Init receives database connect info instead of filesystem info...
216  bool bSuccessInit = pStorage->Init("IP ADDRESS", "PORT", "USERNAME",
217  "PASSWORD", "DATABASE NAME");
218 
219  etc.
220 
221 
222  // So what if I want to use the default, but I want that DEFAULT to be CouchDB
223  and Google?
224  // Just do this (near the beginning of the execution of the application):
225 
226  bool bInit = InitDefaultStorage(STORE_COUCHDB, PACK_PROTOCOL_BUFFERS,
227  "IP ADDRESS", "PORT", "USERNAME", "PASSWORD", "DB NAME");
228 
229  if (true == bInit)
230  {
231  // Then do this as normal:
232 
233  Storage * pStorage = GetDefaultStorage();
234  OT_ASSERT(nullptr!=pStorage);
235 
236  bool bSuccessStore = pStorage->StoreString(strContents, strFolder,
237  strFilename);
238  bool bSuccessQuery = pStorage->QueryString(strRetrieved, strFolder,
239  strFilename);
240  }
241 
242 
243  // What if you want to store an OBJECT in that location instead of a string?
244  // The object must be instantiated by the Storage Context...
245 
246  BitcoinAcct * pAcct = pStorage->CreateObject(STORED_OBJ_BITCOIN_ACCT);
247  OT_ASSERT(nullptr != pAcct);
248 
249  pAcct->acct_id = "jkhsdf987345kjhf8lkjhwef987345";
250  pAcct->bitcoin_acct_name = "Read-Only Label (Bitcoin Internal acct)";
251  pAcct->gui_label = "Editable Label (Moneychanger)";
252 
253 
254  // Perhaps you want to load up a Wallet and add this BitcoinAcct to it...
255 
256  WalletData * pWalletData =
257  pStorage->QueryObject(STORED_OBJ_WALLET_DATA, "moneychanger", "wallet.pak");
258 
259  if (nullptr != pWalletData) // It loaded.
260  {
261  if (pWalletData->AddBitcoinAcct(*pAcct))
262  bool bSuccessStore = pStorage->StoreObject(*pWalletData, "moneychanger",
263  strFilename);
264  else
265  delete pAcct;
266 
267  delete pWalletData;
268  }
269 
270  // Voila! The above code creates a BitcoinAcct (data object, not the real
271  thing)
272  // and then loads up the Moneychanger WalletData object, adds the BitcoinAcct
273  to
274  // it, and then stores it again.
275 
276  // SIMPLE, RIGHT?
277 
278  // Through this mechanism:
279  //
280  // 1) You can store your objects using the same storage context as the rest of
281  OT.
282  // 2) You can dictate a different storage context, just for yourself, or for
283  the entire OT library as well.
284  // 3) You can subclass OTDB::Storage and thus invent new storage methods.
285  // 4) You can easily store and load objects and strings.
286  // 5) You can swap out the packing code (msgpack, protobuf, json, etc) with no
287  change to any other code.
288  // 6) It's consistent and easy-to-use for all object types.
289  // 7) For generic objects, there is a Blob type, a String type, and a StringMap
290  type.
291  */
292 
294 
296  nullptr; // This is a pointer so I can control what order it is created in,
297  // on
298  // startup.
299 
301  "OTDBString", // Just a string.
302  "Blob", // Binary data of arbitrary size.
303  "StringMap", // A StringMap is a list of Key/Value pairs, useful for storing
304  // nearly anything.
305  "WalletData", // The GUI wallet's stored data
306  "BitcoinAcct", // The GUI wallet's stored data about a Bitcoin acct
307  "BitcoinServer", // The GUI wallet's stored data about a Bitcoin RPC port.
308  "RippleServer", // The GUI wallet's stored data about a Ripple server.
309  "LoomServer", // The GUI wallet's stored data about a Loom server.
310  "ServerInfo", // A Nym has a list of these.
311  "ContactNym", // This is a Nym record inside a contact of your address book.
312  "ContactAcct", // This is an account record inside a contact of your address
313  // book.
314  "Contact", // Your address book has a list of these.
315  "AddressBook", // Your address book.
316  "MarketData", // The description data for any given Market ID.
317  "MarketList", // A list of MarketDatas.
318  "BidData", // Offer details (doesn't contain private details)
319  "AskData", // Offer details (doesn't contain private details)
320  "OfferListMarket", // A list of offer details, for a specific market.
321  "TradeDataMarket", // Trade details (doesn't contain private data)
322  "TradeListMarket", // A list of trade details, for a specific market.
323  "OfferDataNym", // Private offer details for a particular Nym and Offer.
324  "OfferListNym", // A list of private offer details for a particular Nym.
325  "TradeDataNym", // Private trade details for a particular Nym and Trade.
326  "TradeListNym", // A list of private trade details for a particular Nym and
327  // Offer.
328  "StoredObjError" // (Should never be.)
329 };
330 
331 namespace opentxs
332 {
333 
334 namespace OTDB
335 {
336 // NAMESPACE CONSTRUCTOR / DESTRUCTOR
337 
338 // s_pStorage is "private" to the namespace.
339 // Use GetDefaultStorage() to access this variable.
340 // Use InitDefaultStorage() to set up this variable.
341 //
342 // Storage * ::details::s_pStorage = nullptr;
343 // These are actually defined in the namespace (.h file).
344 
345 // mapOfFunctions * details::pFunctionMap;
346 
347 InitOTDBDetails theOTDBConstructor; // Constructor for this instance (define all
348  // namespace variables above this line.)
349 
350 InitOTDBDetails::InitOTDBDetails() // Constructor for namespace
351 {
352 #if defined(OTDB_MESSAGE_PACK) || defined(OTDB_PROTOCOL_BUFFERS)
353  OT_ASSERT(nullptr == details::pFunctionMap);
355 
356  OT_ASSERT(nullptr != details::pFunctionMap);
358 #endif
359 
360 #if defined(OTDB_MESSAGE_PACK)
361  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_STRING)] =
362  &StringMsgpack::Instantiate;
363  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_BLOB)] =
364  &BlobMsgpack::Instantiate;
365  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_STRING_MAP)] =
366  &StringMapMsgpack::Instantiate;
367  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_WALLET_DATA)] =
368  &WalletDataMsgpack::Instantiate;
369  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_BITCOIN_ACCT)] =
370  &BitcoinAcctMsgpack::Instantiate;
371  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_BITCOIN_SERVER)] =
372  &BitcoinServerMsgpack::Instantiate;
373  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_RIPPLE_SERVER)] =
374  &RippleServerMsgpack::Instantiate;
375  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_LOOM_SERVER)] =
376  &LoomServerMsgpack::Instantiate;
377  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_SERVER_INFO)] =
378  &ServerInfoMsgpack::Instantiate;
379  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_CONTACT_ACCT)] =
380  &ContactAcctMsgpack::Instantiate;
381  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_CONTACT_NYM)] =
382  &ContactNymMsgpack::Instantiate;
383  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_CONTACT)] =
384  &ContactMsgpack::Instantiate;
385  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_ADDRESS_BOOK)] =
386  &AddressBookMsgpack::Instantiate;
387  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_MARKET_DATA)] =
388  &MarketDataMsgpack::Instantiate;
389  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_MARKET_LIST)] =
390  &MarketListMsgpack::Instantiate;
391  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_BID_DATA)] =
392  &BidDataMsgpack::Instantiate;
393  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_ASK_DATA)] =
394  &AskDataMsgpack::Instantiate;
395  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_OFFER_LIST_MARKET)] =
396  &OfferListMarketMsgpack::Instantiate;
397  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_TRADE_DATA_MARKET)] =
398  &TradeDataMarketMsgpack::Instantiate;
399  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_TRADE_LIST_MARKET)] =
400  &TradeListMarketMsgpack::Instantiate;
401  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_OFFER_DATA_NYM)] =
402  &OfferDataNymMsgpack::Instantiate;
403  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_OFFER_LIST_NYM)] =
404  &OfferListNymMsgpack::Instantiate;
405  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_TRADE_DATA_NYM)] =
406  &TradeDataNymMsgpack::Instantiate;
407  theMap[std::make_pair(PACK_MESSAGE_PACK, STORED_OBJ_TRADE_LIST_NYM)] =
408  &TradeListNymMsgpack::Instantiate;
409 #endif
410 
411 #if defined(OTDB_PROTOCOL_BUFFERS)
412  GOOGLE_PROTOBUF_VERIFY_VERSION;
413  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_STRING)] =
414  &StringPB::Instantiate;
415  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_BLOB)] =
416  &BlobPB::Instantiate;
417  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_STRING_MAP)] =
418  &StringMapPB::Instantiate;
419  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_WALLET_DATA)] =
420  &WalletDataPB::Instantiate;
421  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_BITCOIN_ACCT)] =
422  &BitcoinAcctPB::Instantiate;
423  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_BITCOIN_SERVER)] =
424  &BitcoinServerPB::Instantiate;
425  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_RIPPLE_SERVER)] =
426  &RippleServerPB::Instantiate;
427  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_LOOM_SERVER)] =
428  &LoomServerPB::Instantiate;
429  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_SERVER_INFO)] =
430  &ServerInfoPB::Instantiate;
431  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_CONTACT_ACCT)] =
432  &ContactAcctPB::Instantiate;
433  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_CONTACT_NYM)] =
434  &ContactNymPB::Instantiate;
435  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_CONTACT)] =
436  &ContactPB::Instantiate;
437  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_ADDRESS_BOOK)] =
438  &AddressBookPB::Instantiate;
439  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_MARKET_DATA)] =
440  &MarketDataPB::Instantiate;
441  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_MARKET_LIST)] =
442  &MarketListPB::Instantiate;
443  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_BID_DATA)] =
444  &BidDataPB::Instantiate;
445  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_ASK_DATA)] =
446  &AskDataPB::Instantiate;
447  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS,
449  &OfferListMarketPB::Instantiate;
450  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS,
452  &TradeDataMarketPB::Instantiate;
453  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS,
455  &TradeListMarketPB::Instantiate;
456  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_OFFER_DATA_NYM)] =
457  &OfferDataNymPB::Instantiate;
458  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_OFFER_LIST_NYM)] =
459  &OfferListNymPB::Instantiate;
460  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_TRADE_DATA_NYM)] =
461  &TradeDataNymPB::Instantiate;
462  theMap[std::make_pair(PACK_PROTOCOL_BUFFERS, STORED_OBJ_TRADE_LIST_NYM)] =
463  &TradeListNymPB::Instantiate;
464 #endif
465 }
466 
467 InitOTDBDetails::~InitOTDBDetails() // Destructor for namespace
468 {
469  OT_ASSERT(nullptr != details::pFunctionMap);
470  delete details::pFunctionMap;
471  details::pFunctionMap = nullptr;
472 
473 #if defined(OTDB_PROTOCOL_BUFFERS)
474  google::protobuf::ShutdownProtobufLibrary();
475 #endif
476 }
477 
478 // INTERFACE for the Namespace (for coders to use.)
479 
481 {
483 }
484 
485 // You might normally create your own Storage object, choosing the storage type
486 // and the packing type, and then call Init() on that object in order to get it
487 // up and running. This function is the equivalent of doing all that, but with
488 // the
489 // DEFAULT storage object (which OT uses when none is specified.)
490 //
491 bool InitDefaultStorage(StorageType eStoreType, PackType ePackType)
492 {
493  // This allows you to call multiple times if you want to change the default
494  // storage.
495  //
496  // if (nullptr != details::s_pStorage)
497  // {
498  // otErr << "OTDB::InitDefaultStorage: Existing storage context
499  // already exists. (Erasing / replacing it.)\n";
500  //
501  // delete details::s_pStorage;
502  // details::s_pStorage = nullptr;
503  // }
504 
505  if (nullptr == details::s_pStorage) {
506  otInfo << "OTDB::InitDefaultStorage: Existing storage context doesn't "
507  "already exist. (Creating it.)\n";
508 
509  details::s_pStorage = Storage::Create(eStoreType, ePackType);
510  }
511 
512  if (nullptr == details::s_pStorage) {
513  otErr << "OTDB::InitDefaultStorage: Failed while calling "
514  "OTDB::Storage::Create()\n";
515  return false;
516  }
517 
518  return true;
519 }
520 
521 // %newobject Factory::createObj();
523 {
524  Storage* pStorage = Storage::Create(eStoreType, ePackType);
525 
526  return pStorage; // caller responsible to delete
527 }
528 
529 // %newobject Factory::createObj();
531 {
532  Storage* pStorage = details::s_pStorage;
533 
534  if (nullptr == pStorage) {
535  return nullptr;
536  }
537 
538  return pStorage->CreateObject(eType);
539 }
540 
541 // bool bSuccess = Store(strInbox, "inbox", "lkjsdf908w345ljkvd");
542 // bool bSuccess = Store(strMint, "mints", SERVER_ID, ASSET_ID);
543 // bool bSuccess = Store(strPurse, "purse", SERVER_ID, USER_ID, ASSET_ID);
544 
545 // BELOW FUNCTIONS use the DEFAULT Storage context.
546 
547 // Check that if oneStr is "", then twoStr and threeStr are "" also... and so
548 // on...
549 bool CheckStringsExistInOrder(std::string& strFolder, std::string& oneStr,
550  std::string& twoStr, std::string& threeStr,
551  const char* szFuncName)
552 {
553  if (nullptr == szFuncName) szFuncName = __FUNCTION__;
554 
555  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
556  ot_threeStr(threeStr);
557 
558  if (ot_strFolder.Exists()) {
559  if (!ot_oneStr.Exists()) {
560  if ((!ot_twoStr.Exists()) && (!ot_threeStr.Exists())) {
561  oneStr = strFolder;
562  strFolder = ".";
563  }
564  else {
565  otErr << szFuncName << ": ot_twoStr or ot_threeStr exist, when "
566  "ot_oneStr doesn't exist! \n";
567  OT_FAIL;
568  }
569  }
570  else if ((!ot_twoStr.Exists()) && (ot_threeStr.Exists())) {
571  otErr << szFuncName << ": ot_twoStr or ot_threeStr exist, when "
572  "ot_oneStr doesn't exist! \n";
573  OT_FAIL;
574  }
575  }
576  else {
577  otErr << szFuncName << ": ot_strFolder must always exist!\n";
578  OT_FAIL;
579  }
580  return true;
581 }
582 
583 // See if the file is there.
584 bool Exists(std::string strFolder, std::string oneStr, std::string twoStr,
585  std::string threeStr)
586 {
587  {
588  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
589  ot_threeStr(threeStr);
590  OT_ASSERT_MSG(ot_strFolder.Exists(),
591  "OTDB::Exists: strFolder is empty.");
592 
593  if (!ot_oneStr.Exists()) {
594  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
595  "Exists: bad options");
596  oneStr = strFolder;
597  strFolder = ".";
598  }
599  }
600 
601  Storage* pStorage = details::s_pStorage;
602 
603  if (nullptr == pStorage) {
604  otOut << "OTDB::" << __FUNCTION__
605  << ": details::s_pStorage is null. (Returning false.)\n";
606  return false;
607  }
608 
609  return pStorage->Exists(strFolder, oneStr, twoStr, threeStr);
610 }
611 
612 int64_t FormPathString(std::string& strOutput, std::string strFolder,
613  std::string oneStr, std::string twoStr,
614  std::string threeStr)
615 {
616  {
617  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
618  ot_threeStr(threeStr);
619  OT_ASSERT_MSG(ot_strFolder.Exists(),
620  "OTDB::FormPathString: strFolder is empty.");
621 
622  if (!ot_oneStr.Exists()) {
623  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
624  "FormPathString: bad options");
625  oneStr = strFolder;
626  strFolder = ".";
627  }
628  }
629 
630  Storage* pStorage = details::s_pStorage;
631 
632  if (nullptr == pStorage) {
633  otOut << "OTDB::" << __FUNCTION__
634  << ": details::s_pStorage is null. (Returning -1.)\n";
635  return -1;
636  }
637 
638  return pStorage->FormPathString(strOutput, strFolder, oneStr, twoStr,
639  threeStr);
640 }
641 
642 // Store/Retrieve a string.
643 
644 bool StoreString(std::string strContents, std::string strFolder,
645  std::string oneStr, std::string twoStr, std::string threeStr)
646 {
647  {
648  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
649  ot_threeStr(threeStr);
650  OT_ASSERT_MSG(ot_strFolder.Exists(),
651  "OTDB::StoreString: strFolder is null");
652 
653  if (!ot_oneStr.Exists()) {
654  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
655  "OTDB::StoreString: bad options");
656  oneStr = strFolder;
657  strFolder = ".";
658  }
659  }
660 
661  Storage* pStorage = details::s_pStorage;
662 
663  if (nullptr == pStorage) {
664  return false;
665  }
666 
667  return pStorage->StoreString(strContents, strFolder, oneStr, twoStr,
668  threeStr);
669 }
670 
671 std::string QueryString(std::string strFolder, std::string oneStr,
672  std::string twoStr, std::string threeStr)
673 {
674  {
675  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
676  ot_threeStr(threeStr);
677 
678  if (!CheckStringsExistInOrder(strFolder, oneStr, twoStr, threeStr,
679  __FUNCTION__))
680  return std::string("");
681 
682  if (!ot_oneStr.Exists()) {
683  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
684  "Storage::StoreString: bad options");
685  oneStr = strFolder;
686  strFolder = ".";
687  }
688  }
689  Storage* pStorage = details::s_pStorage;
690 
691  if (nullptr == pStorage) return std::string("");
692 
693  return pStorage->QueryString(strFolder, oneStr, twoStr, threeStr);
694 }
695 
696 // Store/Retrieve a plain string.
697 
698 bool StorePlainString(std::string strContents, std::string strFolder,
699  std::string oneStr, std::string twoStr,
700  std::string threeStr)
701 {
702  {
703  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
704  ot_threeStr(threeStr);
705  OT_ASSERT_MSG(ot_strFolder.Exists(),
706  "OTDB::StorePlainString: strFolder is null");
707 
708  if (!ot_oneStr.Exists()) {
709  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
710  "OTDB::StorePlainString: bad options");
711  oneStr = strFolder;
712  strFolder = ".";
713  }
714  }
715  Storage* pStorage = details::s_pStorage;
716 
717  OT_ASSERT((strFolder.length() > 3) || (0 == strFolder.compare(0, 1, ".")));
718  OT_ASSERT((oneStr.length() < 1) || (oneStr.length() > 3));
719 
720  if (nullptr == pStorage) {
721  return false;
722  }
723 
724  return pStorage->StorePlainString(strContents, strFolder, oneStr, twoStr,
725  threeStr);
726 }
727 
728 std::string QueryPlainString(std::string strFolder, std::string oneStr,
729  std::string twoStr, std::string threeStr)
730 {
731  {
732  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
733  ot_threeStr(threeStr);
734  OT_ASSERT_MSG(ot_strFolder.Exists(),
735  "OTDB::QueryPlainString: strFolder is null");
736 
737  if (!ot_oneStr.Exists()) {
738  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
739  "OTDB::QueryPlainString: bad options");
740  oneStr = strFolder;
741  strFolder = ".";
742  }
743  }
744 
745  Storage* pStorage = details::s_pStorage;
746 
747  OT_ASSERT((strFolder.length() > 3) || (0 == strFolder.compare(0, 1, ".")));
748  OT_ASSERT((oneStr.length() < 1) || (oneStr.length() > 3));
749 
750  if (nullptr == pStorage) {
751  return std::string("");
752  }
753 
754  return pStorage->QueryPlainString(strFolder, oneStr, twoStr, threeStr);
755 }
756 
757 // Store/Retrieve an object. (Storable.)
758 
759 bool StoreObject(Storable& theContents, std::string strFolder,
760  std::string oneStr, std::string twoStr, std::string threeStr)
761 {
762  {
763  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
764  ot_threeStr(threeStr);
765  OT_ASSERT_MSG(ot_strFolder.Exists(),
766  "OTDB:StoreObject: strFolder is null");
767 
768  if (!ot_oneStr.Exists()) {
769  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
770  "OTDB:StoreObject: bad options");
771  oneStr = strFolder;
772  strFolder = ".";
773  }
774  }
775 
776  Storage* pStorage = details::s_pStorage;
777 
778  if (nullptr == pStorage) {
779  otErr << "OTDB::StoreObject: No default storage object allocated.\n";
780  return false;
781  }
782 
783  return pStorage->StoreObject(theContents, strFolder, oneStr, twoStr,
784  threeStr);
785 }
786 
787 // Use %newobject Storage::Query();
788 Storable* QueryObject(StoredObjectType theObjectType, std::string strFolder,
789  std::string oneStr, std::string twoStr,
790  std::string threeStr)
791 {
792  {
793  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
794  ot_threeStr(threeStr);
795  OT_ASSERT_MSG(ot_strFolder.Exists(),
796  "OTDB::QueryObject: strFolder is null");
797 
798  if (!ot_oneStr.Exists()) {
799  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
800  "OTDB::QueryObject: bad options");
801  oneStr = strFolder;
802  strFolder = ".";
803  }
804  }
805 
806  Storage* pStorage = details::s_pStorage;
807 
808  if (nullptr == pStorage) {
809  return nullptr;
810  }
811 
812  return pStorage->QueryObject(theObjectType, strFolder, oneStr, twoStr,
813  threeStr);
814 }
815 
816 // Store/Retrieve a Storable object to/from an OTASCIIArmor object.
817 
818 std::string EncodeObject(Storable& theContents)
819 {
820  Storage* pStorage = details::s_pStorage;
821 
822  if (nullptr == pStorage) {
823  otErr << "OTDB::EncodeObject: No Default Storage object allocated.\n";
824  return "";
825  }
826  return pStorage->EncodeObject(theContents);
827 }
828 
829 // Use %newobject Storage::DecodeObject();
830 Storable* DecodeObject(StoredObjectType theObjectType, std::string strInput)
831 {
832  Storage* pStorage = details::s_pStorage;
833 
834  if (nullptr == pStorage) {
835  return nullptr;
836  }
837 
838  return pStorage->DecodeObject(theObjectType, strInput);
839 }
840 
841 // Erase a value by location.
842 
843 bool EraseValueByKey(std::string strFolder, std::string oneStr,
844  std::string twoStr, std::string threeStr)
845 {
846  Storage* pStorage = details::s_pStorage;
847 
848  if (nullptr == pStorage) {
849  otErr
850  << "OTDB::EraseValueByKey: No Default Storage object allocated.\n";
851  return false;
852  }
853 
854  return pStorage->EraseValueByKey(strFolder, oneStr, twoStr, threeStr);
855 }
856 
857 // Used internally. Creates the right subclass for any stored object type,
858 // based on which packer is needed.
859 
861 {
862  if (nullptr == details::pFunctionMap) return nullptr;
863 
864  Storable* pStorable = nullptr;
865 
866  // The Pack type, plus the Stored Object type, is the Key to the map of
867  // function pointers.
868  InstantiateFuncKey theKey(thePackType, eType);
869 
870  // If the key works, we get the function pointer to the static Create()
871  // method for
872  // the appropriate object type.
873 
874  auto it = details::pFunctionMap->find(theKey);
875 
876  if (details::pFunctionMap->end() == it) return nullptr;
877 
878  InstantiateFunc* pFunc = it->second;
879 
880  if (nullptr != pFunc) {
881  pStorable = (*pFunc)(); // Now we instantiate the object...
882  }
883 
884  return pStorable; // May return nullptr...
885 }
886 
887 // static. OTPacker Factory.
888 //
890 {
891  OTPacker* pPacker = nullptr;
892 
893  switch (ePackType) {
894 #if defined(OTDB_MESSAGE_PACK)
895  case PACK_MESSAGE_PACK:
896  pPacker = new PackerMsgpack;
897  OT_ASSERT(nullptr != pPacker);
898  break;
899 #endif
900 #if defined(OTDB_PROTOCOL_BUFFERS)
902  pPacker = new PackerPB;
903  OT_ASSERT(nullptr != pPacker);
904  break;
905 #endif
906  case PACK_TYPE_ERROR:
907  default:
908  break;
909  }
910 
911  return pPacker; // May return nullptr...
912 }
913 
915 {
916 #if defined(OTDB_MESSAGE_PACK)
917  if (typeid(*this) == typeid(PackerMsgpack)) return PACK_MESSAGE_PACK;
918 #endif
919 #if defined(OTDB_PROTOCOL_BUFFERS)
920  if (typeid(*this) == typeid(PackerPB)) return PACK_PROTOCOL_BUFFERS;
921 #endif
922  return PACK_TYPE_ERROR;
923 }
924 
925 // Basically, ALL of the Storables have to implement the IStorable interface
926 // (or one of its subclasses). They can override hookBeforePack(), and they
927 // can override onPack(). Those two methods will be where all the action is,
928 // for each subclass of OTPacker.
929 //
931 {
932  IStorable* pStorable = dynamic_cast<IStorable*>(&inObj);
933 
934  if (nullptr ==
935  pStorable) // ALL Storables should implement SOME subinterface
936  // of IStorable
937  {
938  otErr << "OTPacker::Pack: Error: IStorable dynamic_cast failed.\n";
939  return nullptr;
940  }
941 
942  // This is polymorphic, so we get the right kind of buffer for the packer.
943  //
944  PackedBuffer* pBuffer = CreateBuffer();
945  OT_ASSERT(nullptr != pBuffer);
946 
947  // Must delete pBuffer, or return it, below this point.
948 
949  pStorable->hookBeforePack(); // Give the subclass a chance to prepare its
950  // data for packing...
951 
952  // This line (commented out) shows how the line below it would have looked
953  // if I had ended
954  // up using polymorphic templates:
955  // if (!makeTStorablepStorable->pack(*pBuffer))
956 
957  if (!pStorable->onPack(*pBuffer, inObj)) {
958  delete pBuffer;
959  return nullptr;
960  }
961 
962  return pBuffer;
963 }
964 
965 // Similar to Pack, above.
966 // Unpack takes the contents of the PackedBuffer and unpacks them into
967 // the Storable. ASSUMES that the PackedBuffer is the right type for
968 // the Packer, usually because the Packer is the one who instantiated
969 // it. Also assumes that the Storable's actual object type is the
970 // appropriate one for the data that is sitting in that buffer.
971 //
973 {
974  IStorable* pStorable = dynamic_cast<IStorable*>(&outObj);
975 
976  if (nullptr == pStorable) return false;
977 
978  // outObj is the OUTPUT OBJECT.
979  // If we're unable to unpack the contents of inBuf
980  // into outObj, return false.
981  //
982  if (!pStorable->onUnpack(inBuf, outObj)) {
983  return false;
984  }
985 
986  pStorable->hookAfterUnpack(); // Give the subclass a chance to settle its
987  // data after unpacking...
988 
989  return true;
990 }
991 
993 {
994  // This is polymorphic, so we get the right kind of buffer for the packer.
995  //
996  PackedBuffer* pBuffer = CreateBuffer();
997  OT_ASSERT(nullptr != pBuffer);
998 
999  // Must delete pBuffer, or return it, below this point.
1000 
1001  if (!pBuffer->PackString(inObj)) {
1002  delete pBuffer;
1003  return nullptr;
1004  }
1005 
1006  return pBuffer;
1007 }
1008 
1009 bool OTPacker::Unpack(PackedBuffer& inBuf, std::string& outObj)
1010 {
1011 
1012  // outObj is the OUTPUT OBJECT.
1013  // If we're unable to unpack the contents of inBuf
1014  // into outObj, return false.
1015  //
1016  if (!inBuf.UnpackString(outObj)) return false;
1017 
1018  return true;
1019 }
1020 
1021 // NOTICE!!! that when you add something to the list, it is CLONED. (Caller is
1022 // still responsible to delete the argument.)
1023 //
1024 
1025 #define IMPLEMENT_GET_ADD_REMOVE(scope, name) \
1026  \
1027  typedef stlplus::simple_ptr_clone<name> PointerTo##name; \
1028  \
1029  typedef std::deque<PointerTo##name> listOf##name##s; \
1030  \
1031  size_t scope Get##name##Count() \
1032  { \
1033  return list_##name##s.size(); \
1034  } \
1035  \
1036  name* scope Get##name(size_t nIndex) \
1037  { \
1038  if (nIndex < list_##name##s.size()) { \
1039  PointerTo##name theP = list_##name##s.at(nIndex); \
1040  return theP.pointer(); \
1041  } \
1042  return nullptr; \
1043  } \
1044  \
1045  bool scope Remove##name(size_t nIndex##name) \
1046  { \
1047  if (nIndex##name < list_##name##s.size()) { \
1048  list_##name##s.erase(list_##name##s.begin() + nIndex##name); \
1049  return true; \
1050  } else \
1051  return false; \
1052  } \
1053  \
1054  bool scope Add##name(name& disownObject) \
1055  { \
1056  PointerTo##name theP(disownObject.clone()); \
1057  list_##name##s.push_back(theP); \
1058  return true; \
1059  }
1060 
1062  BitcoinServer) // No semicolon on this one!
1063 
1064 IMPLEMENT_GET_ADD_REMOVE(WalletData::, BitcoinAcct) // No semicolon on this one!
1065 
1066 IMPLEMENT_GET_ADD_REMOVE(WalletData::,
1067  RippleServer) // No semicolon on this one!
1068 
1069 IMPLEMENT_GET_ADD_REMOVE(WalletData::, LoomServer) // No semicolon on this one!
1070 
1071 IMPLEMENT_GET_ADD_REMOVE(ContactNym::, ServerInfo) // No semicolon on this one!
1072 
1073 IMPLEMENT_GET_ADD_REMOVE(Contact::, ContactNym) // No semicolon on this one!
1074 
1075 IMPLEMENT_GET_ADD_REMOVE(Contact::, ContactAcct) // No semicolon on this one!
1076 
1077 IMPLEMENT_GET_ADD_REMOVE(AddressBook::, Contact) // No semicolon on this one!
1078 
1079 IMPLEMENT_GET_ADD_REMOVE(MarketList::, MarketData) // No semicolon on this one!
1080 
1082  BidData) // No semicolon on this one!
1083 
1084 IMPLEMENT_GET_ADD_REMOVE(OfferListMarket::,
1085  AskData) // No semicolon on this one!
1086 
1088  TradeDataMarket) // No semicolon on this one!
1089 
1091  OfferDataNym) // No semicolon on this one!
1092 
1094  TradeDataNym) // No semicolon on this one!
1095 
1096 // Make sure SWIG "loses ownership" of any objects pushed onto these lists.
1097 // (So I am safe to destruct them indiscriminately.)
1098 //
1099 // UPDATE: Nevertheless, no need to erase the lists (below) since they now
1100 // store smart pointers, instead of regular pointers, so they are self-cleaning.
1101 //
1102 
1103 ContactNym::~ContactNym()
1104 {
1105  // while (GetServerInfoCount() > 0)
1106  // RemoveServerInfo(0);
1107 }
1108 
1110 {
1111  // while (GetContactNymCount() > 0)
1112  // RemoveContactNym(0);
1113  //
1114  // while (GetContactAcctCount() > 0)
1115  // RemoveContactAcct(0);
1116 }
1117 
1119 {
1120  // while (GetContactCount() > 0)
1121  // RemoveContact(0);
1122 }
1123 
1124 //
1125 // Interface: IStorableMsgpack
1126 //
1127 //
1128 // Msgpack packer.
1129 #if defined(OTDB_MESSAGE_PACK)
1130 
1131 // look into git history for old (dead) code.
1132 
1133 #endif // defined (OTDB_MESSAGE_PACK)
1134 
1135 /* Protocol Buffers notes.
1136 
1137  // optional string bitcoin_id = 1;
1138  inline bool has_bitcoin_id() const;
1139  inline void clear_bitcoin_id();
1140  static const int32_t kBitcoinIdFieldNumber = 1;
1141  inline const ::std::string& bitcoin_id() const;
1142  inline void set_bitcoin_id(const ::std::string& value);
1143  inline void set_bitcoin_id(const char* value);
1144  inline void set_bitcoin_id(const char* value, size_t size);
1145  inline ::std::string* mutable_bitcoin_id();
1146  inline ::std::string* release_bitcoin_id();
1147 
1148  // optional string bitcoin_name = 2;
1149  inline bool has_bitcoin_name() const;
1150  inline void clear_bitcoin_name();
1151  static const int32_t kBitcoinNameFieldNumber = 2;
1152  inline const ::std::string& bitcoin_name() const;
1153  inline void set_bitcoin_name(const ::std::string& value);
1154  inline void set_bitcoin_name(const char* value);
1155  inline void set_bitcoin_name(const char* value, size_t size);
1156  inline ::std::string* mutable_bitcoin_name();
1157  inline ::std::string* release_bitcoin_name();
1158 
1159  // optional string gui_label = 3;
1160  inline bool has_gui_label() const;
1161  inline void clear_gui_label();
1162  static const int32_t kGuiLabelFieldNumber = 3;
1163  inline const ::std::string& gui_label() const;
1164  inline void set_gui_label(const ::std::string& value);
1165  inline void set_gui_label(const char* value);
1166  inline void set_gui_label(const char* value, size_t size);
1167  inline ::std::string* mutable_gui_label();
1168  inline ::std::string* release_gui_label();
1169  */
1170 /*
1171  bool SerializeToString(string* output) const; serializes the message and stores
1172  the bytes in the given string.
1173  (Note that the bytes are binary, not text; we only use the string class as a
1174  convenient container.)
1175  bool ParseFromString(const string& data); parses a message from the given
1176  string.
1177 
1178  bool SerializeToOstream(ostream* output) const; writes the message to the given
1179  C++ ostream.
1180  bool ParseFromIstream(istream* input); parses a message from the given C++
1181  istream.
1182  */
1183 
1184 // This is a case for template polymorphism.
1185 // See this article: http://accu.org/index.php/articles/471
1186 //
1187 /*
1188  template <class T> // TStorable...
1189  class TStorable // a "template subclass" of Storable. This is like a
1190  version of java
1191  { // interfaces, which C++ normally implements via pure
1192  virtual base classes
1193  T const& t; // and multiple inheritance. But in this case, I need to
1194  have a consistent
1195  public: // interface across disparate classes (in various
1196  circumstances including
1197  TStorable(T const& obj) : t(obj) { } // here with protocol buffers) and
1198  template interfaces
1199  bool pack(PackedBuffer& theBuffer) // allow me to do that even with
1200  classes in a different hierarchy.
1201  { return t.onPack(theBuffer); }
1202  };
1203 
1204  template <class T>
1205  TStorable<T> makeTStorable( T& obj )
1206  {
1207  return TStorable<T>( obj );
1208  }
1209  */
1210 
1211 /* // Specialization:
1212  template<>
1213  void TStorable<BigBenClock>::talk()
1214  {
1215  t.playBongs();
1216  }
1217 
1218  // Passing and returning as parameter:
1219 
1220  template <class T>
1221  void makeItTalk( TStorable<T> t )
1222  {
1223  t.talk();
1224  }
1225 
1226  template <class T>
1227  TStorable<T> makeTalkative( T& obj )
1228  {
1229  return TStorable<T>( obj );
1230  }
1231  */
1232 
1233 // Why have IStorablePB::onPack? What is this all about?
1234 //
1235 // Because normally, packing is done by Packer. I have a packer subclass for
1236 // the protocol buffers library, but notice that I don't have a packer for EVERY
1237 // SINGLE STORABLE OT OBJECT, for the protocol buffers library. So when
1238 // Packer::Pack()
1239 // is called, the subclass being activated is PackerPB, not
1240 // PackerForBitcoinAccountOnPB.
1241 //
1242 // With MsgPack, that would be the end of it, since the MsgPack Storables all
1243 // derive from
1244 // the same base class (due to the msgPack define) and a single call handles all
1245 // of them.
1246 // But with Protocol Buffers (and probably with custom objects, which are coming
1247 // next), EACH
1248 // PB-Storable has to wrap an instance of the PB-derived serializable object
1249 // generated by
1250 // protoc. Each instance thus has a PB member of a slightly different type, and
1251 // there is no
1252 // common base class between them that will give me a reference to that member,
1253 // without
1254 // overriding some virtual function IN ALL OF THE PB-SERIALIZABLE OBJECTS so
1255 // that each can
1256 // individually pass back the reference to its unique PB-derived member.
1257 //
1258 // Even if there were, LET US REMEMBER that all of the various Storables
1259 // (instantiated for
1260 // various specific packers), such as BitcoinAcctPB for example, are supposed to
1261 // be derived
1262 // from a data class such as BitcoinAcct. That way, BitcoinAcct can focus on the
1263 // data itself,
1264 // regardless of packer type, and OT can deal with its data in a pure way,
1265 // meanwhile the
1266 // actual object used can be one of 5 different subclasses of that, depending on
1267 // which
1268 // packer was employed. All of those subclasses (for protocol buffers, for
1269 // msgpack, for json,
1270 // etc) must be derived from the data class, BitcoinAcct.
1271 //
1272 // Remember, if ALL of the protocol-buffers wrapper classes, such as
1273 // BitcoinAcctPB,
1274 // BitcoinServerPB, LoomAcctPB, LoomServerPB, etc, are all derived from some
1275 // StorablePB object,
1276 // so they can all share a virtual function and thereby return a reference to
1277 // their internally-
1278 // wrapped object, then how are all of those classes supposed to ALSO be derived
1279 // from their
1280 // DATA classes, such as BitcoinAcct, BitcoinServer, LoomAcct, LoomServer, etc??
1281 //
1282 // The answer is multiple inheritance. Or INTERFACES, to be more specific. I
1283 // have implemented
1284 // Java-style interfaces as well as polymorphism-by-template to resolve these
1285 // issues.
1286 //
1287 // The Storable (parameter to Pack) is actually the object that somehow has to
1288 // override--or implement--the actual packing. Only it really knows. Therefore I
1289 // have decided
1290 // to add an INTERFACE, which is OPTIONAL, which makes it possible to hook and
1291 // override the
1292 // packing/unpacking, but such that things are otherwise handled in a broad
1293 // stroke, without
1294 // having to override EVERY LITTLE THING to accomplish it.
1295 //
1296 // Storables, as I said, will all be derived from their respective data objects,
1297 // no matter
1298 // which packer is being employed. When packing one, the framework will check to
1299 // see if IStorable
1300 // is present. It it is, then the framework will use it instead of continuing
1301 // with the normal
1302 // Pack procedure. It will also call the hook (first) so values can be copied
1303 // where appropriate,
1304 // before the actual packing occurs, or after (for unpacking.)
1305 //
1306 // This means, first, that few of the storables will ever actually have to
1307 // override Pack() or
1308 // Unpack(), as long as they override onPack() as necessary. AND, when onPack()
1309 // IS overridden,
1310 // it will be able to handle many different objects (via the Interface,
1311 // templates, etc), instead
1312 // of each having to provide a separate Pack() implementation for EVERY SINGLE
1313 // PB object. For
1314 // example, the IStorablePB interface handles ALL of the PB objects, without ANY
1315 // of them having
1316 // to override some special pack function.
1317 //
1318 // It WOULD have been possible to add this interface to Storable itself.
1319 // Functions such as
1320 // Pack(), Unpack(), hookBeforePack(), onPack(), etc could have been added there
1321 // and then passed
1322 // down to all the subclasses. But that is not as elegant, for these reasons:
1323 // 1) Remember that BitcoinAcct is purely data-oriented, and is not a
1324 // packing-related class.
1325 // (though its subclasses are.) So the members would be out of context,
1326 // except for some lame
1327 // explanation that the subclasses use them for other purposes unrelated to
1328 // this class.
1329 // 2) EVERY SINGLE class would be forced to provide its own implementation of
1330 // those functions,
1331 // since a common base class for groups of them is already discounted, since
1332 // they are derived
1333 // from their data classes, not their packer classes.
1334 //
1335 //
1336 //
1337 //
1338 //
1339 //
1340 // Interface: IStorablePB
1341 //
1342 
1343 // Protocol Buffers packer.
1344 //
1345 #if defined(OTDB_PROTOCOL_BUFFERS)
1346 
1347 ::google::protobuf::MessageLite* IStorablePB::getPBMessage() // This is really
1348  // only here so it
1349  // can be
1350  // overridden. Only
1351  // subclasses of
1352  // IStorablePB will
1353  // actually exist.
1354 {
1355  return nullptr;
1356 }
1357 
1358 template <class theBaseType, class theInternalType,
1359  StoredObjectType theObjectType>
1360 ::google::protobuf::MessageLite* ProtobufSubclass<theBaseType, theInternalType,
1361  theObjectType>::getPBMessage()
1362 {
1363  return (&__pb_obj);
1364 }
1365 
1366 // if (!makeTStorablepStorable->pack(*pBuffer))
1367 //::google::protobuf::MessageLite& IStorablePB::getPBMessage()
1368 //{
1369 // return makeTStorablePBgetPBMessage();
1370 //}
1371 
1372 bool IStorablePB::onPack(PackedBuffer& theBuffer,
1373  Storable&) // buffer is OUTPUT.
1374 {
1375  // check here to make sure theBuffer is the right TYPE.
1376  BufferPB* pBuffer = dynamic_cast<BufferPB*>(&theBuffer);
1377 
1378  if (nullptr == pBuffer) // Buffer is wrong type!!
1379  return false;
1380 
1381  ::google::protobuf::MessageLite* pMessage = getPBMessage();
1382 
1383  if (nullptr == pMessage) return false;
1384 
1385  if (!pMessage->SerializeToString(&(pBuffer->m_buffer))) return false;
1386 
1387  return true;
1388 }
1389 
1390 bool IStorablePB::onUnpack(PackedBuffer& theBuffer,
1391  Storable&) // buffer is INPUT.
1392 {
1393  // check here to make sure theBuffer is the right TYPE.
1394  BufferPB* pBuffer = dynamic_cast<BufferPB*>(&theBuffer);
1395 
1396  if (nullptr == pBuffer) // Buffer is wrong type!!
1397  return false;
1398 
1399  ::google::protobuf::MessageLite* pMessage = getPBMessage();
1400 
1401  if (nullptr == pMessage) return false;
1402 
1403  if (!pMessage->ParseFromString(pBuffer->m_buffer)) return false;
1404 
1405  return true;
1406 }
1407 
1408 /*
1409  bool SerializeToString(string* output) const;:
1410  Serializes the message and stores the bytes in the given string. Note that the
1411  bytes are binary,
1412  not text; we only use the string class as a convenient container.
1413 
1414  bool ParseFromString(const string& data);:
1415  parses a message from the given string.
1416  */
1417 bool BufferPB::PackString(std::string& theString)
1418 {
1419  StringPB theWrapper;
1420 
1421  ::google::protobuf::MessageLite* pMessage = theWrapper.getPBMessage();
1422 
1423  if (nullptr == pMessage) return false;
1424 
1425  String_InternalPB* pBuffer = dynamic_cast<String_InternalPB*>(pMessage);
1426 
1427  if (nullptr == pBuffer) // Buffer is wrong type!!
1428  return false;
1429 
1430  pBuffer->set_value(theString);
1431 
1432  if (!pBuffer->SerializeToString(&m_buffer)) return false;
1433 
1434  return true;
1435 }
1436 
1437 bool BufferPB::UnpackString(std::string& theString)
1438 {
1439  StringPB theWrapper;
1440 
1441  ::google::protobuf::MessageLite* pMessage = theWrapper.getPBMessage();
1442 
1443  if (nullptr == pMessage) return false;
1444 
1445  String_InternalPB* pBuffer = dynamic_cast<String_InternalPB*>(pMessage);
1446 
1447  if (nullptr == pBuffer) // Buffer is wrong type!!
1448  return false;
1449 
1450  if (!pBuffer->ParseFromString(m_buffer)) return false;
1451 
1452  theString = pBuffer->value();
1453 
1454  return true;
1455 }
1456 
1457 bool BufferPB::ReadFromIStream(std::istream& inStream, int64_t lFilesize)
1458 {
1459  unsigned long size = static_cast<unsigned long>(lFilesize);
1460 
1461  char* buf = new char[size];
1462  OT_ASSERT(nullptr != buf);
1463 
1464  inStream.read(buf, size);
1465 
1466  if (inStream.good()) {
1467  m_buffer.assign(buf, size);
1468  delete[] buf;
1469  return true;
1470  }
1471 
1472  delete[] buf;
1473  buf = nullptr;
1474 
1475  return false;
1476 
1477  // m_buffer.ParseFromIstream(&inStream);
1478 }
1479 
1480 bool BufferPB::WriteToOStream(std::ostream& outStream)
1481 {
1482  // bool SerializeToOstream(ostream* output) const
1483  if (m_buffer.length() > 0) {
1484  outStream.write(m_buffer.c_str(), m_buffer.length());
1485  return outStream.good() ? true : false;
1486  }
1487  else {
1488  otErr << "Buffer had zero length in BufferPB::WriteToOStream\n";
1489  }
1490 
1491  return false;
1492  // m_buffer.SerializeToOstream(&outStream);
1493 }
1494 
1495 const uint8_t* BufferPB::GetData()
1496 {
1497  return reinterpret_cast<const uint8_t*>(m_buffer.c_str());
1498 }
1499 
1500 size_t BufferPB::GetSize()
1501 {
1502  return m_buffer.size();
1503 }
1504 
1505 void BufferPB::SetData(const uint8_t* pData, size_t theSize)
1506 {
1507  m_buffer.assign(reinterpret_cast<const char*>(pData), theSize);
1508 }
1509 
1510 // !! All of these have to provide implementations for the hookBeforePack and
1511 // hookAfterUnpack methods.
1512 // In .cpp file:
1513 /*
1514  void SUBCLASS_HERE::hookBeforePack()
1515  {
1516  __pb_obj.set_PROPERTY_NAME_GOES_HERE(PROPERTY_NAME_GOES_HERE);
1517  }
1518  void SUBCLASS_HERE::hookAfterUnpack()
1519  {
1520  PROPERTY_NAME_GOES_HERE = __pb_obj.PROPERTY_NAME_GOES_HERE();
1521  }
1522  */
1523 //
1524 
1525 #define OT_IMPLEMENT_PB_LIST_PACK(pb_name, element_type) \
1526  __pb_obj.clear_##pb_name(); \
1527  for (auto it = list_##element_type##s.begin(); \
1528  it != list_##element_type##s.end(); ++it) { \
1529  PointerTo##element_type thePtr = (*it); \
1530  element_type##PB* pObject = \
1531  dynamic_cast<element_type##PB*>(thePtr.pointer()); \
1532  OT_ASSERT(nullptr != pObject); \
1533  ::google::protobuf::MessageLite* pMessage = pObject->getPBMessage(); \
1534  OT_ASSERT(nullptr != pMessage); \
1535  element_type##_InternalPB* pInternal = \
1536  dynamic_cast<element_type##_InternalPB*>(pMessage); \
1537  OT_ASSERT(nullptr != pInternal); \
1538  element_type##_InternalPB* pNewInternal = __pb_obj.add_##pb_name(); \
1539  OT_ASSERT(nullptr != pNewInternal); \
1540  pObject->hookBeforePack(); \
1541  pNewInternal->CopyFrom(*pInternal); \
1542  }
1543 
1544 #define OT_IMPLEMENT_PB_LIST_UNPACK(pb_name, element_type, ELEMENT_ENUM) \
1545  while (Get##element_type##Count() > 0) Remove##element_type(0); \
1546  for (int32_t i = 0; i < __pb_obj.pb_name##_size(); i++) { \
1547  const element_type##_InternalPB& theInternal = __pb_obj.pb_name(i); \
1548  element_type##PB* pNewWrapper = dynamic_cast<element_type##PB*>( \
1549  Storable::Create(ELEMENT_ENUM, PACK_PROTOCOL_BUFFERS)); \
1550  OT_ASSERT(nullptr != pNewWrapper); \
1551  ::google::protobuf::MessageLite* pMessage = \
1552  pNewWrapper->getPBMessage(); \
1553  OT_ASSERT(nullptr != pMessage); \
1554  element_type##_InternalPB* pInternal = \
1555  dynamic_cast<element_type##_InternalPB*>(pMessage); \
1556  OT_ASSERT(nullptr != pInternal); \
1557  pInternal->CopyFrom(theInternal); \
1558  pNewWrapper->hookAfterUnpack(); \
1559  PointerTo##element_type thePtr( \
1560  dynamic_cast<element_type*>(pNewWrapper)); \
1561  list_##element_type##s.push_back(thePtr); \
1562  }
1563 
1564 template <>
1566 {
1567  OT_IMPLEMENT_PB_LIST_PACK(bitcoin_server, BitcoinServer)
1568  OT_IMPLEMENT_PB_LIST_PACK(bitcoin_acct, BitcoinAcct)
1569  OT_IMPLEMENT_PB_LIST_PACK(ripple_server, RippleServer)
1570  OT_IMPLEMENT_PB_LIST_PACK(loom_server, LoomServer)
1571 }
1572 
1573 template <>
1574 void WalletDataPB::hookAfterUnpack()
1575 {
1576  OT_IMPLEMENT_PB_LIST_UNPACK(bitcoin_server, BitcoinServer,
1578  OT_IMPLEMENT_PB_LIST_UNPACK(bitcoin_acct, BitcoinAcct,
1580  OT_IMPLEMENT_PB_LIST_UNPACK(ripple_server, RippleServer,
1582  OT_IMPLEMENT_PB_LIST_UNPACK(loom_server, LoomServer, STORED_OBJ_LOOM_SERVER)
1583 }
1584 
1585 template <>
1586 void StringMapPB::hookBeforePack()
1587 {
1588  __pb_obj.clear_node(); // "node" is the repeated field of Key/Values.
1589 
1590  // Loop through all the key/value pairs in the map, and add them to
1591  // __pb_obj.node.
1592  //
1593  for (auto it = the_map.begin(); it != the_map.end(); ++it) {
1594  KeyValue_InternalPB* pNode = __pb_obj.add_node();
1595  pNode->set_key(it->first);
1596  pNode->set_value(it->second);
1597  }
1598 }
1599 
1600 template <>
1602 {
1603  // the_map = __pb_obj.the_map();
1604 
1605  the_map.clear();
1606 
1607  for (int32_t i = 0; i < __pb_obj.node_size(); i++) {
1608  const KeyValue_InternalPB& theNode = __pb_obj.node(i);
1609 
1610  the_map.insert(std::pair<std::string, std::string>(theNode.key(),
1611  theNode.value()));
1612  }
1613 }
1614 
1615 template <>
1617 {
1618  __pb_obj.set_value(m_string);
1619  // The way StringPB is used, this function will never actually get called.
1620  // (But if you used it like the others, it would work, since this function
1621  // is here.)
1622 }
1623 template <>
1625 {
1626  m_string = __pb_obj.value();
1627  // The way StringPB is used, this function will never actually get called.
1628  // (But if you used it like the others, it would work, since this function
1629  // is here.)
1630 }
1631 
1632 template <>
1634 {
1635  if (m_memBuffer.size() > 0)
1636  __pb_obj.set_value(m_memBuffer.data(), m_memBuffer.size());
1637 }
1638 template <>
1640 {
1641  if (__pb_obj.has_value()) {
1642  std::string strTemp = __pb_obj.value();
1643  m_memBuffer.assign(strTemp.begin(), strTemp.end());
1644  }
1645 }
1646 
1647 template <>
1649 {
1650  __pb_obj.set_gui_label(gui_label);
1651  __pb_obj.set_contact_id(contact_id);
1652  __pb_obj.set_email(email);
1653  __pb_obj.set_public_key(public_key);
1654  __pb_obj.set_memo(memo);
1655 
1656  OT_IMPLEMENT_PB_LIST_PACK(nyms, ContactNym)
1657  OT_IMPLEMENT_PB_LIST_PACK(accounts, ContactAcct)
1658 }
1659 
1660 template <>
1661 void ContactPB::hookAfterUnpack()
1662 {
1663  gui_label = __pb_obj.gui_label();
1664  contact_id = __pb_obj.contact_id();
1665  email = __pb_obj.email();
1666  public_key = __pb_obj.public_key();
1667  memo = __pb_obj.memo();
1668 
1669  OT_IMPLEMENT_PB_LIST_UNPACK(nyms, ContactNym, STORED_OBJ_CONTACT_NYM)
1670  OT_IMPLEMENT_PB_LIST_UNPACK(accounts, ContactAcct, STORED_OBJ_CONTACT_ACCT)
1671 }
1672 
1673 template <>
1674 void ContactNymPB::hookBeforePack()
1675 {
1676  __pb_obj.set_gui_label(gui_label);
1677  __pb_obj.set_nym_id(nym_id);
1678  __pb_obj.set_nym_type(nym_type);
1679  __pb_obj.set_public_key(public_key);
1680  __pb_obj.set_memo(memo);
1681 
1682  OT_IMPLEMENT_PB_LIST_PACK(servers, ServerInfo)
1683 }
1684 
1685 template <>
1687 {
1688  gui_label = __pb_obj.gui_label();
1689  nym_id = __pb_obj.nym_id();
1690  nym_type = __pb_obj.nym_type();
1691  public_key = __pb_obj.public_key();
1692  memo = __pb_obj.memo();
1693 
1694  OT_IMPLEMENT_PB_LIST_UNPACK(servers, ServerInfo, STORED_OBJ_SERVER_INFO)
1695 }
1696 
1697 template <>
1699 {
1700  OT_IMPLEMENT_PB_LIST_PACK(contacts, Contact)
1701 }
1702 
1703 template <>
1705 {
1706  OT_IMPLEMENT_PB_LIST_UNPACK(contacts, Contact, STORED_OBJ_CONTACT)
1707 }
1708 
1709 template <>
1711 {
1712  __pb_obj.set_gui_label(gui_label);
1713  __pb_obj.set_server_id(server_id);
1714  __pb_obj.set_server_type(server_type);
1715  __pb_obj.set_asset_type_id(asset_type_id);
1716  __pb_obj.set_acct_id(acct_id);
1717  __pb_obj.set_nym_id(nym_id);
1718  __pb_obj.set_memo(memo);
1719  __pb_obj.set_public_key(public_key);
1720 }
1721 template <>
1723 {
1724  gui_label = __pb_obj.gui_label();
1725  server_id = __pb_obj.server_id();
1726  server_type = __pb_obj.server_type();
1727  asset_type_id = __pb_obj.asset_type_id();
1728  acct_id = __pb_obj.acct_id();
1729  nym_id = __pb_obj.nym_id();
1730  memo = __pb_obj.memo();
1731  public_key = __pb_obj.public_key();
1732 }
1733 
1734 template <>
1736 {
1737  __pb_obj.set_server_id(server_id);
1738  __pb_obj.set_server_type(server_type);
1739 }
1740 template <>
1742 {
1743  server_id = __pb_obj.server_id();
1744  server_type = __pb_obj.server_type();
1745 }
1746 
1747 template <>
1749 {
1750  __pb_obj.set_gui_label(gui_label);
1751  __pb_obj.set_acct_id(acct_id);
1752  __pb_obj.set_server_id(server_id);
1753  __pb_obj.set_bitcoin_acct_name(bitcoin_acct_name);
1754 }
1755 template <>
1757 {
1758  gui_label = __pb_obj.gui_label();
1759  acct_id = __pb_obj.acct_id();
1760  server_id = __pb_obj.server_id();
1761  bitcoin_acct_name = __pb_obj.bitcoin_acct_name();
1762 }
1763 
1764 template <>
1766 {
1767  __pb_obj.set_gui_label(gui_label);
1768  __pb_obj.set_server_id(server_id);
1769  __pb_obj.set_server_type(server_type);
1770  __pb_obj.set_server_host(server_host);
1771  __pb_obj.set_server_port(server_port);
1772  __pb_obj.set_bitcoin_username(bitcoin_username);
1773  __pb_obj.set_bitcoin_password(bitcoin_password);
1774 }
1775 template <>
1777 {
1778  gui_label = __pb_obj.gui_label();
1779  server_id = __pb_obj.server_id();
1780  server_type = __pb_obj.server_type();
1781  server_host = __pb_obj.server_host();
1782  server_port = __pb_obj.server_port();
1783  bitcoin_username = __pb_obj.bitcoin_username();
1784  bitcoin_password = __pb_obj.bitcoin_password();
1785 }
1786 
1787 template <>
1789 {
1790  __pb_obj.set_gui_label(gui_label);
1791  __pb_obj.set_server_id(server_id);
1792  __pb_obj.set_server_type(server_type);
1793  __pb_obj.set_server_host(server_host);
1794  __pb_obj.set_server_port(server_port);
1795  __pb_obj.set_ripple_username(ripple_username);
1796  __pb_obj.set_ripple_password(ripple_password);
1797  __pb_obj.set_namefield_id(namefield_id);
1798  __pb_obj.set_passfield_id(passfield_id);
1799 }
1800 template <>
1802 {
1803  gui_label = __pb_obj.gui_label();
1804  server_id = __pb_obj.server_id();
1805  server_type = __pb_obj.server_type();
1806  server_host = __pb_obj.server_host();
1807  server_port = __pb_obj.server_port();
1808  ripple_username = __pb_obj.ripple_username();
1809  ripple_password = __pb_obj.ripple_password();
1810  namefield_id = __pb_obj.namefield_id();
1811  passfield_id = __pb_obj.passfield_id();
1812 }
1813 
1814 template <>
1816 {
1817  __pb_obj.set_gui_label(gui_label);
1818  __pb_obj.set_server_id(server_id);
1819  __pb_obj.set_server_type(server_type);
1820  __pb_obj.set_server_host(server_host);
1821  __pb_obj.set_server_port(server_port);
1822  __pb_obj.set_loom_username(loom_username);
1823  __pb_obj.set_namefield_id(namefield_id);
1824 }
1825 template <>
1827 {
1828  gui_label = __pb_obj.gui_label();
1829  server_id = __pb_obj.server_id();
1830  server_type = __pb_obj.server_type();
1831  server_host = __pb_obj.server_host();
1832  server_port = __pb_obj.server_port();
1833  loom_username = __pb_obj.loom_username();
1834  namefield_id = __pb_obj.namefield_id();
1835 }
1836 
1837 template <>
1839 {
1840  __pb_obj.set_gui_label(gui_label);
1841  __pb_obj.set_server_id(server_id);
1842  __pb_obj.set_market_id(market_id);
1843  __pb_obj.set_asset_type_id(asset_type_id);
1844  __pb_obj.set_currency_type_id(currency_type_id);
1845  __pb_obj.set_scale(scale);
1846  __pb_obj.set_total_assets(total_assets);
1847  __pb_obj.set_number_bids(number_bids);
1848  __pb_obj.set_number_asks(number_asks);
1849  __pb_obj.set_last_sale_price(last_sale_price);
1850  __pb_obj.set_last_sale_date(last_sale_date);
1851  __pb_obj.set_current_bid(current_bid);
1852  __pb_obj.set_current_ask(current_ask);
1853  __pb_obj.set_volume_trades(volume_trades);
1854  __pb_obj.set_volume_assets(volume_assets);
1855  __pb_obj.set_volume_currency(volume_currency);
1856  __pb_obj.set_recent_highest_bid(recent_highest_bid);
1857  __pb_obj.set_recent_lowest_ask(recent_lowest_ask);
1858 }
1859 
1860 template <>
1862 {
1863  gui_label = __pb_obj.gui_label();
1864  server_id = __pb_obj.server_id();
1865  market_id = __pb_obj.market_id();
1866  asset_type_id = __pb_obj.asset_type_id();
1867  currency_type_id = __pb_obj.currency_type_id();
1868  scale = __pb_obj.scale();
1869  total_assets = __pb_obj.total_assets();
1870  number_bids = __pb_obj.number_bids();
1871  number_asks = __pb_obj.number_asks();
1872  last_sale_price = __pb_obj.last_sale_price();
1873  last_sale_date = __pb_obj.last_sale_date();
1874  current_bid = __pb_obj.current_bid();
1875  current_ask = __pb_obj.current_ask();
1876  volume_trades = __pb_obj.volume_trades();
1877  volume_assets = __pb_obj.volume_assets();
1878  volume_currency = __pb_obj.volume_currency();
1879  recent_highest_bid = __pb_obj.recent_highest_bid();
1880  recent_lowest_ask = __pb_obj.recent_lowest_ask();
1881 }
1882 
1883 template <>
1885 {
1886  OT_IMPLEMENT_PB_LIST_PACK(market_data, MarketData)
1887 }
1888 
1889 template <>
1891 {
1892  OT_IMPLEMENT_PB_LIST_UNPACK(market_data, MarketData, STORED_OBJ_MARKET_DATA)
1893 }
1894 
1895 template <>
1897 {
1898  __pb_obj.set_gui_label(gui_label);
1899  __pb_obj.set_transaction_id(transaction_id);
1900  __pb_obj.set_price_per_scale(price_per_scale);
1901  __pb_obj.set_available_assets(available_assets);
1902  __pb_obj.set_minimum_increment(minimum_increment);
1903  __pb_obj.set_date(date);
1904 }
1905 
1906 template <>
1908 {
1909  gui_label = __pb_obj.gui_label();
1910  transaction_id = __pb_obj.transaction_id();
1911  price_per_scale = __pb_obj.price_per_scale();
1912  available_assets = __pb_obj.available_assets();
1913  minimum_increment = __pb_obj.minimum_increment();
1914  date = __pb_obj.date();
1915 }
1916 
1917 template <>
1919 {
1920  __pb_obj.set_gui_label(gui_label);
1921  __pb_obj.set_transaction_id(transaction_id);
1922  __pb_obj.set_price_per_scale(price_per_scale);
1923  __pb_obj.set_available_assets(available_assets);
1924  __pb_obj.set_minimum_increment(minimum_increment);
1925  __pb_obj.set_date(date);
1926 }
1927 
1928 template <>
1930 {
1931  gui_label = __pb_obj.gui_label();
1932  transaction_id = __pb_obj.transaction_id();
1933  price_per_scale = __pb_obj.price_per_scale();
1934  available_assets = __pb_obj.available_assets();
1935  minimum_increment = __pb_obj.minimum_increment();
1936  date = __pb_obj.date();
1937 }
1938 
1939 template <>
1941 {
1942  OT_IMPLEMENT_PB_LIST_PACK(bids, BidData)
1943  OT_IMPLEMENT_PB_LIST_PACK(asks, AskData)
1944 }
1945 
1946 template <>
1947 void OfferListMarketPB::hookAfterUnpack()
1948 {
1949  OT_IMPLEMENT_PB_LIST_UNPACK(bids, BidData, STORED_OBJ_BID_DATA)
1950  OT_IMPLEMENT_PB_LIST_UNPACK(asks, AskData, STORED_OBJ_ASK_DATA)
1951 }
1952 
1953 template <>
1954 void TradeDataMarketPB::hookBeforePack()
1955 {
1956  __pb_obj.set_gui_label(gui_label);
1957  __pb_obj.set_transaction_id(transaction_id);
1958  __pb_obj.set_date(date);
1959  __pb_obj.set_price(price);
1960  __pb_obj.set_amount_sold(amount_sold);
1961 }
1962 
1963 template <>
1965 {
1966  gui_label = __pb_obj.gui_label();
1967  transaction_id = __pb_obj.transaction_id();
1968  date = __pb_obj.date();
1969  price = __pb_obj.price();
1970  amount_sold = __pb_obj.amount_sold();
1971 }
1972 
1973 template <>
1975 {
1976  OT_IMPLEMENT_PB_LIST_PACK(trades, TradeDataMarket)
1977 }
1978 
1979 template <>
1981 {
1982  OT_IMPLEMENT_PB_LIST_UNPACK(trades, TradeDataMarket,
1984 }
1985 
1986 template <>
1988 {
1989  __pb_obj.set_gui_label(gui_label);
1990  __pb_obj.set_valid_from(valid_from);
1991  __pb_obj.set_valid_to(valid_to);
1992  __pb_obj.set_server_id(server_id);
1993  __pb_obj.set_asset_type_id(asset_type_id);
1994  __pb_obj.set_asset_acct_id(asset_acct_id);
1995  __pb_obj.set_currency_type_id(currency_type_id);
1996  __pb_obj.set_currency_acct_id(currency_acct_id);
1997  __pb_obj.set_selling(selling);
1998  __pb_obj.set_scale(scale);
1999  __pb_obj.set_price_per_scale(price_per_scale);
2000  __pb_obj.set_transaction_id(transaction_id);
2001  __pb_obj.set_total_assets(total_assets);
2002  __pb_obj.set_finished_so_far(finished_so_far);
2003  __pb_obj.set_minimum_increment(minimum_increment);
2004  __pb_obj.set_stop_sign(stop_sign);
2005  __pb_obj.set_stop_price(stop_price);
2006  __pb_obj.set_date(date);
2007 }
2008 
2009 template <>
2011 {
2012  gui_label = __pb_obj.gui_label();
2013  valid_from = __pb_obj.valid_from();
2014  valid_to = __pb_obj.valid_to();
2015  server_id = __pb_obj.server_id();
2016  asset_type_id = __pb_obj.asset_type_id();
2017  asset_acct_id = __pb_obj.asset_acct_id();
2018  currency_type_id = __pb_obj.currency_type_id();
2019  currency_acct_id = __pb_obj.currency_acct_id();
2020  selling = __pb_obj.selling();
2021  scale = __pb_obj.scale();
2022  price_per_scale = __pb_obj.price_per_scale();
2023  transaction_id = __pb_obj.transaction_id();
2024  total_assets = __pb_obj.total_assets();
2025  finished_so_far = __pb_obj.finished_so_far();
2026  minimum_increment = __pb_obj.minimum_increment();
2027  stop_sign = __pb_obj.stop_sign();
2028  stop_price = __pb_obj.stop_price();
2029  date = __pb_obj.date();
2030 }
2031 
2032 template <>
2034 {
2035  OT_IMPLEMENT_PB_LIST_PACK(offers, OfferDataNym)
2036 }
2037 
2038 template <>
2040 {
2041  OT_IMPLEMENT_PB_LIST_UNPACK(offers, OfferDataNym, STORED_OBJ_OFFER_DATA_NYM)
2042 }
2043 
2044 template <>
2046 {
2047  __pb_obj.set_gui_label(gui_label);
2048  __pb_obj.set_transaction_id(transaction_id);
2049  __pb_obj.set_completed_count(completed_count);
2050  __pb_obj.set_date(date);
2051  __pb_obj.set_price(price);
2052  __pb_obj.set_amount_sold(amount_sold);
2053  __pb_obj.set_updated_id(updated_id);
2054  __pb_obj.set_offer_price(offer_price);
2055  __pb_obj.set_finished_so_far(finished_so_far);
2056  __pb_obj.set_asset_id(asset_id);
2057  __pb_obj.set_currency_id(currency_id);
2058  __pb_obj.set_currency_paid(currency_paid);
2059 }
2060 
2061 template <>
2063 {
2064  gui_label = __pb_obj.gui_label();
2065  transaction_id = __pb_obj.transaction_id();
2066  completed_count = __pb_obj.completed_count();
2067  date = __pb_obj.date();
2068  price = __pb_obj.price();
2069  amount_sold = __pb_obj.amount_sold();
2070  updated_id = __pb_obj.updated_id();
2071  offer_price = __pb_obj.offer_price();
2072  finished_so_far = __pb_obj.finished_so_far();
2073  asset_id = __pb_obj.asset_id();
2074  currency_id = __pb_obj.currency_id();
2075  currency_paid = __pb_obj.currency_paid();
2076 }
2077 
2078 template <>
2080 {
2081  OT_IMPLEMENT_PB_LIST_PACK(trades, TradeDataNym)
2082 }
2083 
2084 template <>
2086 {
2087  OT_IMPLEMENT_PB_LIST_UNPACK(trades, TradeDataNym, STORED_OBJ_TRADE_DATA_NYM)
2088 }
2089 
2090 #endif // defined (OTDB_PROTOCOL_BUFFERS)
2091 
2092 //
2093 // STORAGE :: GetPacker
2094 //
2095 // Use this to access the OTPacker, throughout duration of this Storage object.
2096 // If it doesn't exist yet, this function will create it on the first call. (The
2097 // parameter allows you the choose what type will be created, other than
2098 // default.
2099 // You probably won't use it. But if you do, you'll only call it once per
2100 // instance
2101 // of Storage.)
2102 //
2104 {
2105  // Normally if you use Create(), the packer is created at that time.
2106  // However, in the future, coders using the API may create subclasses of
2107  // Storage through SWIG, which Create could not anticipate. This mechanism
2108  // makes sure that in those cases, the packer still gets set (on the first
2109  // Get() call), and the coder using the API still has the ability to choose
2110  // what type of packer will be used.
2111  //
2112  if (nullptr == m_pPacker) {
2113  m_pPacker = OTPacker::Create(ePackType);
2114  }
2115 
2116  return m_pPacker; // May return nullptr. (If Create call above fails.)
2117 }
2118 
2119 // (SetPacker(), from .h file)
2120 // This is called once, in the factory.
2121 // void Storage::SetPacker(OTPacker& thePacker) { OT_ASSERT(nullptr ==
2122 // m_pPacker);
2123 // m_pPacker = &thePacker; }
2124 
2125 //
2126 // Factory for Storable objects...
2127 //
2129 {
2130  OTPacker* pPacker = GetPacker();
2131 
2132  if (nullptr == pPacker) {
2133  otErr << "OTDB::Storage::CreateObject: Failed, since GetPacker() "
2134  "returned nullptr.\n";
2135  return nullptr;
2136  }
2137 
2138  Storable* pStorable = Storable::Create(eType, pPacker->GetType());
2139 
2140  return pStorable; // May return nullptr.
2141 }
2142 
2143 // Factory for the Storage context itself.
2144 //
2145 Storage* Storage::Create(StorageType eStorageType, PackType ePackType)
2146 {
2147  Storage* pStore = nullptr;
2148 
2149  switch (eStorageType) {
2150  case STORE_FILESYSTEM:
2151  pStore = StorageFS::Instantiate();
2152  OT_ASSERT(nullptr != pStore);
2153  break;
2154  // case STORE_COUCH_DB:
2155  // pStore = new StorageCouchDB; OT_ASSERT(nullptr != pStore);
2156  // break;
2157  default:
2158  otErr << "OTDB::Storage::Create: Failed: Unknown storage type.\n";
2159  break;
2160  }
2161 
2162  // IF we successfully created the storage context, now let's
2163  // try to create the packer that goes with it.
2164  // (They are created together and linked until death.)
2165 
2166  if (nullptr != pStore) {
2167  OTPacker* pPacker = OTPacker::Create(ePackType);
2168 
2169  if (nullptr == pPacker) {
2170  otErr << "OTDB::Storage::Create: Failed while creating packer.\n";
2171 
2172  // For whatever reason, we failed. Memory issues or whatever.
2173  delete pStore;
2174  pStore = nullptr;
2175  return nullptr;
2176  }
2177 
2178  // Now they're married.
2179  pStore->SetPacker(*pPacker);
2180  }
2181  else
2182  otErr << "OTDB::Storage::Create: Failed, since pStore is nullptr.\n";
2183 
2184  return pStore; // Possible to return nullptr.
2185 }
2186 
2188 {
2189  // If I find the type, then I return it. Otherwise I ASSUME
2190  // that the coder using the API has subclassed Storage, and
2191  // that this is a custom Storage type invented by the API user.
2192 
2193  if (typeid(*this) == typeid(StorageFS)) return STORE_FILESYSTEM;
2194  // else if (typeid(*this) == typeid(StorageCouchDB))
2195  // return STORE_COUCH_DB;
2196  // Etc.
2197  //
2198  else
2199  return STORE_TYPE_SUBCLASS; // The Java coder using API must have
2200  // subclassed Storage himself.
2201 }
2202 
2203 bool Storage::StoreString(std::string strContents, std::string strFolder,
2204  std::string oneStr, std::string twoStr,
2205  std::string threeStr)
2206 {
2207  OTString ot_strFolder(strFolder), ot_oneStr(oneStr), ot_twoStr(twoStr),
2208  ot_threeStr(threeStr);
2209  OT_ASSERT_MSG(ot_strFolder.Exists(),
2210  "Storage::StoreString: strFolder is null");
2211 
2212  if (!ot_oneStr.Exists()) {
2213  OT_ASSERT_MSG((!ot_twoStr.Exists() && !ot_threeStr.Exists()),
2214  "Storage::StoreString: bad options");
2215  oneStr = strFolder;
2216  strFolder = ".";
2217  }
2218 
2219  OTPacker* pPacker = GetPacker();
2220 
2221  if (nullptr == pPacker) return false;
2222 
2223  PackedBuffer* pBuffer = pPacker->Pack(strContents);
2224 
2225  if (nullptr == pBuffer) return false;
2226 
2227  bool bSuccess =
2228  onStorePackedBuffer(*pBuffer, strFolder, oneStr, twoStr, threeStr);
2229 
2230  // Don't want any leaks here, do we?
2231  delete pBuffer;
2232  pBuffer = nullptr;
2233 
2234  return bSuccess;
2235 }
2236 
2237 std::string Storage::QueryString(std::string strFolder, std::string oneStr,
2238  std::string twoStr, std::string threeStr)
2239 {
2240  std::string theString("");
2241 
2242  OTPacker* pPacker = GetPacker();
2243 
2244  if (nullptr == pPacker) return theString;
2245 
2246  PackedBuffer* pBuffer = pPacker->CreateBuffer();
2247 
2248  if (nullptr == pBuffer) return theString;
2249 
2250  // Below this point, responsible for pBuffer.
2251 
2252  bool bSuccess =
2253  onQueryPackedBuffer(*pBuffer, strFolder, oneStr, twoStr, threeStr);
2254 
2255  if (!bSuccess) {
2256  delete pBuffer;
2257  pBuffer = nullptr;
2258  return theString;
2259  }
2260 
2261  // We got the packed buffer back from the query!
2262  // Now let's unpack it and return the Storable object.
2263 
2264  bool bUnpacked = pPacker->Unpack(*pBuffer, theString);
2265 
2266  if (!bUnpacked) {
2267  delete pBuffer;
2268  theString = "";
2269  return theString;
2270  }
2271 
2272  // Success :-)
2273 
2274  // Don't want any leaks here, do we?
2275  delete pBuffer;
2276  pBuffer = nullptr;
2277 
2278  return theString;
2279 }
2280 
2281 // For when you want NO PACKING.
2282 
2283 bool Storage::StorePlainString(std::string strContents, std::string strFolder,
2284  std::string oneStr, std::string twoStr,
2285  std::string threeStr)
2286 {
2287  return onStorePlainString(strContents, strFolder, oneStr, twoStr, threeStr);
2288 }
2289 
2290 std::string Storage::QueryPlainString(std::string strFolder, std::string oneStr,
2291  std::string twoStr, std::string threeStr)
2292 {
2293  std::string theString("");
2294 
2295  if (!onQueryPlainString(theString, strFolder, oneStr, twoStr, threeStr))
2296  theString = "";
2297 
2298  return theString;
2299 }
2300 
2301 bool Storage::StoreObject(Storable& theContents, std::string strFolder,
2302  std::string oneStr, std::string twoStr,
2303  std::string threeStr)
2304 {
2305  OTPacker* pPacker = GetPacker();
2306 
2307  if (nullptr == pPacker) {
2308  otErr << "No packer allocated in Storage::StoreObject\n";
2309  return false;
2310  }
2311 
2312  PackedBuffer* pBuffer = pPacker->Pack(theContents);
2313 
2314  if (nullptr == pBuffer) {
2315  otErr << "Packing failed in Storage::StoreObject\n";
2316  return false;
2317  }
2318 
2319  bool bSuccess =
2320  onStorePackedBuffer(*pBuffer, strFolder, oneStr, twoStr, threeStr);
2321 
2322  if (!bSuccess) {
2323  otErr << "Storing failed in Storage::StoreObject (calling "
2324  "onStorePackedBuffer) \n";
2325  return false;
2326  }
2327 
2328  // Don't want any leaks here, do we?
2329  delete pBuffer;
2330 
2331  return bSuccess;
2332 }
2333 
2334 // Use %newobject Storage::Query();
2335 //
2337  std::string strFolder, std::string oneStr,
2338  std::string twoStr, std::string threeStr)
2339 {
2340  OTPacker* pPacker = GetPacker();
2341 
2342  if (nullptr == pPacker) return nullptr;
2343 
2344  PackedBuffer* pBuffer = pPacker->CreateBuffer();
2345 
2346  if (nullptr == pBuffer) return nullptr;
2347 
2348  // Below this point, responsible for pBuffer.
2349 
2350  Storable* pStorable = CreateObject(theObjectType);
2351 
2352  if (nullptr == pStorable) {
2353  delete pBuffer;
2354  return nullptr;
2355  }
2356 
2357  // Below this point, responsible for pBuffer AND pStorable.
2358 
2359  bool bSuccess =
2360  onQueryPackedBuffer(*pBuffer, strFolder, oneStr, twoStr, threeStr);
2361 
2362  if (!bSuccess) {
2363  delete pBuffer;
2364  delete pStorable;
2365 
2366  return nullptr;
2367  }
2368 
2369  // We got the packed buffer back from the query!
2370  // Now let's unpack it and return the Storable object.
2371 
2372  bool bUnpacked = pPacker->Unpack(*pBuffer, *pStorable);
2373 
2374  if (!bUnpacked) {
2375  delete pBuffer;
2376  delete pStorable;
2377 
2378  return nullptr;
2379  }
2380 
2381  // Success :-)
2382 
2383  // Don't want any leaks here, do we?
2384  delete pBuffer;
2385 
2386  return pStorable; // caller is responsible to delete.
2387 }
2388 
2389 std::string Storage::EncodeObject(Storable& theContents)
2390 {
2391  std::string strReturnValue("");
2392 
2393  OTPacker* pPacker = GetPacker();
2394 
2395  if (nullptr == pPacker) {
2396  otErr << "Storage::EncodeObject: No packer allocated.\n";
2397  return strReturnValue;
2398  }
2399 
2400  PackedBuffer* pBuffer = pPacker->Pack(theContents);
2401 
2402  if (nullptr == pBuffer) {
2403  otErr << "Storage::EncodeObject: Packing failed.\n";
2404  return strReturnValue;
2405  }
2406 
2407  // OTPackedBuffer:
2408  // virtual const uint8_t * GetData()=0;
2409  // virtual size_t GetSize()=0;
2410  //
2411  const uint32_t nNewSize = static_cast<const uint32_t>(pBuffer->GetSize());
2412  const void* pNewData = static_cast<const void*>(pBuffer->GetData());
2413 
2414  if ((nNewSize < 1) || (nullptr == pNewData)) {
2415  delete pBuffer;
2416  pBuffer = nullptr;
2417 
2418  otErr << "Storage::EncodeObject: Packing failed (2).\n";
2419  return strReturnValue;
2420  }
2421 
2422  const OTData theData(pNewData, nNewSize);
2423  const OTASCIIArmor theArmor(theData);
2424 
2425  strReturnValue.assign(theArmor.Get(), theArmor.GetLength());
2426 
2427  // Don't want any leaks here, do we?
2428  delete pBuffer;
2429 
2430  return strReturnValue;
2431 }
2432 
2433 // Use %newobject Storage::DecodeObject();
2434 //
2436  std::string strInput)
2437 {
2438  if (strInput.size() < 1) return nullptr;
2439 
2440  OTPacker* pPacker = GetPacker();
2441 
2442  if (nullptr == pPacker) return nullptr;
2443 
2444  PackedBuffer* pBuffer = pPacker->CreateBuffer();
2445 
2446  if (nullptr == pBuffer) return nullptr;
2447 
2448  // Below this point, responsible for pBuffer.
2449 
2450  Storable* pStorable = CreateObject(theObjectType);
2451 
2452  if (nullptr == pStorable) {
2453  delete pBuffer;
2454  return nullptr;
2455  }
2456 
2457  // Below this point, responsible for pBuffer AND pStorable.
2458 
2459  OTASCIIArmor theArmor;
2460  theArmor.Set(strInput.c_str(), static_cast<uint32_t>(strInput.size()));
2461  const OTPayload thePayload(theArmor);
2462 
2463  // Put thePayload's contents into pBuffer here.
2464  //
2465  pBuffer->SetData(
2466  static_cast<const uint8_t*>(thePayload.GetPayloadPointer()),
2467  thePayload.GetSize());
2468 
2469  // Now let's unpack it and return the Storable object.
2470 
2471  const bool bUnpacked = pPacker->Unpack(*pBuffer, *pStorable);
2472 
2473  if (!bUnpacked) {
2474  delete pBuffer;
2475  delete pStorable;
2476 
2477  return nullptr;
2478  }
2479 
2480  // Success :-)
2481 
2482  // Don't want any leaks here, do we?
2483  delete pBuffer;
2484 
2485  return pStorable; // caller is responsible to delete.
2486 }
2487 
2488 bool Storage::EraseValueByKey(std::string strFolder, std::string oneStr,
2489  std::string twoStr, std::string threeStr)
2490 {
2491  bool bSuccess = onEraseValueByKey(strFolder, oneStr, twoStr, threeStr);
2492 
2493  if (!bSuccess)
2494  otErr << "Storage::EraseValueByKey: Failed trying to erase a value "
2495  "(while calling onEraseValueByKey) \n";
2496 
2497  return bSuccess;
2498 }
2499 
2500 // STORAGE FS (OTDB::StorageFS is the filesystem version of OTDB::Storage.)
2501 
2502 // ConfirmOrCreateFolder()
2503 // Used for making sure that certain necessary folders actually exist. (Creates
2504 // them otherwise.)
2505 //
2506 // If you pass in "spent", then this function will make sure that "<path>/spent"
2507 // actually exists,
2508 // or create it. WARNING: If what you want to pass is
2509 // "spent/sub-folder-to-spent" then make SURE
2510 // you call it with "spent" FIRST, so you are sure THAT folder has been created,
2511 // otherwise the
2512 // folder creation will definitely fail on the sub-folder call (if the primary
2513 // folder wasn't
2514 // already there, that is.)
2515 //
2516 bool StorageFS::ConfirmOrCreateFolder(const char* szFolderName, struct stat*)
2517 {
2518  bool bConfirmOrCreateSuccess = false, bFolderAlreadyExist = false;
2519  OTString strFolderName(szFolderName);
2520  if (!OTPaths::ConfirmCreateFolder(strFolderName, bConfirmOrCreateSuccess,
2521  bFolderAlreadyExist)) {
2522  OT_FAIL;
2523  };
2524  return bConfirmOrCreateSuccess;
2525 }
2526 
2527 // Returns true or false whether a specific file exists.
2528 // Adds the main path prior to checking.
2529 //
2530 bool StorageFS::ConfirmFile(const char* szFileName, struct stat*)
2531 {
2532  OTString strFilePath("");
2533  OTPaths::AppendFile(strFilePath, m_strDataPath, szFileName);
2534  return OTPaths::PathExists(strFilePath);
2535 }
2536 
2537 /*
2538  - Based on the input, constructs the full path and returns it in strOutput.
2539  - This function will try to create all the folders leading up to the
2540  file itself.
2541  - Also returns true/false based on whether the path actually exists.
2542  - If some failure occurs along the way, the path returned will not be the
2543  full path, but the path where the failure occurred.
2544 
2545  New return values:
2546 
2547  -1 -- Error
2548  0 -- File not found
2549  1+ -- File found and it's length.
2550 
2551  */
2552 int64_t StorageFS::ConstructAndCreatePath(std::string& strOutput,
2553  std::string strFolder,
2554  std::string oneStr,
2555  std::string twoStr,
2556  std::string threeStr)
2557 {
2558  return ConstructAndConfirmPathImp(true, strOutput, strFolder, oneStr,
2559  twoStr, threeStr);
2560 }
2561 
2562 int64_t StorageFS::ConstructAndConfirmPath(std::string& strOutput,
2563  std::string strFolder,
2564  std::string oneStr,
2565  std::string twoStr,
2566  std::string threeStr)
2567 {
2568  return ConstructAndConfirmPathImp(false, strOutput, strFolder, oneStr,
2569  twoStr, threeStr);
2570 }
2571 
2572 int64_t StorageFS::ConstructAndConfirmPathImp(
2573  bool bMakePath, std::string& strOutput, std::string zeroStr,
2574  std::string oneStr, std::string twoStr, std::string threeStr)
2575 {
2576  const std::string strRoot(m_strDataPath.c_str());
2577 
2578  const std::string strZero(3 > zeroStr.length() ? "" : zeroStr);
2579  const std::string strOne(3 > oneStr.length() ? "" : oneStr);
2580  const std::string strTwo(3 > twoStr.length() ? "" : twoStr);
2581  const std::string strThree(3 > threeStr.length() ? "" : threeStr);
2582 
2583  // must be 3chars in length, or equal to "."
2584  if (strZero.empty() && (0 != zeroStr.compare("."))) {
2585  otErr << __FUNCTION__ << ": Empty: "
2586  << "zeroStr"
2587  << " is too short (and not \".\").!\n"
2588  "zeroStr was: \"" << zeroStr << "\"\n";
2589  return -1;
2590  }
2591 
2592  // the first string must not be empty
2593  if (strOne.empty()) {
2594  otErr << __FUNCTION__ << ": Empty: "
2595  << "oneStr"
2596  << " passed in!\n";
2597  return -2;
2598  }
2599 
2600  // if the second string is empty, so must the third.
2601  if (strTwo.empty() && !strThree.empty()) {
2602  otErr << __FUNCTION__ << ": Error: strThree passed in: " << strThree
2603  << " while strTwo is empty!\n";
2604  return -3;
2605  }
2606 
2607  const bool bHaveZero = !strZero.empty();
2608  const bool bOneIsLast = strTwo.empty();
2609  const bool bTwoIsLast = !bOneIsLast && strThree.empty();
2610  const bool bThreeIsLast = !bOneIsLast && !bTwoIsLast;
2611 
2612  // main vairables;
2613  std::string strBufFolder("");
2614  std::string strBufPath("");
2615 
2616  // main block
2617  {
2618  // root (either way)
2619  strBufFolder += strRoot;
2620 
2621  // Zero
2622  if (bHaveZero) {
2623  strBufFolder += strZero;
2624  strBufFolder += "/";
2625  }
2626 
2627  // One
2628  if (bOneIsLast) {
2629  strBufPath = strBufFolder;
2630  strBufPath += strOne;
2631  goto ot_exit_block;
2632  }
2633 
2634  strBufFolder += strOne;
2635  strBufFolder += "/";
2636 
2637  // Two
2638  if (bTwoIsLast) {
2639  strBufPath = strBufFolder;
2640  strBufPath += strTwo;
2641  goto ot_exit_block;
2642  }
2643 
2644  strBufFolder += strTwo;
2645  strBufFolder += "/";
2646 
2647  // Three
2648  if (bThreeIsLast) {
2649  strBufPath = strBufFolder;
2650  strBufPath += threeStr;
2651  goto ot_exit_block;
2652  }
2653  // should never get here.
2654  OT_FAIL;
2655  }
2656 ot_exit_block:
2657 
2658  // set as constants. (no more changing).
2659  const std::string strFolder(strBufFolder);
2660  const std::string strPath(strBufPath);
2661  strOutput = strPath;
2662 
2663  if (bMakePath) {
2664  bool bFolderCreated = false;
2665  OTPaths::BuildFolderPath(strFolder.c_str(), bFolderCreated);
2666  }
2667 
2668  {
2669  const bool bFolderExists = OTPaths::PathExists(strFolder.c_str());
2670 
2671  if (bMakePath && !bFolderExists) {
2672  otErr << __FUNCTION__ << ": Error: was told to make path, however "
2673  "cannot confirm the path!\n";
2674  return -4;
2675  }
2676  if (!bMakePath && !bFolderExists) {
2677  otWarn << __FUNCTION__
2678  << ": Debug: Cannot find Folder: " << strFolder << " \n";
2679  }
2680  }
2681 
2682  {
2683  int64_t lFileLength = 0;
2684  const bool bFileExists =
2685  OTPaths::FileExists(strPath.c_str(), lFileLength);
2686 
2687  if (bFileExists)
2688  return lFileLength;
2689  else
2690  return 0;
2691  }
2692 }
2693 
2694 // Store/Retrieve an object. (Storable.)
2695 
2697  std::string strFolder, std::string oneStr,
2698  std::string twoStr, std::string threeStr)
2699 {
2700  std::string strOutput;
2701 
2702  if (0 > ConstructAndCreatePath(strOutput, strFolder, oneStr, twoStr,
2703  threeStr)) {
2704  otErr << __FUNCTION__ << ": Error writing to " << strOutput << ".\n";
2705  return false;
2706  }
2707 
2708  // TODO: Should check here to see if there is a .lock file for the target...
2709 
2710  // TODO: If not, next I should actually create a .lock file for myself right
2711  // here..
2712 
2713  // SAVE to the file here
2714  std::ofstream ofs(strOutput.c_str(), std::ios::out | std::ios::binary);
2715 
2716  if (ofs.fail()) {
2717  otErr << __FUNCTION__ << ": Error opening file: " << strOutput << "\n";
2718  return false;
2719  }
2720 
2721  ofs.clear();
2722  bool bSuccess = theBuffer.WriteToOStream(ofs);
2723  ofs.close();
2724 
2725  // TODO: Remove the .lock file.
2726 
2727  return bSuccess;
2728 }
2729 
2731  std::string strFolder, std::string oneStr,
2732  std::string twoStr, std::string threeStr)
2733 {
2734  std::string strOutput;
2735 
2736  int64_t lRet =
2737  ConstructAndConfirmPath(strOutput, strFolder, oneStr, twoStr, threeStr);
2738 
2739  if (0 > lRet) {
2740  otErr << "StorageFS::" << __FUNCTION__ << ": Error with " << strOutput
2741  << ".\n";
2742  return false;
2743  }
2744  else if (0 == lRet) {
2745  otErr << "StorageFS::" << __FUNCTION__ << ": Failure reading from "
2746  << strOutput << ": file does not exist.\n";
2747  return false;
2748  }
2749 
2750  // READ from the file here
2751 
2752  std::ifstream fin(strOutput.c_str(), std::ios::in | std::ios::binary);
2753 
2754  if (!fin.is_open()) {
2755  otErr << __FUNCTION__ << ": Error opening file: " << strOutput << "\n";
2756  return false;
2757  }
2758 
2759  bool bSuccess = theBuffer.ReadFromIStream(fin, lRet);
2760 
2761  fin.close();
2762 
2763  return bSuccess;
2764 }
2765 
2766 // Store/Retrieve a plain string, (without any packing.)
2767 
2768 bool StorageFS::onStorePlainString(std::string& theBuffer,
2769  std::string strFolder, std::string oneStr,
2770  std::string twoStr, std::string threeStr)
2771 {
2772  std::string strOutput;
2773 
2774  if (0 > ConstructAndCreatePath(strOutput, strFolder, oneStr, twoStr,
2775  threeStr)) {
2776  otErr << "StorageFS::" << __FUNCTION__ << ": Error writing to "
2777  << strOutput << ".\n";
2778  return false;
2779  }
2780 
2781  // TODO: Should check here to see if there is a .lock file for the target...
2782 
2783  // TODO: If not, next I should actually create a .lock file for myself right
2784  // here..
2785 
2786  // SAVE to the file here.
2787  //
2788  // Here's where the serialization code would be changed to CouchDB or
2789  // whatever.
2790  // In a key/value database, szFilename is the "key" and strFinal.Get() is
2791  // the "value".
2792  //
2793  std::ofstream ofs(strOutput.c_str(), std::ios::out | std::ios::binary);
2794 
2795  if (ofs.fail()) {
2796  otErr << __FUNCTION__ << ": Error opening file: " << strOutput << "\n";
2797  return false;
2798  }
2799 
2800  ofs.clear();
2801  ofs << theBuffer;
2802  bool bSuccess = ofs.good();
2803  ofs.close();
2804 
2805  // TODO: Remove the .lock file.
2806 
2807  return bSuccess;
2808 }
2809 
2810 bool StorageFS::onQueryPlainString(std::string& theBuffer,
2811  std::string strFolder, std::string oneStr,
2812  std::string twoStr, std::string threeStr)
2813 {
2814  std::string strOutput;
2815 
2816  int64_t lRet =
2817  ConstructAndConfirmPath(strOutput, strFolder, oneStr, twoStr, threeStr);
2818 
2819  if (0 > lRet) {
2820  otErr << "StorageFS::" << __FUNCTION__ << ": Error with " << strOutput
2821  << ".\n";
2822  return false;
2823  }
2824  else if (0 == lRet) {
2825  otErr << "StorageFS::" << __FUNCTION__ << ": Failure reading from "
2826  << strOutput << ": file does not exist.\n";
2827  return false;
2828  }
2829 
2830  // Open the file here
2831 
2832  std::ifstream fin(strOutput.c_str(), std::ios::in | std::ios::binary);
2833 
2834  if (!fin.is_open()) {
2835  otErr << __FUNCTION__ << ": Error opening file: " << strOutput << "\n";
2836  return false;
2837  }
2838 
2839  // Read from the file as a plain string.
2840 
2841  std::stringstream buffer;
2842  buffer << fin.rdbuf();
2843 
2844  bool bSuccess = fin.good();
2845 
2846  if (bSuccess)
2847  theBuffer = buffer.str(); // here's the actual output of this function.
2848  else {
2849  theBuffer = "";
2850  return false;
2851  }
2852 
2853  bSuccess = (theBuffer.length() > 0);
2854 
2855  fin.close();
2856 
2857  return bSuccess;
2858 }
2859 
2860 // Erase a value by location.
2861 //
2862 bool StorageFS::onEraseValueByKey(std::string strFolder, std::string oneStr,
2863  std::string twoStr, std::string threeStr)
2864 {
2865  std::string strOutput;
2866 
2867  if (0 > ConstructAndConfirmPath(strOutput, strFolder, oneStr, twoStr,
2868  threeStr)) {
2869  otErr << "Error: " << __FUNCTION__
2870  << ": Failed calling ConstructAndConfirmPath with:\n"
2871  "strOutput: " << strOutput << " | strFolder: " << strFolder
2872  << " | oneStr: " << oneStr << " | twoStr: " << twoStr
2873  << " | threeStr: " << threeStr << " \n";
2874 
2875  return false;
2876  }
2877 
2878  // TODO: Should check here to see if there is a .lock file for the target...
2879 
2880  // TODO: If not, next I should actually create a .lock file for myself right
2881  // here..
2882 
2883  // SAVE to the file here. (a blank string.)
2884  //
2885  // Here's where the serialization code would be changed to CouchDB or
2886  // whatever.
2887  // In a key/value database, szFilename is the "key" and strFinal.Get() is
2888  // the "value".
2889  //
2890  std::ofstream ofs(strOutput.c_str(), std::ios::out | std::ios::binary);
2891 
2892  if (ofs.fail()) {
2893  otErr << "Error opening file in StorageFS::onEraseValueByKey: "
2894  << strOutput << "\n";
2895  return false;
2896  }
2897 
2898  ofs.clear();
2899  ofs << "(This space intentionally left blank.)\n";
2900  bool bSuccess = ofs.good() ? true : false;
2901  ofs.close();
2902  // Note: I bet you think I should be overwriting the file 7 times here with
2903  // random data, right? Wrong: YOU need to override OTStorage and create your
2904  // own subclass, where you can override onEraseValueByKey and do that stuff
2905  // yourself. It's outside of the scope of OT.
2906 
2907  if (remove(strOutput.c_str()) != 0) {
2908  bSuccess = false;
2909  otErr << "** Failed trying to delete file: " << strOutput << " \n";
2910  }
2911  else {
2912  bSuccess = true;
2913  otInfo << "** Success deleting file: " << strOutput << " \n";
2914  }
2915 
2916  // TODO: Remove the .lock file.
2917 
2918  return bSuccess;
2919 }
2920 
2921 // Constructor for Filesystem storage context.
2922 //
2924  : Storage()
2925 {
2926  OTString strDataPath;
2927  OTDataFolder::Get(strDataPath);
2928  m_strDataPath = strDataPath.Get();
2929 }
2930 
2932 {
2933 }
2934 
2935 // See if the file is there.
2936 
2937 bool StorageFS::Exists(std::string strFolder, std::string oneStr,
2938  std::string twoStr, std::string threeStr)
2939 {
2940  std::string strOutput;
2941 
2942  return (0 < ConstructAndConfirmPath(strOutput, strFolder, oneStr, twoStr,
2943  threeStr));
2944 }
2945 
2946 // Returns path size, plus path in strOutput.
2947 //
2948 int64_t StorageFS::FormPathString(std::string& strOutput, std::string strFolder,
2949  std::string oneStr, std::string twoStr,
2950  std::string threeStr)
2951 {
2952  return ConstructAndConfirmPath(strOutput, strFolder, oneStr, twoStr,
2953  threeStr);
2954 }
2955 
2956 } // namespace OTDB
2957 
2958 } // namespace opentxs
static EXPORT bool FileExists(const OTString &strFilePath, int64_t &nFileLength)
Definition: OTPaths.cpp:842
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
EXPORT Storage * GetDefaultStorage()
Definition: OTStorage.cpp:480
Storable *( InstantiateFunc)()
Definition: OTStorage.hpp:327
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:530
std::map< InstantiateFuncKey, InstantiateFunc * > mapOfFunctions
Definition: OTStorage.hpp:340
EXPORT bool Unpack(PackedBuffer &inBuf, Storable &outObj)
Definition: OTStorage.cpp:972
static StorageFS * Instantiate()
Definition: OTStorage.hpp:1896
virtual void hookAfterUnpack()
Definition: OTStorage.hpp:384
EXPORT std::string QueryString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:671
EXPORT std::string EncodeObject(Storable &theContents)
Definition: OTStorage.cpp:2389
void SetPacker(OTPacker &thePacker)
Definition: OTStorage.hpp:627
virtual bool onStorePackedBuffer(PackedBuffer &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2696
PackedBuffer * Pack(Storable &inObj)
Definition: OTStorage.cpp:930
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2283
EXPORT bool StoreString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2203
InitOTDBDetails theOTDBConstructor
Definition: OTStorage.cpp:347
virtual bool PackString(std::string &theString)=0
virtual bool ReadFromIStream(std::istream &inStream, int64_t lFilesize)=0
IMPLEMENT_GET_ADD_REMOVE(WalletData::, BitcoinServer) IMPLEMENT_GET_ADD_REMOVE(WalletData
Definition: OTStorage.cpp:1061
virtual int64_t FormPathString(std::string &strOutput, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2948
EXPORT std::string QueryString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2237
EXPORT bool InitDefaultStorage(StorageType eStoreType, PackType ePackType)
Definition: OTStorage.cpp:491
virtual void hookBeforePack()
Definition: OTStorage.hpp:380
OTLOG_IMPORT OTLogStream otOut
virtual bool onEraseValueByKey(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
static EXPORT Storage * Create(StorageType eStorageType, PackType ePackType)
Definition: OTStorage.cpp:2145
EXPORT bool CheckStringsExistInOrder(std::string &strFolder, std::string &oneStr, std::string &twoStr, std::string &threeStr, const char *szFuncName=nullptr)
Definition: OTStorage.cpp:549
static EXPORT bool BuildFolderPath(const OTString &strFolderPath, bool &out_bFolderCreated)
Definition: OTPaths.cpp:1320
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
virtual bool onQueryPlainString(std::string &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
bool ConfirmOrCreateFolder(const char *szFolderName, struct stat *pst=nullptr)
Definition: OTStorage.cpp:2516
EXPORT Storable * QueryObject(StoredObjectType theObjectType, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:788
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT std::string EncodeObject(Storable &theContents)
Definition: OTStorage.cpp:818
EXPORT Storable * DecodeObject(StoredObjectType theObjectType, std::string strInput)
Definition: OTStorage.cpp:2435
virtual bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:2128
virtual bool onQueryPlainString(std::string &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2810
virtual bool onQueryPackedBuffer(PackedBuffer &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
std::pair< PackType, StoredObjectType > InstantiateFuncKey
Definition: OTStorage.hpp:329
virtual void SetData(const uint8_t *pData, size_t theSize)=0
virtual bool WriteToOStream(std::ostream &outStream)=0
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT Storage * CreateStorageContext(StorageType eStoreType, PackType ePackType=OTDB_DEFAULT_PACKER)
Definition: OTStorage.cpp:522
const char * StoredObjectTypeStrings[]
Definition: OTStorage.cpp:300
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
virtual bool onQueryPackedBuffer(PackedBuffer &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2730
int64_t ConstructAndConfirmPath(std::string &strOutput, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2562
#define OT_ASSERT(x)
Definition: Assert.hpp:150
static OTPacker * Create(PackType ePackType)
Definition: OTStorage.cpp:889
virtual bool onStorePlainString(std::string &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
OTDB::Storage * s_pStorage
Definition: OTStorage.cpp:293
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2290
EXPORT bool EraseValueByKey(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:843
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
virtual bool UnpackString(std::string &theString)=0
OTLOG_IMPORT OTLogStream otInfo
virtual bool onStorePackedBuffer(PackedBuffer &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
EXPORT StorageType GetType() const
Definition: OTStorage.cpp:2187
EXPORT bool StoreString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:644
virtual size_t GetSize()=0
#define OT_FAIL
Definition: Assert.hpp:139
bool ConfirmFile(const char *szFileName, struct stat *pst=nullptr)
Definition: OTStorage.cpp:2530
static EXPORT bool ConfirmCreateFolder(const OTString &strExactPath, bool &out_Exists, bool &out_IsNew)
Definition: OTPaths.cpp:921
OTLOG_IMPORT OTLogStream otWarn
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT bool EraseValueByKey(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2488
EXPORT const void * GetPayloadPointer() const
Definition: OTPayload.cpp:318
OTLOG_IMPORT OTLogStream otErr
EXPORT OTPacker * GetPacker(PackType ePackType=OTDB_DEFAULT_PACKER)
Definition: OTStorage.cpp:2103
Storable & inObj
Definition: OTStorage.hpp:376
OTDB::mapOfFunctions * pFunctionMap
Definition: OTStorage.cpp:295
virtual PackedBuffer * CreateBuffer()=0
EXPORT Storable * QueryObject(StoredObjectType theObjectType, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2336
virtual int64_t FormPathString(std::string &strOutput, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")=0
EXPORT int64_t FormPathString(std::string &strOutput, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:612
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
PackType GetType() const
Definition: OTStorage.cpp:914
static EXPORT Storable * Create(StoredObjectType eType, PackType thePackType)
Definition: OTStorage.cpp:860
EXPORT Storable * DecodeObject(StoredObjectType theObjectType, std::string strInput)
Definition: OTStorage.cpp:830
virtual const uint8_t * GetData()=0
virtual bool onEraseValueByKey(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2862
EXPORT bool StoreObject(Storable &theContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:759
static EXPORT bool AppendFile(OTString &out_strPath, const OTString &strBasePath, const OTString &strFileName)
Definition: OTPaths.cpp:1245
virtual bool onUnpack(PackedBuffer &theBuffer, Storable &outObj)=0
static EXPORT bool PathExists(const OTString &strPath)
Definition: OTPaths.cpp:802
static EXPORT OTString Get()
uint32_t GetSize() const
Definition: OTData.hpp:174
virtual bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2937
int64_t ConstructAndCreatePath(std::string &strOutput, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2552
virtual bool onStorePlainString(std::string &theBuffer, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2768
EXPORT bool StoreObject(Storable &theContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:2301