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+ }
0 commit comments