using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using SimpleChat.Models; using System.Collections.Concurrent; namespace SimpleChat { [Authorize] [HubName("chatHub")] public class ChatHub2 : Hub { private static readonly ConcurrentDictionary Users = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase); ChatContext _db = new ChatContext(); public void Send(string message) { string sender = Context.User.Identity.Name; //User sender = Context.User.Identity.Name; string groupName = GetGroupName(sender); // So, broadcast the sender, too. //Clients.OthersInGroup(groupName).received(new { sender = sender, message = message, isPrivate = false }); Clients.Group(groupName).received(new { sender = sender, message = message, isPrivate = false }); //Clients.All.received(new { sender = sender, message = message, isPrivate = false }); } public void SendMessage(string message) { string sender = Context.User.Identity.Name; //User sender = Context.User.Identity.Name; string groupName = GetGroupName(sender); // So, broadcast the sender, too. //Clients.OthersInGroup(groupName).received(new { sender = sender, message = message, isPrivate = false }); //Clients.Group(groupName).received(new { sender = sender, message = message, isPrivate = false }); Clients.Group(groupName).received(new { sender = sender, message = message, isPrivate = false }); } public void Send(string message, string to) { User receiver; if (Users.TryGetValue(to, out receiver)) { User sender = GetUser(Context.User.Identity.Name); IEnumerable allReceivers; lock (receiver.ConnectionIds) { lock (sender.ConnectionIds) { allReceivers = receiver.ConnectionIds.Concat(sender.ConnectionIds); } } foreach (var cid in allReceivers) { Clients.Client(cid).received(new { sender = sender.Name, message = message, isPrivate = true }); } } } public void JoinRoom(string room) { // NOTE: this is not persisted - .... Groups.Add(Context.ConnectionId, room); } public void SendMessageToRoom(string room, string message) { string sender = Context.User.Identity.Name; //User sender = Context.User.Identity.Name; string groupName = GetGroupName(sender); Clients.Group(room).received(new { sender = sender, message = message, isPrivate = false }); } //public Task SendDataAsync() //{ // // async ... work... //} private String GetGroupName(string userName) { return _db.Logins.Single(r => r.Name == userName).GroupName; } public override Task OnConnected() { string username = Context.User.Identity.Name; string groupname = this.GetGroupName(username); Groups.Add(Context.ConnectionId, groupname); string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; string groupName = _db.Logins.Single(r => r.Name == userName).GroupName; var user = Users.GetOrAdd(userName, _ => new User { Name = userName, ConnectionIds = new HashSet(), GroupName = groupName }); lock (user.ConnectionIds) { user.ConnectionIds.Add(connectionId); //Groups.Add(connectionId, groupName); // // broadcast this to all clients other than the caller // Clients.AllExcept(user.ConnectionIds.ToArray()).userConnected(userName); // Or you might want to only broadcast this info if this // is the first connection of the user if (user.ConnectionIds.Count == 1) { Clients.OthersInGroup(groupName).userConnected(userName); } } //SendMonitoringData("Connected", Context.ConnectionId); return base.OnConnected(); } public override Task OnDisconnected() { string userName = Context.User.Identity.Name; string connectionId = Context.ConnectionId; string groupName = GetGroupName(userName); User user; Users.TryGetValue(userName, out user); if (user != null) { lock (user.ConnectionIds) { foreach (string conId in user.ConnectionIds) { Groups.Remove(connectionId, groupName); } user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId)); if (!user.ConnectionIds.Any()) { User removedUser; Users.TryRemove(userName, out removedUser); // You might want to only broadcast this info if this // is the last connection of the user and the user actual is // now disconnected from all connections. Clients.Group(removedUser.GroupName).userDisconnected(userName); //Clients.All.userDisconnected(userName); } } } //SendMonitoringData("Disconnected", Context.ConnectionId); return base.OnDisconnected(); } public override Task OnReconnected() { //SendMonitoringData("Reconnected", Context.ConnectionId); return base.OnReconnected(); } private void SendMonitoringData(string eventType, string connection) { var context = GlobalHost.ConnectionManager.GetHubContext(); context.Clients.All.newEvent(eventType, connection); } protected override void Dispose(bool disposing) { _db.Dispose(); base.Dispose(disposing); } public IEnumerable GetConnectedUsers() { //User sender = GetUser(Context.User.Identity.Name); var users = Users.Where(x => { lock (x.Value.ConnectionIds) { return !x.Value.ConnectionIds.Contains(Context.ConnectionId, StringComparer.InvariantCultureIgnoreCase); } }); return users.Where(x => { lock (x.Value.GroupName) { return x.Value.GroupName == this.GetGroupName(Context.User.Identity.Name); } }).Select(x => x.Key); } private User GetUser(string username) { User user; Users.TryGetValue(username, out user); return user; } } }