Don't use a stinky Timer for user bumps and exclude AFK.

This commit is contained in:
flash 2023-02-08 01:01:55 +01:00
parent 36f3ff6385
commit 27c28aafcd
6 changed files with 77 additions and 66 deletions

View file

@ -1,35 +1,22 @@
using SharpChat.Events;
using SharpChat.Flashii;
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 ChannelManager Channels { get; }
public UserManager Users { get; }
public ChatEventManager Events { get; }
public string TargetName => @"@broadcast";
public ChatContext(HttpClient httpClient, SockChatServer server) {
HttpClient = httpClient;
Server = server;
public ChatContext() {
Users = new(this);
Channels = new(this);
Events = new(this);
BumpTimer = new Timer(e => FlashiiBump.SubmitAsync(HttpClient, Users.WithActiveConnections()).Wait(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
}
public void Update() {
@ -173,7 +160,6 @@ namespace SharpChat {
return;
IsDisposed = true;
BumpTimer?.Dispose();
Events?.Dispose();
Channels?.Dispose();
Users?.Dispose();

View file

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace SharpChat.Flashii {
public class FlashiiBump {
[JsonPropertyName(@"id")]
public long UserId { get; set; }
[JsonPropertyName(@"ip")]
public string UserIP { get; set; }
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())
await SubmitAsync(httpClient, bups);
}
public static async Task SubmitAsync(HttpClient httpClient, IEnumerable<FlashiiBump> users) {
if(httpClient == null)
throw new ArgumentNullException(nameof(httpClient));
if(users == null)
throw new ArgumentNullException(nameof(users));
if(!users.Any())
return;
byte[] data = JsonSerializer.SerializeToUtf8Bytes(users);
HttpRequestMessage request = new(HttpMethod.Post, FlashiiUrls.BumpURL) {
Content = new ByteArrayContent(data),
Headers = {
{ @"X-SharpChat-Signature", data.GetSignedHash() },
}
};
await httpClient.SendAsync(request);
}
}
}

View file

@ -1,12 +1,18 @@
using System.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace SharpChat.Flashii {
public static class FlashiiUrls {
private const string BASE_URL_FILE = "msz_url.txt";
private const string BASE_URL_FALLBACK = "https://flashii.net";
private const string VERIFY = "/_sockchat/verify";
private const string BUMP = "/_sockchat/bump";
private const string VERIFY = "/_sockchat/verify";
private const string BANS_CHECK = "/_sockchat/bans/check?u={0}&a={1}&x={2}&n={3}";
private const string BANS_CREATE = "/_sockchat/bans/create";
@ -42,5 +48,45 @@ namespace SharpChat.Flashii {
public static string GetURL(string path) {
return GetBaseURL() + path;
}
public static async Task BumpUsersOnlineAsync(HttpClient client, IEnumerable<(string userId, string ipAddr)> list) {
if(client == null)
throw new ArgumentNullException(nameof(client));
if(list == null)
throw new ArgumentNullException(nameof(list));
if(!list.Any())
return;
string now = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
StringBuilder sb = new();
sb.AppendFormat("bump#{0}", now);
Dictionary<string, string> formData = new() {
{ "t", now }
};
foreach(var (userId, ipAddr) in list) {
sb.AppendFormat("#{0}:{1}", userId, ipAddr);
formData.Add(string.Format("u[{0}]", userId), ipAddr);
}
HttpRequestMessage req = new(HttpMethod.Post, BumpURL) {
Headers = {
{ "X-SharpChat-Signature", sb.ToString().GetSignedHash() }
},
Content = new FormUrlEncodedContent(formData),
};
using HttpResponseMessage res = await client.SendAsync(req);
try {
res.EnsureSuccessStatusCode();
} catch(HttpRequestException) {
Logger.Debug(await res.Content.ReadAsStringAsync());
#if DEBUG
throw;
#endif
}
}
}
}

View file

@ -32,7 +32,9 @@ namespace SharpChat {
if(hasCancelled) return;
using HttpClient httpClient = new();
using HttpClient httpClient = new(new HttpClientHandler() {
UseProxy = false, // we will never and the initial resolving takes forever on linux
});
httpClient.DefaultRequestHeaders.Add(@"User-Agent", @"SharpChat/20230206");
if(hasCancelled) return;

View file

@ -59,7 +59,7 @@ namespace SharpChat {
HttpClient = httpClient;
Context = new ChatContext(HttpClient, this);
Context = new ChatContext();
Context.Channels.Add(new ChatChannel(@"Lounge"));
#if DEBUG
@ -129,6 +129,10 @@ namespace SharpChat {
Context.Update();
}
private readonly object BumpAccess = new();
private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1);
private DateTimeOffset LastBump = DateTimeOffset.MinValue;
private void OnMessage(IWebSocketConnection conn, string msg) {
Context.Update();
@ -172,6 +176,22 @@ namespace SharpChat {
sess.BumpPing();
sess.Send(new PongPacket(sess.LastPing));
lock(BumpAccess) {
if(LastBump < DateTimeOffset.UtcNow - BumpInterval) {
(string, string)[] bumpList = Context.Users
.Where(u => u.HasSessions && u.Status == ChatUserStatus.Online)
.Select(u => (u.UserId.ToString(), u.RemoteAddresses.FirstOrDefault()?.ToString() ?? string.Empty))
.ToArray();
if(bumpList.Any())
Task.Run(async () => {
await FlashiiUrls.BumpUsersOnlineAsync(HttpClient, bumpList);
}).Wait();
LastBump = DateTimeOffset.UtcNow;
}
}
break;
case "1":

View file

@ -54,6 +54,10 @@ namespace SharpChat {
|| (includeNickName && x.Nickname?.ToLowerInvariant() == username)
|| (includeDisplayName && x.DisplayName.ToLowerInvariant() == username));
}
public IEnumerable<ChatUser> Where(Func<ChatUser, bool> selector) {
return Users.Where(selector);
}
public IEnumerable<ChatUser> OfHierarchy(int hierarchy) {
lock(Users)