46 changed files with 325 additions and 12447 deletions
File diff suppressed because it is too large
@ -1,33 +0,0 @@ |
|||||
using LINGYUN.Abp.RealTime.Client; |
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace LINGYUN.Abp.IM.SignalR |
|
||||
{ |
|
||||
public class UserOnlineChecker : IUserOnlineChecker, ITransientDependency |
|
||||
{ |
|
||||
private readonly IOnlineClientManager _onlineClientManager; |
|
||||
|
|
||||
public UserOnlineChecker( |
|
||||
IOnlineClientManager onlineClientManager) |
|
||||
{ |
|
||||
_onlineClientManager = onlineClientManager; |
|
||||
} |
|
||||
|
|
||||
public virtual Task<bool> CheckAsync( |
|
||||
Guid? tenantId, |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
var onlineClients = _onlineClientManager |
|
||||
.GetAllClients(client => client.UserId.Equals(userId)); |
|
||||
|
|
||||
var userOnlined = onlineClients?.Any() == true; |
|
||||
|
|
||||
return Task.FromResult(userOnlined); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class NullUserOnlineChanger : IUserOnlineChanger, ISingletonDependency |
||||
|
{ |
||||
|
public Task ChangeAsync(Guid? tenantId, Guid userId, UserOnlineState state, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class NullUserOnlineChecker : IUserOnlineChecker, ISingletonDependency |
||||
|
{ |
||||
|
public Task<bool> CheckAsync(Guid? tenantId, Guid userId, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return Task.FromResult(false); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,10 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public interface IClient |
|
||||
{ |
|
||||
Task OnConnectedAsync(IOnlineClient client); |
|
||||
Task OnDisconnectedAsync(IOnlineClient client); |
|
||||
} |
|
||||
} |
|
||||
@ -1,28 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public interface IOnlineClient |
|
||||
{ |
|
||||
string ConnectionId { get; } |
|
||||
|
|
||||
string IpAddress { get; } |
|
||||
|
|
||||
Guid? TenantId { get; } |
|
||||
|
|
||||
Guid? UserId { get; } |
|
||||
|
|
||||
string UserAccount { get; } |
|
||||
|
|
||||
string UserName { get; } |
|
||||
|
|
||||
DateTime ConnectTime { get; } |
|
||||
|
|
||||
string[] Roles { get; } |
|
||||
|
|
||||
object this[object key] { get; set; } |
|
||||
|
|
||||
IDictionary<object, object> Properties { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
using JetBrains.Annotations; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq.Expressions; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public interface IOnlineClientManager |
|
||||
{ |
|
||||
event EventHandler<OnlineClientEventArgs> ClientConnected; |
|
||||
|
|
||||
event EventHandler<OnlineClientEventArgs> ClientDisconnected; |
|
||||
|
|
||||
event EventHandler<OnlineUserEventArgs> UserConnected; |
|
||||
|
|
||||
event EventHandler<OnlineUserEventArgs> UserDisconnected; |
|
||||
|
|
||||
void Add(IOnlineClient client); |
|
||||
|
|
||||
bool Remove(string connectionId); |
|
||||
|
|
||||
IOnlineClient GetByConnectionIdOrNull(string connectionId); |
|
||||
|
|
||||
IReadOnlyList<IOnlineClient> GetAllClients(); |
|
||||
|
|
||||
IReadOnlyList<IOnlineClient> GetAllClients(Expression<Func<IOnlineClient, bool>> predicate); |
|
||||
|
|
||||
IReadOnlyList<IOnlineClient> GetAllByContext([NotNull] OnlineClientContext context); |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq.Expressions; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public interface IOnlineClientStore |
|
||||
{ |
|
||||
void Add(IOnlineClient client); |
|
||||
|
|
||||
bool Remove(string connectionId); |
|
||||
|
|
||||
bool TryRemove(string connectionId, out IOnlineClient client); |
|
||||
|
|
||||
bool TryGet(string connectionId, out IOnlineClient client); |
|
||||
|
|
||||
bool Contains(string connectionId); |
|
||||
|
|
||||
IReadOnlyList<IOnlineClient> GetAll(); |
|
||||
|
|
||||
IReadOnlyList<IOnlineClient> GetAll(Expression<Func<IOnlineClient, bool>> predicate); |
|
||||
} |
|
||||
} |
|
||||
@ -1,57 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Concurrent; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.Linq; |
|
||||
using System.Linq.Expressions; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public class InMemoryOnlineClientStore : IOnlineClientStore, ISingletonDependency |
|
||||
{ |
|
||||
protected ConcurrentDictionary<string, IOnlineClient> Clients { get; } |
|
||||
|
|
||||
public InMemoryOnlineClientStore() |
|
||||
{ |
|
||||
Clients = new ConcurrentDictionary<string, IOnlineClient>(); |
|
||||
} |
|
||||
|
|
||||
public void Add(IOnlineClient client) |
|
||||
{ |
|
||||
Clients.AddOrUpdate(client.ConnectionId, client, (s, o) => client); |
|
||||
} |
|
||||
|
|
||||
public bool Remove(string connectionId) |
|
||||
{ |
|
||||
return TryRemove(connectionId, out _); |
|
||||
} |
|
||||
|
|
||||
public bool TryRemove(string connectionId, out IOnlineClient client) |
|
||||
{ |
|
||||
return Clients.TryRemove(connectionId, out client); |
|
||||
} |
|
||||
|
|
||||
public bool TryGet(string connectionId, out IOnlineClient client) |
|
||||
{ |
|
||||
return Clients.TryGetValue(connectionId, out client); |
|
||||
} |
|
||||
|
|
||||
public bool Contains(string connectionId) |
|
||||
{ |
|
||||
return Clients.ContainsKey(connectionId); |
|
||||
} |
|
||||
|
|
||||
public IReadOnlyList<IOnlineClient> GetAll() |
|
||||
{ |
|
||||
return Clients.Values.ToImmutableList(); |
|
||||
} |
|
||||
|
|
||||
public IReadOnlyList<IOnlineClient> GetAll(Expression<Func<IOnlineClient, bool>> predicate) |
|
||||
{ |
|
||||
return Clients.Values |
|
||||
.Where(predicate.Compile()) |
|
||||
.ToImmutableList(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,72 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
[Serializable] |
|
||||
public class OnlineClient : IOnlineClient |
|
||||
{ |
|
||||
public object this[object key] |
|
||||
{ |
|
||||
get { return Properties[key]; } |
|
||||
set { Properties[key] = value; } |
|
||||
} |
|
||||
|
|
||||
public string ConnectionId { get; set; } |
|
||||
|
|
||||
public string IpAddress { get; set; } |
|
||||
|
|
||||
public Guid? TenantId { get; set; } |
|
||||
|
|
||||
public Guid? UserId { get; } |
|
||||
public string UserAccount { get; set; } |
|
||||
|
|
||||
public string UserName { get; set; } |
|
||||
|
|
||||
public string[] Roles { get; set; } |
|
||||
|
|
||||
public DateTime ConnectTime { get; set; } |
|
||||
|
|
||||
private IDictionary<object, object> _properties; |
|
||||
public IDictionary<object, object> Properties |
|
||||
{ |
|
||||
get { return _properties; } |
|
||||
set |
|
||||
{ |
|
||||
if (value == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(value)); |
|
||||
} |
|
||||
|
|
||||
_properties = value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public OnlineClient() |
|
||||
{ |
|
||||
ConnectTime = DateTime.Now; |
|
||||
} |
|
||||
|
|
||||
public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId) |
|
||||
: this() |
|
||||
{ |
|
||||
ConnectionId = connectionId; |
|
||||
IpAddress = ipAddress; |
|
||||
TenantId = tenantId; |
|
||||
UserId = userId; |
|
||||
|
|
||||
Roles = new string[0]; |
|
||||
Properties = new Dictionary<object, object>(); |
|
||||
} |
|
||||
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
return string.Concat( |
|
||||
"-- ConnectionId:", ConnectionId, |
|
||||
"-- Connection Time:", ConnectTime, |
|
||||
"-- IpAddress:", IpAddress ?? "::1", |
|
||||
"-- UserName:", UserName, |
|
||||
"-- TenantId:", TenantId.HasValue ? TenantId.Value.ToString() : "None"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
using System; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public class OnlineClientContext |
|
||||
{ |
|
||||
public Guid? TenantId { get; } |
|
||||
|
|
||||
public Guid UserId { get; } |
|
||||
|
|
||||
public OnlineClientContext(Guid? tenantId, Guid userId) |
|
||||
{ |
|
||||
TenantId = tenantId; |
|
||||
UserId = userId; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
using System; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public class OnlineClientEventArgs : EventArgs |
|
||||
{ |
|
||||
public IOnlineClient Client { get; } |
|
||||
|
|
||||
public OnlineClientEventArgs(IOnlineClient client) |
|
||||
{ |
|
||||
Client = client; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
using JetBrains.Annotations; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public static class OnlineClientExtensions |
|
||||
{ |
|
||||
[CanBeNull] |
|
||||
public static OnlineClientContext ToClientContextOrNull(this IOnlineClient onlineClient) |
|
||||
{ |
|
||||
return onlineClient.UserId.HasValue |
|
||||
? new OnlineClientContext(onlineClient.TenantId, onlineClient.UserId.Value) |
|
||||
: null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,111 +0,0 @@ |
|||||
using JetBrains.Annotations; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.Linq; |
|
||||
using System.Linq.Expressions; |
|
||||
using Volo.Abp; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public class OnlineClientManager : IOnlineClientManager, ISingletonDependency |
|
||||
{ |
|
||||
public event EventHandler<OnlineClientEventArgs> ClientConnected; |
|
||||
public event EventHandler<OnlineClientEventArgs> ClientDisconnected; |
|
||||
|
|
||||
public event EventHandler<OnlineUserEventArgs> UserConnected; |
|
||||
public event EventHandler<OnlineUserEventArgs> UserDisconnected; |
|
||||
|
|
||||
protected IOnlineClientStore Store { get; } |
|
||||
|
|
||||
protected readonly object SyncObj = new object(); |
|
||||
|
|
||||
public OnlineClientManager(IOnlineClientStore store) |
|
||||
{ |
|
||||
Store = store; |
|
||||
} |
|
||||
|
|
||||
public virtual void Add(IOnlineClient client) |
|
||||
{ |
|
||||
lock (SyncObj) |
|
||||
{ |
|
||||
var userWasAlreadyOnline = false; |
|
||||
var context = client.ToClientContextOrNull(); |
|
||||
|
|
||||
if (context != null) |
|
||||
{ |
|
||||
userWasAlreadyOnline = this.IsOnline(context); |
|
||||
} |
|
||||
|
|
||||
Store.Add(client); |
|
||||
|
|
||||
ClientConnected?.Invoke(this, new OnlineClientEventArgs(client)); |
|
||||
|
|
||||
if (context != null && !userWasAlreadyOnline) |
|
||||
{ |
|
||||
UserConnected?.Invoke(this, new OnlineUserEventArgs(context, client)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public virtual bool Remove(string connectionId) |
|
||||
{ |
|
||||
lock (SyncObj) |
|
||||
{ |
|
||||
var result = Store.TryRemove(connectionId, out IOnlineClient client); |
|
||||
if (result) |
|
||||
{ |
|
||||
if (UserDisconnected != null) |
|
||||
{ |
|
||||
var context = client.ToClientContextOrNull(); |
|
||||
|
|
||||
if (context != null && !this.IsOnline(context)) |
|
||||
{ |
|
||||
UserDisconnected.Invoke(this, new OnlineUserEventArgs(context, client)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ClientDisconnected?.Invoke(this, new OnlineClientEventArgs(client)); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public virtual IOnlineClient GetByConnectionIdOrNull(string connectionId) |
|
||||
{ |
|
||||
lock (SyncObj) |
|
||||
{ |
|
||||
if (Store.TryGet(connectionId, out IOnlineClient client)) |
|
||||
{ |
|
||||
return client; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public virtual IReadOnlyList<IOnlineClient> GetAllClients() |
|
||||
{ |
|
||||
return Store.GetAll(); |
|
||||
} |
|
||||
|
|
||||
public virtual IReadOnlyList<IOnlineClient> GetAllClients(Expression<Func<IOnlineClient, bool>> predicate) |
|
||||
{ |
|
||||
return Store.GetAll(predicate); |
|
||||
} |
|
||||
|
|
||||
[NotNull] |
|
||||
public virtual IReadOnlyList<IOnlineClient> GetAllByContext([NotNull] OnlineClientContext context) |
|
||||
{ |
|
||||
Check.NotNull(context, nameof(context)); |
|
||||
|
|
||||
return GetAllClients() |
|
||||
.Where(c => c.TenantId == context.TenantId && c.UserId.Equals(context.UserId)) |
|
||||
.ToImmutableList(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,26 +0,0 @@ |
|||||
using JetBrains.Annotations; |
|
||||
using System.Linq; |
|
||||
using Volo.Abp; |
|
||||
|
|
||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public static class OnlineClientManagerExtensions |
|
||||
{ |
|
||||
public static bool IsOnline( |
|
||||
[NotNull] this IOnlineClientManager onlineClientManager, |
|
||||
[NotNull] OnlineClientContext context) |
|
||||
{ |
|
||||
return onlineClientManager.GetAllByContext(context).Any(); |
|
||||
} |
|
||||
|
|
||||
public static bool Remove( |
|
||||
[NotNull] this IOnlineClientManager onlineClientManager, |
|
||||
[NotNull] IOnlineClient client) |
|
||||
{ |
|
||||
Check.NotNull(onlineClientManager, nameof(onlineClientManager)); |
|
||||
Check.NotNull(client, nameof(client)); |
|
||||
|
|
||||
return onlineClientManager.Remove(client.ConnectionId); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,13 +0,0 @@ |
|||||
namespace LINGYUN.Abp.RealTime.Client |
|
||||
{ |
|
||||
public class OnlineUserEventArgs : OnlineClientEventArgs |
|
||||
{ |
|
||||
public OnlineClientContext Context { get; } |
|
||||
|
|
||||
public OnlineUserEventArgs(OnlineClientContext context, IOnlineClient client) |
|
||||
: base(client) |
|
||||
{ |
|
||||
Context = context; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue