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 @@ ...@@ -34,86 +34,67 @@
#include <cerrno> #include <cerrno>
#include <cc++/file.h> #include <cc++/file.h>
#include <ctime> #include <ctime>
#include "config/config.h" #include "global.h"
#include "logger.h"
namespace { namespace {
int get_unix_timestamp_equivalent(int days) int oldestAllowed(int days)
{ {
// Number of seconds in one day: 60 x 60 x 24 time_t currentTimestamp;
static const int DAY_UNIX_TIMESTAMP = 86400; time(&currentTimestamp);
return days * DAY_UNIX_TIMESTAMP; // 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::map;
using std::string; using std::string;
using std::list;
using std::vector; using std::vector;
} }
History::History() : History::History() :
items_(), loaded_(false), path_("") 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()); createPath();
return loaded_; std::ifstream infile(path_.c_str());
if (!infile) {
DEBUG("No history file to load");
return;
} }
while (!infile.eof()) {
void History::loadItems(Conf::ConfigTree &historyList, int limit) HistoryItem item(infile);
{ addNewEntry(item, 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);
} }
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()); DEBUG("History: Saving history in XDG directory: %s", path_.c_str());
return historyList.saveConfigTree(path_.data()); std::ofstream outfile(path_.c_str());
} if (outfile.fail())
return false;
void History::saveItems(Conf::ConfigTree &historyList) const for (vector<HistoryItem>::const_iterator iter = items_.begin();
{ iter != items_.end(); ++iter)
for (vector<HistoryItem>::const_iterator iter = items_.begin(); iter != items_.end(); ++iter) outfile << *iter << std::endl;
iter->save(historyList); 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"; string xdg_data = string(HOMEDIR) + DIR_SEPARATOR_STR + ".local/share/sflphone";
if (path.empty()) {
string userdata; string userdata;
// If the environment variable is set (not null and not empty), we'll use it to save the history // 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 // Else we 'll the standard one, ie: XDG_DATA_HOME = $HOMEDIR/.local/share/sflphone
...@@ -131,9 +112,9 @@ void History::createPath(const string &path) ...@@ -131,9 +112,9 @@ void History::createPath(const string &path)
} }
} }
// Load user's history // Load user's history
setPath(userdata + DIR_SEPARATOR_STR + "history"); path_ = userdata + DIR_SEPARATOR_STR + "history";
} else } else
setPath(path); path_ = path;
} }
...@@ -147,21 +128,19 @@ vector<map<string, string> > History::getSerialized() const ...@@ -147,21 +128,19 @@ vector<map<string, string> > History::getSerialized() const
return result; 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(); items_.clear();
const int oldest = oldestAllowed(limit);
// We want to save only the items recent enough (ie compared to CONFIG_HISTORY_LIMIT) for (vector<map<string, string> >::const_iterator iter = history.begin();
// Get the current timestamp iter != history.end(); ++iter) {
time_t current_timestamp; HistoryItem item(*iter);
time(&current_timestamp); addNewEntry(item, oldest);
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);
} }
} }
void History::setPath(const std::string &path)
{
path_ = path;
}
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#define HISTORY_ #define HISTORY_
#include "historyitem.h" #include "historyitem.h"
#include "global.h" #include <vector>
class History { class History {
...@@ -45,14 +45,14 @@ class History { ...@@ -45,14 +45,14 @@ class History {
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 *@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 *@return bool True if the history file has been successfully read
...@@ -61,10 +61,6 @@ class History { ...@@ -61,10 +61,6 @@ class History {
return loaded_; return loaded_;
} }
void setPath(const std::string &filename) {
path_ = filename;
}
/* /*
*@return int The number of items found in the history file *@return int The number of items found in the history file
*/ */
...@@ -82,29 +78,12 @@ class History { ...@@ -82,29 +78,12 @@ class History {
void setSerialized(const std::vector<std::map<std::string, std::string> > &history, int limit); void setSerialized(const std::vector<std::map<std::string, std::string> > &history, int limit);
private: private:
void loadItems(Conf::ConfigTree &history_list, int limit); void setPath(const std::string &path);
/*
* 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 createPath(const std::string &path = ""); void createPath(const std::string &path = "");
/* /*
* Add a new history item in the data structure * Add a new history item in the data structure
*/ */
void addNewEntry(const HistoryItem &new_item); void addNewEntry(const HistoryItem &new_item, int limit);
/*
* Load the history from a file to the dedicated data structure
*/
bool loadFromFile(Conf::ConfigTree &history_list);
/* /*
* Vector containing the history items * Vector containing the history items
...@@ -119,7 +98,6 @@ class History { ...@@ -119,7 +98,6 @@ class History {
/* /*
* The path to the history file * The path to the history file
*/ */
std::string path_; std::string path_;
friend class HistoryTest; friend class HistoryTest;
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "historyitem.h" #include "historyitem.h"
#include <sstream> #include <sstream>
#include <cstdlib> #include <cstdlib>
#include "config/config.h"
const char * const HistoryItem::ACCOUNT_ID_KEY = "accountid"; const char * const HistoryItem::ACCOUNT_ID_KEY = "accountid";
const char * const HistoryItem::CALLID_KEY = "callid"; const char * const HistoryItem::CALLID_KEY = "callid";
...@@ -41,9 +40,10 @@ const char * const HistoryItem::CONFID_KEY = "confid"; ...@@ -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_NAME_KEY = "peer_name";
const char * const HistoryItem::PEER_NUMBER_KEY = "peer_number"; const char * const HistoryItem::PEER_NUMBER_KEY = "peer_number";
const char * const HistoryItem::RECORDING_PATH_KEY = "recordfile"; 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_START_KEY = "timestamp_start";
const char * const HistoryItem::TIMESTAMP_STOP_KEY = "timestamp_stop"; 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::MISSED_STRING = "missed";
const char * const HistoryItem::INCOMING_STRING = "incoming"; const char * const HistoryItem::INCOMING_STRING = "incoming";
const char * const HistoryItem::OUTGOING_STRING = "outgoing"; const char * const HistoryItem::OUTGOING_STRING = "outgoing";
...@@ -55,34 +55,18 @@ HistoryItem::HistoryItem(const map<string, string> &args) ...@@ -55,34 +55,18 @@ HistoryItem::HistoryItem(const map<string, string> &args)
: entryMap_(args) : entryMap_(args)
{} {}
HistoryItem::HistoryItem(const string &item, const Conf::ConfigTree &historyList) HistoryItem::HistoryItem(std::istream &entry)
: entryMap_() : entryMap_()
{ {
const char *const KEYS [] = { std::string tmp;
ACCOUNT_ID_KEY, while (std::getline(entry, tmp, '\n')) {
CALLID_KEY, size_t pos = tmp.find('=');
CONFID_KEY, if (pos == std::string::npos)
PEER_NAME_KEY, return;
PEER_NUMBER_KEY, std::string key(tmp.substr(0, pos));
RECORDING_PATH_KEY, std::string val(tmp.substr(pos + 1, tmp.length() - pos - 1));
TIMESTAMP_START_KEY, entryMap_[key] = val;
TIMESTAMP_STOP_KEY,
STATE_KEY,
NULL};
for (int i = 0; KEYS[i]; ++i)
entryMap_[KEYS[i]] = historyList.getConfigTreeItemValue(item, KEYS[i]);
} }
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 map<string, string> HistoryItem::toMap() const
...@@ -92,7 +76,7 @@ map<string, string> HistoryItem::toMap() const ...@@ -92,7 +76,7 @@ map<string, string> HistoryItem::toMap() const
bool HistoryItem::youngerThan(int otherTime) const bool HistoryItem::youngerThan(int otherTime) const
{ {
return atol(getTimestampStart().c_str()) >= otherTime; return std::atol(getTimestampStart().c_str()) > otherTime;
} }
bool HistoryItem::hasPeerNumber() const bool HistoryItem::hasPeerNumber() const
...@@ -108,3 +92,17 @@ string HistoryItem::getTimestampStart() const ...@@ -108,3 +92,17 @@ string HistoryItem::getTimestampStart() const
else else
return ""; 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 @@ ...@@ -36,10 +36,6 @@
#include <string> #include <string>
#include <map> #include <map>
namespace Conf {
class ConfigTree;
}
class HistoryItem { class HistoryItem {
public: public:
static const char * const ACCOUNT_ID_KEY; static const char * const ACCOUNT_ID_KEY;
...@@ -56,20 +52,20 @@ class HistoryItem { ...@@ -56,20 +52,20 @@ class HistoryItem {
static const char * const INCOMING_STRING; static const char * const INCOMING_STRING;
static const char * const OUTGOING_STRING; static const char * const OUTGOING_STRING;
HistoryItem(const std::map<std::string, std::string> &args); 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 hasPeerNumber() const;
bool youngerThan(int otherTime) const; bool youngerThan(int otherTime) const;
void save(Conf::ConfigTree &history) const;
std::map<std::string, std::string> toMap() const; std::map<std::string, std::string> toMap() const;
void print(std::ostream &o) const;
private: private:
std::string getTimestampStart() const; std::string getTimestampStart() const;
std::map<std::string, std::string> entryMap_; std::map<std::string, std::string> entryMap_;
}; };
std::ostream& operator << (std::ostream& o, const HistoryItem& item);
#endif // HISTORY_ITEM #endif // HISTORY_ITEM
[207464428]
accountid= accountid=
confid= confid=
id=Account:1239059899 id=Account:1239059899
...@@ -9,7 +8,6 @@ timestamp_start=747638685 ...@@ -9,7 +8,6 @@ timestamp_start=747638685
timestamp_stop=747638765 timestamp_stop=747638765
state=outgoing state=outgoing
[221051947]
accountid=empty accountid=empty
confid= confid=
id= id=
...@@ -20,7 +18,6 @@ timestamp_start=144562000 ...@@ -20,7 +18,6 @@ timestamp_start=144562000
timestamp_stop=144562458 timestamp_stop=144562458
state=missed state=missed
[871962260]
accountid= accountid=
confid= confid=
id=Account:43789459478 id=Account:43789459478
......
...@@ -76,52 +76,30 @@ void HistoryTest::test_load_from_file() ...@@ -76,52 +76,30 @@ void HistoryTest::test_load_from_file()
{ {
DEBUG("-------------------- HistoryTest::test_load_from_file --------------------\n"); DEBUG("-------------------- HistoryTest::test_load_from_file --------------------\n");
Conf::ConfigTree history_list;
history_->createPath(HISTORY_SAMPLE); history_->createPath(HISTORY_SAMPLE);
bool res = history_->loadFromFile(history_list); history_->load(HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->isLoaded()); CPPUNIT_ASSERT(history_->isLoaded());
CPPUNIT_ASSERT(res);
} }
void HistoryTest::test_load_items() void HistoryTest::test_load_items()
{ {
DEBUG("-------------------- HistoryTest::test_load_items_map --------------------\n"); DEBUG("-------------------- HistoryTest::test_load_items_map --------------------\n");
Conf::ConfigTree history_list;
history_->setPath(HISTORY_SAMPLE); history_->setPath(HISTORY_SAMPLE);
history_->loadFromFile(history_list); history_->load(HUGE_HISTORY_LIMIT);
history_->loadItems(history_list, HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->numberOfItems() == HISTORY_SAMPLE_SIZE); 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() void HistoryTest::test_save_to_file()
{ {
DEBUG("-------------------- HistoryTest::test_save_to_file --------------------\n"); 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> res;
std::map<std::string, std::string>::iterator iter; std::map<std::string, std::string>::iterator iter;
history_->setPath(HISTORY_SAMPLE); history_->setPath(HISTORY_SAMPLE);
history_->loadFromFile(history_list); CPPUNIT_ASSERT(history_->save());
history_->loadItems(history_list, HUGE_HISTORY_LIMIT);
history_->saveItems(history_list2);
CPPUNIT_ASSERT(history_->saveToFile(history_list2));
} }
void HistoryTest::test_get_serialized() void HistoryTest::test_get_serialized()
...@@ -131,7 +109,7 @@ void HistoryTest::test_get_serialized() ...@@ -131,7 +109,7 @@ void HistoryTest::test_get_serialized()
std::vector<std::string>::iterator iter; std::vector<std::string>::iterator iter;
std::string tmp; std::string tmp;
history_->load(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE); history_->load(HUGE_HISTORY_LIMIT);
CPPUNIT_ASSERT(history_->getSerialized().size() == HISTORY_SAMPLE_SIZE); CPPUNIT_ASSERT(history_->getSerialized().size() == HISTORY_SAMPLE_SIZE);
} }
......
...@@ -55,7 +55,6 @@ class HistoryTest : public CppUnit::TestCase { ...@@ -55,7 +55,6 @@ class HistoryTest : public CppUnit::TestCase {
*/ */
CPPUNIT_TEST_SUITE(HistoryTest); CPPUNIT_TEST_SUITE(HistoryTest);
CPPUNIT_TEST(test_create_path); CPPUNIT_TEST(test_create_path);
CPPUNIT_TEST(test_save_items);
CPPUNIT_TEST(test_load_from_file); CPPUNIT_TEST(test_load_from_file);
CPPUNIT_TEST(test_load_items); CPPUNIT_TEST(test_load_items);
CPPUNIT_TEST(test_get_serialized); CPPUNIT_TEST(test_get_serialized);
...@@ -76,8 +75,6 @@ class HistoryTest : public CppUnit::TestCase { ...@@ -76,8 +75,6 @@ class HistoryTest : public CppUnit::TestCase {
void test_load_items(); void test_load_items();
void test_save_items();
void test_save_to_file(); void test_save_to_file();
void test_get_serialized(); 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