public override Task OnConnectedAsync() { Consumer consumerToRegister; string clientConnectionId = Context.ConnectionId; var headers = Context.GetHttpContext().Request.Headers; // authorization tokens // TODO: Implement token validation string tenantToken = headers["x-andyx-tenant-authoriziation"]; string componentToken = headers["x-andyx-component-authoriziation"]; string tenant = headers["x-andyx-tenant"].ToString(); string product = headers["x-andyx-product"].ToString(); string component = headers["x-andyx-component"].ToString(); string topic = headers["x-andyx-topic"].ToString(); bool isPersistent = bool.Parse(headers["x-andyx-topic-is-persistent"]); string consumerName = headers["x-andyx-consumer"].ToString(); SubscriptionType subscriptionType = (SubscriptionType)Enum.Parse(typeof(SubscriptionType), headers["x-andyx-consumer-type"].ToString()); InitialPosition initialPosition = (InitialPosition)Enum.Parse(typeof(InitialPosition), headers["x-andyx-consumer-initial-position"].ToString()); logger.LogInformation($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} requested connection"); // check if the consumer is already connected var connectedTenant = tenantRepository.GetTenant(tenant); if (connectedTenant == null) { logger.LogInformation($"Consumer '{consumerName}' failed to connect, tenant '{tenant}' does not exists"); return(OnDisconnectedAsync(new Exception($"There is no tenant registered with this name '{tenant}'"))); } // check tenant token validation bool isTenantTokenValidated = tenantRepository.ValidateTenantToken(tenant, tenantToken); if (isTenantTokenValidated != true) { logger.LogInformation($"Consumer '{consumerName}' failed to connect, access is forbidden. Not authorized"); return(OnDisconnectedAsync(new Exception($"Consumer '{consumerName}' failed to connect, access is forbidden"))); } var connectedProduct = tenantRepository.GetProduct(tenant, product); if (connectedProduct == null) { if (connectedTenant.Settings.AllowProductCreation != true) { logger.LogInformation($"Consumer '{consumerName}' failed to connect, tenant '{tenant}' does not allow to create new product"); return(OnDisconnectedAsync(new Exception($"There is no product registered with this name '{product}'. Tenant '{tenant}' does not allow to create new product"))); } var productDetails = tenantFactory.CreateProduct(product); tenantRepository.AddProduct(tenant, product, productDetails); storageHubService.CreateProductAsync(tenant, productDetails); } else { storageHubService.UpdateProductAsync(tenant, connectedProduct); } var connectedComponent = tenantRepository.GetComponent(tenant, product, component); if (connectedComponent == null) { var componentDetails = tenantFactory.CreateComponent(component); tenantRepository.AddComponent(tenant, product, component, componentDetails); storageHubService.CreateComponentAsync(tenant, product, componentDetails); } else { // check component token validation bool isComponentTokenValidated = tenantRepository.ValidateComponentToken(tenant, product, component, componentToken, consumerName, true); if (isComponentTokenValidated != true) { logger.LogInformation($"Consumer '{consumerName}' failed to connect, access is forbidden. Not authorized, check component token"); return(OnDisconnectedAsync(new Exception($"Consumer '{consumerName}' failed to connect, access is forbidden, check component token"))); } storageHubService.UpdateComponentAsync(tenant, product, connectedComponent); } var connectedTopic = tenantRepository.GetTopic(tenant, product, component, topic); if (connectedTopic == null) { connectedComponent = tenantRepository.GetComponent(tenant, product, component); if (connectedComponent.Settings.AllowTopicCreation != true) { logger.LogInformation($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component."); return(OnDisconnectedAsync(new Exception($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component."))); } var topicDetails = tenantFactory.CreateTopic(topic, isPersistent); tenantRepository.AddTopic(tenant, product, component, topic, topicDetails); storageHubService.CreateTopicAsync(tenant, product, component, topicDetails); } else { storageHubService.UpdateTopicAsync(tenant, product, component, connectedTopic); } string consumerIdOnRepo = $"{tenant}{product}{component}{topic}|{consumerName}"; var consumerConencted = consumerHubRepository.GetConsumerById(consumerIdOnRepo); if (consumerConencted != null) { if (subscriptionType == SubscriptionType.Exclusive) { logger.LogWarning($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is already connected"); return(OnDisconnectedAsync(new Exception($"There is a consumer with name '{consumerName}' and with type 'EXCLUSIVE' is connected to this node"))); } if (subscriptionType == SubscriptionType.Failover) { if (consumerConencted.Connections.Count >= 2) { logger.LogWarning($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is already connected with 2 instances"); return(OnDisconnectedAsync(new Exception($"There are two consumers with name '{consumerName}' and with type 'Failover' are connected to this node"))); } } } consumerToRegister = consumerFactory.CreateConsumer(tenant, product, component, topic, consumerName, subscriptionType, initialPosition); consumerHubRepository.AddConsumer(consumerIdOnRepo, consumerToRegister); consumerHubRepository.AddConsumerConnection(consumerIdOnRepo, clientConnectionId); storageHubService.ConnectConsumerAsync(consumerToRegister); Clients.Caller.ConsumerConnected(new Model.Consumers.Events.ConsumerConnectedDetails() { Id = consumerToRegister.Id, Tenant = tenant, Product = product, Component = component, Topic = topic, ConsumerName = consumerName, SubscriptionType = subscriptionType, InitialPosition = initialPosition }); // if consumer is not persistent, do not store the message, just allow streaming if (isPersistent == true) { // Sent not acknoledged messages to this consumer (for exclusive and for the first shared/failover consumer connected) if (subscriptionType == SubscriptionType.Exclusive) { storageHubService.RequestUnacknowledgedMessagesConsumer(consumerToRegister); } if (subscriptionType == SubscriptionType.Shared || subscriptionType == SubscriptionType.Failover) { if (consumerConencted == null) { storageHubService.RequestUnacknowledgedMessagesConsumer(consumerToRegister); } } } logger.LogInformation($"Consumer '{consumerName}' and subscription type '{subscriptionType}' at {tenant}/{product}/{component}/{topic} is connected"); return(base.OnConnectedAsync()); }
public bool AddProduct(string tenant, string productName) { return(_tenantRepository .AddProduct(tenant, productName, _tenantFactory.CreateProduct(productName))); }
public override Task OnConnectedAsync() { Producer producerToRegister; string clientConnectionId = Context.ConnectionId; var headers = Context.GetHttpContext().Request.Headers; // authorization tokens // TODO: Implement token validation string tenantToken = headers["x-andyx-tenant-authoriziation"]; string componentToken = headers["x-andyx-component-authoriziation"]; string tenant = headers["x-andyx-tenant"].ToString(); string product = headers["x-andyx-product"].ToString(); string component = headers["x-andyx-component"].ToString(); string topic = headers["x-andyx-topic"].ToString(); bool isPersistent = Boolean.Parse(headers["x-andyx-topic-is-persistent"]); string producerName = headers["x-andyx-producer"].ToString(); logger.LogInformation($"Producer '{producerName}' at {tenant}/{product}/{component}/{topic} requested connection"); //check if the producer is already connected var connectedTenant = tenantRepository.GetTenant(tenant); if (connectedTenant == null) { logger.LogInformation($"Producer '{producerName}' failed to connect, tenant '{tenant}' does not exists"); return(OnDisconnectedAsync(new Exception($"There is no tenant registered with this name '{tenant}'"))); } // check tenant token validation bool isTenantTokenValidated = tenantRepository.ValidateTenantToken(tenant, tenantToken); if (isTenantTokenValidated != true) { logger.LogInformation($"Producer '{producerName}' failed to connect, access is forbidden. Not authorized"); return(OnDisconnectedAsync(new Exception($"Producer '{producerName}' failed to connect, access is forbidden"))); } var connectedProduct = tenantRepository.GetProduct(tenant, product); if (connectedProduct == null) { if (connectedTenant.Settings.AllowProductCreation != true) { logger.LogInformation($"Producer '{producerName}' failed to connect, tenant '{tenant}' does not allow to create new product"); return(OnDisconnectedAsync(new Exception($"There is no product registered with this name '{product}'. Tenant '{tenant}' does not allow to create new product"))); } var productDetails = tenantFactory.CreateProduct(product); tenantRepository.AddProduct(tenant, product, productDetails); storageHubService.CreateProductAsync(tenant, productDetails); } else { storageHubService.UpdateProductAsync(tenant, connectedProduct); } var connectedComponent = tenantRepository.GetComponent(tenant, product, component); if (connectedComponent == null) { var componentDetails = tenantFactory.CreateComponent(component); tenantRepository.AddComponent(tenant, product, component, componentDetails); storageHubService.CreateComponentAsync(tenant, product, componentDetails); } else { // check component token validation bool isComponentTokenValidated = tenantRepository.ValidateComponentToken(tenant, product, component, componentToken, producerName, false); if (isComponentTokenValidated != true) { logger.LogInformation($"Producer '{producerName}' failed to connect, access is forbidden. Not authorized, check component token"); return(OnDisconnectedAsync(new Exception($"Producer '{producerName}' failed to connect, access is forbidden, check component token"))); } storageHubService.UpdateComponentAsync(tenant, product, connectedComponent); } var connectedTopic = tenantRepository.GetTopic(tenant, product, component, topic); if (connectedTopic == null) { // Check if the component allows to create a new topic. connectedComponent = tenantRepository.GetComponent(tenant, product, component); if (connectedComponent.Settings.AllowTopicCreation != true) { logger.LogInformation($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component."); return(OnDisconnectedAsync(new Exception($"Component '{component}' does not allow to create a new topic {topic} at '{tenant}/{product}/{component}'. To allow creating update property AllowTopicCreation at component."))); } var topicDetails = tenantFactory.CreateTopic(topic, isPersistent); tenantRepository.AddTopic(tenant, product, component, topic, topicDetails); storageHubService.CreateTopicAsync(tenant, product, component, topicDetails); } else { storageHubService.UpdateTopicAsync(tenant, product, component, connectedTopic); } if (producerHubRepository.GetProducerByProducerName(tenant, product, component, topic, producerName).Equals(default(KeyValuePair <string, Producer>)) != true) { logger.LogWarning($"Producer '{producerName}' at {tenant}/{product}/{component}/{topic} is already connected"); return(OnDisconnectedAsync(new Exception($"There is a producer with name '{producerName}' at {tenant}/{product}/{component}/{topic} connected to this node"))); } producerToRegister = producerFactory.CreateProducer(tenant, product, component, topic, producerName); producerHubRepository.AddProducer(clientConnectionId, producerToRegister); storageHubService.ConnectProducerAsync(producerToRegister); Clients.Caller.ProducerConnected(new Model.Producers.Events.ProducerConnectedDetails() { Id = producerToRegister.Id, Tenant = tenant, Product = product, Component = component, Topic = topic, ProducerName = producerName }); logger.LogInformation($"Producer '{producerName}' at {tenant}/{product}/{component}/{topic} is connected"); return(base.OnConnectedAsync()); }