Esempio n. 1
0
        /// <summary>
        /// Submits an uploaded video to the catalog.
        /// </summary>
        public override async Task <SubmitUploadedVideoResponse> SubmitUploadedVideo(SubmitUploadedVideoRequest request, ServerCallContext context)
        {
            var timestamp = DateTimeOffset.UtcNow;

            // Store the information we have now in Cassandra
            PreparedStatement[] prepared = await _statementCache.GetOrAddAllAsync(
                "INSERT INTO videos (videoid, userid, name, description, tags, location_type, added_date) VALUES (?, ?, ?, ?, ?, ?, ?)",
                "INSERT INTO user_videos (userid, added_date, videoid, name) VALUES (?, ?, ?, ?)"
                );

            var batch = new BatchStatement();

            batch.Add(prepared[0].Bind(request.VideoId.ToGuid(), request.UserId.ToGuid(), request.Name, request.Description,
                                       request.Tags.ToArray(), (int)VideoLocationType.Upload, timestamp))
            .Add(prepared[1].Bind(request.UserId.ToGuid(), timestamp, request.VideoId.ToGuid(), request.Name))
            .SetTimestamp(timestamp);

            await _session.ExecuteAsync(batch).ConfigureAwait(false);

            // Tell the world we've accepted an uploaded video (it hasn't officially been added until we get a location for the
            // video playback and thumbnail)
            await _bus.Publish(new UploadedVideoAccepted
            {
                VideoId   = request.VideoId,
                UploadUrl = request.UploadUrl,
                Timestamp = timestamp.ToTimestamp()
            }).ConfigureAwait(false);

            return(new SubmitUploadedVideoResponse());
        }
Esempio n. 2
0
        private async Task HandleImpl(Uuid videoId, Timestamp addedDate, Uuid userId, string name, string previewImageLocation,
                                      RepeatedField <string> tags, Timestamp timestamp)
        {
            PreparedStatement[] prepared = await _statementCache.GetOrAddAllAsync(
                "INSERT INTO videos_by_tag (tag, videoid, added_date, userid, name, preview_image_location, tagged_date) VALUES (?, ?, ?, ?, ?, ?, ?)",
                "INSERT INTO tags_by_letter (first_letter, tag) VALUES (?, ?)");

            DateTimeOffset ts = timestamp.ToDateTimeOffset();

            // Create a batch for executing the updates
            var batch = new BatchStatement();

            // We need to add multiple statements for each tag
            foreach (string tag in tags)
            {
                // INSERT INTO videos_by_tag
                batch.Add(prepared[0].Bind(tag, videoId.ToGuid(), addedDate.ToDateTimeOffset(), userId.ToGuid(), name, previewImageLocation, ts));

                // INSERT INTO tags_by_letter
                string firstLetter = tag.Substring(0, 1);
                batch.Add(prepared[1].Bind(firstLetter, tag));
            }
            batch.SetTimestamp(ts);

            await _session.ExecuteAsync(batch).ConfigureAwait(false);
        }
Esempio n. 3
0
        /// <summary>
        /// Adds a user's rating of a video.
        /// </summary>
        public override async Task <RateVideoResponse> RateVideo(RateVideoRequest request, ServerCallContext context)
        {
            PreparedStatement[] preparedStatements = await _statementCache.GetOrAddAllAsync(
                "UPDATE video_ratings SET rating_counter = rating_counter + 1, rating_total = rating_total + ? WHERE videoid = ?",
                "INSERT INTO video_ratings_by_user (videoid, userid, rating) VALUES (?, ?, ?)");

            DateTimeOffset timestamp = DateTimeOffset.UtcNow;

            // We can't use a batch here because we can't mix counters with regular DML, but we can run both of them at the same time
            var bound = new[]
            {
                // UPDATE video_ratings... (Driver will throw if we don't cast the rating to a long I guess because counters are data type long)
                preparedStatements[0].Bind((long)request.Rating, request.VideoId.ToGuid()),
                // INSERT INTO video_ratings_by_user
                preparedStatements[1].Bind(request.VideoId.ToGuid(), request.UserId.ToGuid(), request.Rating).SetTimestamp(timestamp)
            };

            await Task.WhenAll(bound.Select(b => _session.ExecuteAsync(b))).ConfigureAwait(false);

            // Tell the world about the rating
            await _bus.Publish(new UserRatedVideo
            {
                VideoId         = request.VideoId,
                UserId          = request.UserId,
                Rating          = request.Rating,
                RatingTimestamp = timestamp.ToTimestamp()
            }).ConfigureAwait(false);

            return(new RateVideoResponse());
        }
Esempio n. 4
0
        /// <summary>
        /// Records a user comment on a video.
        /// </summary>
        public override async Task <CommentOnVideoResponse> CommentOnVideo(CommentOnVideoRequest request, ServerCallContext context)
        {
            // Use a client side timestamp for the writes that we can include when we publish the event
            var timestamp = DateTimeOffset.UtcNow;

            PreparedStatement[] preparedStatements = await _statementCache.GetOrAddAllAsync(
                "INSERT INTO comments_by_video (videoid, commentid, userid, comment) VALUES (?, ?, ?, ?)",
                "INSERT INTO comments_by_user (userid, commentid, videoid, comment) VALUES (?, ?, ?, ?)");

            // Use a batch to insert into all tables
            var batch = new BatchStatement();

            // INSERT INTO comments_by_video
            batch.Add(preparedStatements[0].Bind(request.VideoId.ToGuid(), request.CommentId.ToGuid(), request.UserId.ToGuid(), request.Comment));

            // INSERT INTO comments_by_user
            batch.Add(preparedStatements[1].Bind(request.UserId.ToGuid(), request.CommentId.ToGuid(), request.VideoId.ToGuid(), request.Comment));

            batch.SetTimestamp(timestamp);
            await _session.ExecuteAsync(batch).ConfigureAwait(false);

            // Tell the world about the comment
            await _bus.Publish(new UserCommentedOnVideo
            {
                UserId           = request.UserId,
                VideoId          = request.VideoId,
                CommentId        = request.CommentId,
                CommentTimestamp = timestamp.ToTimestamp()
            }).ConfigureAwait(false);

            return(new CommentOnVideoResponse());
        }
        public async Task Handle(UploadedVideoPublished publishedVideo)
        {
            // Find the video
            PreparedStatement prepared = await _statementCache.GetOrAddAsync("SELECT * FROM videos WHERE videoid = ?");

            BoundStatement bound = prepared.Bind(publishedVideo.VideoId);
            RowSet         rows  = await _session.ExecuteAsync(bound).ConfigureAwait(false);

            Row videoRow = rows.SingleOrDefault();

            if (videoRow == null)
            {
                throw new InvalidOperationException($"Could not find video with id {publishedVideo.VideoId}");
            }

            var locationType = videoRow.GetValue <int>("location_type");

            if (locationType != (int)VideoLocationType.Upload)
            {
                throw new InvalidOperationException($"Video {publishedVideo.VideoId} is not an uploaded video of type {VideoLocationType.Upload} but is type {locationType}");
            }

            // Get some data from the Row
            var userId      = videoRow.GetValue <Guid>("userid");
            var name        = videoRow.GetValue <string>("name");
            var description = videoRow.GetValue <string>("description");
            var tags        = videoRow.GetValue <IEnumerable <string> >("tags");
            var addDate     = videoRow.GetValue <DateTimeOffset>("added_date");

            // Get some data from the event
            string videoUrl     = publishedVideo.VideoUrl;
            string thumbnailUrl = publishedVideo.ThumbnailUrl;
            Guid   videoId      = publishedVideo.VideoId.ToGuid();

            // Update the video locations (and write to denormalized tables) via batch
            PreparedStatement[] writePrepared = await _statementCache.GetOrAddAllAsync(
                "UPDATE videos SET location = ?, preview_image_location = ? WHERE videoid = ?",
                "UPDATE user_videos SET preview_image_location = ? WHERE userid = ? AND added_date = ? AND videoid = ?",
                "INSERT INTO latest_videos (yyyymmdd, added_date, videoid, userid, name, preview_image_location) VALUES (?, ?, ?, ?, ?, ?) USING TTL ?"
                );

            // Calculate date-related data for the video
            string         yyyymmdd  = addDate.ToString("yyyyMMdd");
            DateTimeOffset timestamp = publishedVideo.Timestamp.ToDateTimeOffset();

            var batch = new BatchStatement();

            batch.Add(writePrepared[0].Bind(videoUrl, thumbnailUrl, videoId))
            .Add(writePrepared[1].Bind(thumbnailUrl, userId, addDate, videoId))
            .Add(writePrepared[2].Bind(yyyymmdd, addDate, videoId, userId, name, thumbnailUrl, VideoCatalogServiceImpl.LatestVideosTtlSeconds))
            .SetTimestamp(timestamp);

            await _session.ExecuteAsync(batch).ConfigureAwait(false);

            // Tell the world about the uploaded video that was added
            var addedEvent = new UploadedVideoAdded
            {
                VideoId              = publishedVideo.VideoId,
                UserId               = userId.ToUuid(),
                Name                 = name,
                Description          = description,
                Location             = publishedVideo.VideoUrl,
                PreviewImageLocation = publishedVideo.ThumbnailUrl,
                AddedDate            = addDate.ToTimestamp(),
                Timestamp            = timestamp.ToTimestamp()
            };

            addedEvent.Tags.Add(tags);
            await _bus.Publish(addedEvent).ConfigureAwait(false);
        }