Browse Source

0.9.27 new 'getmentions' api. return known mentions from users we follow.

never miss a mention from your friends anymore! :-)
(twister-html support pending)
miguelfreitas
Miguel Freitas 10 years ago
parent
commit
9d3b0744ff
  1. 3
      src/bitcoinrpc.cpp
  2. 1
      src/bitcoinrpc.h
  3. 2
      src/clientversion.h
  4. 107
      src/twister.cpp
  5. 30
      src/twister_utils.cpp
  6. 5
      src/twister_utils.h

3
src/bitcoinrpc.cpp

@ -251,6 +251,7 @@ static const CRPCCommand vRPCCommands[] = @@ -251,6 +251,7 @@ static const CRPCCommand vRPCCommands[] =
{ "newrtmsg", &newrtmsg, false, true, false },
{ "getposts", &getposts, false, true, false },
{ "getdirectmsgs", &getdirectmsgs, false, true, false },
{ "getmentions", &getmentions, false, true, false },
{ "setspammsg", &setspammsg, false, false, false },
{ "getspammsg", &getspammsg, false, false, false },
{ "follow", &follow, false, true, false },
@ -1308,6 +1309,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri @@ -1308,6 +1309,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "getposts" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "getdirectmsgs" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getdirectmsgs" && n > 2) ConvertTo<Array>(params[2]);
if (strMethod == "getmentions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getmentions" && n > 2) ConvertTo<Object>(params[2]);
if (strMethod == "follow" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "unfollow" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "listusernamespartial" && n > 1) ConvertTo<boost::int64_t>(params[1]);

1
src/bitcoinrpc.h

@ -204,6 +204,7 @@ extern json_spirit::Value newdirectmsg(const json_spirit::Array& params, bool fH @@ -204,6 +204,7 @@ extern json_spirit::Value newdirectmsg(const json_spirit::Array& params, bool fH
extern json_spirit::Value newrtmsg(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getposts(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getdirectmsgs(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getmentions(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value setspammsg(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getspammsg(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value follow(const json_spirit::Array& params, bool fHelp);

2
src/clientversion.h

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 9
#define CLIENT_VERSION_REVISION 26
#define CLIENT_VERSION_REVISION 27
#define CLIENT_VERSION_BUILD 0
// Set to true for release, false for prerelease or test build

107
src/twister.cpp

@ -77,6 +77,8 @@ const int hashtagTimerInterval = 60; // Timer interval (sec) @@ -77,6 +77,8 @@ const int hashtagTimerInterval = 60; // Timer interval (sec)
const double hashtagAgingFactor = pow(0.5, hashtagTimerInterval/hashtagHalfLife);
const double hashtagCriticalValue = pow(0.5, hashtagExpiration/hashtagHalfLife);
const char* msgTokensDelimiter = " \n\t.,:/?!;'\"()[]{}*";
class SimpleThreadCounter {
public:
SimpleThreadCounter(CCriticalSection *lock, int *counter, const char *name) :
@ -1053,6 +1055,7 @@ bool verifySignature(std::string const &strMessage, std::string const &strUserna @@ -1053,6 +1055,7 @@ bool verifySignature(std::string const &strMessage, std::string const &strUserna
return (pubkeyRec.GetID() == pubkey.GetID());
}
// try decrypting new DM received by any torrent we follow
bool processReceivedDM(lazy_entry const* post)
{
bool result = false;
@ -1137,6 +1140,39 @@ bool processReceivedDM(lazy_entry const* post) @@ -1137,6 +1140,39 @@ bool processReceivedDM(lazy_entry const* post)
return result;
}
// check post received in a torrent we follow if they mention local users
void processReceivedPost(lazy_entry const &v, std::string &username, int64 time, std::string &msg)
{
// split and look for mentions for local users
vector<string> tokens;
boost::algorithm::split(tokens,msg,boost::algorithm::is_any_of(msgTokensDelimiter),
boost::algorithm::token_compress_on);
BOOST_FOREACH(string const& token, tokens) {
if( token.length() >= 2 ) {
char delim = token.at(0);
if( delim != '@' ) continue;
string mentionUser = token.substr(1);
#ifdef HAVE_BOOST_LOCALE
mentionUser = boost::locale::to_lower(mentionUser);
#else
boost::algorithm::to_lower(mentionUser);
#endif
LOCK(cs_twister);
// mention of a local user && sent by someone we follow
if( m_users.count(mentionUser) && m_users[mentionUser].m_following.count(username) ) {
std::string postKey = username + ";" + boost::lexical_cast<std::string>(time);
if( m_users[mentionUser].m_mentionsKeys.count(postKey) == 0 ) {
m_users[mentionUser].m_mentionsKeys.insert(postKey);
entry vEntry;
vEntry = v;
m_users[mentionUser].m_mentionsPosts.push_back(vEntry);
}
}
}
}
}
bool acceptSignedPost(char const *data, int data_size, std::string username, int seq, std::string &errmsg, boost::uint32_t *flags)
{
bool ret = false;
@ -1162,6 +1198,7 @@ bool acceptSignedPost(char const *data, int data_size, std::string username, int @@ -1162,6 +1198,7 @@ bool acceptSignedPost(char const *data, int data_size, std::string username, int
int msgUtf8Chars = utf8::num_characters(msg.begin(), msg.end());
int k = post->dict_find_int_value("k",-1);
int height = post->dict_find_int_value("height",-1);
int64 time = post->dict_find_int_value("time",-1);
if( n != username ) {
sprintf(errbuf,"expected username '%s' got '%s'",
@ -1204,10 +1241,14 @@ bool acceptSignedPost(char const *data, int data_size, std::string username, int @@ -1204,10 +1241,14 @@ bool acceptSignedPost(char const *data, int data_size, std::string username, int
}
}
lazy_entry const* dm = post->dict_find_dict("dm");
if( dm && flags ) {
(*flags) |= USERPOST_FLAG_DM;
processReceivedDM(post);
if( flags ) {
lazy_entry const* dm = post->dict_find_dict("dm");
if( dm ) {
(*flags) |= USERPOST_FLAG_DM;
processReceivedDM(post);
} else {
processReceivedPost(v, username, time, msg);
}
}
}
}
@ -1444,7 +1485,7 @@ void updateSeenHashtags(std::string &message, int64_t msgTime) @@ -1444,7 +1485,7 @@ void updateSeenHashtags(std::string &message, int64_t msgTime)
// split and look for hashtags
vector<string> tokens;
set<string> hashtags;
boost::algorithm::split(tokens,message,boost::algorithm::is_any_of(" \n\t.,:/?!;'\"()[]{}*"),
boost::algorithm::split(tokens,message,boost::algorithm::is_any_of(msgTokensDelimiter),
boost::algorithm::token_compress_on);
BOOST_FOREACH(string const& token, tokens) {
if( token.length() >= 2 && token.at(0) == '#' ) {
@ -1793,7 +1834,7 @@ Value newpostmsg(const Array& params, bool fHelp) @@ -1793,7 +1834,7 @@ Value newpostmsg(const Array& params, bool fHelp)
// split and look for mentions and hashtags
vector<string> tokens;
boost::algorithm::split(tokens,strMsg,boost::algorithm::is_any_of(" \n\t.,:/?!;'\"()[]{}*"),
boost::algorithm::split(tokens,strMsg,boost::algorithm::is_any_of(msgTokensDelimiter),
boost::algorithm::token_compress_on);
BOOST_FOREACH(string const& token, tokens) {
if( token.length() >= 2 ) {
@ -2109,6 +2150,60 @@ Value getdirectmsgs(const Array& params, bool fHelp) @@ -2109,6 +2150,60 @@ Value getdirectmsgs(const Array& params, bool fHelp)
return ret;
}
Value getmentions(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3 )
throw runtime_error(
"getmentions <localuser> <count> '{\"max_id\":max_id,\"since_id\":since_id}'\n"
"get (locally stored) mentions to user <localuser> by users followed.\n"
"(use 'dhtget user mention m' for non-followed mentions)\n"
"max_id and since_id may be omited. up to <count> posts are returned.");
string strUsername = params[0].get_str();
int count = params[1].get_int();
int max_id = std::numeric_limits<int>::max();
int since_id = -1;
if( params.size() >= 3 ) {
Object optParms = params[2].get_obj();
for (Object::const_iterator i = optParms.begin(); i != optParms.end(); ++i) {
if( i->name_ == "max_id" ) max_id = i->value_.get_int();
if( i->name_ == "since_id" ) since_id = i->value_.get_int();
}
}
Array ret;
LOCK(cs_twister);
if( strUsername.size() && m_users.count(strUsername) ) {
const std::vector<libtorrent::entry> &mentions = m_users[strUsername].m_mentionsPosts;
max_id = std::min( max_id, (int)mentions.size()-1);
since_id = std::max( since_id, max_id - count );
for( int i = std::max(since_id+1,0); i <= max_id; i++) {
const entry *post = mentions.at(i).find_key("userpost");
if( post && post->type() == entry::dictionary_t ) {
const entry *ptime = post->find_key("time");
if( ptime && ptime->type() == entry::int_t ) {
int64 time = ptime->integer();
if(time <= 0 || time > GetAdjustedTime() + MAX_TIME_IN_FUTURE ) {
printf("getmentions: ignoring far-future post\n");
} else {
entry vEntry;
vEntry = mentions.at(i);
hexcapePost(vEntry);
vEntry["id"] = i;
ret.push_back(entryToJson(vEntry));
}
}
}
}
}
return ret;
}
Value setspammsg(const Array& params, bool fHelp)
{

30
src/twister_utils.cpp

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
#include <libtorrent/bencode.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <stdio.h>
@ -148,6 +149,14 @@ int saveUserData(std::string const& filename, std::map<std::string,UserData> con @@ -148,6 +149,14 @@ int saveUserData(std::string const& filename, std::map<std::string,UserData> con
}
}
if( udata.m_mentionsPosts.size() ) {
entry &userData = userDict[i->first];
entry &mentionsList = userData["mentions"];
BOOST_FOREACH( libtorrent::entry const &mention, udata.m_mentionsPosts) {
mentionsList.list().push_back(mention);
}
}
if( udata.m_directmsg.size() ) {
entry &userData = userDict[i->first];
entry &dmDict = userData["dm"];
@ -200,6 +209,27 @@ int loadUserData(std::string const& filename, std::map<std::string,UserData> &us @@ -200,6 +209,27 @@ int loadUserData(std::string const& filename, std::map<std::string,UserData> &us
}
}
const lazy_entry *mentionsList = userData->dict_find("mentions");
if( mentionsList ) {
if( mentionsList->type() != lazy_entry::list_t ) goto data_error;
for( int j = 0; j < mentionsList->list_size(); j++ ) {
const lazy_entry *v = mentionsList->list_at(j);
if( v->type() != lazy_entry::dict_t ) goto data_error;
lazy_entry const* post = v->dict_find_dict("userpost");
if( !post ) goto data_error;
std::string username = post->dict_find_string_value("n");
int64 time = post->dict_find_int_value("time",-1);
std::string postKey = username + ";" + boost::lexical_cast<std::string>(time);
udata.m_mentionsKeys.insert(postKey);
entry vEntry;
vEntry = *v;
udata.m_mentionsPosts.push_back( vEntry );
}
}
const lazy_entry *dmDict = userData->dict_find("dm");
if( dmDict ) {
if( dmDict->type() != lazy_entry::dict_t ) goto data_error;

5
src/twister_utils.h

@ -18,9 +18,14 @@ struct StoredDirectMsg { @@ -18,9 +18,14 @@ struct StoredDirectMsg {
// in-memory data per wallet user
struct UserData {
// users we follow
std::set<std::string> m_following;
// m_directmsg key is the other username
std::map<std::string, std::vector<StoredDirectMsg> > m_directmsg;
// key for fast checking (log N) if a post is already stored on m_mentionsPosts
std::set<std::string> m_mentionsKeys;
// known posts mentioning this user (by users in m_following)
std::vector<libtorrent::entry> m_mentionsPosts;
};

Loading…
Cancel
Save