198 lines
4.9 KiB
C++
198 lines
4.9 KiB
C++
#include "UserDB.h"
|
|
#include "FilesystemAbstraction.h"
|
|
|
|
const String userDir = "/u/";
|
|
|
|
template <class ForwardIterator, class T>
|
|
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T &val)
|
|
{
|
|
ForwardIterator it;
|
|
int count, step;
|
|
count = last - first;
|
|
while (count > 0)
|
|
{
|
|
it = first;
|
|
step = count / 2;
|
|
it += step;
|
|
if (*it < val)
|
|
{
|
|
first = ++it;
|
|
count -= step + 1;
|
|
}
|
|
else
|
|
count = step;
|
|
}
|
|
return first;
|
|
}
|
|
|
|
static String userFileName(const String &userName)
|
|
{
|
|
return userDir + userName;
|
|
}
|
|
|
|
bool User::load(const String &stringId)
|
|
{
|
|
stringId_ = stringId;
|
|
assert(stringId_.length() > 0);
|
|
const auto fileName = userFileName(stringId_);
|
|
if (!portablefs::exists(fileName.c_str()))
|
|
return false;
|
|
|
|
auto file = portablefs::open(fileName.c_str(), "r");
|
|
|
|
size_t sessionsInFile;
|
|
file.read((uint8_t *)&sessionsInFile, sizeof(numSessions_));
|
|
|
|
init(stringId, sessionsInFile * 2);
|
|
|
|
size_t expectedSize = sizeof(SessionIdType) * numSessions_;
|
|
auto bytesRead = file.read((uint8_t *)sessionIds_, expectedSize);
|
|
numSessions_ = sessionsInFile;
|
|
|
|
assert(expectedSize == bytesRead);
|
|
return true;
|
|
}
|
|
|
|
void User::init(const String &stringId, size_t sessionAllocateSize)
|
|
{
|
|
if (sessionIds_ != nullptr)
|
|
{
|
|
free(sessionIds_);
|
|
sessionIds_ = nullptr;
|
|
}
|
|
stringId_ = stringId;
|
|
numSessionsAllocated_ = sessionAllocateSize;
|
|
sessionIds_ = (SessionIdType *)ps_malloc(sizeof(SessionIdType) * numSessionsAllocated_);
|
|
numSessions_ = 0;
|
|
}
|
|
|
|
void User::save()
|
|
{
|
|
if (!portablefs::exists(userDir.c_str()))
|
|
portablefs::mkdir(userDir.c_str());
|
|
|
|
auto file = portablefs::open(userFileName(stringId_).c_str(), "w");
|
|
file.write((uint8_t *)&numSessions_, sizeof(numSessions_));
|
|
file.write((uint8_t *)sessionIds_, sizeof(SessionIdType) * numSessions_);
|
|
}
|
|
|
|
void User::freeResources()
|
|
{
|
|
if (sessionIds_ != nullptr)
|
|
{
|
|
free(sessionIds_);
|
|
sessionIds_ = nullptr;
|
|
}
|
|
}
|
|
|
|
void User::remove()
|
|
{
|
|
portablefs::remove(userFileName(stringId_).c_str());
|
|
freeResources();
|
|
stringId_ = "";
|
|
numSessions_ = 0;
|
|
numSessionsAllocated_ = 0;
|
|
}
|
|
|
|
void User::growSessionArrayIfNecessary()
|
|
{
|
|
assert(numSessions_ <= numSessionsAllocated_);
|
|
|
|
if (numSessions_ < numSessionsAllocated_)
|
|
return;
|
|
|
|
numSessionsAllocated_ *= 2;
|
|
sessionIds_ = (SessionIdType *)ps_realloc(sessionIds_, numSessionsAllocated_);
|
|
|
|
assert(numSessions_ < numSessionsAllocated_);
|
|
}
|
|
|
|
void User::insertSession(SessionIdType newSessionId)
|
|
{
|
|
growSessionArrayIfNecessary();
|
|
assert(numSessionsAllocated_ > numSessions_);
|
|
SessionIdType *insertPos = lower_bound(sessionIds_, sessionIds_ + numSessions_, newSessionId);
|
|
const size_t moveStartIdx = sessionIds_ + numSessions_ - insertPos;
|
|
for (size_t i = numSessions_ - 1; i >= moveStartIdx; --i)
|
|
sessionIds_[i + 1] = sessionIds_[i];
|
|
sessionIds_[moveStartIdx] = newSessionId;
|
|
numSessions_ += 1;
|
|
}
|
|
|
|
bool User::removeSession(SessionIdType sessionIdToRemove)
|
|
{
|
|
SessionIdType *removePos = lower_bound(sessionIds_, sessionIds_ + numSessions_, sessionIdToRemove);
|
|
const size_t removeIdx = sessionIds_ + numSessions_ - removePos;
|
|
if (sessionIds_[removeIdx] != sessionIdToRemove)
|
|
return false;
|
|
|
|
for (size_t i = removeIdx; i < numSessions_ - 1; ++i)
|
|
sessionIds_[i] = sessionIds_[i + 1];
|
|
|
|
numSessions_ -= 1;
|
|
return true;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
|
|
User *UserStorage::getUserInfo(const String &stringId)
|
|
{
|
|
// index 0 is the unassigned user
|
|
for (size_t i = 1; i < numUsers_; ++i)
|
|
if (users_[i].stringId() == stringId)
|
|
return &users_[i];
|
|
return nullptr;
|
|
}
|
|
|
|
User *UserStorage::getUnassignedUser()
|
|
{
|
|
return &users_[0];
|
|
}
|
|
|
|
User *UserStorage::addNewUser(const String &stringId)
|
|
{
|
|
if (numUsers_ >= MAX_USERS)
|
|
return nullptr;
|
|
|
|
if(stringId.length() >= USER_STRING_ID_MAX_LEN)
|
|
return nullptr;
|
|
|
|
auto userIdx = numUsers_;
|
|
numUsers_++;
|
|
assert(numUsers_ < MAX_USERS);
|
|
users_[userIdx].init(stringId);
|
|
return &users_[userIdx];
|
|
}
|
|
|
|
bool UserStorage::deleteUser(const String &stringId)
|
|
{
|
|
User *userPtr = getUserInfo(stringId);
|
|
|
|
if (userPtr == nullptr)
|
|
return false;
|
|
size_t userIdx = userPtr - users_;
|
|
userPtr->remove();
|
|
assert(numUsers_ > 0);
|
|
if (userIdx != numUsers_ - 1)
|
|
users_[userIdx] = users_[numUsers_ - 1];
|
|
return true;
|
|
}
|
|
|
|
void UserStorage::fillFromFileSystem()
|
|
{
|
|
for (size_t i = 0; i < numUsers_; ++i)
|
|
users_[i].freeResources();
|
|
|
|
numUsers_ = 1;
|
|
|
|
users_[0].load("_unassigned");
|
|
portablefs::Dir d(userDir);
|
|
while (d.next())
|
|
{
|
|
if (d.isFile() && d.fileName()[0] != '_')
|
|
{
|
|
users_[numUsers_].load(d.fileName());
|
|
++numUsers_;
|
|
}
|
|
}
|
|
} |