diff --git a/src/twister.cpp b/src/twister.cpp index 9c4eb700..99d9ac09 100644 --- a/src/twister.cpp +++ b/src/twister.cpp @@ -31,6 +31,7 @@ twister::twister() #include "libtorrent/aux_/session_impl.hpp" #define DEBUG_ACCEPT_POST 1 +#define DEBUG_EXPIRE_DHT_ITEM 1 using namespace libtorrent; static session *ses = NULL; @@ -47,8 +48,12 @@ static map m_userTorrent; static std::string m_preferredSpamLang = "[en]"; static std::string m_receivedSpamMsgStr; static std::string m_receivedSpamUserStr; +static int64 m_lastSpamTime = 0; static std::map m_users; +#define USER_DATA_FILE "user_data" +#define GLOBAL_DATA_FILE "global_data" + sha1_hash dhtTargetHash(std::string const &username, std::string const &resource, std::string const &type) { entry target; @@ -96,6 +101,47 @@ int lastPostKfromTorrent(std::string const &username) return status.last_have; } +int saveGlobalData(std::string const& filename) +{ + LOCK(cs_twister); + entry globalDict; + + globalDict["preferredSpamLang"] = m_preferredSpamLang; + globalDict["receivedSpamMsg"] = m_receivedSpamMsgStr; + globalDict["receivedSpamUser"] = m_receivedSpamUserStr; + globalDict["lastSpamTime"] = m_lastSpamTime; + + std::vector buf; + bencode(std::back_inserter(buf), globalDict); + return save_file(filename, buf); +} + +int loadGlobalData(std::string const& filename) +{ + LOCK(cs_twister); + std::vector in; + if (load_file(filename, in) == 0) { + lazy_entry userDict; + error_code ec; + if (lazy_bdecode(&in[0], &in[0] + in.size(), userDict, ec) == 0) { + if( userDict.type() != lazy_entry::dict_t ) goto data_error; + + m_preferredSpamLang = userDict.dict_find_string_value("preferredSpamLang"); + m_receivedSpamMsgStr = userDict.dict_find_string_value("receivedSpamMsg"); + m_receivedSpamUserStr = userDict.dict_find_string_value("receivedSpamUser"); + m_lastSpamTime = userDict.dict_find_int_value("lastSpamTime"); + + return 0; + } + } + return -1; + +data_error: + printf("loadGlobalData: unexpected bencode type - global_data corrupt!\n"); + return -2; +} + + void ThreadWaitExtIP() { RenameThread("wait-extip"); @@ -172,9 +218,12 @@ void ThreadWaitExtIP() break; } + boost::filesystem::path globalDataPath = GetDataDir() / GLOBAL_DATA_FILE; + loadGlobalData(globalDataPath.string()); + { LOCK(cs_twister); - boost::filesystem::path userDataPath = GetDataDir() / "user_data"; + boost::filesystem::path userDataPath = GetDataDir() / USER_DATA_FILE; loadUserData(userDataPath.string(), m_users); printf("loaded user_data for %zd users\n", m_users.size()); @@ -448,18 +497,21 @@ void stopSessionTorrent() entry session_state; ses->save_state(session_state); - std::vector out; - bencode(std::back_inserter(out), session_state); - boost::filesystem::path sesStatePath = GetDataDir() / "ses_state"; - save_file(sesStatePath.string(), out); + std::vector out; + bencode(std::back_inserter(out), session_state); + boost::filesystem::path sesStatePath = GetDataDir() / "ses_state"; + save_file(sesStatePath.string(), out); - delete ses; - ses = NULL; + delete ses; + ses = NULL; } + boost::filesystem::path globalDataPath = GetDataDir() / GLOBAL_DATA_FILE; + saveGlobalData(globalDataPath.string()); + if( m_users.size() ) { printf("saving user_data (followers and DMs)...\n"); - boost::filesystem::path userDataPath = GetDataDir() / "user_data"; + boost::filesystem::path userDataPath = GetDataDir() / USER_DATA_FILE; saveUserData(userDataPath.string(), m_users); } @@ -829,7 +881,9 @@ bool shouldDhtResourceExpire(std::string resource, bool multi, int height) { if ((height + BLOCK_AGE_TO_EXPIRE_DHT_ENTRY) < getBestHeight() ) { if( multi ) { +#ifdef DEBUG_EXPIRE_DHT_ITEM printf("shouldDhtResourceExpire: expiring resource multi '%s'\n", resource.c_str()); +#endif return true; } @@ -849,12 +903,16 @@ bool shouldDhtResourceExpire(std::string resource, bool multi, int height) } else { if( !m_noExpireResources[resourceBasic] && resourceNumber >= 0 ) { // this resource admits no number. expire it! +#ifdef DEBUG_EXPIRE_DHT_ITEM printf("shouldDhtResourceExpire: expiring resource with unexpected numbering '%s'\n", resource.c_str()); +#endif return true; } if( m_noExpireResources[resourceBasic] && resourceNumber > 200 ) { // try keeping a sane number here, otherwise expire it! +#ifdef DEBUG_EXPIRE_DHT_ITEM printf("shouldDhtResourceExpire: expiring resource with numbering too big '%s'\n", resource.c_str()); +#endif return true; } } @@ -865,8 +923,13 @@ bool shouldDhtResourceExpire(std::string resource, bool multi, int height) void receivedSpamMessage(std::string const &message, std::string const &user) { LOCK(cs_twister); - if( !m_receivedSpamMsgStr.length() || - (m_preferredSpamLang.length() && message.find(m_preferredSpamLang) != string::npos) ) { + bool hasSingleLangCode = (message.find("[") == message.rfind("[")); + bool hasPreferredLang = m_preferredSpamLang.length(); + bool isSameLang = hasPreferredLang && hasSingleLangCode && + message.find(m_preferredSpamLang) != string::npos; + bool currentlyEmpty = !m_receivedSpamMsgStr.length(); + + if( currentlyEmpty || (isSameLang && rand() < (RAND_MAX/2)) ) { m_receivedSpamMsgStr = message; m_receivedSpamUserStr = user; } @@ -1196,7 +1259,10 @@ Value getposts(const Array& params, bool fHelp) LOCK(cs_twister); if( m_receivedSpamMsgStr.length() ) { // we must agree on an acceptable level here - if( rand() < (RAND_MAX/10) ) { + // what about one every eight hours? (not cumulative) + if( GetAdjustedTime() > m_lastSpamTime + (8*3600) ) { + m_lastSpamTime = GetAdjustedTime(); + entry v; entry &userpost = v["userpost"];