Skip to content

Commit 65301d0

Browse files
committed
Added NetLimitter Module
1 parent 1be7ff4 commit 65301d0

File tree

9 files changed

+445
-10
lines changed

9 files changed

+445
-10
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace BHD_ServerManager.Classes.Services.NetLimiter
2+
{
3+
public class Command
4+
{
5+
public required string Action { get; set; }
6+
public Dictionary<string, string> Parameters { get; set; } = new Dictionary<string, string>();
7+
8+
}
9+
10+
public class Response
11+
{
12+
public bool Success { get; set; }
13+
public string? Message { get; set; }
14+
public object? Data { get; set; }
15+
}
16+
17+
public class ConnectionInfo
18+
{
19+
public string? RemoteAddress { get; set; }
20+
public int RemotePort { get; set; }
21+
public string? LocalAddress { get; set; }
22+
public int LocalPort { get; set; }
23+
public string? Protocol { get; set; }
24+
}
25+
}
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
using BHD_ServerManager.Classes.SupportClasses;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.IO;
6+
using System.IO.Pipes;
7+
using System.Text;
8+
using System.Text.Json;
9+
using System.Threading.Tasks;
10+
11+
namespace BHD_ServerManager.Classes.Services.NetLimiter
12+
{
13+
public static class NetLimiterClient
14+
{
15+
private const string PipeName = "NetLimiterPipe";
16+
private const int Timeout = 5000;
17+
18+
private static NamedPipeClientStream _pipeClient;
19+
private static SemaphoreSlim _pipeLock = new SemaphoreSlim(1, 1);
20+
21+
private static Process _bridgeProcess;
22+
23+
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
24+
{
25+
PropertyNameCaseInsensitive = true,
26+
WriteIndented = false
27+
};
28+
29+
public static async Task<Response> SendCommandAsync(Command command)
30+
{
31+
await _pipeLock.WaitAsync();
32+
try
33+
{
34+
// Create connection if not exists or disconnected
35+
if (_pipeClient == null || !_pipeClient.IsConnected)
36+
{
37+
_pipeClient?.Dispose();
38+
_pipeClient =
39+
new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
40+
await _pipeClient.ConnectAsync(Timeout);
41+
}
42+
43+
// Send command
44+
string commandJson = JsonSerializer.Serialize(command, JsonOptions);
45+
using (var writer = new StreamWriter(_pipeClient, Encoding.UTF8, 1024, true))
46+
{
47+
await writer.WriteLineAsync(commandJson);
48+
await writer.FlushAsync();
49+
}
50+
51+
// Receive response
52+
using (var reader = new StreamReader(_pipeClient, Encoding.UTF8, false, 1024, true))
53+
{
54+
string responseJson = await reader.ReadLineAsync();
55+
if (string.IsNullOrEmpty(responseJson))
56+
{
57+
throw new InvalidOperationException("No response received from server");
58+
}
59+
60+
Response response = JsonSerializer.Deserialize<Response>(responseJson, JsonOptions)!;
61+
return response!;
62+
}
63+
}
64+
finally
65+
{
66+
_pipeLock.Release();
67+
}
68+
}
69+
70+
71+
public static async Task<int> GetAppId(string appPath)
72+
{
73+
AppDebug.Log("GetAppIdAsync", "Grabbing Application ID");
74+
75+
var command = new Command
76+
{
77+
Action = "getappid",
78+
Parameters = new Dictionary<string, string> { { "appPath", appPath } }
79+
};
80+
81+
var response = await SendCommandAsync(command);
82+
if (!response.Success || response.Data == null)
83+
{
84+
return 0;
85+
}
86+
87+
// Convert JsonElement to int
88+
if (response.Data is JsonElement jsonElement)
89+
{
90+
return jsonElement.GetInt32();
91+
}
92+
93+
return Convert.ToInt32(response.Data);
94+
}
95+
96+
public static async Task<List<ConnectionInfo>> GetConnectionsAsync(int appId)
97+
{
98+
var command = new Command
99+
{
100+
Action = "getconnections",
101+
Parameters = new Dictionary<string, string> { { "appId", appId.ToString() } }
102+
};
103+
104+
var response = await SendCommandAsync(command);
105+
if (response.Success && response.Data != null)
106+
{
107+
// Deserialize JsonElement to List<ConnectionInfo>
108+
var jsonElement = (JsonElement)response.Data;
109+
return JsonSerializer.Deserialize<List<ConnectionInfo>>(jsonElement.GetRawText(), JsonOptions)!;
110+
}
111+
return new List<ConnectionInfo>();
112+
}
113+
114+
public static async Task<bool> AddIpToFilterAsync(string filterName, string ipAddress)
115+
{
116+
var command = new Command
117+
{
118+
Action = "addIpToFilter",
119+
Parameters = new Dictionary<string, string>
120+
{
121+
{ "filterName", filterName },
122+
{ "ipAddress", ipAddress }
123+
}
124+
};
125+
126+
var response = await SendCommandAsync(command);
127+
return response.Success;
128+
}
129+
130+
public static async Task<bool> RemoveIpFromFilterAsync(string filterName, string ipAddress)
131+
{
132+
var command = new Command
133+
{
134+
Action = "removeIpFromFilter",
135+
Parameters = new Dictionary<string, string>
136+
{
137+
{ "filterName", filterName },
138+
{ "ipAddress", ipAddress }
139+
}
140+
};
141+
142+
var response = await SendCommandAsync(command);
143+
return response.Success;
144+
}
145+
146+
public static async Task<bool> SetConnectionLimitAsync(int limit)
147+
{
148+
var command = new Command
149+
{
150+
Action = "setConnectionLimit",
151+
Parameters = new Dictionary<string, string> { { "limit", limit.ToString() } }
152+
};
153+
154+
var response = await SendCommandAsync(command);
155+
return response.Success;
156+
}
157+
158+
public static async Task<bool> EnableConnectionLimitAsync(bool enabled)
159+
{
160+
var command = new Command
161+
{
162+
Action = "enableConnectionLimit",
163+
Parameters = new Dictionary<string, string> { { "enabled", enabled.ToString() } }
164+
};
165+
166+
var response = await SendCommandAsync(command);
167+
return response.Success;
168+
}
169+
170+
public static async Task<bool> EndProgramAsync()
171+
{
172+
var command = new Command { Action = "endProgram" };
173+
var response = await SendCommandAsync(command);
174+
return response.Success;
175+
}
176+
177+
public static void StartBridgeProcess(string hostname = "localhost", ushort port = 11111, string username = "", string password = "")
178+
{
179+
if (_bridgeProcess != null && !_bridgeProcess.HasExited)
180+
{
181+
AppDebug.Log("NetLimiterClient", "Bridge process already running");
182+
return;
183+
}
184+
185+
try
186+
{
187+
var bridgePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NetLimiterBridge", "NetLimiterBridge.exe");
188+
189+
if (!File.Exists(bridgePath))
190+
{
191+
throw new FileNotFoundException($"NetLimiterBridge.exe not found at {bridgePath}");
192+
}
193+
194+
var startInfo = new ProcessStartInfo
195+
{
196+
FileName = bridgePath,
197+
Arguments = $"{hostname} {port} {username} {password}",
198+
UseShellExecute = false,
199+
CreateNoWindow = true, // Hide console window
200+
RedirectStandardOutput = true,
201+
RedirectStandardError = true,
202+
WindowStyle = ProcessWindowStyle.Hidden
203+
};
204+
205+
_bridgeProcess = Process.Start(startInfo);
206+
207+
// Optional: Capture output for debugging
208+
_bridgeProcess.OutputDataReceived += (sender, e) =>
209+
{
210+
if (!string.IsNullOrEmpty(e.Data))
211+
AppDebug.Log("NetLimiterBridge", e.Data);
212+
};
213+
_bridgeProcess.ErrorDataReceived += (sender, e) =>
214+
{
215+
if (!string.IsNullOrEmpty(e.Data))
216+
AppDebug.Log("NetLimiterBridge [ERROR]", e.Data);
217+
};
218+
219+
_bridgeProcess.BeginOutputReadLine();
220+
_bridgeProcess.BeginErrorReadLine();
221+
222+
AppDebug.Log("NetLimiterClient", "Bridge process started");
223+
224+
// Give it time to initialize
225+
Task.Delay(1000).Wait();
226+
}
227+
catch (Exception ex)
228+
{
229+
AppDebug.Log("NetLimiterClient", $"Failed to start bridge process: {ex.Message}");
230+
throw;
231+
}
232+
}
233+
234+
public static void StopBridgeProcess()
235+
{
236+
if (_bridgeProcess != null && !_bridgeProcess.HasExited)
237+
{
238+
try
239+
{
240+
_bridgeProcess.Kill();
241+
_bridgeProcess.Dispose();
242+
_bridgeProcess = null;
243+
AppDebug.Log("NetLimiterClient", "Bridge process stopped");
244+
}
245+
catch (Exception ex)
246+
{
247+
AppDebug.Log("NetLimiterClient", $"Error stopping bridge process: {ex.Message}");
248+
}
249+
}
250+
}
251+
252+
}
253+
}

BHD-ServerManager/Classes/Tickers/tickerBanManagement.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ public static void runTicker()
4444
AppDebug.Log("tickerBanManagement", "Server process is not attached. Ticker Skipping.");
4545
}
4646

47+
if (tickerNetLimiterMonitor.IsInitialized)
48+
{
49+
tickerNetLimiterMonitor.runTicker();
50+
}
51+
else
52+
{
53+
AppDebug.Log("tickerBanManagement", "NetLimiter not initialized. Ticker skipping.");
54+
}
55+
56+
4757
});
4858
}
4959

0 commit comments

Comments
 (0)