mirror of
git://git.acid.vegas/anope.git
synced 2024-11-30 11:36:41 +00:00
336 lines
7.8 KiB
C++
336 lines
7.8 KiB
C++
/*
|
|
*
|
|
* (C) 2003-2022 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*/
|
|
|
|
#ifndef SERIALIZE_H
|
|
#define SERIALIZE_H
|
|
|
|
#include <sstream>
|
|
|
|
#include "anope.h"
|
|
#include "base.h"
|
|
|
|
namespace Serialize
|
|
{
|
|
class Data
|
|
{
|
|
public:
|
|
enum Type
|
|
{
|
|
DT_TEXT,
|
|
DT_INT
|
|
};
|
|
|
|
virtual ~Data() { }
|
|
|
|
virtual std::iostream& operator[](const Anope::string &key) = 0;
|
|
virtual std::set<Anope::string> KeySet() const { throw CoreException("Not supported"); }
|
|
virtual size_t Hash() const { throw CoreException("Not supported"); }
|
|
|
|
virtual void SetType(const Anope::string &key, Type t) { }
|
|
virtual Type GetType(const Anope::string &key) const { return DT_TEXT; }
|
|
};
|
|
|
|
extern void RegisterTypes();
|
|
extern void CheckTypes();
|
|
|
|
class Type;
|
|
template<typename T> class Checker;
|
|
template<typename T> class Reference;
|
|
}
|
|
|
|
/** A serializable object. Serializable objects can be serialized into
|
|
* abstract data types (Serialize::Data), and then reconstructed or
|
|
* updated later at any time.
|
|
*/
|
|
class CoreExport Serializable : public virtual Base
|
|
{
|
|
private:
|
|
/* A list of every serializable item in Anope.
|
|
* Some of these are static and constructed at runtime,
|
|
* so this list must be on the heap, as it is not always
|
|
* constructed before other objects are if it isn't.
|
|
*/
|
|
static std::list<Serializable *> *SerializableItems;
|
|
friend class Serialize::Type;
|
|
/* The type of item this object is */
|
|
Serialize::Type *s_type;
|
|
/* Iterator into serializable_items */
|
|
std::list<Serializable *>::iterator s_iter;
|
|
/* The hash of the last serialized form of this object committed to the database */
|
|
size_t last_commit;
|
|
/* The last time this object was committed to the database */
|
|
time_t last_commit_time;
|
|
|
|
protected:
|
|
Serializable(const Anope::string &serialize_type);
|
|
Serializable(const Serializable &);
|
|
|
|
Serializable &operator=(const Serializable &);
|
|
|
|
public:
|
|
virtual ~Serializable();
|
|
|
|
/* Unique ID (per type, not globally) for this object */
|
|
uint64_t id;
|
|
|
|
/* Only used by redis, to ignore updates */
|
|
unsigned short redis_ignore;
|
|
|
|
/** Marks the object as potentially being updated "soon".
|
|
*/
|
|
void QueueUpdate();
|
|
|
|
bool IsCached(Serialize::Data &);
|
|
void UpdateCache(Serialize::Data &);
|
|
|
|
bool IsTSCached();
|
|
void UpdateTS();
|
|
|
|
/** Get the type of serializable object this is
|
|
* @return The serializable object type
|
|
*/
|
|
Serialize::Type* GetSerializableType() const { return this->s_type; }
|
|
|
|
virtual void Serialize(Serialize::Data &data) const = 0;
|
|
|
|
static const std::list<Serializable *> &GetItems();
|
|
};
|
|
|
|
/* A serializable type. There should be one of these classes for each type
|
|
* of class that inherits from Serializable. Used for unserializing objects
|
|
* of this type, as it requires a function pointer to a static member function.
|
|
*/
|
|
class CoreExport Serialize::Type : public Base
|
|
{
|
|
typedef Serializable* (*unserialize_func)(Serializable *obj, Serialize::Data &);
|
|
|
|
static std::vector<Anope::string> TypeOrder;
|
|
static std::map<Anope::string, Serialize::Type *> Types;
|
|
|
|
/* The name of this type, should be a class name */
|
|
Anope::string name;
|
|
unserialize_func unserialize;
|
|
/* Owner of this type. Used for placing objects of this type in separate databases
|
|
* based on what module, if any, owns it.
|
|
*/
|
|
Module *owner;
|
|
|
|
/* The timestamp for this type. All objects of this type are as up to date as
|
|
* this timestamp. if curtime == timestamp then we have the most up to date
|
|
* version of every object of this type.
|
|
*/
|
|
time_t timestamp;
|
|
|
|
public:
|
|
/* Map of Serializable::id to Serializable objects */
|
|
std::map<uint64_t, Serializable *> objects;
|
|
|
|
/** Creates a new serializable type
|
|
* @param n Type name
|
|
* @param f Func to unserialize objects
|
|
* @param owner Owner of this type. Leave NULL for the core.
|
|
*/
|
|
Type(const Anope::string &n, unserialize_func f, Module *owner = NULL);
|
|
~Type();
|
|
|
|
/** Gets the name for this type
|
|
* @return The name, eg "NickAlias"
|
|
*/
|
|
const Anope::string &GetName() { return this->name; }
|
|
|
|
/** Unserialized an object.
|
|
* @param obj NULL if this object doesn't yet exist. If this isn't NULL, instead
|
|
* update the contents of this object.
|
|
* @param data The data to unserialize
|
|
* @return The unserialized object. If obj != NULL this should be obj.
|
|
*/
|
|
Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
|
|
|
|
/** Check if this object type has any pending changes and update them.
|
|
*/
|
|
void Check();
|
|
|
|
/** Gets the timestamp for the object type. That is, the time we know
|
|
* all objects of this type are updated at least to.
|
|
*/
|
|
time_t GetTimestamp() const;
|
|
|
|
/** Bumps object type timestamp to current time
|
|
*/
|
|
void UpdateTimestamp();
|
|
|
|
Module* GetOwner() const { return this->owner; }
|
|
|
|
static Serialize::Type *Find(const Anope::string &name);
|
|
|
|
static const std::vector<Anope::string> &GetTypeOrder();
|
|
|
|
static const std::map<Anope::string, Serialize::Type *>& GetTypes();
|
|
};
|
|
|
|
/** Should be used to hold lists and other objects of a specific type,
|
|
* but not a specific object. Used for ensuring that any access to
|
|
* this object type is always up to date. These are usually constructed
|
|
* at run time, before main is called, so no types are registered. This
|
|
* is why there are static Serialize::Type* variables in every function.
|
|
*/
|
|
template<typename T>
|
|
class Serialize::Checker
|
|
{
|
|
Anope::string name;
|
|
T obj;
|
|
mutable ::Reference<Serialize::Type> type;
|
|
|
|
inline void Check() const
|
|
{
|
|
if (!type)
|
|
type = Serialize::Type::Find(this->name);
|
|
if (type)
|
|
type->Check();
|
|
}
|
|
|
|
public:
|
|
Checker(const Anope::string &n) : name(n), type(NULL) { }
|
|
|
|
inline const T* operator->() const
|
|
{
|
|
this->Check();
|
|
return &this->obj;
|
|
}
|
|
inline T* operator->()
|
|
{
|
|
this->Check();
|
|
return &this->obj;
|
|
}
|
|
|
|
inline const T& operator*() const
|
|
{
|
|
this->Check();
|
|
return this->obj;
|
|
}
|
|
inline T& operator*()
|
|
{
|
|
this->Check();
|
|
return this->obj;
|
|
}
|
|
|
|
inline operator const T&() const
|
|
{
|
|
this->Check();
|
|
return this->obj;
|
|
}
|
|
inline operator T&()
|
|
{
|
|
this->Check();
|
|
return this->obj;
|
|
}
|
|
};
|
|
|
|
/** Used to hold references to serializable objects. Reference should always be
|
|
* used when holding references to serializable objects for extended periods of time
|
|
* to ensure that the object it refers to it always up to date. This also behaves like
|
|
* Reference in that it will invalidate itself if the object it refers to is
|
|
* destructed.
|
|
*/
|
|
template<typename T>
|
|
class Serialize::Reference : public ReferenceBase
|
|
{
|
|
protected:
|
|
T *ref;
|
|
|
|
public:
|
|
Reference() : ref(NULL)
|
|
{
|
|
}
|
|
|
|
Reference(T *obj) : ref(obj)
|
|
{
|
|
if (obj)
|
|
obj->AddReference(this);
|
|
}
|
|
|
|
Reference(const Reference<T> &other) : ReferenceBase(other), ref(other.ref)
|
|
{
|
|
if (ref && !invalid)
|
|
this->ref->AddReference(this);
|
|
}
|
|
|
|
~Reference()
|
|
{
|
|
if (ref && !invalid)
|
|
this->ref->DelReference(this);
|
|
}
|
|
|
|
inline Reference<T>& operator=(const Reference<T> &other)
|
|
{
|
|
if (this != &other)
|
|
{
|
|
if (ref && !invalid)
|
|
this->ref->DelReference(this);
|
|
|
|
this->ref = other.ref;
|
|
this->invalid = other.invalid;
|
|
|
|
if (ref && !invalid)
|
|
this->ref->AddReference(this);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
inline operator bool() const
|
|
{
|
|
if (!this->invalid)
|
|
return this->ref != NULL;
|
|
return false;
|
|
}
|
|
|
|
inline operator T*() const
|
|
{
|
|
if (!this->invalid)
|
|
{
|
|
if (this->ref)
|
|
// This can invalidate me
|
|
this->ref->QueueUpdate();
|
|
if (!this->invalid)
|
|
return this->ref;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
inline T* operator*() const
|
|
{
|
|
if (!this->invalid)
|
|
{
|
|
if (this->ref)
|
|
// This can invalidate me
|
|
this->ref->QueueUpdate();
|
|
if (!this->invalid)
|
|
return this->ref;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
inline T* operator->() const
|
|
{
|
|
if (!this->invalid)
|
|
{
|
|
if (this->ref)
|
|
// This can invalidate me
|
|
this->ref->QueueUpdate();
|
|
if (!this->invalid)
|
|
return this->ref;
|
|
}
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
#endif // SERIALIZE_H
|