Skip to content

Commit

Permalink
Split up DiscordApiClient into generic base RelayBotSender too
Browse files Browse the repository at this point in the history
  • Loading branch information
UnknownShadow200 committed May 23, 2021
1 parent 5092e84 commit bd4a499
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 54 deletions.
1 change: 1 addition & 0 deletions MCGalaxy/MCGalaxy_.csproj
Expand Up @@ -593,6 +593,7 @@
<Compile Include="Modules\Relay\IRC\IRCPlugin.cs" />
<Compile Include="Modules\Relay\RelayBot.cs" />
<Compile Include="Modules\Relay\RelayBotCmd.cs" />
<Compile Include="Modules\Relay\RelayBotSender.cs" />
<Compile Include="Network\BaseWebSocket.cs" />
<Compile Include="Network\Heartbeat\ClassiCube.cs" />
<Compile Include="Network\Heartbeat\Heartbeat.cs" />
Expand Down
58 changes: 4 additions & 54 deletions MCGalaxy/Modules/Relay/Discord/DiscordApiClient.cs
Expand Up @@ -114,14 +114,9 @@ public class ChannelSendEmbed : ChannelSendMessage {
/// <summary> Implements a basic web client for sending messages to the Discord API </summary>
/// <remarks> https://discord.com/developers/docs/reference </remarks>
/// <remarks> https://discord.com/developers/docs/resources/channel#create-message </remarks>
public sealed class DiscordApiClient {
public sealed class DiscordApiClient : RelayBotSender<DiscordApiMessage> {
public string Token;
const string host = "https://discord.com/api/v8";
AutoResetEvent handle = new AutoResetEvent(false);
volatile bool terminating;

Queue<DiscordApiMessage> requests = new Queue<DiscordApiMessage>();
readonly object reqLock = new object();

DiscordApiMessage GetNextRequest() {
if (requests.Count == 0) return null;
Expand All @@ -136,12 +131,13 @@ public sealed class DiscordApiClient {
return first;
}

void HandleNext() {
protected override string ThreadName { get { return "Discord-ApiClient"; } }
protected override void HandleNext() {
DiscordApiMessage msg = null;
WebResponse res = null;

lock (reqLock) { msg = GetNextRequest(); }
if (msg == null) { handle.WaitOne(); return; }
if (msg == null) { WaitForWork(); return; }

for (int retry = 0; retry < 10; retry++) {
try {
Expand Down Expand Up @@ -169,34 +165,6 @@ public sealed class DiscordApiClient {
}


void SendLoop() {
for (;;) {
if (terminating) break;

try {
HandleNext();
} catch (Exception ex) {
Logger.LogError(ex);
}
}

// cleanup state
try {
lock (reqLock) requests.Clear();
handle.Dispose();
} catch {
}
}

void WakeupWorker() {
try {
handle.Set();
} catch (ObjectDisposedException) {
// for very rare case where handle's already been destroyed
}
}


static void SleepForRetryPeriod(WebResponse res) {
string resetAfter = res.Headers["X-RateLimit-Reset-After"];
string retryAfter = res.Headers["Retry-After"];
Expand Down Expand Up @@ -227,24 +195,6 @@ public sealed class DiscordApiClient {
}


public void RunAsync() {
Thread worker = new Thread(SendLoop);
worker.Name = "Discord-ApiClient";
worker.IsBackground = true;
worker.Start();
}

public void StopAsync() {
terminating = true;
WakeupWorker();
}

/// <summary> Asynchronously sends a message to the Discord API </summary>
public void SendAsync(DiscordApiMessage msg) {
lock (reqLock) requests.Enqueue(msg);
WakeupWorker();
}

public void SendMessageAsync(string channelID, string message) {
SendAsync(new ChannelSendMessage(channelID, message));
}
Expand Down
85 changes: 85 additions & 0 deletions MCGalaxy/Modules/Relay/RelayBotSender.cs
@@ -0,0 +1,85 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.Threading;

namespace MCGalaxy.Modules.Relay {

/// <summary> Asynchronously sends data to an external communication service </summary>
public abstract class RelayBotSender<T> {
AutoResetEvent handle = new AutoResetEvent(false);
volatile bool terminating;

protected Queue<T> requests = new Queue<T>();
protected readonly object reqLock = new object();

protected abstract void HandleNext();
/// <summary> Name to assign the worker thread </summary>
protected abstract string ThreadName { get; }

void SendLoop() {
for (;;) {
if (terminating) break;

try {
HandleNext();
} catch (Exception ex) {
Logger.LogError(ex);
}
}

// cleanup state
try {
lock (reqLock) requests.Clear();
handle.Dispose();
} catch {
}
}

void WakeupWorker() {
try {
handle.Set();
} catch (ObjectDisposedException) {
// for very rare case where handle's already been destroyed
}
}

protected void WaitForWork() { handle.WaitOne(); }


/// <summary> Starts the background worker thread </summary>
public void RunAsync() {
Thread worker = new Thread(SendLoop);
worker.Name = ThreadName;
worker.IsBackground = true;
worker.Start();
}

public void StopAsync() {
terminating = true;
WakeupWorker();
}

/// <summary> Asynchronously sends data </summary>
public void SendAsync(T msg) {
lock (reqLock) requests.Enqueue(msg);
WakeupWorker();
}
}
}

0 comments on commit bd4a499

Please sign in to comment.