private async Task ListenTo(string json) { bool isValidJson = true; JObject jObject = null; try { jObject = JObject.Parse(json); } catch (JsonReaderException) { isValidJson = false; #if DEBUG Console.WriteLine($"Illegal JSON message: {json}"); #endif } if (!isValidJson) { return; } if (jObject["type"].Value <string>() == "message") { var channelID = jObject["channel"].Value <string>(); SlackChatHub hub = null; if (ConnectedHubs.ContainsKey(channelID)) { hub = ConnectedHubs[channelID]; } else { hub = SlackChatHub.FromID(channelID); var hubs = new Dictionary <string, SlackChatHub>(ConnectedHubs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); hubs.Add(hub.ID, hub); ConnectedHubs = hubs; } // some messages may not have text or a user (like unfurled data from URLs) var messageText = (jObject["text"] != null ? jObject["text"].Value <string>() : null); SlackMessage message = new SlackMessage() { ChatHub = hub, // check to see if bot has been mentioned MentionsBot = (messageText != null ? Regex.IsMatch(messageText, BotNameRegex, RegexOptions.IgnoreCase) : false), RawData = json, Text = messageText, User = (jObject["user"] != null ? new SlackUser() { ID = jObject["user"].Value <string>() } : null) }; ResponseContext context = new ResponseContext() { BotHasResponded = false, BotUserID = UserID, BotUserName = UserName, Message = message, TeamID = TeamID, UserNameCache = new ReadOnlyDictionary <string, string>(UserNameCache) }; // if the end dev has added any static entries to the ResponseContext collection of Bot, add them to the context being passed to the responders. if (ResponseContext != null) { foreach (string key in ResponseContext.Keys) { context.Set(key, ResponseContext[key]); } } // margie can never respond to herself and requires that the message have text and be from an actual person if (message.User != null && message.User.ID != UserID && message.Text != null) { foreach (var responder in Responders ?? Enumerable.Empty <IResponder>()) { if (responder != null && responder.CanRespond(context)) { await SendIsTyping(message.ChatHub); await Say(responder.GetResponse(context), context); context.BotHasResponded = true; } } } } RaiseMessageReceived(json); }
private async Task ListenTo(string json) { JObject jObject = JObject.Parse(json); if (jObject["type"].Value <string>() == "message") { string channelID = jObject["channel"].Value <string>(); SlackChatHub hub = null; if (ConnectedHubs.ContainsKey(channelID)) { hub = ConnectedHubs[channelID]; } else { hub = SlackChatHub.FromID(channelID); List <SlackChatHub> hubs = new List <SlackChatHub>(); hubs.AddRange(ConnectedHubs.Values); hubs.Add(hub); } string messageText = (jObject["text"] != null ? jObject["text"].Value <string>() : null); // check to see if bot has been mentioned SlackMessage message = new SlackMessage() { ChatHub = hub, MentionsBot = (messageText != null ? Regex.IsMatch(messageText, BotNameRegex, RegexOptions.IgnoreCase) : false), RawData = json, // some messages may not have text or a user (like unfurled data from URLs) Text = messageText, User = (jObject["user"] != null ? new SlackUser() { ID = jObject["user"].Value <string>() } : null) }; ResponseContext context = new ResponseContext() { BotHasResponded = false, BotUserID = UserID, BotUserName = UserName, Message = message, TeamID = this.TeamID, UserNameCache = new ReadOnlyDictionary <string, string>(this.UserNameCache) }; if (StaticResponseContextData != null) { foreach (string key in StaticResponseContextData.Keys) { context.Set(key, StaticResponseContextData[key]); } } // margie can never respond to herself and requires that the message have text and be from an actual person if (message.User != null && message.User.ID != UserID && message.Text != null) { foreach (IResponseProcessor processor in ResponseProcessors) { if (processor.CanRespond(context)) { await Say(processor.GetResponse(context), context); context.BotHasResponded = true; } } } } RaiseMessageReceived(json); }
private async Task ListenTo(string json) { JObject jObject = JObject.Parse(json); if (jObject["type"].Value <string>() == "message") { string channelID = jObject["channel"].Value <string>(); SlackChatHub hub = null; if (ConnectedHubs.ContainsKey(channelID)) { hub = ConnectedHubs[channelID]; } else { hub = SlackChatHub.FromID(channelID); Dictionary <string, SlackChatHub> hubs = new Dictionary <string, SlackChatHub>(ConnectedHubs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); hubs.Add(hub.ID, hub); ConnectedHubs = hubs; } string messageText = (jObject["text"] != null ? jObject["text"].Value <string>() : null); // check to see if bot has been mentioned SlackMessageContent message = new SlackMessageContent() { ChatHub = hub, MentionsBot = (messageText != null ? Regex.IsMatch(messageText, BotNameRegex, RegexOptions.IgnoreCase) : false), RawData = json, // some messages may not have text or a user (like unfurled data from URLs) Text = messageText, User = (jObject["user"] != null ? new SlackUser() { ID = jObject["user"].Value <string>() } : null) }; SlackMessage context = new SlackMessage() { Creator = this, BotHasResponded = false, BotUserID = UserID, BotUserName = UserName, Message = message, TeamID = this.TeamID, UserNameCache = new ReadOnlyDictionary <string, string>(this.UserNameCache) }; context.Answer = async(arg) => { await this.Say(arg, context); context.BotHasResponded = true; }; // if the end dev has added any static entries to the ResponseContext collection of Bot, add them to the context being passed to the responders. if (ResponseContext != null) { foreach (string key in ResponseContext.Keys) { context.Set(key, ResponseContext[key]); } } // margie can never respond to herself and requires that the message have text and be from an actual person if (message.User != null && message.User.ID != UserID && message.Text != null) { foreach (var obs in observers) { obs.OnNext(context); } } } RaiseMessageReceived(json); }
/// <summary> /// Listens to events sent from the rtm Interface. Uses a simple web socket to get the requests /// </summary> /// <param name="json">The json.</param> /// <returns></returns> private async Task ListenTo(string json) { ResponseContext context = null; JObject jObject = JObject.Parse(json); if (jObject["type"] != null && jObject["type"].Value <string>() == "message") { string channelID = jObject["channel"].Value <string>(); SlackMessage message = new SlackMessage() { ChatHub = null, RawData = json, Attachments = new List <SlackAttachment>(), Files = new List <SlackFile>() }; if (ConnectedHubs.ContainsKey(channelID)) { message.ChatHub = ConnectedHubs[channelID]; } else { message.ChatHub = SlackChatHub.FromID(channelID); List <SlackChatHub> hubs = new List <SlackChatHub>(); hubs.AddRange(ConnectedHubs.Values); hubs.Add(message.ChatHub); } try { message.Text = (jObject["text"] != null ? jObject["text"].Value <string>() : string.Empty); message.User = new SlackUser(); if (jObject["user"] != null) { WebClient client = new WebClient(); string responseJson = await client.GetResponse("https://slack.com/api/users.info?", WebClient.RequestMethod.Post, "token", this.SlackKey, "user", jObject["user"].Value <string>()); JObject jData = JObject.Parse(responseJson); message.User.ID = jObject["user"].Value <string>(); message.User.Name = jData["user"]["real_name"].Value <string>(); message.User.ImageUrl = jData["user"]["profile"]["image_192"].Value <string>(); } if (jObject["bot_id"] != null && jObject["username"] != null) { message.User.ID = jObject["bot_id"].Value <string>(); message.User.IsBot = true; message.User.Name = jObject["username"].Value <string>(); if (!string.IsNullOrEmpty(message.User.ID) && !UserNameCache.ContainsKey(message.User.ID)) { UserNameCache.Add(message.User.ID, message.User.Name); } } if (jObject["attachments"] != null) { List <string> msg = new List <string>(); foreach (JObject attachment in jObject["attachments"]) { SlackAttachment sla = new SlackAttachment() { Fallback = attachment["fallback"] != null ? attachment["fallback"].Value <string>() : string.Empty, ColorHex = attachment["color"] != null ? attachment["color"].Value <string>(): string.Empty, Text = attachment["text"] != null ? attachment["text"].Value <string>() : string.Empty, Title = attachment["title"] != null? attachment["title"].Value <string>(): string.Empty, }; message.Attachments.Add(sla); msg.Add(sla.Title); msg.Add(sla.Text); } if (string.IsNullOrEmpty(message.Text)) { message.Text = string.Empty; } message.Text += string.Join(Environment.NewLine, msg); } if (jObject["files"] != null) { foreach (JObject file in jObject["files"]) { message.Files.Add(new SlackFile() { Id = file["id"]?.Value <string>() ?? string.Empty, Name = file["name"]?.Value <string>() ?? string.Empty, Title = file["title"]?.Value <string>() ?? string.Empty, Filetype = file["filetype"]?.Value <string>() ?? string.Empty, Mimetype = file["mimetype"]?.Value <string>() ?? string.Empty, Size = file["size"]?.Value <int>() ?? 0, Permalink = file["permalink"]?.Value <string>() ?? string.Empty, Url_private = file["url_private"]?.Value <string>() ?? string.Empty }); } } // check to see if bot has been mentioned if (message.Text != null && Regex.IsMatch(message.Text, BotNameRegex, RegexOptions.IgnoreCase)) { message.MentionsBot = true; } context = new ResponseContext() { BotHasResponded = false, BotUserID = UserID, BotUserName = UserName, Message = message, TeamID = this.TeamID, UserNameCache = new ReadOnlyDictionary <string, string>(this.UserNameCache), }; // if the end dev has added any static entries to the ResponseContext collection of Bot, add them to the context being passed to the responders. if (ResponseContext != null) { foreach (string key in ResponseContext.Keys) { context.Set(key, ResponseContext[key]); } } } catch (Exception ee) { BotMessage errorMessage = new BotMessage() { ChatHub = message.ChatHub, Text = "ERROR parsing message : " + ee.Message + " " + ee.StackTrace }; logger.Error(errorMessage.Text); if (errorChannel != null) { //TODO //await Say(errorMessage); } } try { // Avoid to answer to yourself if (context != null && context.Message != null && context.Message.Text != null && !string.IsNullOrEmpty(context.Message.User.ID) && context.Message.User.ID != context.BotUserID) { foreach (IResponder responder in Responders) { if (responder.CanRespond(context)) { await Say(responder.GetResponse(context), context); context.BotHasResponded = true; } } } } catch (Exception ee) { BotMessage errorMessage = new BotMessage() { ChatHub = message.ChatHub, Text = "ERROR in responder: " + ee.Message + " " + ee.StackTrace }; logger.Error(errorMessage.Text); if (errorChannel != null) { //TODO //await Say(errorMessage); } } try { RaiseMessageReceived(context); } catch (Exception ee) { BotMessage errorMessage = new BotMessage() { ChatHub = message.ChatHub, Text = "ERROR with Message received event: " + ee.Message + " " + ee.StackTrace }; logger.Error(errorMessage.Text); if (errorChannel != null) { //TODO //await Say(errorMessage); } } } }
/// <summary> /// Connects the bot with the specified slack key. /// </summary> /// <returns></returns> public async Task Connect() { try { if (WebSocket != null && WebSocket.IsAlive) { WebSocket.OnOpen -= WebSocket_OnOpen; WebSocket.OnMessage -= WebSocket_OnMessage; WebSocket.OnError -= WebSocket_OnError; WebSocket.OnClose -= WebSocket_OnClose; WebSocket.Close(); } // kill the regex for our bot's name - we'll rebuild it upon request with some of the info we get here BotNameRegex = string.Empty; WebClient client = new WebClient(); string json = await client.GetResponse("https://slack.com/api/rtm.start", WebClient.RequestMethod.Post, "token", this.SlackKey); JObject jData = JObject.Parse(json); TeamID = jData["team"]["id"].Value <string>(); TeamName = jData["team"]["name"].Value <string>(); UserID = jData["self"]["id"].Value <string>(); UserName = jData["self"]["name"].Value <string>(); string webSocketUrl = jData["url"].Value <string>(); UserNameCache.Clear(); foreach (JObject userObject in jData["users"]) { UserNameCache.Add(userObject["id"].Value <string>(), userObject["name"].Value <string>()); } // load the channels, groups, and DMs that margie's in Dictionary <string, SlackChatHub> hubs = new Dictionary <string, SlackChatHub>(); ConnectedHubs = hubs; // channelz if (jData["channels"] != null) { foreach (JObject channelData in jData["channels"]) { if (!channelData["is_archived"].Value <bool>() && channelData["is_member"].Value <bool>()) { SlackChatHub channel = new SlackChatHub() { ID = channelData["id"].Value <string>(), Name = "#" + channelData["name"].Value <string>(), Type = SlackChatHubType.Channel }; hubs.Add(channel.ID, channel); } } } // groupz if (jData["groups"] != null) { foreach (JObject groupData in jData["groups"]) { if (!groupData["is_archived"].Value <bool>() && groupData["members"].Values <string>().Contains(UserID)) { SlackChatHub group = new SlackChatHub() { ID = groupData["id"].Value <string>(), Name = groupData["name"].Value <string>(), Type = SlackChatHubType.Group }; hubs.Add(group.ID, group); } } } // dmz if (jData["ims"] != null) { foreach (JObject dmData in jData["ims"]) { string userID = dmData["user"].Value <string>(); SlackChatHub dm = new SlackChatHub() { ID = dmData["id"].Value <string>(), Name = "@" + (UserNameCache.ContainsKey(userID) ? UserNameCache[userID] : userID), Type = SlackChatHubType.DM }; hubs.Add(dm.ID, dm); } } // dmz if (jData["bots"] != null) { foreach (JObject dmData in jData["bots"]) { if (!dmData["deleted"].Value <bool>()) { string userID = dmData["id"].Value <string>(); SlackChatHub cbot = new SlackChatHub() { ID = dmData["id"].Value <string>(), Name = "@" + (UserNameCache.ContainsKey(userID) ? UserNameCache[userID] : userID), Type = SlackChatHubType.Bot }; hubs.Add(cbot.ID, cbot); } } } if (!string.IsNullOrEmpty(this.ErrorMessageChannel) && ConnectedHubs.ContainsKey(this.ErrorMessageChannel)) { errorChannel = ConnectedHubs[this.ErrorMessageChannel]; } WebSocket = new WebSocket(webSocketUrl); WebSocket.OnOpen += WebSocket_OnConnect; WebSocket.OnMessage += WebSocket_OnMessage; //WebSocket.OnError += WebSocket_OnError; //WebSocket.OnClose += WebSocket_OnClose; WebSocket.Connect(); pinger = new Timer(TimerCallback, null, 0, 15000); } catch (Exception ee) { Disconnect(); } }
public Task StartAsync(CancellationToken cancellationToken) { log.LogInformation($"Start Hub Service for {chainSettings.Symbol}."); Protection protection = new Protection(); Mnemonic recoveryPhrase; DirectoryInfo dataFolder = new DirectoryInfo(hubSettings.DataFolder); if (!dataFolder.Exists) { dataFolder.Create(); } string path = Path.Combine(dataFolder.FullName, "recoveryphrase.txt"); if (!File.Exists(path)) { recoveryPhrase = new Mnemonic(Wordlist.English, WordCount.Twelve); string cipher = protection.Protect(recoveryPhrase.ToString()); File.WriteAllText(path, cipher); } else { string cipher = File.ReadAllText(path); recoveryPhrase = new Mnemonic(protection.Unprotect(cipher)); } if (recoveryPhrase.ToString() != "border indicate crater public wealth luxury derive media barely survey rule hen") { //throw new ApplicationException("RECOVERY PHRASE IS DIFFERENT!"); } // Read the identity from the secure storage and provide it here. //host.Setup(new Identity(recoveryPhrase.ToString()), stoppingToken); IPAddress[] IPAddresses = Dns.GetHostAddresses(hubSettings.Server); if (IPAddresses.Length == 0) { throw new ApplicationException("Did not find any IP address for the hub server."); } //ServerEndpoint = new IPEndPoint(IPAddress.Parse(hubSettings.Server), hubSettings.Port); // TODO: #4 ServerEndpoint = new IPEndPoint(IPAddresses[0], hubSettings.Port); LocalHubInfo = new HubInfo(); AckResponces = new List <Ack>(); UDPClientGateway.AllowNatTraversal(true); UDPClientGateway.Client.SetIPProtectionLevel(IPProtectionLevel.Unrestricted); UDPClientGateway.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); LocalHubInfo.Name = Environment.MachineName; LocalHubInfo.ConnectionType = ConnectionTypes.Unknown; LocalHubInfo.Id = Guid.NewGuid().ToString(); //LocalHubInfo.Id = DateTime.Now.Ticks; IEnumerable <IPAddress> IPs = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork); foreach (IPAddress IP in IPs) { log.LogInformation("Internal Address: {IP}", IP); LocalHubInfo.InternalAddresses.Add(IP); } // To avoid circular reference we must resolve these in the startup. messageProcessing = serviceProvider.GetService <IHubMessageProcessing>(); messageSerializer = serviceProvider.GetService <MessageSerializer>(); // Prepare the messaging processors for message handling. MessageMaps maps = messageProcessing.Build(); messageSerializer.Maps = maps; hub.Subscribe <ConnectionAddedEvent>(this, e => { StringBuilder entry = new StringBuilder(); entry.AppendLine($"ConnectionAddedEvent: {e.Data.Id}"); entry.AppendLine($" : ExternalIPAddress: {e.Data.ExternalEndpoint}"); entry.AppendLine($" : InternalIPAddress: {e.Data.InternalEndpoint}"); entry.AppendLine($" : Name: {e.Data.Name}"); foreach (System.Net.IPAddress address in e.Data.InternalAddresses) { entry.AppendLine($" : Address: {address}"); } log.LogInformation(entry.ToString()); //var msg = new MessageModel //{ // Type = "ConnectionAddedEvent", // Date = DateTime.UtcNow, // Message = entry.ToString(), // Data = e //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <ConnectionRemovedEvent>(this, e => { log.LogInformation($"ConnectionRemovedEvent: {e.Data.Id}"); log.LogInformation($"ConnectionRemovedEvent: {e.Data.Id}"); if (ConnectedHubs.ContainsKey(e.Data.Id)) { ConnectedHubs.Remove(e.Data.Id); } //var msg = new MessageModel //{ // Type = "ConnectionRemovedEvent", // Date = DateTime.UtcNow, // Message = e.Data.ToString(), // Data = e.Data //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <ConnectionStartedEvent>(this, e => { log.LogInformation($"ConnectionStartedEvent: {e.Endpoint}"); //var msg = new MessageModel //{ // Type = "ConnectionStartedEvent", // Date = DateTime.UtcNow, // Message = e.Endpoint.ToString(), // Data = e.Endpoint.ToString() //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <ConnectionStartingEvent>(this, e => { log.LogInformation($"ConnectionStartingEvent: {e.Data.Id}"); //var msg = new MessageModel //{ // Type = "ConnectionStartingEvent", // Date = DateTime.UtcNow, // Message = e.Data.Id.ToString(), // Data = e.Data.Id.ToString() //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <ConnectionUpdatedEvent>(this, e => { log.LogInformation($"ConnectionUpdatedEvent: {e.Data.Id}"); //var msg = new MessageModel //{ // Type = "ConnectionUpdatedEvent", // Date = DateTime.UtcNow, // Message = e.Data.Id.ToString(), // Data = e.Data.Id //}; hubContext.Clients.All.SendAsync("Event", e); // Automatically connect to discovered hubs. if (LocalHubInfo.Id != e.Data.Id) { ConnectToClient(e.Data); } }); hub.Subscribe <GatewayConnectedEvent>(this, e => { log.LogInformation("Connected to Gateway"); //var msg = new MessageModel //{ // Type = "GatewayConnectedEvent", // Date = DateTime.UtcNow, // Message = "", // Data = "" //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <GatewayShutdownEvent>(this, e => { log.LogInformation("Disconnected from Gateway"); //var msg = new MessageModel //{ // Type = "GatewayShutdownEvent", // Date = DateTime.UtcNow, // Message = "", // Data = "" //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <HubInfoEvent>(this, e => { //var msg = new MessageModel //{ // Type = "HubInfoEvent", // Date = DateTime.UtcNow, // Message = e.Data.ToString(), // Data = e.Data //}; //if (e.Data.Id == Identity.Id) //{ // return; //} AvailableHubs.Add(e.Data.Id, new HubInfo(e.Data)); hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <MessageReceivedEvent>(this, e => { log.LogInformation($"MessageReceivedEvent: {e.Data.Content}"); //var msg = new MessageModel //{ // Type = "MessageReceivedEvent", // Date = DateTime.UtcNow, // Message = e.Data.Content, // Data = e.Data.Content //}; hubContext.Clients.All.SendAsync("Event", e); }); hub.Subscribe <GatewayErrorEvent>(this, e => { log.LogInformation($"GatewayErrorEvent: {e.Message}"); //var msg = new MessageModel //{ // Type = "GatewayErrorEvent", // Date = DateTime.UtcNow, // Message = e.Message, // Data = e.Message //}; hubContext.Clients.All.SendAsync("Event", e); }); Task.Run(async() => { try { bool connectedToGateway = false; while (!cancellationToken.IsCancellationRequested) { //Task tcpTask = Task.Run(() => //{ // TcpWorker(cancellationToken); //}, cancellationToken); //Task udTask = Task.Run(() => //{ // UdpWorker(cancellationToken); //}, cancellationToken); //Task.WaitAll(new Task[] { tcpTask, udTask }, cancellationToken); if (!connectedToGateway) { connectedToGateway = ConnectGateway(); } // TODO: This loop will just continue to run after connected to gateway. It should check status and attempt to recycle and reconnect when needed. Task.Delay(TimeSpan.FromSeconds(retryInterval), cancellationToken).Wait(cancellationToken); //Task.Delay(TimeSpan.FromSeconds(retryInterval), cancellationToken).Wait(cancellationToken); //var tokenSource = new CancellationTokenSource(); //cancellationToken.Register(() => { tokenSource.Cancel(); }); //try //{ // using (IServiceScope scope = scopeFactory.CreateScope()) // { // Runner runner = scope.ServiceProvider.GetService<Runner>(); // System.Collections.Generic.IEnumerable<Task> runningTasks = runner.RunAll(tokenSource); // Task.WaitAll(runningTasks.ToArray(), cancellationToken); // if (cancellationToken.IsCancellationRequested) // { // tokenSource.Cancel(); // } // } // break; //} //catch (OperationCanceledException) //{ // // do nothing the task was cancel. // throw; //} //catch (AggregateException ae) //{ // if (ae.Flatten().InnerExceptions.OfType<SyncRestartException>().Any()) // { // log.LogInformation("Sync: ### - Restart requested - ###"); // log.LogTrace("Sync: Signalling token cancelation"); // tokenSource.Cancel(); // continue; // } // foreach (Exception innerException in ae.Flatten().InnerExceptions) // { // log.LogError(innerException, "Sync"); // } // tokenSource.Cancel(); // int retryInterval = 10; // log.LogWarning($"Unexpected error retry in {retryInterval} seconds"); // //this.tracer.ReadLine(); // // Blokcore Indexer is designed to be idempotent, we want to continue running even if errors are found. // // so if an unepxected error happened we log it wait and start again // Task.Delay(TimeSpan.FromSeconds(retryInterval), cancellationToken).Wait(cancellationToken); // continue; //} //catch (Exception ex) //{ // log.LogError(ex, "Sync"); // break; //} } } catch (OperationCanceledException) { // do nothing the task was cancel. throw; } catch (Exception ex) { log.LogError(ex, "Gateway"); throw; } }, cancellationToken); return(Task.CompletedTask); }