public async Task <APIGatewayProxyResponse> Broadcast(APIGatewayProxyRequest request, ILambdaContext context)
        {
            LambdaLogger.Log(JObject.FromObject(request).ToString());
            try
            {
                var domainName = request.RequestContext.DomainName;
                var stage      = request.RequestContext.Stage;
                var endpoint   = $"https://{domainName}/{stage}";
                LambdaLogger.Log("API Gateway management endpoint:" + endpoint);
                var message      = JsonConvert.DeserializeObject <JObject>(request.Body);
                var data         = message["data"]?.ToString();
                var stream       = new MemoryStream(UTF8Encoding.UTF8.GetBytes(data));
                var scanResponse = await wsdm.scanAllSubcribers();

                var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                {
                    ServiceURL = endpoint
                });

                return(await _broadcast(scanResponse, apiClient, stream));
            }
            catch (Exception e)
            {
                LambdaLogger.Log("Error disconnecting: " + e.Message);
                LambdaLogger.Log(e.StackTrace);
                return(new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"Failed to send message: {e.Message}"
                });
            }
        }
Esempio n. 2
0
 public ApiGatewayClient()
 {
     _apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
     {
         ServiceURL = $"https://{Environment.GetEnvironmentVariable("ws_id")}.execute-api.ap-southeast-2.amazonaws.com/{Environment.GetEnvironmentVariable("environment")}"
     });
 }
Esempio n. 3
0
        internal static Task SendMessage(string apiUrl, string connectionId, string room, JObject message)
        {
            Task result = Task.Run(() => {
                MemoryStream stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(message.ToString(Newtonsoft.Json.Formatting.None)));
                AmazonApiGatewayManagementApiConfig config = new AmazonApiGatewayManagementApiConfig()
                {
                    ServiceURL = apiUrl
                };
                AmazonApiGatewayManagementApiClient client = new AmazonApiGatewayManagementApiClient(config);
                PostToConnectionRequest postReq            = new PostToConnectionRequest()
                {
                    ConnectionId = connectionId, Data = stream
                };
                try
                {
                    Logging.LogDebug("Sending to: " + connectionId);
                    Task <PostToConnectionResponse> task = client.PostToConnectionAsync(postReq);
                    task.Wait();
                    Logging.LogDebug("Sent to: " + connectionId);
                }
                catch (Exception ex)
                {
                    Logging.LogDebug("Deleteing conneciton " + connectionId);
                    error = apiUrl + " - " + connectionId + " - " + ex.ToString();
                    Connection.Delete(apiUrl, room, connectionId);
                    Logging.LogDebug("Deleted conneciton " + connectionId);
                }
            });

            return(result);
        }
        public APIGatewayProxyResponse Message(APIGatewayProxyRequest request)
        {
            Console.WriteLine("ConnectionId: " + request.RequestContext.ConnectionId);
            Request finalRequest = JsonConvert.DeserializeObject <Request>(request.Body);

            Asset    asset    = new Asset();
            Document document = asset.getItem(finalRequest.ContractId);
            AmazonApiGatewayManagementApiClient client = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig()
            {
                ServiceURL = "https://" + request.RequestContext.DomainName + "/" + request.RequestContext.Stage
            });

            MemoryStream            stream      = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(document)));
            PostToConnectionRequest postRequest = new PostToConnectionRequest()
            {
                ConnectionId = request.RequestContext.ConnectionId,
                Data         = stream
            };

            var result = client.PostToConnectionAsync(postRequest);

            result.Wait();

            return(new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK
            });
        }
Esempio n. 5
0
        public void ProcessDynamoEvent(DynamoDBEvent dynamoDBEvent, ILambdaContext context)
        {
            AmazonApiGatewayManagementApiClient client = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig()
            {
                ServiceURL = "https://g49fepw5h8.execute-api.us-west-2.amazonaws.com/Test"
            });

            AmazonDynamoDBClient amazonDynamoDbClient = new AmazonDynamoDBClient();

            Console.WriteLine("Voy a empezar");
            Console.WriteLine(dynamoDBEvent.Records);

            foreach (var dynamoRecord in dynamoDBEvent.Records)
            {
                MemoryStream stream      = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(dynamoRecord.Dynamodb.NewImage)));
                String[]     connections = GetConnections(amazonDynamoDbClient, dynamoRecord.Dynamodb.NewImage);
                foreach (string connection in connections)
                {
                    PostToConnectionRequest postRequest = new PostToConnectionRequest()
                    {
                        ConnectionId = connection,
                        Data         = stream
                    };

                    var result = client.PostToConnectionAsync(postRequest);
                    result.Wait();
                }
            }
        }
Esempio n. 6
0
        private async Task <APIGatewayProxyResponse> _broadcast(ScanResponse list, AmazonApiGatewayManagementApiClient apiClient, MemoryStream stream, ILambdaContext context)
        {
            var count = 0;

            foreach (var item in list.Items)
            {
                var connectionId = item[Constants.ConnectionIdField].S;

                var postConnectionRequest = new PostToConnectionRequest
                {
                    ConnectionId = connectionId,
                    Data         = stream
                };

                try
                {
                    LambdaLogger.Log($"Post to connection {count}: {connectionId}");
                    stream.Position = 0;
                    await apiClient.PostToConnectionAsync(postConnectionRequest);

                    count++;
                }
                catch (AmazonServiceException e)
                {
                    // API Gateway returns a status of 410 GONE when the connection is no
                    // longer available. If this happens, we simply delete the identifier
                    // from our DynamoDB table.
                    if (e.StatusCode == HttpStatusCode.Gone)
                    {
                        var ddbDeleteRequest = new DeleteItemRequest
                        {
                            TableName = Constants.WEBSOCKET_TABLE,
                            Key       = new Dictionary <string, AttributeValue>
                            {
                                { Constants.ConnectionIdField, new AttributeValue {
                                      S = connectionId
                                  } }
                            }
                        };

                        context.Logger.LogLine($"Deleting gone connection: {connectionId}");
                        await _ddbClient.DeleteItemAsync(ddbDeleteRequest);
                    }
                    else
                    {
                        context.Logger.LogLine($"Error posting message to {connectionId}: {e.Message}");
                        context.Logger.LogLine(e.StackTrace);
                    }
                }
            }

            return(new APIGatewayProxyResponse
            {
                StatusCode = 200,
                Body = "Data send to " + count + " connection" + (count == 1 ? "" : "s")
            });
        }
Esempio n. 7
0
        protected IAmazonApiGatewayManagementApi CreateClient(AWSCredentials credentials, RegionEndpoint region)
        {
            var config = new AmazonApiGatewayManagementApiConfig {
                RegionEndpoint = region
            };

            Amazon.PowerShell.Utils.Common.PopulateConfig(this, config);
            this.CustomizeClientConfig(config);
            var client = new AmazonApiGatewayManagementApiClient(credentials, config);

            client.BeforeRequestEvent += RequestEventHandler;
            client.AfterResponseEvent += ResponseEventHandler;
            return(client);
        }
Esempio n. 8
0
        public async Task <APIGatewayProxyResponse> Publication(APIGatewayProxyRequest request, ILambdaContext context)
        {
            try
            {
                context.Logger.LogLine($"request : {JObject.FromObject(request).ToString()}");

                var publicationId = request.Headers["PublicationId"];
                context.Logger.LogLine($"publicationId : {publicationId}");

                var scanRequest = new ScanRequest
                {
                    TableName = Constants.WEBSOCKET_TABLE,
                    ReturnConsumedCapacity   = "TOTAL",
                    ProjectionExpression     = "connectionId,#pubId",
                    ExpressionAttributeNames = new Dictionary <string, string> {
                        { "#pubId", "publicationId" }
                    },
                    ExpressionAttributeValues = new Dictionary <string, AttributeValue> {
                        { ":v_publicationId", new AttributeValue {
                              S = publicationId
                          } }
                    },
                    FilterExpression = "#pubId = :v_publicationId",
                };

                var scanResponse = await _ddbClient.ScanAsync(scanRequest);

                var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                {
                    ServiceURL = Environment.GetEnvironmentVariable("WSGateway")
                });
                var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(request.Body));

                return(await _broadcast(scanResponse, apiClient, stream, context));
            }
            catch (Exception e)
            {
                context.Logger.LogLine("Error disconnecting: " + e.Message);
                context.Logger.LogLine(e.StackTrace);
                return(new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"Failed to publication: {e.Message}"
                });
            }
        }
        public async Task <APIGatewayProxyResponse> StreamReceiver(DynamoDBEvent dynamoEvent, ILambdaContext context)
        {
            var scanResponse = await wsdm.scanAllSubcribers();

            var appVersion = await _getApplicationVersion(dynamoEvent);

            var appVersionS = JObject.FromObject(appVersion).ToString();

            LambdaLogger.Log("App version: " + appVersionS);
            var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(appVersionS));

            var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
            {
                ServiceURL = "https://poun74c64b.execute-api.us-east-1.amazonaws.com/dev"
            });

            return(await _broadcast(scanResponse, apiClient, stream));
        }
Esempio n. 10
0
        internal static void SendCatchup(string serviceUrl, string connectionId, string room, JArray messages)
        {
            JObject message = new JObject()
            {
                { "action", "catchup" }, { "room", room }, { "messages", messages }
            };
            MemoryStream stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(message.ToString(Newtonsoft.Json.Formatting.None)));
            AmazonApiGatewayManagementApiConfig config = new AmazonApiGatewayManagementApiConfig()
            {
                ServiceURL = serviceUrl
            };
            AmazonApiGatewayManagementApiClient client  = new AmazonApiGatewayManagementApiClient(config);
            PostToConnectionRequest             postReq = new PostToConnectionRequest()
            {
                ConnectionId = connectionId, Data = stream
            };

            client.PostToConnectionAsync(postReq);
        }
        public static void SendPosition(ProxyRequestContext context, string contractId)
        {
            Asset    asset    = new Asset();
            Document document = asset.getItem(contractId);
            AmazonApiGatewayManagementApiClient client = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig()
            {
                ServiceURL = "https://" + context.DomainName + "/" + context.Stage
            });

            MemoryStream            stream      = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(document)));
            PostToConnectionRequest postRequest = new PostToConnectionRequest()
            {
                ConnectionId = context.ConnectionId,
                Data         = stream
            };

            var result = client.PostToConnectionAsync(postRequest);

            result.Wait();
        }
Esempio n. 12
0
        // public static IServiceCollection AddDeveloperAwsOptions(this IServiceCollection services, IConfiguration config)
        // {
        //     var options = config.GetAWSOptions();

        //     string accessKey = config.GetSection("AWS").GetValue<string>("AccessKey");
        //     string accessSecret = config.GetSection("AWS").GetValue<string>("SecretKey");
        //     if (accessKey != null && accessSecret != null)
        //     {
        //         options.Credentials = new Amazon.Runtime.BasicAWSCredentials(accessKey, accessSecret);
        //     }

        //     services.AddDefaultAWSOptions(options);

        //     return services;
        // }

        // public static IServiceCollection AddDynamoDBWithDeveloperOptions(this IServiceCollection services, IConfiguration config)
        // {
        //     var dynamoDbConfig = config.GetSection("DynamoDb");
        //     var runLocalDynamoDb = dynamoDbConfig.GetValue<bool>("LocalMode");

        //     if (runLocalDynamoDb)
        //     {
        //         services.AddSingleton<IAmazonDynamoDB>(sp =>
        //         {
        //             var clientConfig = new AmazonDynamoDBConfig { ServiceURL = dynamoDbConfig.GetValue<string>("LocalServiceUrl") };
        //             return new AmazonDynamoDBClient(clientConfig);
        //         });
        //     }
        //     else
        //     {
        //         services.AddAWSService<IAmazonDynamoDB>();
        //     }

        //     return services;
        // }

        public static IServiceCollection AddAWSWebsockets(this IServiceCollection services)
        {
            services
            .AddHttpContextAccessor()
            .AddAWSService <IAmazonDynamoDB>();

            services.AddScoped <IAmazonApiGatewayManagementApi>(c =>
            {
                var request         = c.GetRequiredService <IHttpContextAccessor>().HttpContext.Items["LambdaRequestObject"] as APIGatewayProxyRequest;
                var config          = c.GetRequiredService <IConfiguration>();
                var websocketApiUrl = config["websocketapi"];
                var client          = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig()
                {
                    ServiceURL = websocketApiUrl
                                 //$"https://{request.RequestContext.DomainName}/{request.RequestContext.Stage}"
                });
                return(client);
            });
            services.AddScoped <IDynamoDBContext>(c =>
            {
                var context = new DynamoDBContext(c.GetRequiredService <IAmazonDynamoDB>());


                return(context);
            });

            services
            .AddScoped <IHubClients, AWSHubCallerClients>()
            .AddScoped <IGroupManager, AWSSocketGroupManager>()
            .AddScoped <IAWSSocketConnectionStore <SocketConnection>, DynamoDbSocketConnectionStore>()
            .AddScoped <IAWSSocketManager, AWSSocketManager>()
            .AddTransient <HubCallerContext, AWSHubCallerContext>();


            return(services);
        }
Esempio n. 13
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var awsOptions = CreateAWSOptions();

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "WebApiTest", Version = "v1"
                });
            });

            services.AddDefaultAWSOptions(awsOptions);
            services.AddAWSService <IAmazonSecretsManager>();
            services.AddAWSService <IAmazonDynamoDB>();
            services.AddAWSService <IAmazonComprehend>();
            services.AddAWSService <IAmazonCloudWatch>();
            services.AddAWSService <IAmazonKinesisFirehose>();
            services.AddAWSService <IAmazonCognitoIdentityProvider>();
            services.AddAWSService <IAmazonServiceDiscovery>();
            services.AddAWSService <IAmazonAthena>();
            services.AddAWSService <IAmazonSQS>();
            services.AddSingleton <ISentimentReporter>((svc) =>
            {
                var athena    = svc.GetRequiredService <IAmazonAthena>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                var logger    = svc.GetRequiredService <ILogger <AthenaSentimentReporter> >();
                return(new AthenaSentimentReporter(athena, "chatlogs", "data", resources.Analytics, logger));
            });
            services.AddSingleton <IMetricsFactory>((svc) =>
            {
                var cloudwatch         = svc.GetRequiredService <IAmazonCloudWatch>();
                string metricNamespace = "HoratioBot";
                return(new CloudWatchMetricsFactory(cloudwatch, metricNamespace));
            });
            services.AddSingleton <IResourceDiscoverer>((svc) =>
            {
                string serviceId = Environment.GetEnvironmentVariable("SERVICE_DISCOVERY_ID") ?? "srv-rby7ki3kzcsqk4vp";
                var discovery    = svc.GetRequiredService <IAmazonServiceDiscovery>();
                return(new CloudMapResourceDiscoverer(discovery, serviceId));
            });
            services.AddSingleton <ISocketSessionStorage>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                return(new DynamoSocketSessionStorage(ddb, resources.Storage.SocketSessionsTable));
            });
            services.AddSingleton <IAlertBroadcaster>((svc) =>
            {
                var resources      = svc.GetRequiredService <IResourceDiscoverer>();
                var sessionStorage = svc.GetRequiredService <ISocketSessionStorage>();
                var logger         = svc.GetRequiredService <ILogger <ApiGatewayWebsocketAlertBroadcaster> >();
                var client         = new AmazonApiGatewayManagementApiClient(awsOptions.Credentials,
                                                                             new AmazonApiGatewayManagementApiConfig()
                {
                    RegionEndpoint = awsOptions.Region,
                    ServiceURL     =
                        $"https://api-ws.95horatio.johndavis.dev",
                    AuthenticationRegion = "us-east-2"
                });
                return(new ApiGatewayWebsocketAlertBroadcaster(client, sessionStorage, logger));
            });
            services.AddSingleton <IPaginationTokensStorage>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                return(new DynamoPaginationTokensStorage(ddb, resources.Storage.PaginationTokensTable));
            });
            services.AddSingleton <ILinkRequestsStorageManager>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();
                return(new DynamoLinkRequestsStorageManager(ddb, resources.Storage.LinkRequestsTable));
            });
            services.AddSingleton <IUserIdsStorageManager>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                return(new DynamoUserIdsStorageManager(ddb, resources.Storage.UserIdsTable));
            });
            services.AddSingleton <IChatMessageStorage>((svc) =>
            {
                var paginationStorage = svc.GetRequiredService <IPaginationTokensStorage>();
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                return(new DynamoChatMessageStorage(paginationStorage, ddb, resources.Storage.ChatMessagesTable));
            });
            services.AddSingleton <ISentimentSnapshotsStorage>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();;
                return(new DynamoSentimentSnapshotsStorage(ddb, resources.Storage.SentimentSnapshotTable));
            });
            services.AddSingleton <IMessageArchiver>((svc) =>
            {
                var kinesis                   = svc.GetRequiredService <IAmazonKinesisFirehose>();
                var comprehend                = svc.GetRequiredService <IAmazonComprehend>();
                var chatMessageStorage        = svc.GetRequiredService <IChatMessageStorage>();
                var userIdsStorage            = svc.GetRequiredService <IUserIdsStorageManager>();
                var sentimentSnapshotsStorage = svc.GetRequiredService <ISentimentSnapshotsStorage>();
                var logger      = svc.GetRequiredService <ILogger <KinesisMessageArchiver> >();
                var resources   = svc.GetRequiredService <IResourceDiscoverer>();
                var broadcaster = svc.GetRequiredService <IAlertBroadcaster>();
                return(new KinesisMessageArchiver(
                           kinesis,
                           comprehend,
                           chatMessageStorage,
                           userIdsStorage,
                           sentimentSnapshotsStorage,
                           broadcaster,
                           logger,
                           resources.Analytics.ChatStreamName));
            });
            services.AddSingleton <IKudosStorageManager>((svc) =>
            {
                var ddb       = svc.GetRequiredService <IAmazonDynamoDB>();
                var logger    = svc.GetRequiredService <ILogger <DynamoKudosStorageManager> >();
                var resources = svc.GetRequiredService <IResourceDiscoverer>();
                return(new DynamoKudosStorageManager(ddb, resources.Storage.KudosTable, logger));
            });
            services.AddSingleton <IUsersClient>((svc) =>
            {
                var cognito        = svc.GetRequiredService <IAmazonCognitoIdentityProvider>();
                var userIdsStorage = svc.GetRequiredService <IUserIdsStorageManager>();
                var resources      = svc.GetRequiredService <IResourceDiscoverer>();
                return(new CognitoUsersClient(cognito, userIdsStorage, resources.Auth.UserPoolId));
            });
            services.AddSingleton <ISentimentAnalysisClient, ComprehendSentimentAnalysisClient>();
            services.AddSingleton <KudosCommandHandler>((svc) =>
            {
                var storage         = svc.GetRequiredService <IKudosStorageManager>();
                var sentimentClient = svc.GetRequiredService <ISentimentAnalysisClient>();
                var logger          = svc.GetRequiredService <ILogger <KudosCommandHandler> >();
                ulong serverId      = 799375962998833152;
                ulong channelId     = 799395846915489822;
                return(new KudosCommandHandler(storage, sentimentClient, serverId, channelId, logger));
            });
            services.AddSingleton <TwitchLinkCommandHandler>();
            services.AddSingleton <DiscordSocketClient>();
            services.AddSingleton <IEnumerable <IDiscordCommandHandler> >((svc) =>
            {
                var kudosHandler = svc.GetRequiredService <KudosCommandHandler>();
                var linkHandler  = svc.GetRequiredService <TwitchLinkCommandHandler>();
                return(new IDiscordCommandHandler[]
                {
                    kudosHandler,
                    linkHandler,
                });
            });
            services.AddSingleton <IEnumerable <ITwitchCommandHandler> >((svc) =>
            {
                var kudosHandler = svc.GetRequiredService <TwitchLinkCommandHandler>();
                return(new[]
                {
                    kudosHandler
                });
            });
            services.AddSingleton <IDiscordCredentialProvider>((svc) =>
            {
                var client        = svc.GetRequiredService <IAmazonSecretsManager>();
                string secretName = "prod/web/Discord";
                var logger        = svc.GetRequiredService <ILogger <SecretManagerDiscordCredentialProvider> >();
                return(new SecretManagerDiscordCredentialProvider(
                           client,
                           secretName,
                           logger));
            });
            services.AddSingleton <ITwitchCredentialsProvider>((svc) =>
            {
                var client        = svc.GetRequiredService <IAmazonSecretsManager>();
                string secretName = "prod/web/Twitch";
                var logger        = svc.GetRequiredService <ILogger <SecretManagerTwitchCredentialProvider> >();
                return(new SecretManagerTwitchCredentialProvider(
                           client,
                           secretName,
                           logger));
            });
            services.AddHostedService <TwitchBotWorker>();
            services.AddHostedService <DiscordBotWorker>();
            services.AddHostedService <SentimentReportGenerator>((svc) =>
            {
                var sqs             = svc.GetRequiredService <IAmazonSQS>();
                var resources       = svc.GetRequiredService <IResourceDiscoverer>();
                var reporter        = svc.GetRequiredService <ISentimentReporter>();
                var userIdsStorage  = svc.GetRequiredService <IUserIdsStorageManager>();
                var snapshotStorage = svc.GetRequiredService <ISentimentSnapshotsStorage>();
                var logger          = svc.GetRequiredService <ILogger <SentimentReportGenerator> >();
                return(new SentimentReportGenerator(sqs, reporter, resources.Analytics,
                                                    userIdsStorage, snapshotStorage, logger));
            });
        }
Esempio n. 14
0
        public async Task <APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
        {
            LambdaLogger.Log(JObject.FromObject(request).ToString());

            try
            {
                var domainName = request.RequestContext.DomainName;
                var stage      = request.RequestContext.Stage;
                var endpoint   = $"https://{domainName}/{stage}";
                LambdaLogger.Log("API Gateway management endpoint:" + endpoint);

                var message = JsonConvert.DeserializeObject <JObject>(request.Body);
                var data    = message["data"]?.ToString();

                var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(data));

                var scanRequest = new ScanRequest
                {
                    TableName            = Environment.GetEnvironmentVariable("DynamoChatTable"),
                    ProjectionExpression = "ConnectionId"
                };

                var scanResponse = await ddbClient.ScanAsync(scanRequest);

                var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                {
                    ServiceURL = endpoint
                });

                var count = 0;
                foreach (var item in scanResponse.Items)
                {
                    var connectionId = item["ConnectionId"].S;


                    var postConnectionRequest = new PostToConnectionRequest
                    {
                        ConnectionId = connectionId,
                        Data         = stream
                    };

                    try
                    {
                        context.Logger.LogLine($"Post to connection {count}: {connectionId}");
                        stream.Position = 0;
                        await apiClient.PostToConnectionAsync(postConnectionRequest);

                        count++;
                    }
                    catch (AmazonServiceException e)
                    {
                        // API Gateway returns a status of 410 GONE when the connection is no
                        // longer available. If this happens, we simply delete the identifier
                        // from our DynamoDB table.
                        if (e.StatusCode == HttpStatusCode.Gone)
                        {
                            var ddbDeleteRequest = new DeleteItemRequest
                            {
                                TableName = Environment.GetEnvironmentVariable("DynamoChatTable"),
                                Key       = new Dictionary <string, AttributeValue>
                                {
                                    { "ConnectionId", new AttributeValue {
                                          S = connectionId
                                      } }
                                }
                            };

                            context.Logger.LogLine($"Deleting gone connection: {connectionId}");
                            await ddbClient.DeleteItemAsync(ddbDeleteRequest);
                        }
                        else
                        {
                            context.Logger.LogLine($"Error posting message to {connectionId}: {e.Message}");
                            context.Logger.LogLine(e.StackTrace);
                        }
                    }
                }

                return(new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = "Data send to " + count + " connection" + (count == 1 ? "" : "s")
                });
            }
            catch (Exception e)
            {
                LambdaLogger.Log("Error disconnecting: " + e.Message);
                LambdaLogger.Log(e.StackTrace);
                return(new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"Failed to send message: {e.Message}"
                });
            }
        }
Esempio n. 15
0
        public async Task <APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
        {
            try
            {
                var domainName = request.RequestContext.DomainName;
                var stage      = request.RequestContext.Stage;
                var endpoint   = $"https://{domainName}/{stage}";
                context.Logger.LogLine($"API Gateway management endpoint: {endpoint}");

                var message = JsonConvert.DeserializeObject <JObject>(request.Body);
                var data    = message["data"]?.ToString();

                var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(data));

                var scanRequest = new ScanRequest
                {
                    TableName            = Constants.TABLE_NAME,
                    ProjectionExpression = Constants.ConnectionIdField
                };

                var scanResponse = await _ddbClient.ScanAsync(scanRequest);

                var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                {
                    ServiceURL = endpoint
                });

                var count = 0;
                foreach (var item in scanResponse.Items)
                {
                    var connectionId = item[Constants.ConnectionIdField].S;

                    var postConnectionRequest = new PostToConnectionRequest
                    {
                        ConnectionId = connectionId,
                        Data         = stream
                    };

                    try
                    {
                        context.Logger.LogLine($"Post to connection {count}: {connectionId}");
                        stream.Position = 0;
                        await apiClient.PostToConnectionAsync(postConnectionRequest);

                        count++;
                    }
                    catch (AmazonServiceException e)
                    {
                        if (e.StatusCode == HttpStatusCode.Gone)
                        {
                            var ddbDeleteRequest = new DeleteItemRequest
                            {
                                TableName = Constants.TABLE_NAME,
                                Key       = new Dictionary <string, AttributeValue>
                                {
                                    { Constants.ConnectionIdField, new AttributeValue {
                                          S = connectionId
                                      } }
                                }
                            };

                            context.Logger.LogLine($"Deleting gone connection: {connectionId}");
                            await _ddbClient.DeleteItemAsync(ddbDeleteRequest);
                        }
                        else
                        {
                            context.Logger.LogLine($"Error posting message to {connectionId}: {e.Message}");
                            context.Logger.LogLine(e.StackTrace);
                        }
                    }
                }

                return(new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = "Data send to " + count + " connection" + (count == 1 ? "" : "s")
                });
            }
            catch (Exception e)
            {
                context.Logger.LogLine("Error disconnecting: " + e.Message);
                context.Logger.LogLine(e.StackTrace);
                return(new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"Failed to send message: {e.Message}"
                });
            }
        }
Esempio n. 16
0
        public async Task <APIGatewayProxyResponse> Handler(APIGatewayProxyRequest input, ILambdaContext context)
        {
            var client = new AmazonDynamoDBClient();

            var scanRequest = new ScanRequest
            {
                TableName            = Environment.ExpandEnvironmentVariables("%TABLE_NAME%"),
                ProjectionExpression = "connectionId"
            };

            ScanResponse connections = null;

            try
            {
                connections = await client.ScanAsync(scanRequest);
            }
            catch (Exception e)
            {
                return(new APIGatewayProxyResponse
                {
                    StatusCode = (int)HttpStatusCode.InternalServerError,
                    Body = e.Message,
                    Headers = new Dictionary <string, string> {
                        { "Content-Type", "text/plain" }
                    },
                });
            }

            var data      = JObject.Parse(input.Body)["data"].ToString();
            var byteArray = Encoding.UTF8.GetBytes(data);

            var config = new AmazonApiGatewayManagementApiConfig
            {
                ServiceURL = $"https://{input.RequestContext.DomainName}/{input.RequestContext.Stage}"
            };

            var apiClient = new AmazonApiGatewayManagementApiClient(config);

            var connectionIds = connections.Items.Select(item => item["connectionId"].S).ToList();

            foreach (var connectionId in connectionIds)
            {
                var postData = new MemoryStream(byteArray);

                try
                {
                    var postToRequest = new PostToConnectionRequest
                    {
                        ConnectionId = connectionId,
                        Data         = postData
                    };

                    await apiClient.PostToConnectionAsync(postToRequest);
                }
                catch (GoneException)
                {
                    Console.WriteLine($"Found dead connection, deleting {connectionId}");

                    var attributes = new Dictionary <string, AttributeValue>();

                    attributes["connectionId"] = new AttributeValue {
                        S = connectionId
                    };

                    var deleteRequest = new DeleteItemRequest
                    {
                        TableName = Environment.ExpandEnvironmentVariables("%TABLE_NAME%"),
                        Key       = attributes
                    };

                    try
                    {
                        await client.DeleteItemAsync(deleteRequest);
                    }
                    catch (Exception e)
                    {
                        return(new APIGatewayProxyResponse
                        {
                            StatusCode = (int)HttpStatusCode.InternalServerError,
                            Body = e.Message,
                            Headers = new Dictionary <string, string> {
                                { "Content-Type", "text/plain" }
                            },
                        });
                    }
                }
                catch (Exception e)
                {
                    return(new APIGatewayProxyResponse
                    {
                        StatusCode = (int)HttpStatusCode.InternalServerError,
                        Body = e.Message,
                        Headers = new Dictionary <string, string> {
                            { "Content-Type", "text/plain" }
                        },
                    });
                }
            }

            return(new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = "data sent",
                Headers = new Dictionary <string, string> {
                    { "Content-Type", "text/plain" }
                },
            });
        }
Esempio n. 17
0
        public async Task <APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
        {
            try
            {
                var domainName = request.RequestContext.DomainName;
                var stage      = request.RequestContext.Stage;
                var endpoint   = $"https://{domainName}/{stage}";
                context.Logger.LogLine($"API Gateway management endpoint: {endpoint}");

                var message       = JsonConvert.DeserializeObject <JObject>(request.Body);
                var data          = message["data"]?.ToString();
                var connection_id = message["connection_id"]?.ToString();
                var channel       = message["channel"]?.ToString();

                var stream = new MemoryStream(Encoding.UTF8.GetBytes(data));

                var apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                {
                    ServiceURL = endpoint
                });

                bool post_multiple = false;
                bool post_single   = false;
                List <ConnectionSocketModel> list_connections = new List <ConnectionSocketModel>();
                ConnectionSocketModel        connection       = new ConnectionSocketModel();

                if (CheckJObjectKeyValue(connection_id) == false && CheckJObjectKeyValue(channel) == false)
                {
                    context.Logger.LogLine($"Not have connection_id and channel");
                    list_connections = await _connectionService.ListConnection();

                    post_multiple = true;
                }
                else if (CheckJObjectKeyValue(connection_id) && CheckJObjectKeyValue(channel))
                {
                    context.Logger.LogLine($"Have connection_id as: {connection_id}, and channel as: {channel}");
                    connection = await _connectionService.SendToConnectionChannel(connection_id, channel);

                    post_single = true;
                }
                else if (CheckJObjectKeyValue(channel) && CheckJObjectKeyValue(connection_id) == false)
                {
                    context.Logger.LogLine($"Have only channel as: {channel}");
                    list_connections = await _connectionService.ListConnectionInChannel(channel);

                    post_multiple = true;
                }
                else if (CheckJObjectKeyValue(connection_id) && CheckJObjectKeyValue(channel) == false)
                {
                    context.Logger.LogLine($"Have only connection_id as: {connection_id}");
                    connection = await _connectionService.SendToConnection(connection_id);

                    post_single = true;
                }

                if (post_single)
                {
                    if (connection != null)
                    {
                        context.Logger.LogLine($"Post to single connection {connection.connection_id}");
                        await PostToConnection(connection, stream, _connectionService, apiClient, context);
                    }
                }

                if (post_multiple)
                {
                    if (list_connections.Any())
                    {
                        foreach (var connection_item in list_connections)
                        {
                            context.Logger.LogLine($"Post to multiple connection {connection_item.connection_id}");
                            await PostToConnection(connection_item, stream, _connectionService, apiClient, context);
                        }
                    }
                }

                return(new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = "Data sent"
                });
            }
            catch (Exception e)
            {
                context.Logger.LogLine("Error disconnecting: " + e.Message);
                context.Logger.LogLine(e.StackTrace);
                return(new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = $"Failed to send message: {e.Message}"
                });
            }
        }
Esempio n. 18
0
        public async Task PostToConnection(ConnectionSocketModel connection, MemoryStream stream, ConnectionSocketService connectionService, AmazonApiGatewayManagementApiClient apiClient, ILambdaContext context)
        {
            var connectionId = connection.connection_id;

            context.Logger.LogLine($"Get Connection ID from DB: {connectionId}");

            var postConnectionRequest = new PostToConnectionRequest
            {
                ConnectionId = connectionId,
                Data         = stream
            };

            try
            {
                context.Logger.LogLine($"Post to connection: {connectionId}");
                stream.Position = 0;
                await apiClient.PostToConnectionAsync(postConnectionRequest);
            }
            catch (AmazonServiceException e)
            {
                if (e.StatusCode == HttpStatusCode.Gone)
                {
                    connectionService.GetConnection(connectionId);
                    context.Logger.LogLine($"Deleting gone connection: {connectionId}");
                }
                else
                {
                    context.Logger.LogLine($"Error posting message to {connectionId}: {e.Message}");
                    context.Logger.LogLine(e.StackTrace);
                }
            }
        }
        public async Task SendMessage(MessageEvent evnt)
        {
            if (string.IsNullOrEmpty(_ddbTableName))
            {
                return;
            }

            var payload = JsonConvert.SerializeObject(evnt);
            var stream  = new MemoryStream(Encoding.UTF8.GetBytes(payload));


            QueryResponse queryResponse;

            if (!_connectionsCache.TryGetValue(evnt.TargetUser, out ICacheEntry entry) ||
                entry.AbsoluteExpiration < DateTime.UtcNow)
            {
                var queryRequest = new QueryRequest
                {
                    TableName = _ddbTableName,
                    IndexName = "username",
                    KeyConditionExpression    = $"{UsernameField} = :u",
                    ExpressionAttributeValues = new Dictionary <string, AttributeValue>
                    {
                        { ":u", new AttributeValue {
                              S = evnt.TargetUser
                          } }
                    }
                };
                queryResponse = await _ddbClient.QueryAsync(queryRequest);

                entry = _connectionsCache.CreateEntry(evnt.TargetUser);
                entry.AbsoluteExpiration = DateTime.UtcNow.AddSeconds(10);
                entry.SetValue(queryResponse);
                _connectionsCache.Set(evnt.TargetUser, entry);
            }
            else
            {
                queryResponse = entry.Value as QueryResponse;
            }

            AmazonApiGatewayManagementApiClient apiClient = null;

            try
            {
                var goneConnections = new List <Dictionary <string, AttributeValue> >();
                foreach (var item in queryResponse.Items)
                {
                    var endpoint = item[EndpointField].S;

                    if (apiClient == null || !apiClient.Config.ServiceURL.Equals(endpoint, StringComparison.Ordinal))
                    {
                        if (apiClient != null)
                        {
                            apiClient.Dispose();
                            apiClient = null;
                        }

                        apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
                        {
                            ServiceURL = endpoint
                        });
                    }

                    var connectionId = item[ConnectionIdField].S;

                    stream.Position = 0;
                    var postConnectionRequest = new PostToConnectionRequest
                    {
                        ConnectionId = connectionId,
                        Data         = stream
                    };

                    try
                    {
                        await apiClient.PostToConnectionAsync(postConnectionRequest);
                    }
                    catch (GoneException)
                    {
                        goneConnections.Add(item);
                    }
                }

                // Remove connections from the cache that have disconnected.
                foreach (var goneConnectionItem in goneConnections)
                {
                    queryResponse.Items.Remove(goneConnectionItem);
                }
            }
            catch
            {
                // Never stop rendering based on communication errors.
            }
            finally
            {
                apiClient?.Dispose();
            }
        }
        private async Task <APIGatewayProxyResponse> _broadcast(List <WSConnection> list, AmazonApiGatewayManagementApiClient client, MemoryStream stream)
        {
            var count = 0;

            foreach (var item in list)
            {
                var connectionId          = item.connectionId;
                var postConnectionRequest = new PostToConnectionRequest
                {
                    ConnectionId = connectionId,
                    Data         = stream
                };

                try
                {
                    LambdaLogger.Log($"Post to connection {count}: {connectionId}");
                    stream.Position = 0;
                    await client.PostToConnectionAsync(postConnectionRequest);

                    count++;
                }
                catch (AmazonServiceException e)
                {
                    LambdaLogger.Log($"Connection had appeared to have a problem! " + e.StatusCode);
                    // API Gateway returns a status of 410 GONE when the connection is no
                    // longer available. If this happens, we simply delete the identifier
                    // from our DynamoDB table.
                    if (e.StatusCode == HttpStatusCode.Gone)
                    {
                        var wsConnection = new WSConnection();
                        wsConnection.connectionId = connectionId;
                        LambdaLogger.Log($"Deleting gone connection: {connectionId}");
                        await wsdm.deleteSubcriber(wsConnection);
                    }
                    else
                    {
                        var wsConnection = new WSConnection();
                        wsConnection.connectionId = connectionId;
                        LambdaLogger.Log($"Deleting invalid connection: {connectionId}");
                        await wsdm.deleteSubcriber(wsConnection);

                        LambdaLogger.Log(e.StackTrace);
                        //LambdaLogger.Log($"Error posting message to {connectionId}: {e.Message}");
                    }
                }
            }

            return(new APIGatewayProxyResponse
            {
                StatusCode = 200,
                Body = "Connected."
            });
        }