Skip to content

Instantly share code, notes, and snippets.

@vcardins
Last active August 29, 2015 14:02
Show Gist options
  • Save vcardins/862f8c4cff124ac08873 to your computer and use it in GitHub Desktop.
Save vcardins/862f8c4cff124ac08873 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using Microsoft.AspNet.SignalR;
using Omu.ValueInjecter;
using SimpleInjector;
using TechsApp.Core.Extensions.Membership;
using TechsApp.Core.Interfaces.Data;
using TechsApp.Core.Interfaces.Service;
using TechsApp.Core.Models;
using TechsApp.Core.Models.Account;
using TechsApp.Core.ViewModels.Partnership;
using TechsApp.Core.ViewModels.Users;
using TechsApp.Infrastructure.Data;
using TechsApp.Web.Models;
using WebBackgrounder;
using IDependencyResolver = System.Web.Http.Dependencies.IDependencyResolver;
using Task = System.Threading.Tasks.Task;
namespace TechsApp.Web.Hubs
{
[Microsoft.AspNet.SignalR.Authorize]
public abstract class BaseHub : Hub
{
private readonly IDataContext _datacontext;
protected int UserId;
protected string Username;
public static string ConnectionId;
protected static readonly ConcurrentDictionary<string, AppUser> AppUsers = new ConcurrentDictionary<string, AppUser>();
protected static readonly ConcurrentDictionary<string, AppUser> OfflineUsers = new ConcurrentDictionary<string, AppUser>();
protected AppUser Me;
protected static readonly ConcurrentDictionary<string, IList<UserKeys>> Partners = new ConcurrentDictionary<string, IList<UserKeys>>();
protected static readonly JobHost _jobHost = new JobHost();
protected IDependencyResolver _di;
protected static IUserService _userService;
protected IQueryable<User> _queryUser;
protected IQueryable<Chat> _queryChat;
//protected static IPartnershipService _partnershipService;
//protected static IUserMobileDeviceService _mobileDeviceService;
protected BaseHub()
{
_di = GlobalConfiguration.Configuration.DependencyResolver;
//_partnershipService = (IPartnershipService)_di.GetService(typeof(IPartnershipService));
//_mobileDeviceService = (IUserMobileDeviceService)_di.GetService(typeof(IUserMobileDeviceService));
_userService = (IUserService)_di.GetService(typeof(IUserService));
//_datacontext = new DatabaseFactory().Get();
}
public override Task OnConnected()
{
Connect(true);
return base.OnConnected();
}
public override Task OnReconnected()
{
Connect(false);
return base.OnReconnected();
}
private string GetDeviceId()
{
var headers = Context.Request.Headers;
return (headers!=null) ? headers["X-ATT-DeviceId"] : null;
}
protected void Connect(bool isOnConnected)
{
UserId = Context.User.GetUserID();
Username = Context.User.Identity.Name;
ConnectionId = Context.ConnectionId;
var appUser = GetUserByConnectionId(ConnectionId);
if (appUser != null)
return;
appUser = AddUser();
Me = appUser;
Groups.Add(ConnectionId, Username);
}
//public override Task OnDisconnected()
//{
// Disconnect();
// return base.OnDisconnected();
//}
public IList<AppUser> OnlineUsers()
{
var users = new List<AppUser>();
if (AppUsers.Count == 0)
return users;
users = (List<AppUser>)AppUsers.Select(user => user.Value);
return users.ToList();
}
public IList<BaseAppUser> OnlinePartners()
{
var appUser = GetUserByUsername(Context.User.Identity.Name);
return (appUser!=null) ? appUser.Partners.Where(pp => GetUserByUsername(pp.Username) != null).ToList() : new List<BaseAppUser>();
}
//POST
public void SetStatus(bool status)
{
var userId = Context.User.GetUserID();
var username = Context.User.Identity.Name;
var user = GetUserByUsername(username);
if (user == null)
return;
user.IsMobileActive = status;
var result = new
{
U = username,
I = userId,
T = DateTimeOffset.UtcNow.ToLocalTime(),
P = user.Partners,
M = user.IsMobileAccess,
A = user.IsMobileActive
};
foreach (var p in user.Partners)
{
Clients.Group(p.Username).onMobileStatusChange(result);
}
}
protected object Disconnect()
{
var username = Context.User.Identity.Name;
//var appUser = GetUserByUsername(username);
//var connId = appUser.ConnectionIds.FirstOrDefault(x => x == Context.ConnectionId);
//appUser.ConnectionIds.Remove(connId);
var partners = OnlinePartners();
foreach (var p in partners) //.Where(p => !appUser.ConnectionIds.Any())
{
//Remove the user group for the just disconnected user
Clients.Group(p.Username).onUserDisconnected(username);
}
//remove the leaving users from all partners objects
var ok = RemoveUser();
return ok;
}
protected AppUser GetUserByUserId(int userId)
{
return AppUsers.Values.FirstOrDefault(u => u.UserId == userId);
}
protected AppUser GetUserByUsername(string username)
{
AppUser appUser;
AppUsers.TryGetValue(username, out appUser);
return appUser;
}
protected bool RemoveUser()
{
AppUser appUser;
var username = Context.User.Identity.Name;
return AppUsers.TryRemove(username, out appUser);
}
protected UserHubInfo GetHubInfo(int userId)
{
UserId = Context.User.GetUserID();
_queryUser = _datacontext.DbSet<User>();
var user = _queryUser.FirstOrDefault(u => u.UserId == userId);
if (user == null)
return null;
var userHubInfo = new UserHubInfo().InjectFrom(user) as UserHubInfo;
if (user.MobileDevice != null && userHubInfo != null)
{
userHubInfo.DeviceId = user.MobileDevice.Token;
userHubInfo.DeviceOS = user.MobileDevice.Model;
}
if (user.Partnerships == null) return userHubInfo;
foreach (var p in user.Partnerships)
{
userHubInfo.Partners.Add(
new UserKeys
{
DisplayName = p.Partner.DisplayName,
UserId = p.PartnerId,
Username = p.Partner.Username
});
}
return userHubInfo;
}
protected AppUser AddUser()
{
AppUser appUser;
UserId = Context.User.GetUserID();
Username = Context.User.Identity.Name;
ConnectionId = Context.ConnectionId;
var deviceId = GetDeviceId();
if (AppUsers.TryGetValue(Username, out appUser))
{
appUser.ConnectionIds.Add(ConnectionId);
}
else
{
var user = _userService.GetHubInfo(UserId);
if (user==null)
{
return null;
}
//if (!string.IsNullOrEmpty(user.DeviceId) && !deviceId.Equals(user.DeviceId))
//{
// Clients.Caller.notAuthorized("Device token invalid");
// return null;
//}
appUser = new AppUser
{
Username = Username,
UserId = Context.User.GetUserID(),
ConnectionIds = new List<string> {ConnectionId},
DeviceId = deviceId,
DeviceOS = user.DeviceOS,
Partners = user.Partners.Select(p => new BaseAppUser().InjectFrom(p) as BaseAppUser).ToList()
};
AppUsers.TryAdd(Username, appUser);
}
//At first, if the user connected from mobile, both properties are true
appUser.IsMobileAccess = !string.IsNullOrEmpty(deviceId);
appUser.IsMobileActive = !string.IsNullOrEmpty(deviceId);
appUser.Updated = DateTimeOffset.UtcNow;
return appUser;
}
protected AppUser GetUserByConnectionId(string connectionId)
{
return AppUsers.Values.FirstOrDefault(u => u.ConnectionIds.Any(z => z == connectionId));
}
internal Scope Scope { get; set; }
protected override void Dispose(bool disposing)
{
if (disposing && Scope != null)
{
Scope.Dispose();
}
base.Dispose(disposing);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using Omu.ValueInjecter;
using TechsApp.Core.Extensions.Membership;
using TechsApp.Core.Interfaces.Messaging;
using TechsApp.Core.Interfaces.Service;
using TechsApp.Core.Models.Messaging;
using TechsApp.Core.ViewModels.Chat;
using TechsApp.Web.Models;
namespace TechsApp.Web.Hubs
{
public class ChatHub : BaseHub
{
private static IChatService _chatService;
private readonly IPushNotificationService _pushService;
public ChatHub()
{
_di = GlobalConfiguration.Configuration.DependencyResolver;
_chatService = (IChatService)_di.GetService(typeof(IChatService));
_pushService = (IPushNotificationService)_di.GetService(typeof(IPushNotificationService));
}
//GET
public IEnumerable<ChatMessageResponse> GetMessages(string partnerUsername)
{
var messages = _chatService.GetLastest(Context.User.Identity.Name, partnerUsername, 10).ToList();
return messages;
}
//POST
public void SendMessage(string to, string message, string guid)
{
var fromUser = Context.User;
var fromUserId = fromUser.GetUserID();
var from = fromUser.Identity.Name;
var gid = guid ?? Guid.NewGuid().ToString();
var chatResponse = new ChatMessageResponse
{
FromUserId = fromUserId,
From = from,
To = to,
Message = message,
Guid = gid,
Created = DateTime.Now
};
//Try to get the user from the Online dictionary
var userTo = GetUserByUsername(to);
if (userTo == null)
{
//If not online, check the latest offline ones who tried to send message
if (!OfflineUsers.TryGetValue(to, out userTo))
{
//If not yet, get the mobile record
var user = _userService.GetHubInfo(UserId);
// if the mobile is registered, add the user in the offline collection and send a push
if (user != null)
{
OfflineUsers.TryAdd(to, userTo = new AppUser().InjectFrom(user) as AppUser);
}
}
userTo = userTo ?? new AppUser();
}
if (!userTo.IsMobileActive && !string.IsNullOrEmpty(userTo.DeviceId))
{
userTo.UnreadMessages++;
var push = new PushNotification
{
Data = new Dictionary<string, object>
{
{"from", from },
{"to",to },
{"message", message},
{"guid", gid},
{"created", chatResponse.Created}
},
Message = userTo.DisplayName + "\r\n" + message,
DeviceToken = userTo.DeviceId,
Channel = userTo.Username,
Badge = userTo.UnreadMessages,
Sound = "new-message",
Device = userTo.DeviceOS
};
_pushService.Send(push);
}
Clients.Group(to).receiveMessage(chatResponse);
Clients.Group(from).receiveMessage(chatResponse);
var chatInput = new ChatMessageInput
{
FromUserId = fromUserId,
From = from,
To = to,
Message = message
};
Action persistChat = () => PersistMessage(chatInput);
_jobHost.DoWork(new Task(persistChat));
}
//POST
public object HandleTyping(string to)
{
var from = Context.User.Identity.Name;
var obj = new {From = from, To = to};
Clients.Group(to).listenTyping(obj);
return obj;
}
private static void PersistMessage(ChatMessageInput model)
{
_chatService.Save(model);
}
//POST
public void SetMessagesAsRead()
{
var username = Context.User.Identity.Name;
var user = AppUsers[username];
if (user != null)
{
AppUsers[username].UnreadMessages = 0;
}
}
}
}
private static void RegisterServices(Container container)
{
var hybridLifestyle = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new ExecutionContextScopeLifestyle(),
new WebRequestLifestyle());
// infrastructure
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
container.RegisterPerWebRequest<IDatabaseFactory, DatabaseFactory>();
...
container.Register<IChatService, ChatService>(hybridLifestyle);
container.Register<IChatRepository, ChatRepository>(hybridLifestyle);
using System;
using System.Threading.Tasks;
namespace TechsApp.Web.Hubs
{
public class UserPresenceHub : BaseHub
{
//private static IConnectionService _connService;
private readonly object _sync = new object();
public override Task OnConnected()
{
base.OnConnected();
return HandleConnection();
}
public override Task OnReconnected()
{
base.OnReconnected();
return HandleConnection();
}
public override Task OnDisconnected()
{
Disconnect();
return base.OnDisconnected();
}
private Task HandleConnection()
{
var onLinePartners = OnlinePartners();
//Tell all my partners that I'm online by calling the client method : onUserConnected
var appUser = GetUserByUsername(Context.User.Identity.Name);
Me = appUser;
foreach (var p in onLinePartners)
{
Clients.Group(p.Username).onUserConnected(new { User = appUser, Timestamp = DateTime.Now });
}
//Call the client userConnected method for all users contained in the in just connected user group
return Clients.Caller.onConnected(new { Me, Partners = onLinePartners });
}
public object SignOff()
{
return new { Data = Disconnect() };
}
}
}
@vcardins
Copy link
Author

This does not work ...
if I have:
container.RegisterPerWebRequest<IChatService, ChatService>();
container.RegisterPerWebRequest<IChatRepository, ChatRepository>();
Sometimes it does, sometimes it does not work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment