EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CachedObjectMgr.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur
24 */
25 
77 #include "eve-common.h"
78 
79 #include "cache/CachedObjectMgr.h"
80 #include "marshal/EVEMarshal.h"
82 #include "packets/ObjectCaching.h"
83 #include "python/PyVisitor.h"
84 #include "python/PyRep.h"
85 #include "python/PyDumpVisitor.h"
86 #include "utils/EVEUtils.h"
87 
88 const uint32 CacheFileMagic = 0xFF886622;
89 static const uint32 HackCacheNodeID = 333444;
90 
92 {
93  CachedObjMapItr cur, end;
94  cur = m_cachedObjects.begin();
95  end = m_cachedObjects.end();
96 
97  for(; cur != end; cur++) {
98  SafeDelete( cur->second );
99  }
100 }
101 
102 /************************************************************************/
103 /* CacheRecord */
104 /************************************************************************/
105 CachedObjectMgr::CacheRecord::CacheRecord() : objectID(nullptr), timestamp(0), version(0), cache(nullptr) {}
107 {
108  PyDecRef( objectID );
109  PyDecRef( cache );
110 }
111 
113 {
114  objectCaching_CachedObject_spec spec;
115 
116  spec.objectID = objectID->Clone();
117  spec.nodeID = HackCacheNodeID;
118  spec.timestamp = timestamp;
119  spec.version = version;
120 
121  return(spec.Encode());
122 }
123 
124 
125 /*
126  * # Cache Logging:
127  * CACHE=1
128  * CACHE__ERROR=1
129  * CACHE__WARNING=0
130  * CACHE__MESSAGE=0
131  * CACHE__DEBUG=0
132  * CACHE__INFO=0
133  * CACHE__TRACE=0
134  * CACHE__DUMP=0
135  */
136 //extract out the string contents of the object ID... if its a single string,
137 // then this visit will be boring, but if its a nested structure of strings,
138 // its more interesting, either way we should come out with some string...
139 std::string CachedObjectMgr::OIDToString(const PyRep *objectID)
140 {
142  if ( !objectID->visit( v ) ) {
143  sLog.Error("Cached Obj Mgr", "Failed to convert cache hind object ID into collapsed string:");
144  objectID->Dump(CACHE__DUMP, " ");
145  assert(false);
146  return "";
147  }
148  return v.result;
149 }
150 
151 bool CachedObjectMgr::HaveCached(const std::string &objectID) const
152 {
153  //this is very sub-optimal, but it keeps things more consistent (in case StringCollapseVisitor ever gets more complicated)
154  PyString *str = new PyString( objectID );
155  bool ret = HaveCached(str);
156  PyDecRef(str);
157  return ret;
158 }
159 
160 bool CachedObjectMgr::HaveCached(const PyRep *objectID) const
161 {
162  PyIncRef(objectID);
163  const std::string str = OIDToString(objectID);
164 
165  return (m_cachedObjects.find(str) != m_cachedObjects.end());
166 }
167 
169 {
170  PyIncRef(objectID);
171  const std::string str = OIDToString(objectID);
172  CachedObjMapItr res = m_cachedObjects.find(str);
173 
174  if (res != m_cachedObjects.end()) {
175  SafeDelete( res->second );
176  m_cachedObjects.erase(res);
177  }
178 }
179 
180 //#define RAW_CACHE_CONTENTS
181 
182 void CachedObjectMgr::UpdateCacheFromSS(const std::string &objectID, PySubStream **in_cached_data)
183 {
184  PyCachedObjectDecoder cache;
185  if (!cache.Decode(in_cached_data)) {
186  sLog.Error("CachedObjMgr","Failed to decode stream");
187  return;
188  }
189 
190  PyString* str = new PyString( objectID );
191  PyBuffer* buf = cache.cache->data();
192  _UpdateCache(str, &buf);
193 
194  PyDecRef( str );
195 }
196 
197 void CachedObjectMgr::UpdateCache(const std::string &objectID, PyRep **in_cached_data)
198 {
199  PyString *str = new PyString( objectID );
200  UpdateCache(str, in_cached_data);
201  PyDecRef(str);
202 }
203 
204 void CachedObjectMgr::UpdateCache(const PyRep *objectID, PyRep **in_cached_data)
205 {
206  PyRep* cached_data(*in_cached_data);
207  *in_cached_data = nullptr;
208 
209  //if (is_log_enabled(CACHE__DUMP)) {
210  // PyLogsysDump dumper(CACHE__DUMP, CACHE__DUMP, false, true);
211  //cached_data->visit(&dumper, 0);
212  //}
213 
214  Buffer* buf = new Buffer();
215  bool res = MarshalDeflate( cached_data, *buf );
216 
217  if ( res ) {
218  PyBuffer* pbuf = new PyBuffer( &buf );
219  _UpdateCache( objectID, &pbuf );
220  } else {
221  sLog.Error( "Cached Obj Mgr", "Failed to marshal or deflate new cache object." );
222  }
223 
224  SafeDelete( buf );
225 }
226 
227 void CachedObjectMgr::_UpdateCache(const PyRep *objectID, PyBuffer **pbuf)
228 {
229  //this is the hard one..
230  CacheRecord *r = new CacheRecord();
231  r->timestamp = GetFileTimeNow();
232  r->objectID = objectID->Clone();
233 
234  // retake ownership
235  r->cache = *pbuf;
236  *pbuf = nullptr;
237 
238  r->version = CRC32::Generate( &r->cache->content()[0], r->cache->content().size() );
239 
240  const std::string str = OIDToString(objectID);
241 
242  //find and destroy any older version of this object.
243  CachedObjMapItr res = m_cachedObjects.find(str);
244 
245  if (res != m_cachedObjects.end()) {
246 
247  sLog.Debug("CachedObjMgr","Destroying old cached object with ID '%s' of length %u with checksum 0x%x", str.c_str(), res->second->cache->content().size(), res->second->version);
248  SafeDelete( res->second );
249  }
250 
251  sLog.Debug("CachedObjMgr","Registering new cached object with ID '%s' of length %u with checksum 0x%x", str.c_str(), r->cache->content().size(), r->version);
252 
253  m_cachedObjects[str] = r;
254 }
255 
256 PyObject *CachedObjectMgr::MakeCacheHint(const std::string &objectID)
257 {
258  //this is sub-optimal, but it keeps things more consistent (in case StringCollapseVisitor ever gets more complicated)
259  PyString* str = new PyString( objectID );
260  PyObject* obj(MakeCacheHint(str));
261  PyDecRef(str);
262  return obj;
263 }
264 
266 {
267  const std::string str = OIDToString(objectID);
268 
269  CachedObjMapItr res = m_cachedObjects.find(str);
270  if (res == m_cachedObjects.end())
271  return nullptr;
272 
273  return res->second->EncodeHint();
274 }
275 
276 PyObject *CachedObjectMgr::GetCachedObject(const std::string &objectID)
277 {
278  //this is sub-optimal, but it keeps things more consistent (in case StringCollapseVisitor ever gets more complicated)
279  PyString* str = new PyString( objectID );
280  PyObject* obj(GetCachedObject(str));
281  PyDecRef(str);
282  return obj;
283 }
284 
286 {
287  const std::string str = OIDToString(objectID);
288 
289  CachedObjMapItr res = m_cachedObjects.find(str);
290  if (res == m_cachedObjects.end())
291  return nullptr;
292 
293  PyCachedObject co;
294  co.timestamp = res->second->timestamp;
295  co.version = res->second->version;
296  co.nodeID = HackCacheNodeID; //hack, doesn't matter until we have multi-node networks.
297  co.shared = true;
298  co.objectID = res->second->objectID->Clone();
299  co.cache = res->second->cache;
300 
301  if (res->second->cache->content().size() == 0 || res->second->cache->content()[0] == MarshalHeaderByte)
302  co.compressed = false;
303  else
304  co.compressed = true;
305 
306  sLog.Debug("CachedObjMgr","Returning cached object '%s' with checksum 0x%x", str.c_str(), co.version);
307 
308  PyObject* result = co.Encode();
309  co.cache = nullptr; //avoid a copy
310 
311  return result;
312 }
313 
314 bool CachedObjectMgr::IsCacheUpToDate(const PyRep *objectID, uint32 version, int64 timestamp)
315 {
316  const std::string str = OIDToString(objectID);
317 
318  CachedObjMapItr res = m_cachedObjects.find(str);
319  if (res == m_cachedObjects.end())
320  return false;
321 
322  //for now, only support exact matches...
323  return ( res->second->version == version
324  && res->second->timestamp == timestamp);
325 }
326 
327 bool CachedObjectMgr::LoadCachedFromFile(const std::string &cacheDir, const std::string &objectID)
328 {
329  //this is sub-optimal, but it keeps things more consistent (in case StringCollapseVisitor ever gets more complicated)
330  PyString* str = new PyString(objectID);
331  bool ret = LoadCachedFromFile(cacheDir, str);
332  PyDecRef(str);
333  return ret;
334 }
335 
341 bool CachedObjectMgr::LoadCachedFromFile(const std::string &cacheDir, const PyRep *objectID)
342 {
343  const std::string str = OIDToString(objectID);
344 
345  std::string filename(cacheDir);
346  filename += "/" + str + ".cache";
347 
348  FILE *f = fopen(filename.c_str(), "rb");
349 
350  if (f == nullptr)
351  return false;
352 
353  CacheFileHeader header;
354  if (fread(&header, sizeof(header), 1, f) != 1) {
355  fclose(f);
356  return false;
357  }
358 
359  /* check if its a valid cache file */
360  if (header.magic != CacheFileMagic) {
361  fclose(f);
362  return false;
363  }
364 
365  Buffer* buf = new Buffer( header.length );
366 
367  if ( fread( &(*buf)[0], sizeof( uint8 ), header.length, f ) != header.length ) {
368  SafeDelete( buf );
369  fclose( f );
370  return false;
371  }
372 
373  fclose( f );
374 
375  CachedObjMapItr res = m_cachedObjects.find( str );
376 
377  if ( res != m_cachedObjects.end() )
378  SafeDelete( res->second );
379 
380  CacheRecord* cache = m_cachedObjects[ str ] = new CacheRecord;
381  cache->objectID = objectID->Clone();
382  cache->cache = new PyBuffer( &buf );
383  cache->timestamp = header.timestamp;
384  cache->version = header.version;
385 
386  m_cachedObjects[ str ] = cache;
387 
388  SafeDelete( buf );
389  return true;
390 }
391 
392 //this is sub-optimal, but it keeps things more consistent (in case StringCollapseVisitor ever gets more complicated)
393 bool CachedObjectMgr::SaveCachedToFile(const std::string &cacheDir, const std::string &objectID) const
394 {
395  PyString* str = new PyString(objectID);
396  bool ret = SaveCachedToFile(cacheDir, str);
397  PyDecRef(str);
398  return ret;
399 }
400 
401 bool CachedObjectMgr::SaveCachedToFile(const std::string &cacheDir, const PyRep *objectID) const
402 {
403  const std::string str = OIDToString(objectID);
404  CachedObjMapConstItr res = m_cachedObjects.find(str);
405 
406  /* make sure we don't try to save a object we don't have */
407  if (res == m_cachedObjects.end())
408  return false;
409 
410  std::string filename(cacheDir);
411  filename += "/";
412  filename += str;
413  filename += ".cache";
414 
415  FILE *f = fopen(filename.c_str(), "wb");
416 
417  if (f == nullptr)
418  return false;
419 
420  CacheFileHeader header;
421  header.timestamp = res->second->timestamp;
422  header.version = res->second->version;
423  header.magic = CacheFileMagic;
424  header.length = res->second->cache->content().size();
425 
426  if (fwrite(&header, sizeof(header), 1, f) != 1) {
427  fclose(f);
428  return false;
429  }
430 
431  if (fwrite(&res->second->cache->content()[0], sizeof(uint8), header.length, f) != header.length) {
432  assert(false);
433  fclose(f);
434  return false;
435  }
436  fclose(f);
437  return true;
438 }
439 
440 /*
441 void CachedObjectMgr::AddCacheHint(const char *oname, const char *key, PyDict *into) {
442  PyRep *t = _MakeCacheHint(oname);
443  if (t == nullptr)
444  return;
445  into->add(key, t);
446 }
447 */
448 
449 
450 /*bool CachedObjectMgr::AddCachedFileContents(const char *filename, const char
451  *oname, PySubStream *into) { PySubStream *cache;
452  if (!LoadCachedFile(filename, oname, cache))
453  return false;
454 
455 }*/
456 
458 {
459  PyString* str = new PyString(obj_name);
460  PySubStream* ret = LoadCachedFile(str, obj_name);
461  PyDecRef(str);
462  return ret;
463 }
464 
466 {
467  std::string fname;
468  GetCacheFileName(key, fname);
469 
470  std::string abs_fname = "../data/cache/";
471  abs_fname += fname;
472 
473  return LoadCachedFile(abs_fname.c_str(), oname);
474 }
475 
476 PySubStream* CachedObjectMgr::LoadCachedFile( const char* abs_fname, const char* oname )
477 {
478  FILE* f = fopen( abs_fname, "rb" );
479 
480  if ( f == nullptr ) {
481  sLog.Error("CachedObjMgr","Unable to open cache file '%s' for oname '%s': %s", abs_fname, oname, strerror( errno ) );
482  return 0;
483  }
484 
485  int64 file_length = filesize( f );
486  if ( file_length == 0 )
487  {
488  sLog.Error("CachedObjMgr","Unable to stat cache file '%s' for oname '%s'", abs_fname, oname );
489  fclose( f );
490  return 0;
491  }
492 
493  Buffer* buf = new Buffer(static_cast<size_t>(file_length));
494 
495  if ( file_length != fread( &( *buf )[0], sizeof( uint8 ), static_cast<size_t>(file_length), f ) ) {
496  sLog.Error("CachedObjMgr","Unable to read cache file '%s' for oname '%s%': %s", abs_fname, oname, strerror( errno ) );
497  SafeDelete( buf );
498  fclose( f );
499  return 0;
500  }
501 
502  fclose( f );
503  sLog.Debug("CachedObjMgr","Loaded cache file for '%s': length %u", oname, file_length );
504 
506  PySubStream* res = new PySubStream( new PyBuffer( &buf ) );
507  SafeDelete( buf );
508  return res;
509 }
510 
511 PyCachedObjectDecoder *CachedObjectMgr::LoadCachedObject(const char *filename, const char *oname)
512 {
513  PySubStream* ss = LoadCachedFile(filename, oname);
514  if ( ss == nullptr )
515  return nullptr;
516 
518  if (!obj->Decode(&ss)) { //ss is consumed.
519  SafeDelete( obj );
520  return nullptr;
521  }
522 
523  return obj;
524 }
525 
526 PyCachedCall *CachedObjectMgr::LoadCachedCall(const char *filename, const char *oname)
527 {
528  PySubStream* ss = LoadCachedFile(filename, oname);
529  if ( ss == nullptr )
530  return nullptr;
531 
532  PyCachedCall *obj = new PyCachedCall();
533  if (!obj->Decode(&ss)) { //ss is consumed.
534  SafeDelete( obj );
535  return nullptr;
536  }
537 
538  return obj;
539 }
540 
541 // Base64 encoding utilities
542 #include <Base64.h>
543 void CachedObjectMgr::GetCacheFileName(PyRep *key, std::string &into)
544 {
545  Buffer data;
546  Marshal( key, data );
547 
548  Base64::encode( &data[0], data.size(), into, false );
549 
550  std::string::size_type epos = into.find('=');
551  if (epos != std::string::npos)
552  into.resize(epos);
553 
554  into += ".cache";
555 }
556 
557 /*
558 PyRep *CachedObjectMgr::_MakeCacheHint(const char *oname) {
559  //this is a ton of work we are doing here to generate a simple hint, but
560  //theres not really a better way to do it while we are using the on-disk
561  //cache files as the data source.
562  PyCachedObject *obj = LoadCachedObject(oname);
563  if (obj == nullptr) {
564  _log(SERVICE__ERROR, "Unable to load cache file for '%s' in order to build hint", oname);
565  return nullptr;
566  }
567 
568  PyRep *hint = obj->EncodeHint();
569  delete obj;
570  return(hint);
571 }
572 */
573 
575 : timestamp(0),
576  version(0),
577  nodeID(0),
578  shared(false),
579  cache(nullptr),
580  compressed(false),
581  objectID(nullptr)
582 {
583 }
584 
586 {
587  PySafeDecRef( cache );
589 }
590 
592 : timestamp(0),
593  version(0),
594  nodeID(0),
595  shared(false),
596  cache(nullptr),
597  compressed(false),
598  objectID(nullptr)
599 {
600 }
601 
603 {
604  PySafeDecRef( cache );
606 }
607 
609 {
610  PyCachedObject *res = new PyCachedObject();
611  res->timestamp = timestamp;
612  res->version = version;
613  res->nodeID = nodeID;
614  res->shared = shared;
615  res->cache = (PyBuffer *) cache->Clone();
616  res->compressed = compressed;
617  res->objectID = objectID->Clone();
618  return res;
619 }
620 
621 void PyCachedObjectDecoder::Dump(FILE *into, const char *pfx, bool contents_too)
622 {
623  std::string s(pfx);
624  s += " ";
625  fprintf(into, "%sCached Object:\n", pfx);
626  fprintf(into, "%s ObjectID:\n", pfx);
627  objectID->Dump(into, s.c_str());
628  fprintf(into, "%s Version Time: %" PRIu64 "\n", pfx, timestamp);
629  fprintf(into, "%s Version: %u\n", pfx, version);
630  fprintf(into, "%s NodeID: %u\n", pfx, nodeID);
631  fprintf(into, "%s Shared: %s\n", pfx, shared?"yes":"no");
632  fprintf(into, "%s Compressed: %s\n", pfx, compressed?"yes":"no");
633  if (contents_too) {
634  fprintf(into, "%s Contents:\n", pfx);
635  cache->Dump(into, s.c_str());
636  }
637 }
638 
639 void PyCachedObject::Dump(FILE *into, const char *pfx, bool contents_too)
640 {
641  std::string s(pfx);
642  s += " ";
643  fprintf(into, "%sCached Object:\n", pfx);
644  fprintf(into, "%s ObjectID:\n", pfx);
645  objectID->Dump(into, s.c_str());
646  fprintf(into, "%s Version Time: %" PRIu64 "\n", pfx, timestamp);
647  fprintf(into, "%s Version: %u\n", pfx, version);
648  fprintf(into, "%s NodeID: %u\n", pfx, nodeID);
649  fprintf(into, "%s Shared: %s\n", pfx, shared?"yes":"no");
650  fprintf(into, "%s Compressed: %s\n", pfx, compressed?"yes":"no");
651  if (contents_too) {
652  fprintf(into, "%s Contents:\n", pfx);
653  cache->Dump(into, s.c_str());
654  }
655 }
656 
658 {
659  PySubStream *ss = *in_ss; //consume
660  *in_ss = nullptr;
661 
662  PySafeDecRef( cache );
664 
665  ss->DecodeData();
666  if (ss->decoded() == nullptr) {
667  sLog.Error("PyCachedObjectDecoder","Unable to decode initial stream for PycachedObject");
668 
669  PyDecRef( ss );
670  return false;
671  }
672 
673  if (!ss->decoded()->IsObject()) {
674  sLog.Error("PyCachedObjectDecoder","Cache substream does not contain an object: %s", ss->decoded()->TypeString());
675 
676  PyDecRef( ss );
677  return false;
678  }
679  PyObject *po = (PyObject *) ss->decoded();
680  //TODO: could check type string, dont care... (should be objectCaching.CachedObject)
681 
682  if (!po->arguments()->IsTuple()) {
683  sLog.Error("PyCachedObjectDecoder","Cache object's args is not a tuple: %s", po->arguments()->TypeString());
684 
685  PyDecRef( ss );
686  return false;
687  }
688  PyTuple *args = (PyTuple *) po->arguments();
689 
690  if (args->items.size() != 7) {
691  sLog.Error("PyCachedObjectDecoder","Cache object's args tuple has %lu elements instead of 7", args->items.size());
692 
693  PyDecRef( ss );
694  return false;
695  }
696 
697  if (!args->items[0]->IsTuple()) {
698  sLog.Error("PyCachedObjectDecoder","Cache object's arg %d is not a Tuple: %s", 0, args->items[0]->TypeString());
699 
700  PyDecRef( ss );
701  return false;
702  }
703  //ignore unknown [1]
704  /*if (!args->items[1]->IsInt()) {
705  _log(SERVICE__ERROR, "Cache object's arg %d is not a None: %s", 1, args->items[1]->TypeString());
706 
707  PyDecRef( ss );
708  return false;
709  }*/
710  if (!args->items[2]->IsInt()) {
711  sLog.Error("PyCachedObjectDecoder","Cache object's arg %d is not an Integer: %s", 2, args->items[2]->TypeString());
712  PyDecRef( ss );
713  return false;
714  }
715 
716  if (!args->items[3]->IsInt()) {
717  sLog.Error("PyCachedObjectDecoder","Cache object's arg %d is not an Integer: %s", 3, args->items[3]->TypeString());
718  PyDecRef( ss );
719  return false;
720  }
721 
722  if (!args->items[5]->IsInt()) {
723  sLog.Error("PyCachedObjectDecoder","Cache object's arg %d is not a : %s", 5, args->items[5]->TypeString());
724  PyDecRef( ss );
725  return false;
726  }
727 
728  PyTuple *objVt = (PyTuple *) args->items[0];
729  if (!objVt->items[0]->IsInt()) {
730  sLog.Error("PyCachedObjectDecoder","Cache object's version tuple %d is not an Integer: %s", 0, objVt->items[0]->TypeString());
731  PyDecRef( ss );
732  return false;
733  }
734 
735  if (!objVt->items[1]->IsInt()) {
736  sLog.Error("PyCachedObjectDecoder","Cache object's version tuple %d is not an Integer: %s", 1, objVt->items[1]->TypeString());
737  PyDecRef( ss );
738  return false;
739  }
740 
741  PyInt *nodeidr = (PyInt *) args->items[2];
742  PyInt *sharedr = (PyInt *) args->items[3];
743  PyInt *compressedr = (PyInt *) args->items[5];
744  PyInt *timer = (PyInt *) objVt->items[0];
745  PyInt *versionr = (PyInt *) objVt->items[1];
746 
747  timestamp = timer->value();
748  version = versionr->value();
749  nodeID = nodeidr->value();
750  shared = ( sharedr->value() != 0 );
751  compressed = ( compressedr->value() != 0 );
752 
753  //content (do this as the last thing, since its the heavy lifting):
754  if (args->items[4]->IsSubStream()) {
755  cache = (PySubStream *) args->items[4];
756  //take it
757  args->items[4] = nullptr;
758  } else if (args->items[4]->IsBuffer()) {
759  //this is a data buffer, likely compressed.
760  PyBuffer* buf = args->items[4]->AsBuffer();
761  cache = new PySubStream( buf );
762  } else if (args->items[4]->IsString()) {
763  //this is a data buffer, likely compressed, not sure why it comes through as a string...
764  PyString* str = args->items[4]->AsString();
765  cache = new PySubStream( new PyBuffer( *str ) );
766  } else {
767  sLog.Error("PyCachedObjectMgr", "Cache object's arg %d is not a substream or buffer: %s", 4, args->items[4]->TypeString());
768  PyDecRef( ss );
769  return false;
770  }
771 
772  objectID = args->items[6]->Clone();
773 
774  PyDecRef( ss );
775  return true;
776 }
777 
779 {
780  PyTuple *arg_tuple = new PyTuple(7);
781  arg_tuple->items[0] = new_tuple(new PyLong(timestamp), new PyInt(version));
782  arg_tuple->items[1] = new PyNone();
783  arg_tuple->items[2] = new PyInt(nodeID);
784  arg_tuple->items[3] = new PyInt(shared?1:0);
785 
786  //compression or not, we want to encode this into bytes so it doesn't
787  //get cloned in object form just to be encoded later
788 /* cache->EncodeData();
789  if (compressed) {
790  uint8 *buf = new uint8[cache->length];
791  uint32 deflen = DeflatePacket(cache->data, cache->length, buf, cache->length);
792  if (deflen == 0 || deflen >= cache->length) {
793  //failed to deflate or it did no good (client checks this)
794  memcpy(buf, cache->data, cache->length);
795  deflen = cache->length;
796  compressed = false;
797  }
798  //buf is consumed:
799  arg_tuple->items[4] = new PyBuffer(&buf, deflen);
800  } else {
801  //TODO: we dont really need to clone this if we can figure out a way to say "this is read only"
802  //or if we can change this encode method to consume the PyCachedObject (which will almost always be the case)
803  arg_tuple->items[4] = cache->Clone();
804  }*/
805  //TODO: we don't really need to clone this if we can figure out a way to say "this is read only"
806  //or if we can change this encode method to consume the PyCachedObject (which will almost always be the case)
807  arg_tuple->items[4] = cache->Clone();
808  arg_tuple->items[5] = new PyInt(compressed?1:0);
809  //same cloning statement as above.
810  arg_tuple->items[6] = objectID->Clone();
811 
812  return new PyObject( "objectCaching.CachedObject", arg_tuple );
813 }
814 
816  PyTuple *versiont = new PyTuple(2);
817  versiont->items[0] = new PyLong(timestamp);
818  versiont->items[1] = new PyInt(version);
819  PyTuple *arg_tuple = new PyTuple(3);
820  arg_tuple->items[0] = objectID->Clone();
821  arg_tuple->items[1] = new PyInt(nodeID);
822  arg_tuple->items[2] = versiont;
823 
824  return new PyObject( "util.CachedObject", arg_tuple );
825 }
826 
827 
828 PyCachedCall::PyCachedCall() : result(nullptr) {}
830 {
831  PySafeDecRef( result );
832 }
833 
835  PyCachedCall *res = new PyCachedCall();
836  res->result = result->Clone();
837  return res;
838 }
839 
840 void PyCachedCall::Dump(FILE *into, const char *pfx, bool contents_too)
841 {
842  std::string s(pfx);
843  s += " ";
844  fprintf(into, "%sCached Call: (empty right now) \n", pfx);
845  if (contents_too) {
846  fprintf(into, "%s Contents:\n", pfx);
847  result->Dump(into, s.c_str());
848  }
849 }
850 
852 {
853  PySubStream *ss = *in_ss; //consume
854  *in_ss = nullptr;
855 
856  PySafeDecRef( result );
857 
858  ss->DecodeData();
859  if (ss->decoded() == nullptr) {
860  sLog.Error("PyCachedCall","Unable to decode initial stream for PyCachedCall");
861  PyDecRef( ss );
862  return false;
863  }
864 
865  if (!ss->decoded()->IsDict()) {
866  sLog.Error("PyCachedCall","Cached call substream does not contain a dict: %s", ss->decoded()->TypeString());
867  PyDecRef( ss );
868  return false;
869  }
870  PyDict *po = (PyDict *) ss->decoded();
871 
872  PyDict::const_iterator cur, end;
873  cur = po->begin();
874  end = po->end();
875  for(; cur != end; cur++) {
876  if (!cur->first->IsString())
877  continue;
878  PyString *key = (PyString *) cur->first;
879  if ( key->content() == "lret" )
880  result = cur->second->Clone();
881  }
882 
883  PyDecRef( ss );
884  return (result != nullptr);
885 }
bool IsCacheUpToDate(const PyRep *objectID, uint32 version, int64 timestamp)
CachedObjMap::const_iterator CachedObjMapConstItr
Base Python wire object.
Definition: PyRep.h:66
unsigned __int8 uint8
Definition: eve-compat.h:46
bool MarshalDeflate(const PyRep *rep, Buffer &into, const uint32 deflationLimit)
Definition: EVEMarshal.cpp:44
PyCachedCall * LoadCachedCall(const char *filename, const char *oname)
void GetCacheFileName(PyRep *key, std::string &into)
bool HaveCached(const std::string &objectID) const
Python string.
Definition: PyRep.h:430
int32 value() const
Definition: PyRep.h:247
Python's dictionary.
Definition: PyRep.h:719
const Buffer & content() const
Get the const PyBuffer content.
Definition: PyRep.h:407
bool IsTuple() const
Definition: PyRep.h:108
virtual PyRep * Clone() const =0
Clones object.
PyCachedObject * Clone() const
PyBuffer * data() const
Definition: PyRep.h:1047
static const uint32 HackCacheNodeID
PyRep * Clone() const
Clones object.
Definition: PyRep.cpp:773
PyObject * MakeCacheHint(const PyRep *objectID)
bool IsObject() const
Definition: PyRep.h:115
bool Marshal(const PyRep *rep, Buffer &into)
Definition: EVEMarshal.cpp:36
Python tuple.
Definition: PyRep.h:567
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
void UpdateCache(const std::string &objectID, PyRep **in_cached_data)
PyRep * arguments() const
Definition: PyRep.h:845
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
PyCachedCall * Clone() const
* args
PyRep * decoded() const
Definition: PyRep.h:1048
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
Generic class for buffers.
Definition: Buffer.h:40
void DecodeData() const
Definition: PyRep.cpp:1125
Python object.
Definition: PyRep.h:826
PySubStream * LoadCachedFile(const char *obj_name)
PyTuple * new_tuple(int64 arg1)
Definition: PyRep.cpp:1160
void Dump(FILE *into, const char *pfx, bool contents_too=false)
Python's "none".
Definition: PyRep.h:352
PyObject * Encode()
bool SaveCachedToFile(const std::string &cacheDir, const std::string &objectID) const
void UpdateCacheFromSS(const std::string &objectID, PySubStream **in_cached_data)
const uint32 CacheFileMagic
Python integer.
Definition: PyRep.h:231
CachedObjMap m_cachedObjects
CachedObjMap::iterator CachedObjMapItr
void InvalidateCache(const PyRep *objectID)
static uint32 Generate(const uint8 *buf, size_t bufsize)
Definition: crc32.h:41
void Dump(FILE *into, const char *pfx, bool contents_too=false)
#define PyDecRef(op)
Definition: PyRep.h:57
static void encode(FILE *, std::string &, bool add_crlf=true)
Definition: Base64.cpp:54
unsigned __int32 uint32
Definition: eve-compat.h:50
if(sConfig.world.saveOnMove)
#define PyIncRef(op)
Definition: PyRep.h:56
const_iterator begin() const
Definition: PyRep.h:766
static std::string OIDToString(const PyRep *objectID)
double GetFileTimeNow()
Definition: utils_time.cpp:84
bool IsDict() const
Definition: PyRep.h:110
signed __int64 int64
Definition: eve-compat.h:51
#define PRIu64
Definition: eve-compat.h:85
static const uint8 MarshalHeaderByte
storage_type::const_iterator const_iterator
Definition: PyRep.h:750
void _UpdateCache(const PyRep *objectID, PyBuffer **buffer)
size_type size() const
Definition: Buffer.h:610
PyObject * EncodeHint() const
const std::string & content() const
Get the PyString content.
Definition: PyRep.h:458
void Dump(FILE *into, const char *pfx, bool contents_too=false)
const_iterator end() const
Definition: PyRep.h:767
bool Decode(PySubStream **ss)
#define PySafeDecRef(op)
Definition: PyRep.h:61
PyObject * GetCachedObject(const PyRep *objectID)
Python buffer.
Definition: PyRep.h:382
storage_type items
Definition: PyRep.h:628
PyCachedObjectDecoder * LoadCachedObject(const char *filename, const char *oname)
typeID Spawn an NPC with the specified type text Search for items matching the specified query() type() key(value)-Send an OnRemoteMessage" ) COMMAND( setbpattr
const char * TypeString() const
Definition: PyRep.cpp:76
bool LoadCachedFromFile(const std::string &cacheDir, const std::string &objectID)
int64 filesize(const char *filename)
Obtains filesize.
Definition: misc.cpp:75
virtual bool visit(PyVisitor &v) const =0
Visits object.
bool Decode(PySubStream **ss)
Python long integer.
Definition: PyRep.h:261