-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathDebugBackend.cs
248 lines (225 loc) · 9.19 KB
/
DebugBackend.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using RemoteX.Data;
using System.Drawing.Bitmap;
/// <summary>
/// 调试后端
/// 因为Unity项目在Editorm模式中没办法使用win32中程序通信间的办法
/// 所以搞出这个调试后端,将控制器的输入都储存到后端上
/// Unity中使用Editor模式时,用WebRequest获取这些东西
/// </summary>
namespace RemoteX.DebugBackend
{
public class DebugBackend
{
private static DebugBackend _Instance;
public static DebugBackend Instance
{
get
{
if(_Instance == null)
{
_Instance = new DebugBackend();
}
return _Instance;
}
}
public bool Running { get; private set; }
public event EventHandler OnServerStart;
public event EventHandler OnServerFailed;
public event EventHandler OnServerClosed;
/// <summary>
/// 储存最新的输入数据
/// </summary>
private Dictionary<int, RemoteXControlMessage> latestControlMessage;
/// <summary>
/// 当被获取后这些数据就从后端删除
/// 避免在调试中出现按下按键弹不开的那种情况
/// </summary>
private Queue<RCMWithEnqueueTime> unfetchedControlMessageBuffer;
private Object unfetchedControlMessageBufferLock;
/// <summary>
/// 当超过这个时间就判超时
/// </summary>
public TimeSpan RemoveBufferTimeout
{
get
{
return new TimeSpan(0, 0, 0, 1, 0);
}
}
public DebugBackend()
{
unfetchedControlMessageBuffer = new Queue<RCMWithEnqueueTime>();
unfetchedControlMessageBufferLock = new object();
}
public void StartBackend(int port)
{
latestControlMessage = new Dictionary<int, RemoteXControlMessage>();
Running = true;
Port = port;
Task startServerTask = startServerAsync();
//Task removeTimeoutBufferTask = removeTimeoutBufferAsync();
}
public void Set(RemoteXControlMessage controlMessage)
{
if (!Running)
{
return;
}
if (latestControlMessage.ContainsKey(controlMessage.DataType))
{
latestControlMessage[controlMessage.DataType] = controlMessage;
}
else
{
latestControlMessage.Add(controlMessage.DataType, controlMessage);
}
RCMWithEnqueueTime rcmWithEnqueueTime = new RCMWithEnqueueTime(DateTime.Now, controlMessage);
lock (unfetchedControlMessageBufferLock)
{
unfetchedControlMessageBuffer.Enqueue(rcmWithEnqueueTime);
DateTime nowDateTime = DateTime.Now;
DateTime earliestBufferEnqueueTime = unfetchedControlMessageBuffer.Peek().EnqueueDateTime;
while((nowDateTime - earliestBufferEnqueueTime) > RemoveBufferTimeout && unfetchedControlMessageBuffer.Count>0)
{
unfetchedControlMessageBuffer.Dequeue();
earliestBufferEnqueueTime = unfetchedControlMessageBuffer.Peek().EnqueueDateTime;
}
}
}
public Bitmap ServerInfoQRCode
{
}
public int Port { get; private set; }
private async Task startServerAsync()
{
HttpListener httpListener = new HttpListener();
httpListener.Prefixes.Add("http://*:" + Port + "/");
try
{
httpListener.Start();
HttpListenerResponse response = null;
System.Diagnostics.Debug.WriteLine("DEBUGBACKEND::Start Listening...");
OnServerStart?.Invoke(this, null);
while (true)
{
try
{
//HttpListenerContext context = httpListener.GetContext();
HttpListenerContext context = await httpListener.GetContextAsync();
HttpListenerRequest request = context.Request;
string[] segments = request.Url.Segments;
int dataTypeInt = 0;
bool hasDataType = false;
foreach(string segment in segments)
{
Console.Write("(" + segment + ")");
}
response = context.Response;
if (segments[1] == "get/")
{
hasDataType = int.TryParse(segments[2], out dataTypeInt);
byte[] responseBuffer = null;
if (hasDataType)
{
if (latestControlMessage.ContainsKey(dataTypeInt))
{
responseBuffer = Encoding.Default.GetBytes(latestControlMessage[dataTypeInt].ToString());
}
else
{
responseBuffer = Encoding.Default.GetBytes("null");
}
response.ContentLength64 = responseBuffer.Length;
Stream output = response.OutputStream;
output.Write(responseBuffer, 0, responseBuffer.Length);
}
else if (segments[2].ToLower() == "buffer")
{
RCMWithEnqueueTime[] bufferArray;
lock (unfetchedControlMessageBufferLock)
{
bufferArray = unfetchedControlMessageBuffer.ToArray();
unfetchedControlMessageBuffer.Clear();
}
string s = "";
foreach (var buffer in bufferArray)
{
s += buffer.RemoteXControlMessage.ToString();
s += '/';
}
responseBuffer = Encoding.Default.GetBytes(s);
response.ContentLength64 = responseBuffer.Length;
Stream output = response.OutputStream;
output.Write(responseBuffer, 0, responseBuffer.Length);
}
else if(segments[2].ToLower() == "serverqrcode.png")
{
response.ContentType = "image/png";
}
}
}
catch(HttpListenerException ex)
{
Console.WriteLine("ERROR IN RESPONSE AND REQUEST: " + ex.Message);
}
finally
{
if(response != null)
{
response.Close();
}
}
}
}
catch(HttpListenerException ex)
{
Console.WriteLine("ERROR IN FUCKING CONNECTION: " + ex.Message);
OnServerFailed?.Invoke(this, null);
}
finally
{
httpListener.Close();
}
}
private Task removeTimeoutBufferAsync()
{
return Task.Run(() =>
{
while (true)
{
lock (unfetchedControlMessageBufferLock)
{
if (unfetchedControlMessageBuffer.Count > 0)
{
RCMWithEnqueueTime rcmWithEnqueueTime = unfetchedControlMessageBuffer.Peek();
if ((DateTime.Now - rcmWithEnqueueTime.EnqueueDateTime) > RemoveBufferTimeout)
{
unfetchedControlMessageBuffer.Dequeue();
}
}
}
}
});
}
/// <summary>
/// 全称:RemoteX Control Message With EnqueueTime
/// </summary>
struct RCMWithEnqueueTime
{
public RemoteXControlMessage RemoteXControlMessage;
public DateTime EnqueueDateTime;
public RCMWithEnqueueTime(DateTime enqueueTime, RemoteXControlMessage controlMessage)
{
this.RemoteXControlMessage = controlMessage;
this.EnqueueDateTime = enqueueTime;
}
}
}
}