Example #1
0
 public DesktopFrame()
 {
     PointerPosition = new PointerPosition();
     PointerShape    = new PointerShape();
 }
Example #2
0
        public Task ObserveWithUnwaveringSight(ObservationRequest observerInfo, CancellationToken token)
        {
            if (observerInfo == null)
            {
                throw new ArgumentNullException(nameof(observerInfo));
            }

            var streamDesktopThumbnails = true;

            if (observerInfo.StreamDesktopThumbnail.HasValue)
            {
                streamDesktopThumbnails = observerInfo.StreamDesktopThumbnail.Value;
            }

            var desktopThumbnailStreamSettings = new DesktopThumbnailStreamSettings();

            if (observerInfo.DesktopThumbnailStreamSettings != null)
            {
                if (observerInfo.DesktopThumbnailStreamSettings.MaxFps.HasValue && observerInfo.DesktopThumbnailStreamSettings.MaxFps.Value > 0)
                {
                    desktopThumbnailStreamSettings.MaxFps = observerInfo.DesktopThumbnailStreamSettings.MaxFps.Value;
                }

                if (observerInfo.DesktopThumbnailStreamSettings.ScaleFactor.HasValue && observerInfo.DesktopThumbnailStreamSettings.ScaleFactor.Value > 0)
                {
                    desktopThumbnailStreamSettings.ScaleFactor = observerInfo.DesktopThumbnailStreamSettings.ScaleFactor.Value;
                }
            }

            var streamPointerPosition = true;

            if (observerInfo.StreamPointerPosition.HasValue)
            {
                streamPointerPosition = observerInfo.StreamPointerPosition.Value;
            }

            // Observe the screen on a seperate thread.
            return(Task.Factory.StartNew(() =>
            {
                var duplicatorInstance = new DesktopDuplicator(_logger, observerInfo.AdapterIndex ?? 0, observerInfo.DeviceIndex ?? 0);

                int?lastMatrixFrameIdSent = null;
                DateTime?lastdesktopThumbnailSent = null;
                PointerPosition lastPointerPosition = null;
                int lastWidth = 0, lastHeight = 0;

                _logger.LogInformation("The cold stare of the Beholder's unwavering glare is now focused upon the screen...");

                //TODO: Process each frame on a separate thread -- we get a "Object is in use elsewhere" from the DesktopImage when we do this though.
                foreach (var desktopFrame in duplicatorInstance.DuplicateDesktop(token))
                {
                    if (token.IsCancellationRequested || desktopFrame == null || desktopFrame.DesktopWidth == 0 || desktopFrame.DesktopHeight == 0 || desktopFrame.IsDesktopImageBufferEmpty)
                    {
                        continue;
                    }

                    if (lastWidth != desktopFrame.DesktopWidth || lastHeight != desktopFrame.DesktopHeight)
                    {
                        NexusConnection?.SendAsync("EyeReport", "ScreenDimensions", new object[] { desktopFrame.DesktopWidth, desktopFrame.DesktopHeight });
                        lastWidth = desktopFrame.DesktopWidth;
                        lastHeight = desktopFrame.DesktopHeight;
                    }

                    if (streamDesktopThumbnails)
                    {
                        if (!lastdesktopThumbnailSent.HasValue || DateTime.Now.Subtract(lastdesktopThumbnailSent.Value) > TimeSpan.FromSeconds(desktopThumbnailStreamSettings.MaxFps.Value))
                        {
                            var width = (int)Math.Ceiling(desktopFrame.DesktopWidth * desktopThumbnailStreamSettings.ScaleFactor.Value);
                            var height = (int)Math.Ceiling(desktopFrame.DesktopHeight * desktopThumbnailStreamSettings.ScaleFactor.Value);

                            var thumbnailImage = desktopFrame.GetThumbnailImage(width, height);

                            var now = DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
                            var key = $"Eye_Thumb_{now}.png";

                            try
                            {
                                var db = Redis.GetDatabase();
                                db.StringSet(key, thumbnailImage, TimeSpan.FromSeconds(30));
                                NexusConnection?.SendAsync("EyeReport", "Thumbnail", new object[] { key, width, height });
                            }
                            catch (RedisException ex)
                            {
                                _logger.LogError(ex, $"Unable to store thumbnail in redis. {ex.Message}");
                            }
                        }
                    }

                    if (streamPointerPosition)
                    {
                        var newPointerPosition = desktopFrame.PointerPosition;

                        if (lastPointerPosition == null || (lastPointerPosition.X != newPointerPosition.X || lastPointerPosition.Y != newPointerPosition.Y || lastPointerPosition.Visible != newPointerPosition.Visible))
                        {
                            NexusConnection?.SendAsync("EyeReport", "PointerPosition", new object[] { newPointerPosition });
                            lastPointerPosition = newPointerPosition;
                        }

                        var pointerData = desktopFrame.GetPointerImage();
                        if (pointerData != null && lastPointerPosition.Visible.Value)
                        {
                            var hash = _hashAlgorithm.ComputeHash(pointerData);
                            var key = $"Eye_Pointer_{Convert.ToBase64String(hash)}.png";

                            try
                            {
                                var db = Redis.GetDatabase();
                                if (!db.KeyExists(key))
                                {
                                    db.StringSet(key, pointerData);
                                }
                            }
                            catch (RedisException ex)
                            {
                                _logger.LogError(ex, $"Unable to store pointer in redis. {ex.Message}");
                            }
                            finally
                            {
                                NexusConnection?.SendAsync("EyeReport", "PointerShape", new object[] { desktopFrame.PointerShape, key });
                            }
                        }
                    }

                    // Double-check locking for a snapshot request.
                    if (SnapshotRequest != null)
                    {
                        lock (_snapshotLock)
                        {
                            if (SnapshotRequest != null)
                            {
                                if (SnapshotRequest.ScaleFactor.HasValue == false)
                                {
                                    SnapshotRequest.ScaleFactor = 1.0;
                                }

                                if (SnapshotRequest.Format.HasValue == false)
                                {
                                    SnapshotRequest.Format = SnapshotFormat.Png;
                                }

                                var width = (int)Math.Ceiling(desktopFrame.DesktopWidth * SnapshotRequest.ScaleFactor.Value);
                                var height = (int)Math.Ceiling(desktopFrame.DesktopHeight * SnapshotRequest.ScaleFactor.Value);

                                var snapshot = desktopFrame.GetSnapshot(width, height, SnapshotRequest.Format.Value);

                                var now = DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
                                var key = $"Eye_Snapshot_{now}";
                                switch (SnapshotRequest.Format)
                                {
                                case SnapshotFormat.Jpeg:
                                    key += ".jpg";
                                    break;

                                case SnapshotFormat.Png:
                                default:
                                    key += ".png";
                                    break;
                                }

                                try
                                {
                                    var db = Redis.GetDatabase();
                                    db.StringSet(key, snapshot, TimeSpan.FromHours(2));

                                    if (SnapshotRequest.Metadata != null)
                                    {
                                        var metadataKey = $"Eye_Snapshot_Metadata_{now}";
                                        db.StringSet(metadataKey, JsonSerializer.Serialize(SnapshotRequest.Metadata), TimeSpan.FromHours(2));
                                    }

                                    NexusConnection?.SendAsync("EyeReport", "Snapshot", new object[] { key, width, height });
                                }
                                catch (RedisException ex)
                                {
                                    _logger.LogError(ex, $"Unable to store snapshot in redis. {ex.Message}");
                                }

                                // We've taken a snapshot, clear the request.
                                SnapshotRequest = null;
                            }
                        }
                    }

                    if (AlignRequest != null)
                    {
                        lock (_alignLock)
                        {
                            if (AlignRequest != null)
                            {
                                var pixelSize = 2;
                                if (AlignRequest.PixelSIze.HasValue && AlignRequest.PixelSIze.Value > 0)
                                {
                                    pixelSize = AlignRequest.PixelSIze.Value;
                                }

                                var map = desktopFrame.GenerateAlignmentMap(pixelSize);

                                try
                                {
                                    var db = Redis.GetDatabase();
                                    db.StringSet(AlignmentMapKey, JsonSerializer.Serialize(map));

                                    NexusConnection?.SendAsync("EyeReport", "AlignmentMapUpdated", new object[] { AlignmentMapKey });
                                }
                                catch (RedisException ex)
                                {
                                    _logger.LogError(ex, $"Unable to store alignment maP in redis. {ex.Message}");
                                }


                                AlignRequest = null;
                            }
                        }
                    }

                    foreach (var region in observerInfo.Regions)
                    {
                        switch (region.Kind)
                        {
                        case ObservationRegionKind.MatrixFrame:
                            if (region.MatrixSettings == null)
                            {
                                //TODO: some sort of logging that won't generate a bunch of redundant data?
                                continue;
                            }

                            if (region.MatrixSettings.Map == null)
                            {
                                try
                                {
                                    var db = Redis.GetDatabase();
                                    var json = db.StringGet(AlignmentMapKey);
                                    if (json.HasValue)
                                    {
                                        region.MatrixSettings.Map = JsonSerializer.Deserialize <IList <int> >(json);
                                    }
                                }
                                catch (RedisException)
                                {
                                    // Do Nothing
                                }
                            }

                            if (region.MatrixSettings.DataFormat == null)
                            {
                                region.MatrixSettings.DataFormat = DataMatrixFormat.MatrixEvents;
                            }

                            var matrixFrame = desktopFrame.DecodeMatrixFrame(region.MatrixSettings);
                            if (matrixFrame != null && lastMatrixFrameIdSent != matrixFrame.FrameId)
                            {
                                NexusConnection?.SendAsync("EyeReport", "MatrixFrame", new object[] { matrixFrame });
                                lastMatrixFrameIdSent = matrixFrame.FrameId;
                            }

                            break;

                        case ObservationRegionKind.Image:
                        default:
                            break;
                        }
                    }
                }
                ;

                _logger.LogInformation("The Beholder has focused its attention elsewhere.");
            }, token, TaskCreationOptions.None, TaskScheduler.Default));
        }