Beispiel #1
0
        public async Task OnGetAsync()
        {
            var sw = Stopwatch.StartNew();

            //一瞬でも速くしたいので先にTaskを作って必要なところでawaitする
            var TargetUserTask = DB.SelectUser(UserId);

            Params = new TLUserParameters();
            var ParamsTask = Params.InitValidate(HttpContext);

            if (Date.HasValue)
            {
                Before = SnowFlake.SecondinSnowFlake(DateTimeOffset.FromUnixTimeSeconds(Date.Value), true);
            }
            long LastTweet = Before ?? After ?? SnowFlake.Now(true);
            bool IsBefore  = Before.HasValue || !After.HasValue;

            await ParamsTask.ConfigureAwait(false);

            //crawlinfoは「自分のツイート」のときだけ取得する
            var CrawlInfoTask = Params.ID == UserId?DB.SelectCrawlInfo(UserId) : null;

            var TweetsTask = DB.SimilarMediaUser(UserId, Params.ID, LastTweet, Params.TLUser_Count, 3, Params.TLUser_RT, Params.TLUser_Show0, IsBefore);

            await Task.WhenAll(TargetUserTask, TweetsTask).ConfigureAwait(false);

            if (CrawlInfoTask != null)
            {
                Crawlinfo = await CrawlInfoTask.ConfigureAwait(false);
            }
            TargetUser = TargetUserTask.Result;
            Tweets     = TweetsTask.Result;
            if (Tweets.Length == 0)
            {
                HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
            }
            QueryElapsedMilliseconds = sw.ElapsedMilliseconds;
        }
Beispiel #2
0
        public async Task <ActionResult> OnGetAsync()
        {
            var sw = Stopwatch.StartNew();

            //一瞬でも速くしたいので先にTaskを作って必要なところでawaitする
            Params = new TLUserParameters();
            var ParamsTask = Params.InitValidate(HttpContext);

            if (Date.HasValue)
            {
                Before = SnowFlake.SecondinSnowFlake(DateTimeOffset.FromUnixTimeSeconds(Date.Value), true);
            }
            long LastTweet = Before ?? After ?? SnowFlake.Now(true);
            bool IsBefore  = Before.HasValue || !After.HasValue;

            await ParamsTask.ConfigureAwait(false);

            if (!Params.ID.HasValue)
            {
                return(LocalRedirect("/"));
            }
            var CrawlInfoTask  = DB.SelectCrawlInfo(Params.ID.Value);
            var TargetUserTask = DB.SelectUser(Params.ID.Value);
            var TweetsTask     = DB.SimilarMediaTimeline(Params.ID.Value, Params.ID, LastTweet, Params.TLUser_Count, 3, Params.TLUser_RT, Params.TLUser_Show0, IsBefore);

            await Task.WhenAll(TargetUserTask, TweetsTask, CrawlInfoTask).ConfigureAwait(false);

            TargetUser = TargetUserTask.Result;
            Tweets     = TweetsTask.Result;
            Crawlinfo  = CrawlInfoTask.Result;
            if (Tweets.Length == 0)
            {
                HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
            }
            QueryElapsedMilliseconds = sw.ElapsedMilliseconds;
            return(Page());
        }
Beispiel #3
0
        const int MultipleMediaOffset = 3;  //複画は今のところ4枚まで これを同ページに収めたいマン
        /// <summary>
        /// 指定したユーザーのタイムライン上のツイートをずらりと
        /// 鍵かつフォロー外なら何も出ない
        /// </summary>
        /// <param name="target_user_id"></param>
        /// <param name="login_user_id"></param>
        /// <param name="LastTweet"></param>
        /// <param name="TweetCount">最大件数(複画がラストに来ると増える)</param>
        /// <param name="SimilarLimit">類似画像の枚数上限(古い順)</param>
        /// <param name="GetRetweet">RTを含める</param>
        /// <param name="ShowNoDup">類似画像がない</param>
        /// <param name="Before">true→LastTweetより古いツイートを検索する/false→(同文)新しいツイート(同文)</param>
        /// <returns></returns>
        public async Task <SimilarMediaTweet[]> SimilarMediaTimeline(long target_user_id, long?login_user_id, long LastTweet, int TweetCount, int SimilarLimit, bool GetRetweet, bool ShowNoDup, bool Before)
        {
            //鍵垢のTLはフォローしてない限り表示しない
            //未登録のアカウントもここで弾かれる
            TweetData._user TargetUserInfo = await SelectUser(target_user_id).ConfigureAwait(false);

            if (TargetUserInfo != null && TargetUserInfo.isprotected && login_user_id != target_user_id)
            {
                if (login_user_id == null)
                {
                    return(new SimilarMediaTweet[0]);
                }
                using (MySqlCommand cmd = new MySqlCommand(@"SELECT COUNT(*) FROM friend WHERE user_id = @login_user_id AND friend_id = @target_user_id"))
                {
                    cmd.Parameters.Add("@login_user_id", MySqlDbType.Int64).Value  = login_user_id;
                    cmd.Parameters.Add("@target_user_id", MySqlDbType.Int64).Value = target_user_id;
                    switch (await SelectCount(cmd).ConfigureAwait(false))
                    {
                    case 0:
                        return(new SimilarMediaTweet[0]);

                    case -1:
                        throw new Exception("SelectCount() failed.");
                        //それ以外は↓の処理を続行する
                    }
                }
            }

            const long QueryRangeSnowFlake   = 90 * 1000 * SnowFlake.msinSnowFlake;
            long       QuerySnowFlake        = LastTweet;
            long       NowSnowFlake          = SnowFlake.Now(true);
            long       NoTweetSnowFlake      = 0;
            const long NoTweetLimitSnowFlake = 86400 * 1000 * SnowFlake.msinSnowFlake;
            const int  GiveupMilliSeconds    = 5000;
            Stopwatch  sw = new Stopwatch();

            sw.Start();

            CancellationTokenSource       CancelToken = new CancellationTokenSource();
            ExecutionDataflowBlockOptions op          = new ExecutionDataflowBlockOptions()
            {
                CancellationToken         = CancelToken.Token,
                MaxDegreeOfParallelism    = Environment.ProcessorCount,
                SingleProducerConstrained = true
            };
            string QueryText;

            if (GetRetweet)
            {
                QueryText = SimilarMediaHeadRT + @"
FROM friend f 
JOIN user ou ON f.friend_id = ou.user_id
JOIN tweet o USE INDEX (PRIMARY) ON ou.user_id = o.user_id
LEFT JOIN tweet rt ON o.retweet_id = rt.tweet_id
LEFT JOIN user ru ON rt.user_id = ru.user_id
JOIN tweet_media t ON COALESCE(rt.tweet_id, o.tweet_id) = t.tweet_id
JOIN media m ON t.media_id = m.media_id
LEFT JOIN tweet_text ot ON o.tweet_id = ot.tweet_id
LEFT JOIN tweet_text rtt ON rt.tweet_id = rtt.tweet_id
LEFT JOIN media_text mt ON m.media_id = mt.media_id
WHERE " + (ShowNoDup ? "" : @"(
    EXISTS (SELECT * FROM media WHERE dcthash = m.dcthash AND media_id != m.media_id)
    OR EXISTS (SELECT * FROM dcthashpairslim WHERE hash_small = m.dcthash)
    OR EXISTS (SELECT * FROM dcthashpairslim WHERE hash_large = m.dcthash)
) AND") + @"
o.tweet_id BETWEEN " + (Before ? "@time - @timerange AND @time" : "@time AND @time + @timerange") + @"
AND f.user_id = @target_user_id
AND (@login_user_id = @target_user_id
    OR ou.isprotected = 0 
    OR ou.user_id = @login_user_id
    OR EXISTS (SELECT * FROM friend WHERE user_id = @login_user_id AND friend_id = ou.user_id)
)
AND NOT EXISTS (SELECT * FROM block WHERE user_id = @login_user_id AND target_id = rt.user_id)
AND NOT EXISTS(
    SELECT *
    FROM friend fs
    JOIN user ous ON fs.user_id = ous.user_id
    JOIN tweet os ON ous.user_id = os.user_id
    WHERE os.retweet_id = rt.tweet_id
    AND fs.user_id = @target_user_id
    AND (@login_user_id = @target_user_id
        OR (ous.isprotected = 0
        OR ous.user_id = @login_user_id
        OR EXISTS (SELECT * FROM friend WHERE user_id = @login_user_id AND friend_id = ous.user_id))
    )
    AND o.tweet_id < os.tweet_id
)
ORDER BY o.tweet_id " + (Before ? "DESC" : "ASC") + " LIMIT @limitplus;";
            }
            else
            {
                QueryText = SimilarMediaHeadnoRT + @"
FROM friend f 
JOIN user ou ON f.friend_id = ou.user_id
JOIN tweet o USE INDEX (PRIMARY) ON ou.user_id = o.user_id
JOIN tweet_media t ON o.tweet_id = t.tweet_id
JOIN media m ON t.media_id = m.media_id
LEFT JOIN tweet_text ot ON o.tweet_id = ot.tweet_id
LEFT JOIN media_text mt ON m.media_id = mt.media_id
WHERE " + (ShowNoDup ? "" : @"(
    EXISTS (SELECT * FROM media WHERE dcthash = m.dcthash AND media_id != m.media_id)
    OR EXISTS (SELECT * FROM dcthashpairslim WHERE hash_small = m.dcthash)
    OR EXISTS (SELECT * FROM dcthashpairslim WHERE hash_large = m.dcthash)
) AND") + @"
f.user_id = @target_user_id
AND o.tweet_id BETWEEN " + (Before ? "@time - @timerange AND @time" : "@time AND @time + @timerange") + @"
AND o.retweet_id IS NULL
AND (@login_user_id = @target_user_id
    OR ou.user_id = @login_user_id
    OR ou.isprotected = 0
    OR EXISTS (SELECT * FROM friend WHERE user_id = @login_user_id AND friend_id = ou.user_id)
)
ORDER BY o.tweet_id " + (Before ? "DESC" : "ASC") + " LIMIT @limitplus;";
            }

            var GetTimelineBlock = new TransformBlock <int, SimilarMediaTweet[]>(
                async(int i) =>
            {
                using (MySqlCommand cmd = new MySqlCommand(QueryText))
                {
                    cmd.Parameters.Add("@target_user_id", MySqlDbType.Int64).Value = target_user_id;
                    cmd.Parameters.Add("@login_user_id", MySqlDbType.Int64).Value  = login_user_id;
                    cmd.Parameters.Add("@time", MySqlDbType.Int64).Value           = (Before ? QuerySnowFlake - QueryRangeSnowFlake * i : QuerySnowFlake + QueryRangeSnowFlake * i);
                    cmd.Parameters.Add("@timerange", MySqlDbType.Int64).Value      = QueryRangeSnowFlake;
                    //類似画像が表示できない画像を弾くときだけ多めに取得する
                    cmd.Parameters.Add("@limitplus", MySqlDbType.Int64).Value = ShowNoDup ? TweetCount : TweetCount + MultipleMediaOffset;
                    return(await TableToTweet(cmd, login_user_id, SimilarLimit, ShowNoDup).ConfigureAwait(false));
                }
            }, op);
            int PostedCount = 0;

            for (; PostedCount <= Environment.ProcessorCount; PostedCount++)
            {
                GetTimelineBlock.Post(PostedCount);
            }

            var ret           = new List <SimilarMediaTweet>();
            int RecievedCount = 0;

            do
            {
                var Tweets = await GetTimelineBlock.ReceiveAsync().ConfigureAwait(false);

                RecievedCount++;

                //ツイートがない期間が続いたら打ち切る
                if (Tweets.Length > 0)
                {
                    NoTweetSnowFlake = 0;
                }
                else
                {
                    NoTweetSnowFlake += QueryRangeSnowFlake;
                }

                //必要数が取得できたら打ち切る 複画の分だけ多めに取得する
                foreach (var tweet in Tweets)
                {
                    ret.Add(tweet);
                    if (ret.Count >= TweetCount + MultipleMediaOffset)
                    {
                        break;
                    }
                }

                if (Before || QuerySnowFlake + QueryRangeSnowFlake * (PostedCount - 1) < NowSnowFlake)   //未来は取得しない
                {
                    GetTimelineBlock.Post(PostedCount);
                    PostedCount++;
                }
            } while (PostedCount > RecievedCount && (ret.Count < TweetCount) &&
                     NoTweetSnowFlake < NoTweetLimitSnowFlake &&
                     sw.ElapsedMilliseconds < GiveupMilliSeconds);
            CancelToken.Cancel();

            if (!Before)
            {
                ret.Reverse();
            }
            //TableToTweetで類似画像が表示できないやつが削られるので
            //多めに拾ってきて溢れた分を捨てる
            //あと複画は件数超えても同ページに入れる
            for (int i = TweetCount; i < ret.Count; i++)
            {
                if (ret[i].tweet.tweet_id != ret[TweetCount - 1].tweet.tweet_id)
                {
                    return(ret.Take(i - 1).ToArray());
                }
            }
            return(ret.ToArray());
        }