Better HttpClient handling.
This commit is contained in:
parent
d2fef02e08
commit
513539319f
11 changed files with 145 additions and 122 deletions
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019-2022 flashwave
|
||||
Copyright (c) 2019-2023 flashwave
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -5,6 +5,15 @@ VisualStudioVersion = 17.2.32630.192
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpChat", "SharpChat\SharpChat.csproj", "{DDB24C19-B802-4C96-AC15-0449C6FC77F2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF7A7073-A67A-4D93-92C6-F9D0F95E2359}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitattributes = .gitattributes
|
||||
.gitignore = .gitignore
|
||||
LICENSE = LICENSE
|
||||
Protocol.md = Protocol.md
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
|
@ -3,6 +3,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat {
|
||||
public interface IBan {
|
||||
|
@ -43,25 +45,28 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public class BanManager : IDisposable {
|
||||
private readonly List<IBan> BanList = new List<IBan>();
|
||||
private readonly List<IBan> BanList = new();
|
||||
|
||||
private readonly HttpClient HttpClient;
|
||||
public readonly ChatContext Context;
|
||||
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public BanManager(ChatContext context) {
|
||||
public BanManager(HttpClient httpClient, ChatContext context) {
|
||||
HttpClient = httpClient;
|
||||
Context = context;
|
||||
RefreshFlashiiBans();
|
||||
RefreshFlashiiBans().Wait();
|
||||
}
|
||||
|
||||
public void Add(ChatUser user, DateTimeOffset expires) {
|
||||
if (expires <= DateTimeOffset.Now)
|
||||
if(expires <= DateTimeOffset.Now)
|
||||
return;
|
||||
|
||||
lock (BanList) {
|
||||
lock(BanList) {
|
||||
BannedUser ban = BanList.OfType<BannedUser>().FirstOrDefault(x => x.UserId == user.UserId);
|
||||
|
||||
if (ban == null)
|
||||
if(ban == null)
|
||||
Add(new BannedUser { UserId = user.UserId, Expires = expires, Username = user.Username });
|
||||
else
|
||||
ban.Expires = expires;
|
||||
|
@ -69,13 +74,13 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void Add(IPAddress addr, DateTimeOffset expires) {
|
||||
if (expires <= DateTimeOffset.Now)
|
||||
if(expires <= DateTimeOffset.Now)
|
||||
return;
|
||||
|
||||
lock (BanList) {
|
||||
lock(BanList) {
|
||||
BannedIPAddress ban = BanList.OfType<BannedIPAddress>().FirstOrDefault(x => x.Address.Equals(addr));
|
||||
|
||||
if (ban == null)
|
||||
if(ban == null)
|
||||
Add(new BannedIPAddress { Address = addr, Expires = expires });
|
||||
else
|
||||
ban.Expires = expires;
|
||||
|
@ -83,11 +88,11 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
private void Add(IBan ban) {
|
||||
if (ban == null)
|
||||
if(ban == null)
|
||||
return;
|
||||
|
||||
lock (BanList)
|
||||
if (!BanList.Contains(ban))
|
||||
lock(BanList)
|
||||
if(!BanList.Contains(ban))
|
||||
BanList.Add(ban);
|
||||
}
|
||||
|
||||
|
@ -102,12 +107,12 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void Remove(IBan ban) {
|
||||
lock (BanList)
|
||||
lock(BanList)
|
||||
BanList.Remove(ban);
|
||||
}
|
||||
|
||||
public DateTimeOffset Check(ChatUser user) {
|
||||
if (user == null)
|
||||
if(user == null)
|
||||
return DateTimeOffset.MinValue;
|
||||
|
||||
lock(BanList)
|
||||
|
@ -115,26 +120,26 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public DateTimeOffset Check(IPAddress addr) {
|
||||
if (addr == null)
|
||||
if(addr == null)
|
||||
return DateTimeOffset.MinValue;
|
||||
|
||||
lock (BanList)
|
||||
lock(BanList)
|
||||
return BanList.OfType<BannedIPAddress>().Where(x => x.Address.Equals(addr)).FirstOrDefault()?.Expires ?? DateTimeOffset.MinValue;
|
||||
}
|
||||
|
||||
public BannedUser GetUser(string username) {
|
||||
if (username == null)
|
||||
if(username == null)
|
||||
return null;
|
||||
|
||||
if (!long.TryParse(username, out long userId))
|
||||
if(!long.TryParse(username, out long userId))
|
||||
userId = 0;
|
||||
|
||||
lock (BanList)
|
||||
lock(BanList)
|
||||
return BanList.OfType<BannedUser>().FirstOrDefault(x => x.Username.ToLowerInvariant() == username.ToLowerInvariant() || (userId > 0 && x.UserId == userId));
|
||||
}
|
||||
|
||||
public BannedIPAddress GetIPAddress(IPAddress addr) {
|
||||
lock (BanList)
|
||||
lock(BanList)
|
||||
return BanList.OfType<BannedIPAddress>().FirstOrDefault(x => x.Address.Equals(addr));
|
||||
}
|
||||
|
||||
|
@ -143,47 +148,40 @@ namespace SharpChat {
|
|||
BanList.RemoveAll(x => x.Expires <= DateTimeOffset.Now);
|
||||
}
|
||||
|
||||
public void RefreshFlashiiBans() {
|
||||
FlashiiBan.GetList(SockChatServer.HttpClient).ContinueWith(x => {
|
||||
if(x.IsFaulted) {
|
||||
Logger.Write($@"Ban Refresh: {x.Exception}");
|
||||
return;
|
||||
}
|
||||
public async Task RefreshFlashiiBans() {
|
||||
IEnumerable<FlashiiBan> bans = await FlashiiBan.GetListAsync(HttpClient);
|
||||
|
||||
if(!x.Result.Any())
|
||||
if(!bans.Any())
|
||||
return;
|
||||
|
||||
lock(BanList) {
|
||||
foreach(FlashiiBan fb in x.Result) {
|
||||
lock(BanList)
|
||||
foreach(FlashiiBan fb in bans) {
|
||||
if(!BanList.OfType<BannedUser>().Any(x => x.UserId == fb.UserId))
|
||||
Add(new BannedUser(fb));
|
||||
if(!BanList.OfType<BannedIPAddress>().Any(x => x.Address.ToString() == fb.UserIP))
|
||||
Add(new BannedIPAddress(fb));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<IBan> All() {
|
||||
lock (BanList)
|
||||
lock(BanList)
|
||||
return BanList.ToList();
|
||||
}
|
||||
|
||||
~BanManager()
|
||||
=> Dispose(false);
|
||||
=> DoDispose();
|
||||
|
||||
public void Dispose()
|
||||
=> Dispose(true);
|
||||
public void Dispose() {
|
||||
DoDispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing) {
|
||||
if (IsDisposed)
|
||||
private void DoDispose() {
|
||||
if(IsDisposed)
|
||||
return;
|
||||
IsDisposed = true;
|
||||
|
||||
BanList.Clear();
|
||||
|
||||
if (disposing)
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,15 @@ using SharpChat.Packet;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public class ChatContext : IDisposable, IPacketTarget {
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
private readonly HttpClient HttpClient;
|
||||
|
||||
public SockChatServer Server { get; }
|
||||
public Timer BumpTimer { get; }
|
||||
public BanManager Bans { get; }
|
||||
|
@ -19,14 +22,15 @@ namespace SharpChat {
|
|||
|
||||
public string TargetName => @"@broadcast";
|
||||
|
||||
public ChatContext(SockChatServer server) {
|
||||
public ChatContext(HttpClient httpClient, SockChatServer server) {
|
||||
HttpClient = httpClient;
|
||||
Server = server;
|
||||
Bans = new BanManager(this);
|
||||
Bans = new BanManager(httpClient, this);
|
||||
Users = new UserManager(this);
|
||||
Channels = new ChannelManager(this);
|
||||
Events = new ChatEventManager(this);
|
||||
|
||||
BumpTimer = new Timer(e => FlashiiBump.Submit(SockChatServer.HttpClient, Users.WithActiveConnections()), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
|
||||
BumpTimer = new Timer(e => FlashiiBump.SubmitAsync(HttpClient, Users.WithActiveConnections()).Wait(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
|
@ -166,13 +170,16 @@ namespace SharpChat {
|
|||
user.Send(packet);
|
||||
}
|
||||
|
||||
~ChatContext()
|
||||
=> Dispose(false);
|
||||
~ChatContext() {
|
||||
DoDispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> Dispose(true);
|
||||
public void Dispose() {
|
||||
DoDispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing) {
|
||||
private void DoDispose() {
|
||||
if (IsDisposed)
|
||||
return;
|
||||
IsDisposed = true;
|
||||
|
@ -182,9 +189,6 @@ namespace SharpChat {
|
|||
Channels?.Dispose();
|
||||
Users?.Dispose();
|
||||
Bans?.Dispose();
|
||||
|
||||
if (disposing)
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
@ -49,7 +48,7 @@ namespace SharpChat.Flashii {
|
|||
[JsonPropertyName(@"perms")]
|
||||
public ChatUserPermissions Permissions { get; set; }
|
||||
|
||||
public static async Task<FlashiiAuth> Attempt(HttpClient httpClient, FlashiiAuthRequest authRequest) {
|
||||
public static async Task<FlashiiAuth> AttemptAsync(HttpClient httpClient, FlashiiAuthRequest authRequest) {
|
||||
if(httpClient == null)
|
||||
throw new ArgumentNullException(nameof(httpClient));
|
||||
if(authRequest == null)
|
||||
|
@ -68,7 +67,7 @@ namespace SharpChat.Flashii {
|
|||
};
|
||||
#endif
|
||||
|
||||
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, FlashiiUrls.AuthURL) {
|
||||
HttpRequestMessage request = new(HttpMethod.Post, FlashiiUrls.AuthURL) {
|
||||
Content = new ByteArrayContent(authRequest.GetJSON()),
|
||||
Headers = {
|
||||
{ @"X-SharpChat-Signature", authRequest.Hash },
|
||||
|
|
|
@ -21,11 +21,11 @@ namespace SharpChat.Flashii {
|
|||
[JsonPropertyName(@"username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
public static async Task<IEnumerable<FlashiiBan>> GetList(HttpClient httpClient) {
|
||||
public static async Task<IEnumerable<FlashiiBan>> GetListAsync(HttpClient httpClient) {
|
||||
if(httpClient == null)
|
||||
throw new ArgumentNullException(nameof(httpClient));
|
||||
|
||||
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, FlashiiUrls.BansURL) {
|
||||
HttpRequestMessage request = new(HttpMethod.Get, FlashiiUrls.BansURL) {
|
||||
Headers = {
|
||||
{ @"X-SharpChat-Signature", STRING.GetSignedHash() },
|
||||
},
|
||||
|
|
|
@ -14,14 +14,17 @@ namespace SharpChat.Flashii {
|
|||
[JsonPropertyName(@"ip")]
|
||||
public string UserIP { get; set; }
|
||||
|
||||
public static void Submit(HttpClient httpClient, IEnumerable<ChatUser> users) {
|
||||
List<FlashiiBump> bups = users.Where(u => u.HasSessions).Select(x => new FlashiiBump { UserId = x.UserId, UserIP = x.RemoteAddresses.First().ToString() }).ToList();
|
||||
public static async Task SubmitAsync(HttpClient httpClient, IEnumerable<ChatUser> users) {
|
||||
FlashiiBump[] bups = users.Where(u => u.HasSessions).Select(x => new FlashiiBump {
|
||||
UserId = x.UserId,
|
||||
UserIP = x.RemoteAddresses.First().ToString()
|
||||
}).ToArray();
|
||||
|
||||
if (bups.Any())
|
||||
Submit(httpClient, bups);
|
||||
if(bups.Any())
|
||||
await SubmitAsync(httpClient, bups);
|
||||
}
|
||||
|
||||
public static void Submit(HttpClient httpClient, IEnumerable<FlashiiBump> users) {
|
||||
public static async Task SubmitAsync(HttpClient httpClient, IEnumerable<FlashiiBump> users) {
|
||||
if(httpClient == null)
|
||||
throw new ArgumentNullException(nameof(httpClient));
|
||||
if(users == null)
|
||||
|
@ -31,17 +34,14 @@ namespace SharpChat.Flashii {
|
|||
|
||||
byte[] data = JsonSerializer.SerializeToUtf8Bytes(users);
|
||||
|
||||
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, FlashiiUrls.BumpURL) {
|
||||
HttpRequestMessage request = new(HttpMethod.Post, FlashiiUrls.BumpURL) {
|
||||
Content = new ByteArrayContent(data),
|
||||
Headers = {
|
||||
{ @"X-SharpChat-Signature", data.GetSignedHash() },
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.SendAsync(request).ContinueWith(x => {
|
||||
if(x.IsFaulted)
|
||||
Logger.Write($@"Flashii Bump Error: {x.Exception}");
|
||||
});
|
||||
await httpClient.SendAsync(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace SharpChat.Packet {
|
|||
|
||||
// Abbreviated class name because otherwise shit gets wide
|
||||
public static class LCR {
|
||||
public const string GENERIC_ERROR = @"generr";
|
||||
public const string COMMAND_NOT_FOUND = @"nocmd";
|
||||
public const string COMMAND_NOT_ALLOWED = @"cmdna";
|
||||
public const string COMMAND_FORMAT_ERROR = @"cmderr";
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using SharpChat.Flashii;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
|
@ -21,9 +19,27 @@ namespace SharpChat {
|
|||
|
||||
Database.ReadConfig();
|
||||
|
||||
using ManualResetEvent mre = new ManualResetEvent(false);
|
||||
using SockChatServer scs = new SockChatServer(mre, PORT);
|
||||
Console.CancelKeyPress += (s, e) => { e.Cancel = true; mre.Set(); };
|
||||
using ManualResetEvent mre = new(false);
|
||||
bool hasCancelled = false;
|
||||
|
||||
void cancelKeyPressHandler(object sender, ConsoleCancelEventArgs ev) {
|
||||
Console.CancelKeyPress -= cancelKeyPressHandler;
|
||||
hasCancelled = true;
|
||||
ev.Cancel = true;
|
||||
mre.Set();
|
||||
};
|
||||
Console.CancelKeyPress += cancelKeyPressHandler;
|
||||
|
||||
if(hasCancelled) return;
|
||||
|
||||
using HttpClient httpClient = new();
|
||||
httpClient.DefaultRequestHeaders.Add(@"User-Agent", @"SharpChat/20230206");
|
||||
|
||||
if(hasCancelled) return;
|
||||
|
||||
using SockChatServer scs = new(httpClient, PORT);
|
||||
scs.Listen(mre);
|
||||
|
||||
mre.WaitOne();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -39,7 +38,7 @@ namespace SharpChat {
|
|||
public IWebSocketServer Server { get; }
|
||||
public ChatContext Context { get; }
|
||||
|
||||
public static HttpClient HttpClient { get; }
|
||||
private readonly HttpClient HttpClient;
|
||||
|
||||
private IReadOnlyCollection<IChatCommand> Commands { get; } = new IChatCommand[] {
|
||||
new AFKCommand(),
|
||||
|
@ -53,21 +52,15 @@ namespace SharpChat {
|
|||
return Sessions.FirstOrDefault(x => x.Connection == conn);
|
||||
}
|
||||
|
||||
static SockChatServer() {
|
||||
// "fuck it"
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(@"SharpChat");
|
||||
}
|
||||
|
||||
private ManualResetEvent Shutdown { get; }
|
||||
private ManualResetEvent Shutdown { get; set; }
|
||||
private bool IsShuttingDown = false;
|
||||
|
||||
public SockChatServer(ManualResetEvent mre, ushort port) {
|
||||
public SockChatServer(HttpClient httpClient, ushort port) {
|
||||
Logger.Write("Starting Sock Chat server...");
|
||||
|
||||
Shutdown = mre ?? throw new ArgumentNullException(nameof(mre));
|
||||
HttpClient = httpClient;
|
||||
|
||||
Context = new ChatContext(this);
|
||||
Context = new ChatContext(HttpClient, this);
|
||||
|
||||
Context.Channels.Add(new ChatChannel(@"Lounge"));
|
||||
#if DEBUG
|
||||
|
@ -79,6 +72,10 @@ namespace SharpChat {
|
|||
Context.Channels.Add(new ChatChannel(@"Staff") { Rank = 5 });
|
||||
|
||||
Server = new SharpChatWebSocketServer($@"ws://0.0.0.0:{port}");
|
||||
}
|
||||
|
||||
public void Listen(ManualResetEvent mre) {
|
||||
Shutdown = mre;
|
||||
|
||||
Server.Start(sock => {
|
||||
if(IsShuttingDown || IsDisposed) {
|
||||
|
@ -143,7 +140,7 @@ namespace SharpChat {
|
|||
return;
|
||||
}
|
||||
|
||||
if(sess.User is ChatUser && sess.User.HasFloodProtection) {
|
||||
if(sess.User is not null && sess.User.HasFloodProtection) {
|
||||
sess.User.RateLimiter.AddTimePoint();
|
||||
|
||||
if(sess.User.RateLimiter.State == ChatRateLimitState.Kick) {
|
||||
|
@ -182,7 +179,7 @@ namespace SharpChat {
|
|||
if(args.Length < 3 || !long.TryParse(args[1], out long aUserId))
|
||||
break;
|
||||
|
||||
FlashiiAuth.Attempt(HttpClient, new FlashiiAuthRequest {
|
||||
FlashiiAuth.AttemptAsync(HttpClient, new FlashiiAuthRequest {
|
||||
UserId = aUserId,
|
||||
Token = args[2],
|
||||
IPAddress = sess.RemoteAddress.ToString(),
|
||||
|
@ -276,7 +273,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
if(messageText.Length > MSG_LENGTH_MAX)
|
||||
messageText = messageText.Substring(0, MSG_LENGTH_MAX);
|
||||
messageText = messageText[..MSG_LENGTH_MAX];
|
||||
|
||||
messageText = messageText.Trim();
|
||||
|
||||
|
@ -293,8 +290,7 @@ namespace SharpChat {
|
|||
break;
|
||||
}
|
||||
|
||||
if(message == null)
|
||||
message = new ChatMessage {
|
||||
message ??= new ChatMessage {
|
||||
Target = mChannel,
|
||||
TargetName = mChannel.TargetName,
|
||||
DateTime = DateTimeOffset.UtcNow,
|
||||
|
@ -335,7 +331,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public IChatMessage HandleV1Command(string message, ChatUser user, ChatChannel channel) {
|
||||
string[] parts = message.Substring(1).Split(' ');
|
||||
string[] parts = message[1..].Split(' ');
|
||||
string commandName = parts[0].Replace(@".", string.Empty).ToLowerInvariant();
|
||||
|
||||
for(int i = 1; i < parts.Length; i++)
|
||||
|
@ -370,8 +366,7 @@ namespace SharpChat {
|
|||
offset = 2;
|
||||
}
|
||||
|
||||
if(targetUser == null)
|
||||
targetUser = user;
|
||||
targetUser ??= user;
|
||||
|
||||
if(parts.Length < offset) {
|
||||
user.Send(new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
|
@ -389,7 +384,7 @@ namespace SharpChat {
|
|||
if(nickStr == targetUser.Username)
|
||||
nickStr = null;
|
||||
else if(nickStr.Length > 15)
|
||||
nickStr = nickStr.Substring(0, 15);
|
||||
nickStr = nickStr[..15];
|
||||
else if(string.IsNullOrEmpty(nickStr))
|
||||
nickStr = null;
|
||||
|
||||
|
@ -454,7 +449,7 @@ namespace SharpChat {
|
|||
Flags = ChatMessageFlags.Action,
|
||||
};
|
||||
case @"who": // gets all online users/online users in a channel if arg
|
||||
StringBuilder whoChanSB = new StringBuilder();
|
||||
StringBuilder whoChanSB = new();
|
||||
string whoChanStr = parts.Length > 1 && !string.IsNullOrEmpty(parts[1]) ? parts[1] : string.Empty;
|
||||
|
||||
if(!string.IsNullOrEmpty(whoChanStr)) {
|
||||
|
@ -476,7 +471,7 @@ namespace SharpChat {
|
|||
if(whoUser == user)
|
||||
whoChanSB.Append(@" style=""font-weight: bold;""");
|
||||
|
||||
whoChanSB.Append(@">");
|
||||
whoChanSB.Append('>');
|
||||
whoChanSB.Append(whoUser.DisplayName);
|
||||
whoChanSB.Append(@"</a>, ");
|
||||
}
|
||||
|
@ -492,7 +487,7 @@ namespace SharpChat {
|
|||
if(whoUser == user)
|
||||
whoChanSB.Append(@" style=""font-weight: bold;""");
|
||||
|
||||
whoChanSB.Append(@">");
|
||||
whoChanSB.Append('>');
|
||||
whoChanSB.Append(whoUser.DisplayName);
|
||||
whoChanSB.Append(@"</a>, ");
|
||||
}
|
||||
|
@ -546,7 +541,8 @@ namespace SharpChat {
|
|||
|
||||
int createChanHierarchy = 0;
|
||||
if(createChanHasHierarchy)
|
||||
int.TryParse(parts[1], out createChanHierarchy);
|
||||
if(!int.TryParse(parts[1], out createChanHierarchy))
|
||||
createChanHierarchy = 0;
|
||||
|
||||
if(createChanHierarchy > user.Rank) {
|
||||
user.Send(new LegacyCommandResponse(LCR.INSUFFICIENT_HIERARCHY));
|
||||
|
@ -554,7 +550,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
string createChanName = string.Join('_', parts.Skip(createChanHasHierarchy ? 2 : 1));
|
||||
ChatChannel createChan = new ChatChannel {
|
||||
ChatChannel createChan = new() {
|
||||
Name = createChanName,
|
||||
IsTemporary = !user.Can(ChatUserPermissions.SetChannelPermanent),
|
||||
Rank = createChanHierarchy,
|
||||
|
@ -848,7 +844,7 @@ namespace SharpChat {
|
|||
Sessions.ForEach(s => s.PrepareForRestart());
|
||||
|
||||
Context.Update();
|
||||
Shutdown.Set();
|
||||
Shutdown?.Set();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -859,13 +855,16 @@ namespace SharpChat {
|
|||
return null;
|
||||
}
|
||||
|
||||
~SockChatServer()
|
||||
=> Dispose(false);
|
||||
~SockChatServer() {
|
||||
DoDispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> Dispose(true);
|
||||
public void Dispose() {
|
||||
DoDispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing) {
|
||||
private void DoDispose() {
|
||||
if(IsDisposed)
|
||||
return;
|
||||
IsDisposed = true;
|
||||
|
@ -876,9 +875,6 @@ namespace SharpChat {
|
|||
Server?.Dispose();
|
||||
Context?.Dispose();
|
||||
HttpClient?.Dispose();
|
||||
|
||||
if(disposing)
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue