mirror of
https://github.com/twisterarmy/twister-core.git
synced 2025-02-02 18:04:23 +00:00
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)
This commit is contained in:
parent
4019d5cfba
commit
9d3b0744ff
@ -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
|
||||
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]);
|
||||
|
@ -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);
|
||||
|
@ -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
107
src/twister.cpp
@ -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
|
||||
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)
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
// 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)
|
||||
|
||||
// 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)
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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…
x
Reference in New Issue
Block a user