Skip to content

Commit

Permalink
Add support for Red Protocol (Chronocat), an alternative QQ notify me…
Browse files Browse the repository at this point in the history
…thod.
  • Loading branch information
azhuge233 committed Oct 12, 2023
1 parent 85de663 commit 021ec3c
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 0 deletions.
6 changes: 6 additions & 0 deletions EGSFreeGamesNotifier/Config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"EnableQQ": false,
"QQAddress": "127.0.0.1",
"QQPort": 5700,

"EnableRed": false,
"RedAddress": "127.0.0.1",
"RedPort": 16530,
"RedToken": "",

"ToQQID": "",

"EnablePushPlus": false,
Expand Down
1 change: 1 addition & 0 deletions EGSFreeGamesNotifier/EGSFreeGamesNotifier.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<PackageReference Include="MimeKit" Version="4.2.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.4" />
<PackageReference Include="Telegram.Bot" Version="19.0.0" />
<PackageReference Include="Websocket.Client" Version="5.0.0" />
</ItemGroup>

<Target Name="CopyNlogConfigAfterBuild" AfterTargets="AfterBuild">
Expand Down
4 changes: 4 additions & 0 deletions EGSFreeGamesNotifier/Models/Config/NotifyConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public class NotifyConfig {
public bool EnableQQ { get; set; }
public string QQAddress { get; set; }
public int QQPort { get; set; }
public bool EnableRed { get; set; }
public string RedAddress { get; set; }
public int RedPort { get; set; }
public string RedToken { get; set; }
public string ToQQID { get; set; }

public bool EnablePushPlus { get; set; }
Expand Down
61 changes: 61 additions & 0 deletions EGSFreeGamesNotifier/Models/WebSocketContent/WSPacket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Text.Json.Serialization;

namespace EGSFreeGamesNotifier.Models.WebSocketContent {
public class WSPacket {
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("payload")]
public object Payload { get; set; }
}

#region Connect Classes
public class ConnectPayload {
[JsonPropertyName("token")]
public string Token { get; set; }
}
#endregion

#region Message Classes
public class MessagePayload {
[JsonPropertyName("peer")]
public Peer Peer { get; set; }
[JsonPropertyName("elements")]
public List<object> Elements { get; set; }
}

public class Peer {
[JsonPropertyName("chatType")]
public int ChatType { get; set; }
[JsonPropertyName("peerUin")]
public string PeerUin { get; set; }
}

public class TextElementRoot {
[JsonPropertyName("elementType")]
public int ElementType { get; set; } = 1;
[JsonPropertyName("textElement")]
public TextElement TextElement { get; set; }
}

public class TextElement {
[JsonPropertyName("content")]
public string Content { get; set; }
}

//public class ReplyElementRoot {
// [JsonPropertyName("elementType")]
// public int ElementType { get; set; } = 7;
// [JsonPropertyName("replyElement")]
// public ReplyElement ReplyElement { get; set; }
//}

//public class ReplyElement {
// [JsonPropertyName("replayMsgSeq")]
// public string ReplayMsgSeq { get; set; }
// [JsonPropertyName("sourceMsgIdInRecords")]
// public string SourceMsgIdInRecords { get; set; }
// [JsonPropertyName("senderUid")]
// public string SenderUid { get; set; }
//}
#endregion
}
2 changes: 2 additions & 0 deletions EGSFreeGamesNotifier/Modules/DI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal static IServiceProvider BuildDiAll() {
.AddTransient<TelegramBot>()
.AddTransient<Email>()
.AddTransient<QQ>()
.AddTransient<QQRed>()
.AddTransient<PushPlus>()
.AddTransient<DingTalk>()
.AddTransient<PushDeer>()
Expand All @@ -40,6 +41,7 @@ internal static IServiceProvider BuildDiNotifierOnly() {
.AddTransient<Bark>()
.AddTransient<Email>()
.AddTransient<QQ>()
.AddTransient<QQRed>()
.AddTransient<PushPlus>()
.AddTransient<DingTalk>()
.AddTransient<PushDeer>()
Expand Down
12 changes: 12 additions & 0 deletions EGSFreeGamesNotifier/Services/ConfigValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ internal void CheckValid(Config config) {
throw new Exception(message: "No QQ ID provided!");
}

//QQ Red (Chronocat)
if (config.EnableRed) {
if (string.IsNullOrEmpty(config.RedAddress))
throw new Exception(message: "No Red address provided!");
if (string.IsNullOrEmpty(config.RedPort.ToString()))
throw new Exception(message: "No Red port provided!");
if (string.IsNullOrEmpty(config.RedToken))
throw new Exception(message: "No Red token provided!");
if (string.IsNullOrEmpty(config.ToQQID))
throw new Exception(message: "No QQ ID provided!");
}

//PushPlus
if (config.EnablePushPlus) {
if (string.IsNullOrEmpty(config.PushPlusToken))
Expand Down
100 changes: 100 additions & 0 deletions EGSFreeGamesNotifier/Services/Notifier/QQRed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using EGSFreeGamesNotifier.Models.Config;
using EGSFreeGamesNotifier.Models.Record;
using EGSFreeGamesNotifier.Models.WebSocketContent;
using EGSFreeGamesNotifier.Strings;
using Microsoft.Extensions.Logging;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using Websocket.Client;

namespace EGSFreeGamesNotifier.Services.Notifier {
internal class QQRed : INotifiable {

private readonly ILogger<QQRed> _logger;

#region debug strings
private readonly string debugSendMessage = "Send notifications to QQ Red (Chronocat)";
private readonly string debugWSReconnection = "Reconnection happened, type: {0}";
private readonly string debugWSMessageRecieved = "Message received: {0}";
private readonly string debugWSDisconnected = "Disconnected: {0}";
#endregion

public QQRed(ILogger<QQRed> logger) {
_logger = logger;
}

private WebsocketClient GetWSClient(NotifyConfig config) {
var url = new Uri(new StringBuilder().AppendFormat(NotifyFormatStrings.qqRedUrlFormat, config.RedAddress, config.RedPort).ToString());

#region new websocket client
var client = new WebsocketClient(url);
client.ReconnectionHappened.Subscribe(info => _logger.LogDebug(debugWSReconnection, info.Type));
client.MessageReceived.Subscribe(msg => _logger.LogDebug(debugWSMessageRecieved, msg));
client.DisconnectionHappened.Subscribe(msg => _logger.LogDebug(debugWSDisconnected, msg));
#endregion

return client;
}

private static WSPacket GetConnectPacket(NotifyConfig config) {
return new WSPacket() {
Type = NotifyFormatStrings.qqRedWSConnectPacketType,
Payload = new ConnectPayload() {
Token = config.RedToken
}
};
}

private static List<WSPacket> GetSendPacket(NotifyConfig config, List<NotifyRecord> records) {
return records.Select(record => new WSPacket() {
Type = NotifyFormatStrings.qqRedWSSendPacketType,
Payload = new MessagePayload() {
Peer = new Peer() {
ChatType = 1,
PeerUin = config.ToQQID
},
Elements = new List<object>() {
new TextElementRoot() {
TextElement = new TextElement() {
Content = record.ToQQMessage()
}
}
}
}
}).ToList();
}

public async Task SendMessage(NotifyConfig config, List<NotifyRecord> records) {
try {
_logger.LogDebug(debugSendMessage);

var packets = GetSendPacket(config, records);

using var client = GetWSClient(config);

await client.Start();

await client.SendInstant(JsonSerializer.Serialize(GetConnectPacket(config)));

foreach (var packet in packets) {
await client.SendInstant(JsonSerializer.Serialize(packet));
await Task.Delay(600);
}

await client.Stop(WebSocketCloseStatus.NormalClosure, string.Empty);

_logger.LogDebug($"Done: {debugSendMessage}");
} catch (Exception) {
_logger.LogDebug($"Error: {debugSendMessage}");
throw;
} finally {
Dispose();
}
}

public void Dispose() {
GC.SuppressFinalize(this);
}
}
}
6 changes: 6 additions & 0 deletions EGSFreeGamesNotifier/Services/NotifyOP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ internal async Task Notify(NotifyConfig config, List<FreeGameRecord> pushList) {
await services.GetRequiredService<QQ>().SendMessage(config, pushListFinal);
} else _logger.LogInformation(debugDisabledFormat, "QQ");

//QQ Red (Chronocat) notifications
if (config.EnableRed) {
_logger.LogInformation(debugEnabledFormat, "QQ Red (Chronocat)");
await services.GetRequiredService<QQRed>().SendMessage(config, pushListFinal);
} else _logger.LogInformation(debugDisabledFormat, "QQ Red (Chronocat)");

// PushPlus notifications
if (config.EnablePushPlus) {
_logger.LogInformation(debugEnabledFormat, "PushPlus");
Expand Down
3 changes: 3 additions & 0 deletions EGSFreeGamesNotifier/Strings/NotifyFormatStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ internal class NotifyFormatStrings {
internal static readonly string emailBodyFormat = "<br>{0}";

internal static readonly string qqUrlFormat = "http://{0}:{1}/send_private_msg?user_id={2}&message=";
internal static readonly string qqRedUrlFormat = "ws://{0}:{1}";
internal static readonly string qqRedWSConnectPacketType = "meta::connect";
internal static readonly string qqRedWSSendPacketType = "message::send";

internal static readonly string pushPlusTitleFormat = "{0} new free game(s) - EGSFreeGamesNotifier";
internal static readonly string pushPlusBodyFormat = "<br>{0}";
Expand Down

0 comments on commit 021ec3c

Please sign in to comment.