Ejemplo n.º 1
0
        public async Task FixWatchLimits(WatchViewSource watchSource, Requester requester, IdLimiter limiter)
        {
            if (limiter.Watches)
            {
                if (requester.userId > 0)
                {
                    var watchSearch = new WatchSearch();
                    watchSearch.UserIds.Add(requester.userId);
                    watchSearch.Reverse = true;

                    limiter.Limit = (await watchSource.SimpleSearchAsync(watchSearch, q =>
                                                                         services.permissions.PermissionWhere(q, requester, Keys.ReadAction)))
                                    .Select(x => new IdLimit()
                    {
                        id = x.contentId, min = x.lastNotificationId
                    }).ToList();
                }

                // Just a silly thing to ensure "0" elements still means "no search" (although I hate that old
                // dicision... even though this one could easily be changed, consistency is better)
                limiter.Limit.Add(new IdLimit()
                {
                    id = long.MaxValue
                });
            }
        }
Ejemplo n.º 2
0
        public override async Task <List <ContentView> > PreparedSearchAsync(ContentSearch search, Requester requester)
        {
            var baseResult = await base.PreparedSearchAsync(search, requester);

            var baseIds = baseResult.Select(x => x.id).ToList();

            if (baseIds.Count > 0 && search.IncludeAbout)
            {
                //This requires intimate knowledge of how watches work. it's increasing the complexity/dependency,
                //but at least... I don't know, it's way more performant. Come up with some system perhaps after
                //you see what you need in other instances.
                var watches = await watchSource.GroupAsync <EntityRelation, long>(
                    watchSource.SearchIds(new WatchSearch()
                {
                    ContentIds = baseIds
                }), watchSource.PermIdSelector);                                                                    //x => x.entityId2);

                var comments = await commentSource.GroupAsync <EntityRelation, long>(
                    commentSource.SearchIds(new CommentSearch()
                {
                    ParentIds = baseIds
                }), commentSource.PermIdSelector);                                                                       //x => x.entityId1);

                var votes = new Dictionary <string, Dictionary <long, SimpleAggregateData> >();

                var watchSearch = new WatchSearch();
                watchSearch.UserIds.Add(requester.userId);
                watchSearch.ContentIds.AddRange(baseIds);
                var userWatching = await watchSource.SimpleSearchAsync(watchSearch);

                //THIS could be an intensive query! Make sure you check the CPU usage!
                var voteSearch = new VoteSearch();
                voteSearch.UserIds.Add(requester.userId);
                voteSearch.ContentIds.AddRange(baseIds);
                var userVotes = await voteSource.SimpleSearchAsync(voteSearch);

                foreach (var voteWeight in Votes.VoteWeights)
                {
                    votes.Add(voteWeight.Key, await voteSource.GroupAsync <EntityRelation, long>(
                                  voteSource.SearchIds(new VoteSearch()
                    {
                        ContentIds = baseIds, Vote = voteWeight.Key
                    }), voteSource.PermIdSelector));                                                                                         //x => x.entityId2));
                }

                baseResult.ForEach(x =>
                {
                    if (watches.ContainsKey(x.id))       //-x.id))
                    {
                        x.about.watches = watches[x.id]; //-x.id];
                    }
                    if (comments.ContainsKey(x.id))
                    {
                        x.about.comments = comments[x.id];
                    }

                    x.about.watching = userWatching.Any(y => y.contentId == x.id);
                    x.about.myVote   = userVotes.FirstOrDefault(y => y.contentId == x.id)?.vote;

                    foreach (var voteWeight in Votes.VoteWeights)
                    {
                        x.about.votes.Add(voteWeight.Key, new SimpleAggregateData());

                        if (votes[voteWeight.Key].ContainsKey(x.id))                     //-x.id))
                        {
                            x.about.votes[voteWeight.Key] = votes[voteWeight.Key][x.id]; //-x.id];
                        }
                    }
                });
            }
            else if (!search.IncludeAbout)
            {
                //Eventually, about is going away anyway
                baseResult.ForEach(x =>
                {
                    x.about = null;
                });
            }

            return(baseResult);
        }
        public override async Task <List <ContentView> > PreparedSearchAsync(ContentSearch search, Requester requester)
        {
            string             key        = JsonSerializer.Serialize(search) + JsonSerializer.Serialize(requester);
            List <ContentView> baseResult = null;

            bool includeAbout = search.IncludeAbout != null && search.IncludeAbout.Count > 0;
            bool useCache     = !includeAbout;

            if (useCache && cache.GetValue(key, ref baseResult))
            {
                return(baseResult);
            }

            List <long> baseIds = null;

            Interlocked.Increment(ref rid);

            var t = services.timer.StartTimer("");

            try
            {
                baseResult = await base.PreparedSearchAsync(search, requester);

                baseIds = baseResult.Select(x => x.id).ToList();
                t.Name  = $"[{rid}] content PreparedSearchAsync {baseResult.Count} ({string.Join(",", baseIds)})";
            }
            finally
            {
                services.timer.EndTimer(t);
            }

            if (includeAbout && baseResult.Count > 0)
            {
                var desired = search.IncludeAbout.Select(x => x.ToLower());

                //TODO: STOP THIS MADNESS!!
                commentSource.JoinPermissions = false;
                watchSource.JoinPermissions   = false;
                voteSource.JoinPermissions    = false;

                try
                {
                    Dictionary <long, SimpleAggregateData> comments = null;
                    Dictionary <long, SimpleAggregateData> watches  = null;
                    Dictionary <string, Dictionary <long, SimpleAggregateData> > votes = null;
                    List <WatchView> userWatching = null;
                    List <VoteView>  userVotes    = null;

                    if (desired.Any(x => x.StartsWith("comment")))
                    {
                        t        = services.timer.StartTimer($"[{rid}] comment pull");
                        comments = await commentSource.GroupAsync <EntityRelation, long>(
                            await commentSource.GetBaseQuery(new CommentSearch()
                        {
                            ParentIds = baseIds
                        }), g => g.relation, commentSource.PermIdSelector);

                        services.timer.EndTimer(t);
                    }

                    if (desired.Any(x => x.StartsWith("watch")))
                    {
                        t = services.timer.StartTimer($"[{rid}] watch pull (both)");

                        //This requires intimate knowledge of how watches work. it's increasing the complexity/dependency,
                        //but at least... I don't know, it's way more performant. Come up with some system perhaps after
                        //you see what you need in other instances.
                        watches = await watchSource.GroupAsync <EntityRelation, long>(
                            await watchSource.SearchIds(new WatchSearch()
                        {
                            ContentIds = baseIds
                        }), watchSource.PermIdSelector);

                        var watchSearch = new WatchSearch();
                        watchSearch.UserIds.Add(requester.userId);
                        watchSearch.ContentIds.AddRange(baseIds);
                        userWatching = await watchSource.SimpleSearchAsync(watchSearch);

                        services.timer.EndTimer(t);
                    }

                    if (desired.Any(x => x.StartsWith("watch")))
                    {
                        //THIS could be an intensive query! Make sure you check the CPU usage!
                        t = services.timer.StartTimer($"[{rid}] vote pull");
                        var voteSearch = new VoteSearch();
                        voteSearch.UserIds.Add(requester.userId);
                        voteSearch.ContentIds.AddRange(baseIds);
                        userVotes = await voteSource.SimpleSearchAsync(voteSearch);

                        services.timer.EndTimer(t);

                        t     = services.timer.StartTimer($"[{rid}] vote aggregate");
                        votes = new Dictionary <string, Dictionary <long, SimpleAggregateData> >();
                        foreach (var voteWeight in Votes.VoteWeights)
                        {
                            votes.Add(voteWeight.Key, await voteSource.GroupAsync <EntityRelation, long>(
                                          await voteSource.SearchIds(new VoteSearch()
                            {
                                ContentIds = baseIds, Vote = voteWeight.Key
                            }), voteSource.PermIdSelector));                                                                                               //x => x.entityId2));
                        }
                        services.timer.EndTimer(t);
                    }

                    baseResult.ForEach(x =>
                    {
                        if (watches != null)
                        {
                            if (watches.ContainsKey(x.id))
                            {
                                x.about.watches = watches[x.id];
                            }
                            x.about.watching = userWatching.Any(y => y.contentId == x.id);
                        }

                        if (comments != null)
                        {
                            if (comments.ContainsKey(x.id))
                            {
                                x.about.comments = comments[x.id];
                            }
                        }

                        if (votes != null)
                        {
                            x.about.myVote = userVotes.FirstOrDefault(y => y.contentId == x.id)?.vote;

                            foreach (var voteWeight in Votes.VoteWeights)
                            {
                                x.about.votes.Add(voteWeight.Key, new SimpleAggregateData());

                                if (votes[voteWeight.Key].ContainsKey(x.id))
                                {
                                    x.about.votes[voteWeight.Key] = votes[voteWeight.Key][x.id];
                                }
                            }
                        }
                    });
                }
                finally
                {
                    commentSource.JoinPermissions = true;
                    watchSource.JoinPermissions   = true;
                    voteSource.JoinPermissions    = true;
                }
            }
            else
            {
                //Eventually, about is going away anyway
                baseResult.ForEach(x =>
                {
                    x.about = null;
                });
            }

            if (useCache)
            {
                cache.StoreItem(key, baseResult);
            }

            return(baseResult);
        }