1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
/* Copyright (C) 2005 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "autoconfig.h"
#include "docseqhist.h"
#include <time.h>
#include <cmath>
#include <cstdlib>
#include "rcldb.h"
#include "fileudi.h"
#include "base64.h"
#include "log.h"
#include "smallut.h"
using std::vector;
using std::string;
// Encode document history entry:
// U + Unix time + base64 of udi
// The U distinguishes udi-based entries from older fn+ipath ones
bool RclDHistoryEntry::encode(string& value)
{
string budi, bdir;
base64_encode(udi, budi);
base64_encode(dbdir, bdir);
value = string("V ") + std::to_string(unixtime) + " " + budi + " " + bdir;
return true;
}
// Decode. We support historical entries which were like "time b64fn [b64ipath]"
// Previous entry format is "U time b64udi"
// Current entry format "V time b64udi [b64dir]"
bool RclDHistoryEntry::decode(const string &value)
{
vector<string> vall;
stringToStrings(value, vall);
vector<string>::const_iterator it = vall.begin();
udi.clear();
dbdir.clear();
string fn, ipath;
switch (vall.size()) {
case 2:
// Old fn+ipath, null ipath case
unixtime = atoll((*it++).c_str());
base64_decode(*it++, fn);
break;
case 3:
if (!it->compare("U") || !it->compare("V")) {
// New udi-based entry, no dir
it++;
unixtime = atoll((*it++).c_str());
base64_decode(*it++, udi);
} else {
// Old fn + ipath. We happen to know how to build an udi
unixtime = atoll((*it++).c_str());
base64_decode(*it++, fn);
base64_decode(*it, ipath);
}
break;
case 4:
// New udi-based entry, with directory
it++;
unixtime = atoll((*it++).c_str());
base64_decode(*it++, udi);
base64_decode(*it++, dbdir);
break;
default:
return false;
}
if (!fn.empty()) {
// Old style entry found, make an udi, using the fs udi maker
fileUdi::make_udi(fn, ipath, udi);
}
LOGDEB1("RclDHistoryEntry::decode: udi [" << udi << "] dbdir [" << dbdir << "]\n");
return true;
}
bool RclDHistoryEntry::equal(const DynConfEntry& other)
{
const RclDHistoryEntry& e = dynamic_cast<const RclDHistoryEntry&>(other);
return e.udi == udi && e.dbdir == dbdir;
}
bool historyEnterDoc(std::shared_ptr<Rcl::Db> db, RclDynConf *dncf, Rcl::Doc& doc)
{
if (!db) {
LOGERR("historyEnterDoc: no DB ??\n");
return false;
}
string udi = db->fetchUdi(doc);
if (udi.empty()) {
LOGERR("historyEnterDoc: could not get udi for doc\n");
return false;
}
std::string dbdir = db->whatIndexForResultDoc(doc);
LOGDEB0("histEnterDoc: [" << udi << ", " << dbdir << "] into " << dncf->getFilename() << "\n");
RclDHistoryEntry ne(time(nullptr), udi, dbdir);
RclDHistoryEntry scratch;
return dncf->insertNew(docHistSubKey, ne, scratch, 200);
}
vector<RclDHistoryEntry> getDocHistory(RclDynConf* dncf)
{
return dncf->getEntries<std::vector, RclDHistoryEntry>(docHistSubKey);
}
bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh)
{
// Retrieve history list
if (!m_hist)
return false;
if (m_history.empty())
m_history = getDocHistory(m_hist);
if (num < 0 || num >= (int)m_history.size())
return false;
// We get the history oldest first, but our users expect newest first
RclDHistoryEntry& hentry = m_history[m_history.size() - 1 - num];
if (sh) {
if (m_prevtime < 0 || std::abs(m_prevtime - hentry.unixtime) > 86400) {
m_prevtime = hentry.unixtime;
time_t t = (time_t)(hentry.unixtime);
*sh = string(ctime(&t));
// Get rid of the final \n in ctime
sh->erase(sh->length()-1);
} else {
sh->erase();
}
}
bool ret = m_db->getDoc(hentry.udi, hentry.dbdir, doc);
if (!ret || doc.pc == -1) {
doc.url = "UNKNOWN";
doc.ipath = "";
}
// Ensure the snippets link won't be shown as it does not make sense (no query terms...)
doc.haspages = 0;
return ret;
}
int DocSequenceHistory::getResCnt()
{
if (m_history.empty())
m_history = getDocHistory(m_hist);
return int(m_history.size());
}
|