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}" }); } }
public ApiGatewayClient() { _apiClient = new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig { ServiceURL = $"https://{Environment.GetEnvironmentVariable("ws_id")}.execute-api.ap-southeast-2.amazonaws.com/{Environment.GetEnvironmentVariable("environment")}" }); }
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 }); }
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(); } } }
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") }); }
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); }
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)); }
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(); }
// 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); }
// 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)); }); }
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}" }); } }
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}" }); } }
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" } }, }); }
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}" }); } }
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." }); }