Skip to content
Snippets Groups Projects
Commit a0e29154 authored by Tristan Matthews's avatar Tristan Matthews
Browse files

* #7264: don't use ConfigTree for history

This way we only have one representation of the history in memory
instead of 2, and we don't need a ConfigTree for this, standard streams are
sufficient.
parent fdf338eb
Branches
Tags
No related merge requests found
......@@ -34,86 +34,67 @@
#include <cerrno>
#include <cc++/file.h>
#include <ctime>
#include "config/config.h"
#include "global.h"
#include "logger.h"
namespace {
int get_unix_timestamp_equivalent(int days)
int oldestAllowed(int days)
{
// Number of seconds in one day: 60 x 60 x 24
static const int DAY_UNIX_TIMESTAMP = 86400;
return days * DAY_UNIX_TIMESTAMP;
time_t currentTimestamp;
time(&currentTimestamp);
// Number of seconds in one day: 60 sec/min x 60 min/hr x 24hr/day
static const int DAY_UNIX_TIMESTAMP = 60 * 60 * 24;
return static_cast<int>(currentTimestamp) - (days * DAY_UNIX_TIMESTAMP);
}
using std::map;
using std::string;
using std::list;
using std::vector;
}
History::History() :
items_(), loaded_(false), path_("")
{}
void History::load(int limit, const string &path)
{
Conf::ConfigTree historyList;
createPath(path);
loadFromFile(historyList);
loadItems(historyList, limit);
}
bool History::save()
{
Conf::ConfigTree historyList;
saveItems(historyList);
return saveToFile(historyList);
}
bool History::loadFromFile(Conf::ConfigTree &historyList)
void History::load(int limit)
{
loaded_ = historyList.populateFromFile(path_.c_str());
return loaded_;
createPath();
std::ifstream infile(path_.c_str());
if (!infile) {
DEBUG("No history file to load");
return;
}
void History::loadItems(Conf::ConfigTree &historyList, int limit)
{
// We want to save only the items recent enough (ie compared to CONFIG_HISTORY_LIMIT)
time_t currentTimestamp;
time(&currentTimestamp);
int historyLimit = get_unix_timestamp_equivalent(limit);
int oldestEntryTime = static_cast<int>(currentTimestamp) - historyLimit;
list<string> sections(historyList.getSections());
for (list<string>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) {
HistoryItem item(*iter, historyList);
// Make a check on the start timestamp to know it is loadable according to CONFIG_HISTORY_LIMIT
if (item.youngerThan(oldestEntryTime))
addNewEntry(item);
while (!infile.eof()) {
HistoryItem item(infile);
addNewEntry(item, limit);
}
loaded_ = true;
}
bool History::saveToFile(const Conf::ConfigTree &historyList) const
bool History::save() const
{
DEBUG("History: Saving history in XDG directory: %s", path_.c_str());
return historyList.saveConfigTree(path_.data());
}
void History::saveItems(Conf::ConfigTree &historyList) const
{
for (vector<HistoryItem>::const_iterator iter = items_.begin(); iter != items_.end(); ++iter)
iter->save(historyList);
std::ofstream outfile(path_.c_str());
if (outfile.fail())
return false;
for (vector<HistoryItem>::const_iterator iter = items_.begin();
iter != items_.end(); ++iter)
outfile << *iter << std::endl;
return true;
}
void History::addNewEntry(const HistoryItem &new_item)
void History::addNewEntry(const HistoryItem &item, int oldest)
{
items_.push_back(new_item);
if (item.hasPeerNumber() and item.youngerThan(oldest))
items_.push_back(item);
}
void History::createPath(const string &path)
void History::createPath(const std::string &path)
{
if (path.empty()) {
string xdg_data = string(HOMEDIR) + DIR_SEPARATOR_STR + ".local/share/sflphone";
if (path.empty()) {
string userdata;
// If the environment variable is set (not null and not empty), we'll use it to save the history
// Else we 'll the standard one, ie: XDG_DATA_HOME = $HOMEDIR/.local/share/sflphone
......@@ -131,9 +112,9 @@ void History::createPath(const string &path)
}
}
// Load user's history
setPath(userdata + DIR_SEPARATOR_STR + "history");
path_ = userdata + DIR_SEPARATOR_STR + "history";
} else
setPath(path);
path_ = path;
}
......@@ -147,21 +128,19 @@ vector<map<string, string> > History::getSerialized() const
return result;
}
void History::setSerialized(const vector<map<string, string> > &history, int limit)
void History::setSerialized(const vector<map<string, string> > &history,
int limit)
{
items_.clear();
// We want to save only the items recent enough (ie compared to CONFIG_HISTORY_LIMIT)
// Get the current timestamp
time_t current_timestamp;
time(&current_timestamp);
int history_limit = get_unix_timestamp_equivalent(limit);
for (vector<map<string, string> >::const_iterator iter = history.begin(); iter != history.end(); ++iter) {
HistoryItem new_item(*iter);
if (new_item.hasPeerNumber() and new_item.youngerThan((int) current_timestamp - history_limit))
addNewEntry(new_item);
const int oldest = oldestAllowed(limit);
for (vector<map<string, string> >::const_iterator iter = history.begin();
iter != history.end(); ++iter) {
HistoryItem item(*iter);
addNewEntry(item, oldest);
}
}
void History::setPath(const std::string &path)
{
path_ = path;
}
......@@ -34,7 +34,7 @@
#define HISTORY_
#include "historyitem.h"
#include "global.h"
#include <vector>
class History {
......@@ -45,14 +45,14 @@ class History {
History();
/**
*@param path A specific file to use; if empty, use the global one
* Load history from file
*/
void load(int limit, const std::string &path="");
void load(int limit);
/**
*@return bool True if the history has been successfully saved in the file
*/
bool save();
bool save() const;
/**
*@return bool True if the history file has been successfully read
......@@ -61,10 +61,6 @@ class History {
return loaded_;
}
void setPath(const std::string &filename) {
path_ = filename;
}
/*
*@return int The number of items found in the history file
*/
......@@ -82,29 +78,12 @@ class History {
void setSerialized(const std::vector<std::map<std::string, std::string> > &history, int limit);
private:
void loadItems(Conf::ConfigTree &history_list, int limit);
/*
* Inverse method, ie save a data structure containing the history into a file
*/
bool saveToFile(const Conf::ConfigTree &history_list) const;
void saveItems(Conf::ConfigTree &history_list) const;
/*
* Set the path to the history file
*
* @param path A specific file to use; if empty, use the global one
*/
void setPath(const std::string &path);
void createPath(const std::string &path = "");
/*
* Add a new history item in the data structure
*/
void addNewEntry(const HistoryItem &new_item);
/*
* Load the history from a file to the dedicated data structure
*/
bool loadFromFile(Conf::ConfigTree &history_list);
void addNewEntry(const HistoryItem &new_item, int limit);
/*
* Vector containing the history items
......@@ -119,7 +98,6 @@ class History {
/*
* The path to the history file
*/
std::string path_;
friend class HistoryTest;
......
......@@ -33,7 +33,6 @@
#include "historyitem.h"
#include <sstream>
#include <cstdlib>
#include "config/config.h"
const char * const HistoryItem::ACCOUNT_ID_KEY = "accountid";
const char * const HistoryItem::CALLID_KEY = "callid";
......@@ -41,9 +40,10 @@ const char * const HistoryItem::CONFID_KEY = "confid";
const char * const HistoryItem::PEER_NAME_KEY = "peer_name";
const char * const HistoryItem::PEER_NUMBER_KEY = "peer_number";
const char * const HistoryItem::RECORDING_PATH_KEY = "recordfile";
const char * const HistoryItem::STATE_KEY = "state";
const char * const HistoryItem::TIMESTAMP_START_KEY = "timestamp_start";
const char * const HistoryItem::TIMESTAMP_STOP_KEY = "timestamp_stop";
const char * const HistoryItem::STATE_KEY = "state";
const char * const HistoryItem::MISSED_STRING = "missed";
const char * const HistoryItem::INCOMING_STRING = "incoming";
const char * const HistoryItem::OUTGOING_STRING = "outgoing";
......@@ -55,34 +55,18 @@ HistoryItem::HistoryItem(const map<string, string> &args)
: entryMap_(args)
{}
HistoryItem::HistoryItem(const string &item, const Conf::ConfigTree &historyList)
HistoryItem::HistoryItem(std::istream &entry)
: entryMap_()
{
const char *const KEYS [] = {
ACCOUNT_ID_KEY,
CALLID_KEY,
CONFID_KEY,
PEER_NAME_KEY,
PEER_NUMBER_KEY,
RECORDING_PATH_KEY,
TIMESTAMP_START_KEY,
TIMESTAMP_STOP_KEY,
STATE_KEY,
NULL};
for (int i = 0; KEYS[i]; ++i)
entryMap_[KEYS[i]] = historyList.getConfigTreeItemValue(item, KEYS[i]);
std::string tmp;
while (std::getline(entry, tmp, '\n')) {
size_t pos = tmp.find('=');
if (pos == std::string::npos)
return;
std::string key(tmp.substr(0, pos));
std::string val(tmp.substr(pos + 1, tmp.length() - pos - 1));
entryMap_[key] = val;
}
void HistoryItem::save(Conf::ConfigTree &history) const
{
// The section is : "[" + random integer = "]"
std::stringstream section;
section << rand();
const string sectionstr = section.str();
typedef map<string, string>::const_iterator EntryIter;
for (EntryIter iter = entryMap_.begin(); iter != entryMap_.end(); ++iter)
history.setConfigTreeItem(sectionstr, iter->first, iter->second);
}
map<string, string> HistoryItem::toMap() const
......@@ -92,7 +76,7 @@ map<string, string> HistoryItem::toMap() const
bool HistoryItem::youngerThan(int otherTime) const
{
return atol(getTimestampStart().c_str()) >= otherTime;
return std::atol(getTimestampStart().c_str()) > otherTime;
}
bool HistoryItem::hasPeerNumber() const
......@@ -108,3 +92,17 @@ string HistoryItem::getTimestampStart() const
else
return "";
}
void HistoryItem::print(std::ostream &o) const
{
// every entry starts with "[" + random integer = "]"
for (map<string, string>::const_iterator iter = entryMap_.begin();
iter != entryMap_.end(); ++iter)
o << iter->first << "=" << iter->second << std::endl;
}
std::ostream& operator << (std::ostream& o, const HistoryItem& item)
{
item.print(o);
return o;
}
......@@ -36,10 +36,6 @@
#include <string>
#include <map>
namespace Conf {
class ConfigTree;
}
class HistoryItem {
public:
static const char * const ACCOUNT_ID_KEY;
......@@ -56,20 +52,20 @@ class HistoryItem {
static const char * const INCOMING_STRING;
static const char * const OUTGOING_STRING;
HistoryItem(const std::map<std::string, std::string> &args);
HistoryItem(const std::string &item, const Conf::ConfigTree &list);
HistoryItem(std::istream &stream);
bool hasPeerNumber() const;
bool youngerThan(int otherTime) const;
void save(Conf::ConfigTree &history) const;
std::map<std::string, std::string> toMap() const;
void print(std::ostream &o) const;
private:
std::string getTimestampStart() const;
std::map<std::string, std::string> entryMap_;
};
std::ostream& operator << (std::ostream& o, const HistoryItem& item);
#endif // HISTORY_ITEM
[207464428]
accountid=
confid=
id=Account:1239059899
......@@ -9,7 +8,6 @@ timestamp_start=747638685
timestamp_stop=747638765
state=outgoing
[221051947]
accountid=empty
confid=
id=
......@@ -20,7 +18,6 @@ timestamp_start=144562000
timestamp_stop=144562458
state=missed
[871962260]
accountid=
confid=
id=Account:43789459478
......
......@@ -76,52 +76,30 @@ void HistoryTest::test_load_from_file()
{
DEBUG("-------------------- HistoryTest::test_load_from_file --------------------\n");
Conf::ConfigTree history_list;
history_->createPath(HISTORY_SAMPLE);
bool res = history_->loadFromFile(history_list);
history_->load(HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->isLoaded());
CPPUNIT_ASSERT(res);
}
void HistoryTest::test_load_items()
{
DEBUG("-------------------- HistoryTest::test_load_items_map --------------------\n");
Conf::ConfigTree history_list;
history_->setPath(HISTORY_SAMPLE);
history_->loadFromFile(history_list);
history_->loadItems(history_list, HUGE_HISTORY_LIMIT);
history_->load(HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->numberOfItems() == HISTORY_SAMPLE_SIZE);
}
void HistoryTest::test_save_items()
{
DEBUG("-------------------- HistoryTest::test_save_items_map --------------------\n");
Conf::ConfigTree history_list, history_list2;
history_->setPath(HISTORY_SAMPLE);
history_->loadFromFile(history_list);
history_->loadItems(history_list, HUGE_HISTORY_LIMIT);
history_->saveItems(history_list2);
}
void HistoryTest::test_save_to_file()
{
DEBUG("-------------------- HistoryTest::test_save_to_file --------------------\n");
Conf::ConfigTree history_list, history_list2;
std::map<std::string, std::string> res;
std::map<std::string, std::string>::iterator iter;
history_->setPath(HISTORY_SAMPLE);
history_->loadFromFile(history_list);
history_->loadItems(history_list, HUGE_HISTORY_LIMIT);
history_->saveItems(history_list2);
CPPUNIT_ASSERT(history_->saveToFile(history_list2));
CPPUNIT_ASSERT(history_->save());
}
void HistoryTest::test_get_serialized()
......@@ -131,7 +109,7 @@ void HistoryTest::test_get_serialized()
std::vector<std::string>::iterator iter;
std::string tmp;
history_->load(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE);
history_->load(HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->getSerialized().size() == HISTORY_SAMPLE_SIZE);
}
......
......@@ -55,7 +55,6 @@ class HistoryTest : public CppUnit::TestCase {
*/
CPPUNIT_TEST_SUITE(HistoryTest);
CPPUNIT_TEST(test_create_path);
CPPUNIT_TEST(test_save_items);
CPPUNIT_TEST(test_load_from_file);
CPPUNIT_TEST(test_load_items);
CPPUNIT_TEST(test_get_serialized);
......@@ -76,8 +75,6 @@ class HistoryTest : public CppUnit::TestCase {
void test_load_items();
void test_save_items();
void test_save_to_file();
void test_get_serialized();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment