#include "../include/odhtdb/DatabaseStorage.hpp" #include "../include/odhtdb/User.hpp" #include "../include/odhtdb/Group.hpp" #include #include using namespace std; namespace odhtdb { const u64 QUARANTINE_STORAGE_TIME_MICROSECONDS = 60 * 1.0e6; DatabaseStorageObject::DatabaseStorageObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) : data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey) { } DatabaseStorageQuarantineObject::DatabaseStorageQuarantineObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) : data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey) { auto time = chrono::high_resolution_clock::now().time_since_epoch(); storedTimestamp = chrono::duration_cast(time).count(); } void DatabaseStorage::createStorage(const Hash &hash, Group *creatorGroup, u64 timestamp, const u8 *data, usize dataSize) { if(storageMap.find(hash) != storageMap.end()) { string errMsg = "Database storage with hash "; errMsg += hash.toString(); errMsg += " already exists"; throw DatabaseStorageAlreadyExists(errMsg); } DatabaseStorageObjectList *databaseStorageObjectList = new DatabaseStorageObjectList(); databaseStorageObjectList->createdTimestamp = timestamp; databaseStorageObjectList->groups.push_back(creatorGroup); databaseStorageObjectList->data = DataView(new u8[dataSize], dataSize); memcpy(databaseStorageObjectList->data.data, data, dataSize); storageMap[hash] = databaseStorageObjectList; groupByIdMap[creatorGroup->getId()] = creatorGroup; for(auto user : creatorGroup->getUsers()) { addUser((User*)user, hash); } } void DatabaseStorage::appendStorage(const Hash &nodeHash, const Hash &dataHash, const User *creatorUser, u64 timestamp, const u8 *data, usize dataSize) { auto it = storageMap.find(nodeHash); if(it == storageMap.end()) { string errMsg = "Database storage with hash "; errMsg += nodeHash.toString(); errMsg += " not found. Storage for a hash needs to be created before data can be appended to it"; throw DatabaseStorageNotFound(errMsg); } auto storeDataHashResult = storedDataHash.insert(dataHash); if(!storeDataHashResult.second) { string errMsg = "Database already contains data with hash: "; errMsg += dataHash.toString(); throw DatabaseStorageAlreadyExists(errMsg); } DataView storageData { new u8[dataSize], dataSize }; memcpy(storageData.data, data, dataSize); DatabaseStorageObject *databaseStorageObject = new DatabaseStorageObject(storageData, timestamp, creatorUser->getPublicKey()); it->second->objects.push_back(databaseStorageObject); } void DatabaseStorage::addToQuarantine(const Hash &dataHash, const Signature::PublicKey &creatorPublicKey, u64 timestamp, const u8 *data, usize dataSize) { auto storeDataHashResult = storedDataHash.insert(dataHash); if(!storeDataHashResult.second) { string errMsg = "Database already contains data with hash: "; errMsg += dataHash.toString(); throw DatabaseStorageAlreadyExists(errMsg); } DataView storageData { new u8[dataSize], dataSize }; memcpy(storageData.data, data, dataSize); DatabaseStorageQuarantineObject *databaseQuarantineStorageObject = new DatabaseStorageQuarantineObject(storageData, timestamp, creatorPublicKey); quarantineStorageMap[creatorPublicKey].emplace_back(databaseQuarantineStorageObject); } void DatabaseStorage::addUser(User *user, const Hash &hash) { userPublicKeyNodeMap[user->getPublicKey()] = new Hash(hash); publicKeyUserMap[user->getPublicKey()] = user; } const DatabaseStorageObjectList* DatabaseStorage::getStorage(const Hash &hash) const { auto it = storageMap.find(hash); if(it != storageMap.end()) return it->second; return nullptr; } const Hash* DatabaseStorage::getNodeByUserPublicKey(const Signature::PublicKey &userPublicKey) const { auto it = userPublicKeyNodeMap.find(userPublicKey); if(it != userPublicKeyNodeMap.end()) return it->second; return nullptr; } // Returns nullptr if no user with public key exists const User* DatabaseStorage::getUserByPublicKey(const Signature::PublicKey &userPublicKey) const { auto it = publicKeyUserMap.find(userPublicKey); if(it != publicKeyUserMap.end()) return it->second; return nullptr; } Group* DatabaseStorage::getGroupById(uint8_t groupId[16]) { auto it = groupByIdMap.find(DataView(groupId, 16)); if(it != groupByIdMap.end()) return it->second; return nullptr; } void DatabaseStorage::update() { auto time = chrono::high_resolution_clock::now().time_since_epoch(); auto timeMicroseconds = chrono::duration_cast(time).count(); for(auto mapIt = quarantineStorageMap.begin(); mapIt != quarantineStorageMap.end(); ) { for(auto vecIt = mapIt->second.begin(); vecIt != mapIt->second.end(); ) { if(timeMicroseconds - (*vecIt)->storedTimestamp > QUARANTINE_STORAGE_TIME_MICROSECONDS) vecIt = mapIt->second.erase(vecIt); else ++vecIt; } if(mapIt->second.empty()) mapIt = quarantineStorageMap.erase(mapIt); else ++mapIt; } } }