146 lines
5.6 KiB
C#
146 lines
5.6 KiB
C#
|
using SharpChat.Bans;
|
|||
|
using SharpChat.Channels;
|
|||
|
using SharpChat.Configuration;
|
|||
|
using SharpChat.Database;
|
|||
|
using SharpChat.DataProvider;
|
|||
|
using SharpChat.Events;
|
|||
|
using SharpChat.Messages;
|
|||
|
using SharpChat.Messages.Storage;
|
|||
|
using SharpChat.RateLimiting;
|
|||
|
using SharpChat.Sessions;
|
|||
|
using SharpChat.Users;
|
|||
|
using SharpChat.Users.Remote;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
namespace SharpChat {
|
|||
|
public class Context : IDisposable {
|
|||
|
public const int ID_LENGTH = 8;
|
|||
|
public string ServerId { get; }
|
|||
|
|
|||
|
public EventDispatcher Events { get; }
|
|||
|
public SessionManager Sessions { get; }
|
|||
|
public UserManager Users { get; }
|
|||
|
public ChannelManager Channels { get; }
|
|||
|
public ChannelUserRelations ChannelUsers { get; }
|
|||
|
public MessageManager Messages { get; }
|
|||
|
public BanManager Bans { get; }
|
|||
|
|
|||
|
public IDataProvider DataProvider { get; }
|
|||
|
public RateLimitManager RateLimiting { get; }
|
|||
|
|
|||
|
public WelcomeMessage WelcomeMessage { get; }
|
|||
|
|
|||
|
public ChatBot Bot { get; } = new();
|
|||
|
|
|||
|
private Timer BumpTimer { get; }
|
|||
|
|
|||
|
public DateTimeOffset Created { get; }
|
|||
|
|
|||
|
public Context(IConfig config, IDatabaseBackend databaseBackend, IDataProvider dataProvider) {
|
|||
|
if(config == null)
|
|||
|
throw new ArgumentNullException(nameof(config));
|
|||
|
|
|||
|
ServerId = RNG.NextString(ID_LENGTH); // maybe read this from the cfg instead
|
|||
|
Created = DateTimeOffset.Now; // read this from config definitely
|
|||
|
|
|||
|
DatabaseWrapper db = new(databaseBackend ?? throw new ArgumentNullException(nameof(databaseBackend)));
|
|||
|
IMessageStorage msgStore = db.IsNullBackend
|
|||
|
? new MemoryMessageStorage()
|
|||
|
: new ADOMessageStorage(db);
|
|||
|
|
|||
|
Events = new EventDispatcher();
|
|||
|
DataProvider = dataProvider ?? throw new ArgumentNullException(nameof(dataProvider));
|
|||
|
Users = new UserManager(Events);
|
|||
|
Sessions = new SessionManager(Events, Users, config.ScopeTo(@"sessions"), ServerId);
|
|||
|
Messages = new MessageManager(Events, msgStore, config.ScopeTo(@"messages"));
|
|||
|
Channels = new ChannelManager(Events, config, Bot);
|
|||
|
ChannelUsers = new ChannelUserRelations(Events, Channels, Users, Sessions, Messages);
|
|||
|
Bans = new BanManager(Users, DataProvider.BanClient, DataProvider.UserClient, Events);
|
|||
|
RateLimiting = new RateLimitManager(config.ScopeTo(@"rateLimit"));
|
|||
|
|
|||
|
WelcomeMessage = new WelcomeMessage(config.ScopeTo(@"welcome"));
|
|||
|
|
|||
|
Events.AddEventHandler(Sessions);
|
|||
|
Events.ProtectEventHandler(Sessions);
|
|||
|
Events.AddEventHandler(Users);
|
|||
|
Events.ProtectEventHandler(Users);
|
|||
|
Events.AddEventHandler(Channels);
|
|||
|
Events.ProtectEventHandler(Channels);
|
|||
|
Events.AddEventHandler(ChannelUsers);
|
|||
|
Events.ProtectEventHandler(ChannelUsers);
|
|||
|
Events.AddEventHandler(Messages);
|
|||
|
Events.ProtectEventHandler(Messages);
|
|||
|
|
|||
|
Events.StartProcessing();
|
|||
|
|
|||
|
Channels.UpdateChannels();
|
|||
|
|
|||
|
// Should probably not rely on Timers in the future
|
|||
|
BumpTimer = new Timer(e => {
|
|||
|
Logger.Write(@"Nuking dead sessions and bumping remote online status...");
|
|||
|
Sessions.CheckTimeOut();
|
|||
|
|
|||
|
Sessions.GetActiveLocalSessions(sessions => {
|
|||
|
Dictionary<IUser, List<ISession>> data = new();
|
|||
|
|
|||
|
foreach(ISession session in sessions) {
|
|||
|
if(!data.ContainsKey(session.User))
|
|||
|
data.Add(session.User, new());
|
|||
|
data[session.User].Add(session);
|
|||
|
}
|
|||
|
|
|||
|
DataProvider.UserClient.BumpUsers(
|
|||
|
data.Select(kvp => new UserBumpInfo(kvp.Key, kvp.Value)),
|
|||
|
() => Logger.Debug(@"Successfully bumped remote online status!"),
|
|||
|
ex => { Logger.Write(@"Failed to bump remote online status."); Logger.Debug(ex); }
|
|||
|
);
|
|||
|
});
|
|||
|
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
|
|||
|
}
|
|||
|
|
|||
|
public void BroadcastMessage(string text) {
|
|||
|
Events.DispatchEvent(this, new BroadcastMessageEvent(Bot, text));
|
|||
|
}
|
|||
|
|
|||
|
[Obsolete(@"Use ChannelUsers.JoinChannel")]
|
|||
|
public void JoinChannel(IUser user, IChannel channel) {
|
|||
|
// handle in channelusers
|
|||
|
//channel.SendPacket(new UserChannelJoinPacket(user));
|
|||
|
|
|||
|
// send after join packet for v1
|
|||
|
//user.SendPacket(new ContextClearPacket(channel, ContextClearMode.MessagesUsers));
|
|||
|
|
|||
|
// send after join
|
|||
|
//ChannelUsers.GetUsers(channel, u => user.SendPacket(new ContextUsersPacket(u.Except(new[] { user }).OrderByDescending(u => u.Rank))));
|
|||
|
|
|||
|
// send after join, maybe add a capability that makes this implicit?
|
|||
|
/*Messages.GetMessages(channel, m => {
|
|||
|
foreach(IMessage msg in m)
|
|||
|
user.SendPacket(new ContextMessagePacket(msg));
|
|||
|
});*/
|
|||
|
|
|||
|
// should happen implicitly for v1 clients
|
|||
|
//user.ForceChannel(channel);
|
|||
|
}
|
|||
|
|
|||
|
private bool IsDisposed;
|
|||
|
~Context()
|
|||
|
=> DoDispose();
|
|||
|
public void Dispose() {
|
|||
|
DoDispose();
|
|||
|
GC.SuppressFinalize(this);
|
|||
|
}
|
|||
|
private void DoDispose() {
|
|||
|
if (IsDisposed)
|
|||
|
return;
|
|||
|
IsDisposed = true;
|
|||
|
|
|||
|
BumpTimer.Dispose();
|
|||
|
Events.FinishProcessing();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|