Socket classes for Hermes
This commit is contained in:
commit
d8522584c4
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
27
HermesSocketLibrary.csproj
Normal file
27
HermesSocketLibrary.csproj
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Serilog" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.1-dev-10391" />
|
||||||
|
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Async" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00972" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.1-dev-00771" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Trace" Version="4.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\CommonSocketLibrary\CommonSocketLibrary.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
33
Quests/ChatterQuestProgression.cs
Normal file
33
Quests/ChatterQuestProgression.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
public class ChatterQuestProgression
|
||||||
|
{
|
||||||
|
private readonly long _chatterId;
|
||||||
|
private readonly Quest _quest;
|
||||||
|
private int _counter;
|
||||||
|
|
||||||
|
public Quest Quest { get => _quest; }
|
||||||
|
public int Counter { get => _counter; }
|
||||||
|
|
||||||
|
public ChatterQuestProgression(long chatterId, Quest quest)
|
||||||
|
{
|
||||||
|
_chatterId = chatterId;
|
||||||
|
_quest = quest;
|
||||||
|
_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool Process(string message, HashSet<string> emotes)
|
||||||
|
{
|
||||||
|
bool good = _quest.Task.Process(_chatterId, message, emotes);
|
||||||
|
if (good)
|
||||||
|
{
|
||||||
|
_counter++;
|
||||||
|
|
||||||
|
return _quest.Task.IsCompleted(_counter);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Quests/DailyQuest.cs
Normal file
11
Quests/DailyQuest.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
public class DailyQuest : Quest
|
||||||
|
{
|
||||||
|
public DailyQuest(short id, IQuestTask task, DateOnly day)
|
||||||
|
: base(id, task, 1, day.ToDateTime(TimeOnly.MinValue), day.ToDateTime(TimeOnly.MaxValue))
|
||||||
|
{
|
||||||
|
Type = task.Type | QuestType.Daily;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
Quests/Quest.cs
Normal file
42
Quests/Quest.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
public abstract class Quest
|
||||||
|
{
|
||||||
|
public short Id { get; }
|
||||||
|
public IQuestTask Task { get; }
|
||||||
|
public DateTime StartTime { get; }
|
||||||
|
public DateTime EndTime { get; }
|
||||||
|
public QuestType Type { get; protected set; }
|
||||||
|
public int Rewards { get; }
|
||||||
|
|
||||||
|
public Quest(short id, IQuestTask task, int rewards, DateTime start, DateTime end)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Task = task;
|
||||||
|
Rewards = rewards;
|
||||||
|
StartTime = start;
|
||||||
|
EndTime = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDaily()
|
||||||
|
{
|
||||||
|
return Type.HasFlag(QuestType.Daily);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWeekly()
|
||||||
|
{
|
||||||
|
return Type.HasFlag(QuestType.Weekly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsMonthly()
|
||||||
|
{
|
||||||
|
return Type.HasFlag(QuestType.Monthly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsOngoing()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
return now >= StartTime && now <= EndTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
Quests/QuestType.cs
Normal file
15
Quests/QuestType.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum QuestType
|
||||||
|
{
|
||||||
|
Message = 0x0001,
|
||||||
|
EmoteMessage = 0x0002,
|
||||||
|
Redemption = 0x0004,
|
||||||
|
WatchTime = 0x0008,
|
||||||
|
|
||||||
|
Daily = 0x1000,
|
||||||
|
Weekly = 0x2000,
|
||||||
|
Monthly = 0x4000
|
||||||
|
}
|
||||||
|
}
|
27
Quests/Tasks/EmoteMessageQuestTask.cs
Normal file
27
Quests/Tasks/EmoteMessageQuestTask.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests.Tasks
|
||||||
|
{
|
||||||
|
public class EmoteMessageQuestTask : IQuestTask
|
||||||
|
{
|
||||||
|
public string Name => $"send {Target} messages";
|
||||||
|
public QuestType Type { get; set; }
|
||||||
|
public int Target { get; }
|
||||||
|
|
||||||
|
public EmoteMessageQuestTask(int target)
|
||||||
|
{
|
||||||
|
Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCompleted(int counter)
|
||||||
|
{
|
||||||
|
return counter >= Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Process(long chatterId, string message, HashSet<string> emotes)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(message))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return emotes.Count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Quests/Tasks/MessageQuestTask.cs
Normal file
30
Quests/Tasks/MessageQuestTask.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests.Tasks
|
||||||
|
{
|
||||||
|
public class MessageQuestTask : IQuestTask
|
||||||
|
{
|
||||||
|
public string Name => $"send {Target} messages";
|
||||||
|
public QuestType Type { get; set; }
|
||||||
|
public int Target { get; }
|
||||||
|
|
||||||
|
public MessageQuestTask(int target)
|
||||||
|
{
|
||||||
|
Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCompleted(int counter)
|
||||||
|
{
|
||||||
|
return counter >= Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Process(long chatterId, string message, HashSet<string> emotes)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(message))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (message.Length < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Quests/Tasks/QuestTask.cs
Normal file
11
Quests/Tasks/QuestTask.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
public interface IQuestTask
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public QuestType Type { get; set; }
|
||||||
|
public int Target { get; }
|
||||||
|
public abstract bool Process(long chatterId, string message, HashSet<string> emotes);
|
||||||
|
public abstract bool IsCompleted(int counter);
|
||||||
|
}
|
||||||
|
}
|
12
Quests/WeeklyQuest.cs
Normal file
12
Quests/WeeklyQuest.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
namespace HermesSocketLibrary.Quests
|
||||||
|
{
|
||||||
|
public class WeeklyQuest : Quest
|
||||||
|
{
|
||||||
|
public WeeklyQuest(short id, IQuestTask task, DateOnly start)
|
||||||
|
: base(id, task, 5, start.ToDateTime(TimeOnly.MinValue), start.AddDays(6).ToDateTime(TimeOnly.MaxValue))
|
||||||
|
{
|
||||||
|
Type = task.Type | QuestType.Weekly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Requests/IRequest.cs
Normal file
9
Requests/IRequest.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HermesSocketLibrary.Requests
|
||||||
|
{
|
||||||
|
public interface IRequest
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
Task<RequestResult> Grant(string sender, IDictionary<string, object> data);
|
||||||
|
}
|
||||||
|
}
|
13
Requests/Messages/EmoteInfo.cs
Normal file
13
Requests/Messages/EmoteInfo.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace HermesSocketLibrary.Requests.Messages
|
||||||
|
{
|
||||||
|
public class EmoteInfo
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
17
Requests/Messages/TTSWordFilter.cs
Normal file
17
Requests/Messages/TTSWordFilter.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace HermesSocketLibrary.Requests.Messages
|
||||||
|
{
|
||||||
|
public class TTSWordFilter
|
||||||
|
{
|
||||||
|
public string? Id { get; set; }
|
||||||
|
public string? Search { get; set; }
|
||||||
|
public string? Replace { get; set; }
|
||||||
|
|
||||||
|
public bool IsRegex { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public TTSWordFilter()
|
||||||
|
{
|
||||||
|
IsRegex = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Requests/Messages/VoiceDetails.cs
Normal file
8
Requests/Messages/VoiceDetails.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HermesSocketLibrary.Requests.Messages
|
||||||
|
{
|
||||||
|
public class VoiceDetails
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
62
Requests/RequestManager.cs
Normal file
62
Requests/RequestManager.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Reflection;
|
||||||
|
using HermesSocketLibrary.Socket.Data;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace HermesSocketLibrary.Requests
|
||||||
|
{
|
||||||
|
public abstract class RequestManager
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, IRequest> _requests;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
|
||||||
|
public RequestManager(IServiceProvider serviceProvider, ILogger logger)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
_requests = new ConcurrentDictionary<string, IRequest>();
|
||||||
|
LoadRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract string AssemblyName { get; }
|
||||||
|
|
||||||
|
private void LoadRequests()
|
||||||
|
{
|
||||||
|
Type basetype = typeof(IRequest);
|
||||||
|
var types = Assembly.Load(AssemblyName).GetTypes().Where(t => t.IsClass && !t.IsAbstract && basetype.IsAssignableFrom(t));
|
||||||
|
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
_logger.Debug($"Loading IRequest for '{type.Name}'.");
|
||||||
|
var request = _serviceProvider.GetRequiredKeyedService<IRequest>(type.Name);
|
||||||
|
_requests.Add(request.Name, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> Grant(string sender, RequestMessage? message)
|
||||||
|
{
|
||||||
|
if (message == null || message.Type == null)
|
||||||
|
return new RequestResult(false, null);
|
||||||
|
|
||||||
|
if (!_requests.TryGetValue(message.Type, out IRequest? request) || request == null)
|
||||||
|
{
|
||||||
|
_logger.Warning($"Did not find request type '{message.Type}'.");
|
||||||
|
return new RequestResult(false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await request.Grant(sender, message.Data);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, $"Failed to grant a request of type '{message.Type}'.");
|
||||||
|
}
|
||||||
|
return new RequestResult(false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Requests/RequestResult.cs
Normal file
16
Requests/RequestResult.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace HermesSocketLibrary.Requests
|
||||||
|
{
|
||||||
|
public class RequestResult
|
||||||
|
{
|
||||||
|
public bool Success;
|
||||||
|
public object? Result;
|
||||||
|
public bool NotifyClientsOnAccount;
|
||||||
|
|
||||||
|
public RequestResult(bool success, object? result, bool notifyClientsOnAccount = true)
|
||||||
|
{
|
||||||
|
Success = success;
|
||||||
|
Result = result;
|
||||||
|
NotifyClientsOnAccount = notifyClientsOnAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Socket/Data/ChatterMessage.cs
Normal file
8
Socket/Data/ChatterMessage.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class ChatterMessage
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
7
Socket/Data/EmoteDetailsMessage.cs
Normal file
7
Socket/Data/EmoteDetailsMessage.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class EmoteDetailsMessage
|
||||||
|
{
|
||||||
|
public Dictionary<string, string> Emotes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
Socket/Data/EmoteUsageMessage.cs
Normal file
11
Socket/Data/EmoteUsageMessage.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class EmoteUsageMessage
|
||||||
|
{
|
||||||
|
public string MessageId { get; set; }
|
||||||
|
public DateTime DateTime { get; set; }
|
||||||
|
public long BroadcasterId { get; set; }
|
||||||
|
public HashSet<string> Emotes { get; set; }
|
||||||
|
public long ChatterId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
20
Socket/Data/ErrorMessage.cs
Normal file
20
Socket/Data/ErrorMessage.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class ErrorMessage
|
||||||
|
{
|
||||||
|
public Exception? Exception { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public ErrorMessage(Exception exception, string message)
|
||||||
|
{
|
||||||
|
Exception = exception;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorMessage(string message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
Exception = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Socket/Data/HeartbeatMessage.cs
Normal file
8
Socket/Data/HeartbeatMessage.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class HeartbeatMessage
|
||||||
|
{
|
||||||
|
public DateTime DateTime { get; set; }
|
||||||
|
public bool Respond { get; set; }
|
||||||
|
}
|
||||||
|
}
|
7
Socket/Data/HermesLoginMessage.cs
Normal file
7
Socket/Data/HermesLoginMessage.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class HermesLoginMessage
|
||||||
|
{
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
Socket/Data/LoginAckMessage.cs
Normal file
8
Socket/Data/LoginAckMessage.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class LoginAckMessage
|
||||||
|
{
|
||||||
|
public string UserId { get; set; }
|
||||||
|
public bool AnotherClient { get; set; }
|
||||||
|
}
|
||||||
|
}
|
9
Socket/Data/RequestAckMessage.cs
Normal file
9
Socket/Data/RequestAckMessage.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class RequestAckMessage
|
||||||
|
{
|
||||||
|
public RequestMessage? Request { get; set; }
|
||||||
|
public string? Nounce { get; set; }
|
||||||
|
public object? Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
9
Socket/Data/RequestMessage.cs
Normal file
9
Socket/Data/RequestMessage.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class RequestMessage
|
||||||
|
{
|
||||||
|
public string? Type { get; set; }
|
||||||
|
public IDictionary<string, object>? Data { get; set; }
|
||||||
|
public string? Nounce { get; set; }
|
||||||
|
}
|
||||||
|
}
|
12
Socket/Data/SocketMessage.cs
Normal file
12
Socket/Data/SocketMessage.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace HermesSocketLibrary.Socket.Data
|
||||||
|
{
|
||||||
|
public class SocketMessage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("op")]
|
||||||
|
public int? OpCode { get; set; }
|
||||||
|
[JsonPropertyName("d")]
|
||||||
|
public object? Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user