Esempio n. 1
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());
        }
Esempio n. 2
0
        /// <summary>
        /// Records that playback has been started for a video.
        /// </summary>
        public override async Task <RecordPlaybackStartedResponse> RecordPlaybackStarted(RecordPlaybackStartedRequest request, ServerCallContext context)
        {
            PreparedStatement prepared = await _statementCache.GetOrAddAsync("UPDATE video_playback_stats SET views = views + 1 WHERE videoid = ?");

            BoundStatement bound = prepared.Bind(request.VideoId.ToGuid());
            await _session.ExecuteAsync(bound).ConfigureAwait(false);

            return(new RecordPlaybackStartedResponse());
        }
Esempio n. 3
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. 4
0
        /// <summary>
        /// Gets a page of videos for a search query.
        /// </summary>
        public override async Task <SearchVideosResponse> SearchVideos(SearchVideosRequest request, ServerCallContext context)
        {
            // Do a Solr query against DSE search to find videos using Solr's ExtendedDisMax query parser. Query the
            // name, tags, and description fields in the videos table giving a boost to matches in the name and tags
            // fields as opposed to the description field
            // More info on ExtendedDisMax: http://wiki.apache.org/solr/ExtendedDisMax
            string solrQuery = "{ \"q\": \"{!edismax qf=\\\"name^2 tags^1 description\\\"}" + request.Query + "\" }";

            PreparedStatement prepared = await _statementCache.GetOrAddAsync(
                "SELECT videoid, userid, name, preview_image_location, added_date FROM videos WHERE solr_query=?");

            // The driver's built-in paging feature just works with DSE Search Solr paging which is pretty cool
            IStatement bound = prepared.Bind(solrQuery)
                               .SetConsistencyLevel(ConsistencyLevel.LocalOne)              // Search queries only support One / LocalOne
                               .SetAutoPage(false)
                               .SetPageSize(request.PageSize);

            // The initial query won't have a paging state, but subsequent calls should if there are more pages
            if (string.IsNullOrEmpty(request.PagingState) == false)
            {
                bound.SetPagingState(Convert.FromBase64String(request.PagingState));
            }

            RowSet rows = await _session.ExecuteAsync(bound).ConfigureAwait(false);

            var response = new SearchVideosResponse
            {
                Query       = request.Query,
                PagingState = rows.PagingState != null && rows.PagingState.Length > 0 ? Convert.ToBase64String(rows.PagingState) : ""
            };

            response.Videos.Add(rows.Select(MapRowToVideoPreview));
            return(response);
        }
Esempio n. 5
0
        /// <summary>
        /// Creates a new user account.
        /// </summary>
        public override async Task <CreateUserResponse> CreateUser(CreateUserRequest request, ServerCallContext context)
        {
            // Hash the user's password
            string hashedPassword = PasswordHash.CreateHash(request.Password);

            // TODO:  Use LINQ to create users
            DateTimeOffset timestamp = DateTimeOffset.UtcNow;

            PreparedStatement preparedCredentials = await _statementCache.GetOrAddAsync(
                "INSERT INTO user_credentials (email, password, userid) VALUES (?, ?, ?) IF NOT EXISTS");

            // Insert the credentials info (this will return false if a user with that email address already exists)
            IStatement insertCredentialsStatement = preparedCredentials.Bind(request.Email, hashedPassword, request.UserId.ToGuid());
            RowSet     credentialsResult          = await _session.ExecuteAsync(insertCredentialsStatement).ConfigureAwait(false);

            // The first column in the row returned will be a boolean indicating whether the change was applied (TODO: Compensating action for user creation failure?)
            var applied = credentialsResult.Single().GetValue <bool>("[applied]");

            if (applied == false)
            {
                var status = new Status(StatusCode.AlreadyExists, "A user with that email address already exists");
                throw new RpcException(status);
            }

            PreparedStatement preparedUser = await _statementCache.GetOrAddAsync(
                "INSERT INTO users (userid, firstname, lastname, email, created_date) VALUES (?, ?, ?, ?, ?)");

            // Insert the "profile" information using a parameterized CQL statement
            IStatement insertUserStatement = preparedUser.Bind(request.UserId.ToGuid(), request.FirstName, request.LastName, request.Email, timestamp)
                                             .SetTimestamp(timestamp);

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

            // Tell the world about the new user
            await _bus.Publish(new UserCreated
            {
                UserId    = request.UserId,
                FirstName = request.FirstName,
                LastName  = request.LastName,
                Email     = request.Email,
                Timestamp = timestamp.ToTimestamp()
            }).ConfigureAwait(false);

            return(new CreateUserResponse());
        }
Esempio n. 6
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());
        }
        public async Task <IEnumerable <DeviceEvent> > GetDeviceEventsAsync(double swLon, double swLat, double neLon, double neLat)
        {
            logger.LogInformation($"In GetDeviceEventsAsync. params = ({swLon},{swLat},{neLon},{neLat})");

            var results = new List <DeviceEvent>();

            var statementQuery = new SimpleStatement("select * from " + tableName + " where solr_query='{\"q\": \"*:*\", \"fq\":\"location:[\\\"" + swLon + " " + swLat + "\\\" TO \\\"" + neLon + " " + neLat + "\\\"]\"}' ORDER BY event_time DESC LIMIT " + MaxDeviceEvents);
            var rowSet         = await session.ExecuteAsync(statementQuery);

            foreach (Row row in rowSet)
            {
                var location  = (Dse.Geometry.Point)row["location"];
                var timestamp = (DateTimeOffset)row["event_time"];
                results.Add(new DeviceEvent
                {
                    id        = row["device_id"].ToString(),
                    Location  = GeometryPoint.Create(location.X, location.Y),
                    Timestamp = timestamp.DateTime
                });
            }

            return(results);
        }
Esempio n. 8
0
        public static async Task RunAsync(
            [EventHubTrigger("%EventHubName%", Connection = "EventHubConnectionString", ConsumerGroup = "%ConsumerGroup%")]
            EventData[] messages,
            ExecutionContext context,
            TraceWriter log)
        {
            CustomTelemetry.TrackMetric(context, "IoTHubMessagesReceived", messages.Length);
            await Task.Delay(0);

            var ticksUTCNow = DateTimeOffset.UtcNow;
            var cutoffTime  = DateTimeOffset.UtcNow.AddMinutes(-5);

            // Track whether messages are arriving at the function late.
            DateTime?firstMsgEnqueuedTicksUtc = messages[0]?.EnqueuedTimeUtc;

            if (firstMsgEnqueuedTicksUtc.HasValue)
            {
                CustomTelemetry.TrackMetric(
                    context,
                    "IoTHubMessagesReceivedFreshnessMsec",
                    (ticksUTCNow - firstMsgEnqueuedTicksUtc.Value).TotalMilliseconds);
            }

            int count           = 0;
            int droppedMessages = 0;

            var batchStatement = new BatchStatement();

            batchStatement.SetBatchType(BatchType.Unlogged);

            foreach (var message in messages)
            {
                // Drop stale messages,
                if (message.EnqueuedTimeUtc < cutoffTime)
                {
                    log.Info($"Dropping late message batch. Enqueued time = {message.EnqueuedTimeUtc}, Cutoff = {cutoffTime}");
                    droppedMessages++;
                    continue;
                }

                var text = Encoding.UTF8.GetString(message.GetBytes());
                log.Info($"Process message: {text}");

                try
                {
                    dynamic telemetry = JObject.Parse(text);
                    if (telemetry.sensorType == DroneSensorEventType)
                    {
                        string position = telemetry.position;
                        var(latitude, longitude) = DroneTelemetryConverter.ConvertPosition(position);

                        string deviceId = telemetry.deviceId;

                        var statementAdd = new SimpleStatement($"INSERT INTO {tableName} (device_id, location, event_time) VALUES (?, ?, ?) USING TTL 259200",
                                                               deviceId, new Point(longitude, latitude), new DateTimeOffset(message.EnqueuedTimeUtc));
                        batchStatement.Add(statementAdd);

                        count++;
                    }
                }
                catch (Exception ex)
                {
                    log.Error("Error processing message", ex);
                }
            }

            try
            {
                await session.ExecuteAsync(batchStatement);

                log.Info("Successfully written batch to cassandra");

                CustomTelemetry.TrackMetric(
                    context,
                    "IoTHubMessagesDropped",
                    droppedMessages);
                CustomTelemetry.TrackMetric(
                    context,
                    "CassandraDocumentsCreated",
                    count);
            }
            catch (Exception ex)
            {
                log.Error("Error processing batch of messages", ex);
            }
        }
        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);
        }