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