implemented some not tested kick
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -19,6 +19,7 @@ private/
|
||||
DataProtection-Keys/
|
||||
RSA-Params.json
|
||||
appsettings.*.json
|
||||
omnisharp.json
|
||||
|
||||
/packages/
|
||||
/src/Yavsc/Avatars-*/
|
||||
@ -30,4 +31,3 @@ appsettings.*.json
|
||||
/src/Yavsc/bower_components/
|
||||
/src/Yavsc/AppData*/
|
||||
/src/test/testingrepo/
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
"Dnx": {
|
||||
"enabled": true,
|
||||
"enablePackageRestore": false,
|
||||
"projects": "src/**/project.json;test/**/project.json"
|
||||
"projects": "src/*/project.json"
|
||||
},
|
||||
"MSBuild": {
|
||||
"enabled": false
|
||||
|
1
omnisharp.log
Normal file
1
omnisharp.log
Normal file
@ -0,0 +1 @@
|
||||
["-s","/home/paul/workspace/yavsc/src","--hostPID","7920","DotNet:enablePackageRestore=false","--encoding","utf-8","--loglevel","warning","FileOptions:SystemExcludeSearchPatterns:0=**/.git","FileOptions:SystemExcludeSearchPatterns:1=**/.svn","FileOptions:SystemExcludeSearchPatterns:2=**/.hg","FileOptions:SystemExcludeSearchPatterns:3=**/CVS","FileOptions:SystemExcludeSearchPatterns:4=**/.DS_Store"]
|
24
src/Yavsc.Abstract/Chat/ChatHubConstants.cs
Normal file
24
src/Yavsc.Abstract/Chat/ChatHubConstants.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace Yavsc.Abstract.Chat
|
||||
{
|
||||
public static class ChatHubConstants
|
||||
{
|
||||
public const string HubGroupAuthenticated = "authenticated";
|
||||
public const string HubGroupAnonymous = "anonymous";
|
||||
public const string HubGroupCops= "cops";
|
||||
public const string HubGroupRomsPrefix = "room_";
|
||||
public const int MaxChanelName = 255;
|
||||
|
||||
public const string HubGroupFollowingPrefix = "fol ";
|
||||
public const string AnonymousUserNamePrefix = "?";
|
||||
public const string KeyParamChatUserName = "username";
|
||||
|
||||
public const string JustCreatedBy = "just created by ";
|
||||
public const string LabYouNotOp = "you're no op.";
|
||||
public const string LabNoSuchUser = "No such user";
|
||||
public const string LabNoSuchChan = "No such chan";
|
||||
public const string HopWontKickOp = "Half operator cannot kick any operator";
|
||||
public const string LabAuthChatUser = "Authenticated chat user";
|
||||
public const string NoKickOnCop = "No, you won´t, you´ĺl never do kick a cop, it is the bad.";
|
||||
public const string LabnoJoinNoSend = "LabnoJoinNoSend";
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ namespace Yavsc
|
||||
public const string Reconnected = "reconnected";
|
||||
public const string UserPart = "userpart";
|
||||
public const string UserJoin = "userjoin";
|
||||
public const string Kick = "kick";
|
||||
public const string Ban = "ban";
|
||||
public const string KickBan = "kickban";
|
||||
public const string Gline = "gline";
|
||||
public const string PrivateMessageDenied = "denied_pv";
|
||||
public const string Error = "error";
|
||||
public const string ContactRefused = "contact_refused";
|
||||
|
@ -57,15 +57,6 @@ namespace Yavsc
|
||||
{ "openid", "profile", "email", "https://www.googleapis.com/auth/calendar" };
|
||||
|
||||
public static readonly string NoneCode = "none";
|
||||
public const string HubGroupAuthenticated = "authenticated";
|
||||
public const string HubGroupAnonymous = "anonymous";
|
||||
public const string HubGroupCops= "cops";
|
||||
public const string HubGroupRomsPrefix = "room_";
|
||||
public const int MaxChanelName = 255;
|
||||
|
||||
public const string HubGroupFollowingPrefix = "fol ";
|
||||
public const string AnonymousUserNamePrefix = "?";
|
||||
public const string KeyParamChatUserName = "username";
|
||||
public const string LabAuthChatUser = "Authenticated chat user";
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace Yavsc.Models.Chat
|
||||
public string Topic { get; set; }
|
||||
|
||||
[Key]
|
||||
[StringLengthAttribute(Constants.MaxChanelName, MinimumLength=3)]
|
||||
[StringLengthAttribute(ChatHubConstants.MaxChanelName, MinimumLength=3)]
|
||||
public string Name { get; set;}
|
||||
|
||||
public string OwnerId { get; set; }
|
||||
|
@ -2,6 +2,12 @@ using System.Collections.Generic;
|
||||
using Yavsc.Models.Chat;
|
||||
|
||||
namespace Yavsc.ViewModels.Chat {
|
||||
|
||||
public class ChannelShortInfo {
|
||||
public string RoomName {get; set;}
|
||||
public string Topic { get; set; }
|
||||
}
|
||||
|
||||
public class ChatUserInfo : IChatUserInfo
|
||||
{
|
||||
|
||||
|
@ -7,7 +7,7 @@ using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.ViewModels.Chat;
|
||||
|
||||
using Yavsc.Services;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
@ -17,11 +17,14 @@ namespace Yavsc.Controllers
|
||||
{
|
||||
ApplicationDbContext dbContext;
|
||||
UserManager<ApplicationUser> userManager;
|
||||
private IConnexionManager _cxManager;
|
||||
public ChatApiController(ApplicationDbContext dbContext,
|
||||
UserManager<ApplicationUser> userManager)
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IConnexionManager cxManager)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.userManager = userManager;
|
||||
_cxManager = cxManager;
|
||||
}
|
||||
|
||||
[HttpGet("users")]
|
||||
@ -86,10 +89,6 @@ namespace Yavsc.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
public class ChannelShortInfo {
|
||||
public string RoomName {get; set;}
|
||||
public string Topic { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get firsts 10 biggest channels having
|
||||
@ -100,7 +99,7 @@ namespace Yavsc.Controllers
|
||||
[HttpGet("chanlist/{chanNamePrefix}")]
|
||||
public IActionResult GetChanList([FromRoute] string chanNamePrefix)
|
||||
{
|
||||
var list = ChatHub.Channels.Where(c => c.Key.StartsWith(chanNamePrefix)).OrderByDescending(c=>c.Value.Users.Count).Select(c=>new ChannelShortInfo { RoomName= c.Key, Topic = c.Value.Topic }).Take(10);
|
||||
var list = _cxManager.ListChannels(chanNamePrefix);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
@ -111,8 +110,7 @@ namespace Yavsc.Controllers
|
||||
[HttpGet("chanlist")]
|
||||
public IActionResult GetChanList()
|
||||
{
|
||||
return Ok(ChatHub.Channels.OrderByDescending(c=>c.Value.Users.Count).Select(c=> new ChannelShortInfo { RoomName= c.Key, Topic = c.Value.Topic })
|
||||
.Take(10));
|
||||
return Ok(_cxManager.ListChannels(null));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,16 +31,21 @@ using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Models;
|
||||
using Models.Chat;
|
||||
using Yavsc.Abstract.Chat;
|
||||
using Yavsc.Services;
|
||||
|
||||
public partial class ChatHub : Hub, IDisposable
|
||||
{
|
||||
// TODO externalize connexion and room presence management
|
||||
|
||||
ApplicationDbContext _dbContext;
|
||||
private IConnexionManager _cxManager;
|
||||
private IStringLocalizer _localizer;
|
||||
ILogger _logger;
|
||||
public static ConcurrentDictionary<string, string> ChatUserNames = new ConcurrentDictionary<string, string>();
|
||||
public static ConcurrentDictionary<string, ChatRoomInfo> Channels = new ConcurrentDictionary<string, ChatRoomInfo>();
|
||||
|
||||
public ChatHub()
|
||||
{
|
||||
@ -51,24 +56,36 @@ namespace Yavsc
|
||||
|
||||
var stringLocFactory = scope.ServiceProvider.GetService<IStringLocalizerFactory>();
|
||||
_localizer = stringLocFactory.Create(typeof(ChatHub));
|
||||
|
||||
_cxManager = scope.ServiceProvider.GetService<IConnexionManager>();
|
||||
_cxManager.SetErrorHandler ((context, error) =>
|
||||
{
|
||||
Clients.Caller.notifyUser(NotificationTypes.Error, context, error);
|
||||
});
|
||||
_logger = loggerFactory.CreateLogger<ChatHub>();
|
||||
}
|
||||
|
||||
void SetUserName(string cxId, string userName)
|
||||
{
|
||||
_cxManager.SetUserName( cxId, userName);
|
||||
}
|
||||
|
||||
public override async Task OnConnected()
|
||||
{
|
||||
bool isAuth = false;
|
||||
bool isCop = false;
|
||||
string userName = setUserName();
|
||||
if (Context.User != null)
|
||||
{
|
||||
isAuth = Context.User.Identity.IsAuthenticated;
|
||||
|
||||
var group = isAuth ?
|
||||
Constants.HubGroupAuthenticated : Constants.HubGroupAnonymous;
|
||||
ChatHubConstants.HubGroupAuthenticated : ChatHubConstants.HubGroupAnonymous;
|
||||
// Log ("Cx: " + group);
|
||||
await Groups.Add(Context.ConnectionId, group);
|
||||
if (isAuth)
|
||||
{
|
||||
_logger.LogInformation(_localizer.GetString(Constants.LabAuthChatUser));
|
||||
_logger.LogInformation(_localizer.GetString(ChatHubConstants.LabAuthChatUser));
|
||||
|
||||
var userId = _dbContext.Users.First(u => u.UserName == userName).Id;
|
||||
|
||||
@ -88,11 +105,16 @@ namespace Yavsc
|
||||
Connected = true
|
||||
});
|
||||
_dbContext.SaveChanges();
|
||||
Clients.Group(Constants.HubGroupFollowingPrefix + userId).notifyuser(NotificationTypes.Connected, userName, null);
|
||||
Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).notifyuser(NotificationTypes.Connected, userName, null);
|
||||
isCop = Context.User.IsInRole(Constants.AdminGroupName) ;
|
||||
if (isCop)
|
||||
{
|
||||
await Groups.Add(Context.ConnectionId, ChatHubConstants.HubGroupCops);
|
||||
}
|
||||
|
||||
foreach (var uid in _dbContext.CircleMembers.Select(m => m.MemberId))
|
||||
{
|
||||
await Groups.Add(Context.ConnectionId, Constants.HubGroupFollowingPrefix + uid);
|
||||
await Groups.Add(Context.ConnectionId, ChatHubConstants.HubGroupFollowingPrefix + uid);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -103,8 +125,9 @@ namespace Yavsc
|
||||
}
|
||||
else
|
||||
{
|
||||
await Groups.Add(Context.ConnectionId, Constants.HubGroupAnonymous);
|
||||
await Groups.Add(Context.ConnectionId, ChatHubConstants.HubGroupAnonymous);
|
||||
}
|
||||
_cxManager.OnConnected(userName, isCop);
|
||||
await base.OnConnected();
|
||||
}
|
||||
string setUserName()
|
||||
@ -112,15 +135,15 @@ namespace Yavsc
|
||||
if (Context.User != null)
|
||||
if (Context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
ChatUserNames[Context.ConnectionId] = Context.User.Identity.Name;
|
||||
SetUserName(Context.ConnectionId, Context.User.Identity.Name);
|
||||
return Context.User.Identity.Name;
|
||||
}
|
||||
anonymousSequence++;
|
||||
|
||||
var queryUname = Context.Request.QueryString[Constants.KeyParamChatUserName];
|
||||
var queryUname = Context.Request.QueryString[ChatHubConstants.KeyParamChatUserName];
|
||||
|
||||
var aname = $"{Constants.AnonymousUserNamePrefix}{queryUname}{anonymousSequence}";
|
||||
ChatUserNames[Context.ConnectionId] = aname;
|
||||
var aname = $"{ChatHubConstants.AnonymousUserNamePrefix}{queryUname}{anonymousSequence}";
|
||||
SetUserName(Context.ConnectionId, aname);
|
||||
return aname;
|
||||
}
|
||||
|
||||
@ -133,7 +156,7 @@ namespace Yavsc
|
||||
{
|
||||
var user = _dbContext.Users.FirstOrDefault(u => u.UserName == userName);
|
||||
var userId = user.Id;
|
||||
Clients.Group(Constants.HubGroupFollowingPrefix + userId).notifyuser(NotificationTypes.DisConnected, userName, null);
|
||||
Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).notifyuser(NotificationTypes.DisConnected, userName, null);
|
||||
|
||||
var cx = _dbContext.ChatConnection.SingleOrDefault(c => c.ConnectionId == Context.ConnectionId);
|
||||
if (cx != null)
|
||||
@ -144,7 +167,7 @@ namespace Yavsc
|
||||
else
|
||||
_logger.LogError($"Could not remove user cx {Context.ConnectionId}");
|
||||
}
|
||||
Abort();
|
||||
_cxManager.Abort(Context.ConnectionId);
|
||||
return base.OnDisconnected(stopCalled);
|
||||
}
|
||||
|
||||
@ -179,12 +202,12 @@ namespace Yavsc
|
||||
public void Nick(string nickName)
|
||||
{
|
||||
var candidate = "?" + nickName;
|
||||
if (ChatUserNames.Any(u => u.Value == candidate))
|
||||
if (_cxManager.IsConnected(candidate))
|
||||
{
|
||||
Clients.Caller.notifyUser(NotificationTypes.ExistingUserName, nickName, "aborting");
|
||||
return;
|
||||
}
|
||||
ChatUserNames[Context.ConnectionId] = "?" + nickName;
|
||||
_cxManager.SetUserName( Context.ConnectionId, candidate);
|
||||
}
|
||||
|
||||
public void JoinAsync(string roomName)
|
||||
@ -192,62 +215,36 @@ namespace Yavsc
|
||||
var info = Join(roomName);
|
||||
Clients.Caller.joint(info);
|
||||
}
|
||||
bool IsPresent(string roomName, string userName)
|
||||
{
|
||||
return _cxManager.IsPresent(roomName, userName);
|
||||
}
|
||||
|
||||
public ChatRoomInfo Join(string roomName)
|
||||
{
|
||||
var userName = ChatUserNames[Context.ConnectionId];
|
||||
var roomGroupName = Constants.HubGroupRomsPrefix + roomName;
|
||||
|
||||
var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
|
||||
var user = _cxManager.GetUserName(Context.ConnectionId);
|
||||
Groups.Add(Context.ConnectionId, roomGroupName);
|
||||
ChatRoomInfo chanInfo;
|
||||
if (Channels.ContainsKey(roomName))
|
||||
if (!_cxManager.IsPresent(roomName, user))
|
||||
{
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (chanInfo.Users.ContainsKey(Context.ConnectionId))
|
||||
_logger.LogWarning("user already joint.");
|
||||
else
|
||||
{
|
||||
chanInfo.Users.Add(Context.ConnectionId, userName);
|
||||
Groups.Add(Context.ConnectionId, roomGroupName);
|
||||
Clients.Caller.joint(chanInfo);
|
||||
Clients.Group(Constants.HubGroupRomsPrefix + roomName).notifyRoom(NotificationTypes.UserJoin, roomName, userName);
|
||||
return chanInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("room seemd to be avaible ... but we could get no info on it.");
|
||||
Clients.Caller.notifyRoom(NotificationTypes.Error, roomName, "join get chan failed ...");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
chanInfo = new ChatRoomInfo();
|
||||
chanInfo.Users.Add(Context.ConnectionId, userName);
|
||||
chanInfo = _cxManager.Join(roomName, user);
|
||||
Clients.Group(roomGroupName).notifyRoom(NotificationTypes.UserJoin, roomName, user);
|
||||
} else{
|
||||
// in case in an additional connection,
|
||||
// one only send info on room without
|
||||
// warning any other user.
|
||||
_cxManager.TryGetChanInfo(roomName, out chanInfo);
|
||||
}
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
chanInfo.Topic = room.Topic;
|
||||
chanInfo.Name = room.Name;
|
||||
}
|
||||
else
|
||||
{ // a first join, we create it.
|
||||
chanInfo.Name = roomName;
|
||||
chanInfo.Topic = "<just created>";
|
||||
}
|
||||
|
||||
if (Channels.TryAdd(roomName, chanInfo))
|
||||
{
|
||||
Groups.Add(Context.ConnectionId, roomGroupName);
|
||||
return (chanInfo);
|
||||
}
|
||||
else _logger.LogError("Chan create failed unexpectly...");
|
||||
return null;
|
||||
// FIXME useless : Mobiles should also reveive the returned value
|
||||
Clients.Caller.joint(chanInfo);
|
||||
|
||||
return chanInfo;
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
public void Register(string room)
|
||||
public void Register([Required] string room)
|
||||
{
|
||||
var existent = _dbContext.ChatRoom.Any(r => r.Name == room);
|
||||
if (existent)
|
||||
@ -257,9 +254,10 @@ namespace Yavsc
|
||||
}
|
||||
string userName = Context.User.Identity.Name;
|
||||
var user = _dbContext.Users.FirstOrDefault(u => u.UserName == userName);
|
||||
|
||||
var newroom = new ChatRoom { Name = room, OwnerId = user.Id };
|
||||
ChatRoomInfo chanInfo;
|
||||
if (Channels.TryGetValue(room, out chanInfo))
|
||||
if (_cxManager.TryGetChanInfo(room, out chanInfo))
|
||||
{
|
||||
// TODO get and require some admin status for current user on this chan
|
||||
newroom.Topic = chanInfo.Topic;
|
||||
@ -269,80 +267,87 @@ namespace Yavsc
|
||||
_dbContext.ChatRoom.Add(newroom);
|
||||
_dbContext.SaveChanges(user.Id);
|
||||
}
|
||||
|
||||
/** TODO chan register on server command
|
||||
room = new ChatRoom { Name = roomName, OwnerId = uid };
|
||||
_dbContext.ChatRoom.Add(room);
|
||||
_dbContext.SaveChanges(uid);
|
||||
room.LatestJoinPart = DateTime.Now;
|
||||
chanInfo.Topic = room.Topic;
|
||||
*/
|
||||
|
||||
|
||||
public void Part(string roomName, string reason)
|
||||
public void KickBan([Required] string roomName, [Required] string userName, [Required] string reason)
|
||||
{
|
||||
Kick(roomName, userName, reason);
|
||||
Ban(roomName, userName, reason);
|
||||
}
|
||||
public void Kick([Required] string roomName, [Required] string userName, [Required] string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
|
||||
if (_cxManager.TryGetChanInfo(roomName, out chanInfo))
|
||||
{
|
||||
var roomGroupName = Constants.HubGroupRomsPrefix + roomName;
|
||||
if (!chanInfo.Users.ContainsKey(Context.ConnectionId))
|
||||
if (!_cxManager.IsPresent(roomName,userName))
|
||||
{
|
||||
NotifyRoomError(roomName, "you didn't join.");
|
||||
NotifyErrorToCallerInRoom(roomName, $"{userName} was not found in {roomName}.");
|
||||
return;
|
||||
}
|
||||
Groups.Remove(Context.ConnectionId, roomGroupName);
|
||||
var group = Clients.Group(roomGroupName);
|
||||
var username = ChatUserNames[Context.ConnectionId];
|
||||
group.notifyRoom(NotificationTypes.UserPart, roomName, $"{username}: {reason}");
|
||||
|
||||
chanInfo.Users.Remove(Context.ConnectionId);
|
||||
ChatRoomInfo deadchanInfo;
|
||||
if (chanInfo.Users.Count == 0)
|
||||
if (Channels.TryRemove(roomName, out deadchanInfo))
|
||||
{
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
room.LatestJoinPart = DateTime.Now;
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyRoomError(roomName, $"could not join: no such room");
|
||||
// in case of Kick returned false, being not allowed to, or for what ever other else failure,
|
||||
// the error handler will send an error message while handling the error.
|
||||
if (!_cxManager.Kick(Context.ConnectionId, userName, roomName, reason)) return;
|
||||
}
|
||||
var ukeys = _cxManager.GetConnexionIds(userName);
|
||||
|
||||
foreach(var ukey in ukeys)
|
||||
Groups.Remove(ukey, roomGroupName);
|
||||
Clients.Group(roomGroupName).notifyRoom(NotificationTypes.Kick, roomName, $"{userName}: {reason}");
|
||||
}
|
||||
|
||||
void NotifyRoomError(string room, string reason)
|
||||
public void Ban([Required] string roomName, [Required] string userName, [Required] string reason)
|
||||
{
|
||||
var cxIds = _cxManager.GetConnexionIds(userName);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public void Gline([Required] string userName, [Required] string reason)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public void Part([Required] string roomName, [Required] string reason)
|
||||
{
|
||||
if (_cxManager.Part(Context.ConnectionId, roomName, reason))
|
||||
{
|
||||
var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
|
||||
var group = Clients.Group(roomGroupName);
|
||||
var userName = _cxManager.GetUserName(Context.ConnectionId);
|
||||
group.notifyRoom(NotificationTypes.UserPart, roomName, $"{userName}: {reason}");
|
||||
Groups.Remove(Context.ConnectionId, roomGroupName);
|
||||
}
|
||||
else {
|
||||
_logger.LogError("Could not part");
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyErrorToCallerInRoom(string room, string reason)
|
||||
{
|
||||
Clients.Caller.notifyUser(NotificationTypes.Error, room, reason);
|
||||
}
|
||||
|
||||
|
||||
public void Send(string roomName, string message)
|
||||
|
||||
public void Send([Required] string roomName, [Required] string message)
|
||||
{
|
||||
var groupname = Constants.HubGroupRomsPrefix + roomName;
|
||||
ChatRoomInfo chanInfo;
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
var groupname = ChatHubConstants.HubGroupRomsPrefix + roomName;
|
||||
ChatRoomInfo chanInfo ;
|
||||
if (!_cxManager.TryGetChanInfo(roomName, out chanInfo))
|
||||
{
|
||||
if (!chanInfo.Users.ContainsKey(Context.ConnectionId))
|
||||
{
|
||||
var notSentMsg = $"could not send to channel ({roomName}) (not joint)";
|
||||
Clients.Caller.notifyUser(NotificationTypes.Error, roomName, notSentMsg);
|
||||
return;
|
||||
}
|
||||
string uname = ChatUserNames[Context.ConnectionId];
|
||||
Clients.Group(groupname).addMessage(uname, roomName, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
var noChanMsg = $"could not send to channel ({roomName}) (no such chan)";
|
||||
var noChanMsg = _localizer.GetString(ChatHubConstants.LabNoSuchChan);
|
||||
Clients.Caller.notifyUser(NotificationTypes.Error, roomName, noChanMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
var userName = _cxManager.GetUserName(Context.ConnectionId);
|
||||
if (!chanInfo.Users.Contains(userName))
|
||||
{
|
||||
var notSentMsg = _localizer.GetString(ChatHubConstants.LabnoJoinNoSend);
|
||||
Clients.Caller.notifyUser(NotificationTypes.Error, roomName, notSentMsg);
|
||||
return;
|
||||
}
|
||||
Clients.Group(groupname).addMessage(userName, roomName, message);
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
public void SendPV(string userName, string message)
|
||||
public void SendPV([Required] string userName, [Required] string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
@ -365,7 +370,7 @@ namespace Yavsc
|
||||
return;
|
||||
}
|
||||
}
|
||||
var cxIds = ChatUserNames.Where(name => name.Value == userName).Select(name => name.Key);
|
||||
var cxIds = _cxManager.GetConnexionIds(userName);
|
||||
|
||||
foreach (var connectionId in cxIds)
|
||||
{
|
||||
@ -376,19 +381,13 @@ namespace Yavsc
|
||||
|
||||
[Authorize]
|
||||
|
||||
public void SendStream(string connectionId, long streamId, string message)
|
||||
public void SendStream([Required] string connectionId, long streamId, [Required] string message)
|
||||
{
|
||||
var sender = Context.User.Identity.Name;
|
||||
var cli = Clients.Client(connectionId);
|
||||
cli.addStreamInfo(sender, streamId, message);
|
||||
}
|
||||
|
||||
void Abort()
|
||||
{
|
||||
string cxId;
|
||||
if (!ChatUserNames.TryRemove(Context.ConnectionId, out cxId))
|
||||
_logger.LogError($"Could not remove user cx {Context.ConnectionId}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,12 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
public partial class ChatHub
|
||||
public class ChatRoomInfo
|
||||
{
|
||||
public class ChatRoomInfo
|
||||
{
|
||||
public string Name;
|
||||
public Dictionary<string, string> Users = new Dictionary<string, string>();
|
||||
public string Topic;
|
||||
}
|
||||
public string Name;
|
||||
public List<string> Users = new List<string>();
|
||||
public List<string> Ops = new List<string>();
|
||||
public List<string> Hops = new List<string>();
|
||||
public string Topic;
|
||||
}
|
||||
}
|
||||
|
66
src/Yavsc/Resources/Yavsc.ChatHub.en.resx
Normal file
66
src/Yavsc/Resources/Yavsc.ChatHub.en.resx
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<!--
|
||||
route name for the api controller used to tag the 'BlogPost' entity
|
||||
-->
|
||||
<data name="Authenticated chat user"><value>Authenticated chat user</value></data>
|
||||
<data name="LabnoJoinNoSend">could not send to channel (not joint)</data>
|
||||
</root>
|
66
src/Yavsc/Resources/Yavsc.ChatHub.fr.resx
Normal file
66
src/Yavsc/Resources/Yavsc.ChatHub.fr.resx
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<!--
|
||||
route name for the api controller used to tag the 'BlogPost' entity
|
||||
-->
|
||||
<data name="Authenticated chat user"><value>Utilisateur de chat authentifié</value></data>
|
||||
<data name="LabnoJoinNoSend"><value>Envoi impossible: vous devez joindre le canal pour y contribuer.</value></data>
|
||||
</root>
|
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<!--
|
||||
route name for the api controller used to tag the 'BlogPost' entity
|
||||
-->
|
||||
<data name="just created by "><value>Vient d'être créé par </value></data>
|
||||
<data name="No such user"><value>pas de tel utilisateur</value></data>
|
||||
<data name="you're no op."><value>Vous n'êtes pas op.</value></data>
|
||||
</root>
|
333
src/Yavsc/Services/ChatHubConnexionManager.cs
Normal file
333
src/Yavsc/Services/ChatHubConnexionManager.cs
Normal file
@ -0,0 +1,333 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Yavsc.Abstract.Chat;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.ViewModels.Chat;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Connexion Manager
|
||||
/// </summary>
|
||||
public class HubConnectionManager : IConnexionManager
|
||||
{
|
||||
ILogger _logger;
|
||||
|
||||
Action<string, string> _errorHandler;
|
||||
|
||||
/// <summary>
|
||||
/// by cx id
|
||||
/// </summary>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <returns></returns>
|
||||
|
||||
static ConcurrentDictionary<string, string> ChatUserNames = new ConcurrentDictionary<string, string>();
|
||||
/// <summary>
|
||||
/// by user name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static ConcurrentDictionary<string, List<string>> ChatCxIds = new ConcurrentDictionary<string, List<string>>();
|
||||
|
||||
/// <summary>
|
||||
/// by user name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static ConcurrentDictionary<string, List<string>> ChatRoomPresence = new ConcurrentDictionary<string, List<string>>();
|
||||
static ConcurrentDictionary<string, bool> _isCop = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
public static ConcurrentDictionary<string, ChatRoomInfo> Channels = new ConcurrentDictionary<string, ChatRoomInfo>();
|
||||
private ApplicationDbContext _dbContext;
|
||||
private IStringLocalizer _localizer;
|
||||
|
||||
public HubConnectionManager()
|
||||
{
|
||||
var scope = Startup.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
|
||||
_dbContext = scope.ServiceProvider.GetService<ApplicationDbContext>();
|
||||
var loggerFactory = scope.ServiceProvider.GetService<ILoggerFactory>();
|
||||
_logger = loggerFactory.CreateLogger<HubConnectionManager>();
|
||||
var stringLocFactory = scope.ServiceProvider.GetService<IStringLocalizerFactory>();
|
||||
_localizer = stringLocFactory.Create(typeof(HubConnectionManager));
|
||||
}
|
||||
|
||||
public void SetUserName(string cxId, string userName)
|
||||
{
|
||||
string oldUname;
|
||||
if (ChatUserNames.TryGetValue(cxId, out oldUname))
|
||||
{
|
||||
// this is a rename
|
||||
if (oldUname == userName) return;
|
||||
ChatCxIds[userName] = ChatCxIds[oldUname];
|
||||
ChatCxIds[oldUname] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a connexion
|
||||
ChatCxIds[userName] = new List<string>() { cxId };
|
||||
}
|
||||
ChatUserNames[cxId] = userName;
|
||||
}
|
||||
|
||||
public void OnConnected(string userName, bool isCop)
|
||||
{
|
||||
ChatRoomPresence[userName] = new List<string>();
|
||||
_isCop[userName] = isCop;
|
||||
}
|
||||
|
||||
public bool IsConnected(string candidate)
|
||||
{
|
||||
return ChatRoomPresence[candidate] != null;
|
||||
}
|
||||
|
||||
public bool IsPresent(string roomName, string userName)
|
||||
{
|
||||
return ChatRoomPresence[userName].Contains(roomName);
|
||||
}
|
||||
|
||||
public bool isCop(string userName)
|
||||
{
|
||||
return _isCop[userName];
|
||||
}
|
||||
public void Abort(string connectionId)
|
||||
{
|
||||
string uname;
|
||||
|
||||
if (!ChatUserNames.TryRemove(connectionId, out uname))
|
||||
_logger.LogError($"Could not remove user name for cx {connectionId}");
|
||||
else
|
||||
{
|
||||
List<string> cxIds;
|
||||
if (ChatCxIds.TryGetValue(uname, out cxIds))
|
||||
{
|
||||
cxIds.Remove(connectionId);
|
||||
}
|
||||
else
|
||||
_logger.LogError($"Could not remove user cx {connectionId}");
|
||||
|
||||
foreach (var room in ChatRoomPresence[uname])
|
||||
{
|
||||
Part(connectionId, room, "connexion aborted");
|
||||
}
|
||||
ChatRoomPresence[uname] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Part(string cxId, string roomName, string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
var userName = ChatUserNames[cxId];
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (!chanInfo.Users.Contains(userName))
|
||||
{
|
||||
// TODO NotifyErrorToCaller(roomName, "you didn't join.");
|
||||
return false;
|
||||
}
|
||||
chanInfo.Users.Remove(userName);
|
||||
if (chanInfo.Users.Count == 0)
|
||||
{
|
||||
ChatRoomInfo deadchanInfo;
|
||||
if (Channels.TryRemove(roomName, out deadchanInfo))
|
||||
{
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
room.LatestJoinPart = DateTime.Now;
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
// TODO NotifyErrorToCallerInRoom(roomName, $"user could not part: no such room");
|
||||
}
|
||||
}
|
||||
|
||||
public ChatRoomInfo Join(string roomName, string userName)
|
||||
{
|
||||
_logger.LogInformation($"Join: {userName}=>{roomName}");
|
||||
ChatRoomInfo chanInfo;
|
||||
// if channel already is open
|
||||
if (Channels.ContainsKey(roomName))
|
||||
{
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (IsPresent(roomName, userName))
|
||||
{
|
||||
// TODO implement some unique connection sharing protocol
|
||||
// between all terminals from a single user.
|
||||
return chanInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isCop(userName))
|
||||
{
|
||||
chanInfo.Ops.Add(userName);
|
||||
}
|
||||
else{
|
||||
chanInfo.Users.Add(userName);
|
||||
}
|
||||
_logger.LogInformation($"existing room joint: {userName}=>{roomName}");
|
||||
ChatRoomPresence[userName].Add(roomName);
|
||||
return chanInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = "room seemd to be avaible ... but we could get no info on it.";
|
||||
_errorHandler(roomName, msg);
|
||||
_logger.LogError(msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// room was closed.
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
chanInfo = new ChatRoomInfo();
|
||||
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
chanInfo.Topic = room.Topic;
|
||||
chanInfo.Name = room.Name;
|
||||
chanInfo.Users.Add(userName);
|
||||
}
|
||||
else
|
||||
{ // a first join, we create it.
|
||||
chanInfo.Name = roomName;
|
||||
chanInfo.Topic = _localizer.GetString(ChatHubConstants.JustCreatedBy)+userName;
|
||||
chanInfo.Ops.Add(userName);
|
||||
}
|
||||
|
||||
if (Channels.TryAdd(roomName, chanInfo))
|
||||
{
|
||||
_logger.LogInformation("new room joint");
|
||||
return (chanInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = "Chan create failed unexpectly...";
|
||||
_errorHandler(roomName, msg);
|
||||
_logger.LogError(msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Op(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Deop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Hop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Dehop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetUserName(string cxId)
|
||||
{
|
||||
return ChatUserNames[cxId];
|
||||
}
|
||||
|
||||
public bool TryGetChanInfo(string room, out ChatRoomInfo chanInfo)
|
||||
{
|
||||
return Channels.TryGetValue(room, out chanInfo);
|
||||
}
|
||||
|
||||
public IEnumerable<ChannelShortInfo> ListChannels(string pattern)
|
||||
{
|
||||
if (pattern != null)
|
||||
return Channels.Where(c => c.Key.Contains(pattern))
|
||||
.OrderByDescending(c => c.Value.Users.Count).Select(c => new ChannelShortInfo { RoomName = c.Key, Topic = c.Value.Topic }).Take(10);
|
||||
|
||||
return Channels
|
||||
.OrderByDescending(c => c.Value.Users.Count).Select(c => new ChannelShortInfo { RoomName = c.Key, Topic = c.Value.Topic }).Take(10);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetConnexionIds(string userName)
|
||||
{
|
||||
return ChatCxIds[userName];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set on error as string couple action
|
||||
/// </summary>
|
||||
/// <param name="errorHandler"></param>
|
||||
public void SetErrorHandler(Action<string, string> errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
public bool Kick(string cxId, string userName, string roomName, string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
if (!Channels.ContainsKey(roomName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchChan));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchChan));
|
||||
return false;
|
||||
}
|
||||
|
||||
var kickerName = GetUserName(cxId);
|
||||
if (!chanInfo.Ops.Contains(kickerName))
|
||||
if (!chanInfo.Hops.Contains(kickerName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabYouNotOp));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPresent(roomName, userName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchUser));
|
||||
return false;
|
||||
}
|
||||
if (chanInfo.Hops.Contains(kickerName))
|
||||
if (chanInfo.Ops.Contains(userName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.HopWontKickOp));
|
||||
return false;
|
||||
}
|
||||
if (isCop(userName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.NoKickOnCop));
|
||||
return false;
|
||||
}
|
||||
|
||||
// all good, time to kick :-)
|
||||
|
||||
if (chanInfo.Users.Contains(userName))
|
||||
chanInfo.Users.Remove(userName);
|
||||
|
||||
else if (chanInfo.Ops.Contains(userName))
|
||||
chanInfo.Ops.Remove(userName);
|
||||
|
||||
else if (chanInfo.Hops.Contains(userName))
|
||||
chanInfo.Hops.Remove(userName);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
34
src/Yavsc/Services/IConnexionManager.cs
Normal file
34
src/Yavsc/Services/IConnexionManager.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Yavsc.ViewModels.Chat;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
public interface IConnexionManager {
|
||||
void SetUserName(string cxId, string userName);
|
||||
|
||||
string GetUserName (string cxId);
|
||||
void OnConnected(string userName, bool isCop);
|
||||
bool IsConnected(string candidate);
|
||||
bool IsPresent(string roomName, string userName);
|
||||
|
||||
ChatRoomInfo Join(string roomName, string userName);
|
||||
|
||||
bool Part(string cxId, string roomName, string reason);
|
||||
|
||||
bool Kick(string cxId, string userName, string roomName, string reason);
|
||||
|
||||
bool Op(string roomName, string userName);
|
||||
bool Deop(string roomName, string userName);
|
||||
bool Hop(string roomName, string userName);
|
||||
bool Dehop(string roomName, string userName);
|
||||
bool TryGetChanInfo(string room, out ChatRoomInfo chanInfo);
|
||||
|
||||
IEnumerable<string> GetConnexionIds(string userName);
|
||||
void Abort(string connectionId);
|
||||
|
||||
void SetErrorHandler(Action<string,string> errorHandler);
|
||||
IEnumerable<ChannelShortInfo> ListChannels(string pattern);
|
||||
|
||||
}
|
||||
}
|
@ -22,12 +22,15 @@ namespace Yavsc.Services
|
||||
private IHubContext hubContext;
|
||||
ApplicationDbContext _dbContext;
|
||||
|
||||
IConnexionManager _cxManager;
|
||||
|
||||
public YavscMessageSender(
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<SiteSettings> sitesOptions,
|
||||
IOptions<SmtpSettings> smtpOptions,
|
||||
IEmailSender emailSender,
|
||||
ApplicationDbContext dbContext
|
||||
ApplicationDbContext dbContext,
|
||||
IConnexionManager cxManager
|
||||
)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<MailSender>();
|
||||
@ -35,7 +38,9 @@ namespace Yavsc.Services
|
||||
siteSettings = sitesOptions?.Value;
|
||||
hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
|
||||
_dbContext = dbContext;
|
||||
_cxManager = cxManager;
|
||||
}
|
||||
|
||||
public async Task <MessageWithPayloadResponse> NotifyEvent<Event>
|
||||
(IEnumerable<string> userIds, Event ev)
|
||||
where Event : IEvent
|
||||
@ -82,7 +87,7 @@ namespace Yavsc.Services
|
||||
|
||||
var body = ev.CreateBody();
|
||||
|
||||
var cxids = ChatHub.ChatUserNames.Where (kv=>kv.Value == user.UserName).Select(kv => kv.Key).ToArray();
|
||||
var cxids = _cxManager.GetConnexionIds(user.UserName).ToArray();
|
||||
|
||||
if (cxids.Length==0)
|
||||
{
|
||||
|
@ -135,7 +135,8 @@ namespace Yavsc
|
||||
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<GoogleAuthSettings>), typeof(OptionsManager<GoogleAuthSettings>)));
|
||||
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<CompanyInfoSettings>), typeof(OptionsManager<CompanyInfoSettings>)));
|
||||
services.Add(ServiceDescriptor.Singleton(typeof(IOptions<RequestLocalizationOptions>), typeof(OptionsManager<RequestLocalizationOptions>)));
|
||||
|
||||
|
||||
|
||||
services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
var supportedCultures = new[]
|
||||
@ -240,6 +241,7 @@ namespace Yavsc
|
||||
services.AddSingleton<IAuthorizationHandler, PostUserFileHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, ViewFileHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, SendMessageHandler>();
|
||||
services.AddSingleton<IConnexionManager, HubConnectionManager>();
|
||||
|
||||
services.AddMvc(config =>
|
||||
{
|
||||
@ -398,7 +400,7 @@ namespace Yavsc
|
||||
}
|
||||
}
|
||||
// before fixing the security protocol, let beleive our lib it's done with it.
|
||||
var cxmgr = ConnectionManager.Instance;
|
||||
var cxmgr = PayPal.Manager.ConnectionManager.Instance;
|
||||
// then, fix it.
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType)0xC00; // Tls12, required by PayPal
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model IEnumerable<Yavsc.Models.Identity.GoogleCloudMobileDeclaration>
|
||||
@model IEnumerable<Yavsc.Models.Identity.DeviceDeclaration>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Index";
|
||||
@ -11,9 +11,6 @@
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.DeclarationDate)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.GCMRegistrationId)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Model)
|
||||
</th>
|
||||
@ -31,9 +28,6 @@
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DeclarationDate)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.GCMRegistrationId)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Model)
|
||||
</td>
|
@ -136,7 +136,7 @@
|
||||
</div>
|
||||
</environment>
|
||||
|
||||
<p class="small">Yavsc - Copyright © 2015 - 2018 Paul Schneider</p>
|
||||
<p class="small">Yavsc - Copyright © 2015 - 2019 Paul Schneider</p>
|
||||
</footer>
|
||||
@RenderSection("scripts", required: false)
|
||||
</body>
|
||||
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"Dnx": {
|
||||
"enabled": true,
|
||||
"enablePackageRestore": false,
|
||||
"projects": "../../src/**/project.json;../../test/**/project.json"
|
||||
},
|
||||
"MSBuild": {
|
||||
"enabled": false
|
||||
},
|
||||
"DotNet": {
|
||||
"enabled": false,
|
||||
"enablePackageRestore": false,
|
||||
"script": {
|
||||
"enableScriptNuGetReferences": true,
|
||||
"defaultTargetFramework": "dnx451"
|
||||
}
|
||||
},
|
||||
"packages": "packages"
|
||||
}
|
@ -245,7 +245,7 @@ window.ChatHubHandler = (function ($) {
|
||||
|
||||
var addChatUser = function (uname) {
|
||||
|
||||
$('#u' + uname).remove();
|
||||
$('#u_' + uname).remove();
|
||||
// ulist.remove("li.user[data='"+uname+"']");
|
||||
|
||||
$('<li class="user"><img src="/Avatars/' + uname + '.xs.png"> ' + uname + '</li>')
|
||||
|
1
src/omnisharp.log
Normal file
1
src/omnisharp.log
Normal file
@ -0,0 +1 @@
|
||||
["-s","/home/paul/workspace/yavsc/src/Yavsc","--hostPID","7920","DotNet:enablePackageRestore=false","--encoding","utf-8","--loglevel","warning","FileOptions:SystemExcludeSearchPatterns:0=**/.git","FileOptions:SystemExcludeSearchPatterns:1=**/.svn","FileOptions:SystemExcludeSearchPatterns:2=**/.hg","FileOptions:SystemExcludeSearchPatterns:3=**/CVS","FileOptions:SystemExcludeSearchPatterns:4=**/.DS_Store"]Store","FileOptions:SystemExcludeSearchPatterns:5=**/bin","FileOptions:SystemExcludeSearchPatterns:6=**/build","FileOptions:SystemExcludeSearchPatterns:7=**/wrap"]
|
Reference in New Issue
Block a user