-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPipeFrame.cs
More file actions
203 lines (176 loc) · 6.16 KB
/
PipeFrame.cs
File metadata and controls
203 lines (176 loc) · 6.16 KB
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
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
namespace DiscordRPC.IO
{
/// <summary>
/// A frame received and sent to the Discord client for RPC communications.
/// </summary>
public struct PipeFrame
{
/// <summary>
/// The maxium size of a pipe frame (16kb).
/// </summary>
public static readonly int MAX_SIZE = 16 * 1024;
/// <summary>
/// The opcode of the frame
/// </summary>
public Opcode Opcode { get; set; }
/// <summary>
/// The length of the frame data
/// </summary>
public uint Length { get { return (uint)Data.Length; } }
/// <summary>
/// The data in the frame
/// </summary>
public byte[] Data { get; set; }
/// <summary>
/// The data represented as a string.
/// </summary>
public string Message
{
get { return GetMessage(); }
set { SetMessage(value); }
}
/// <summary>
/// Creates a new pipe frame instance
/// </summary>
/// <param name="opcode">The opcode of the frame</param>
/// <param name="data">The data of the frame that will be serialized as JSON</param>
public PipeFrame(Opcode opcode, object data)
{
//Set the opcode and a temp field for data
Opcode = opcode;
Data = null;
//Set the data
SetObject(data);
}
/// <summary>
/// Gets the encoding used for the pipe frames
/// </summary>
public Encoding MessageEncoding { get { return Encoding.UTF8; } }
/// <summary>
/// Sets the data based of a string
/// </summary>
/// <param name="str"></param>
private void SetMessage(string str)
{ Data = MessageEncoding.GetBytes(str); }
/// <summary>
/// Gets a string based of the data
/// </summary>
/// <returns></returns>
private string GetMessage()
{ return MessageEncoding.GetString(Data); }
/// <summary>
/// Serializes the object into json string then encodes it into <see cref="Data"/>.
/// </summary>
/// <param name="obj"></param>
public void SetObject(object obj)
{
string json = JsonConvert.SerializeObject(obj);
SetMessage(json);
}
/// <summary>
/// Sets the opcodes and serializes the object into a json string.
/// </summary>
/// <param name="opcode"></param>
/// <param name="obj"></param>
public void SetObject(Opcode opcode, object obj)
{
Opcode = opcode;
SetObject(obj);
}
/// <summary>
/// Deserializes the data into the supplied type using JSON.
/// </summary>
/// <typeparam name="T">The type to deserialize into</typeparam>
/// <returns></returns>
public T GetObject<T>()
{
string json = GetMessage();
return JsonConvert.DeserializeObject<T>(json);
}
/// <summary>
/// Attempts to read the contents of the frame from the stream
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public bool ReadStream(Stream stream)
{
//Try to read the opcode
uint op;
if (!TryReadUInt32(stream, out op))
return false;
//Try to read the length
uint len;
if (!TryReadUInt32(stream, out len))
return false;
uint readsRemaining = len;
//Read the contents
using (var mem = new MemoryStream())
{
byte[] buffer = new byte[Min(2048, len)]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, Min(buffer.Length, readsRemaining))) > 0)
{
readsRemaining -= len;
mem.Write(buffer, 0, bytesRead);
}
byte[] result = mem.ToArray();
if (result.LongLength != len)
return false;
Opcode = (Opcode)op;
Data = result;
return true;
}
//fun
//if (a != null) { do { yield return true; switch (a) { case 1: await new Task(); default: lock (obj) { foreach (b in c) { for (int d = 0; d < 1; d++) { a++; } } } while (a is typeof(int) || (new Class()) != null) } goto MY_LABEL;
}
/// <summary>
/// Returns minimum value between a int and a unsigned int
/// </summary>
private int Min(int a, uint b)
{
if (b >= a) return a;
return (int)b;
}
/// <summary>
/// Attempts to read a UInt32
/// </summary>
/// <param name="stream"></param>
/// <param name="value"></param>
/// <returns></returns>
private bool TryReadUInt32(Stream stream, out uint value)
{
//Read the bytes available to us
byte[] bytes = new byte[4];
int cnt = stream.Read(bytes, 0, bytes.Length);
//Make sure we actually have a valid value
if (cnt != 4)
{
value = default(uint);
return false;
}
value = BitConverter.ToUInt32(bytes, 0);
return true;
}
/// <summary>
/// Writes the frame into the target frame as one big byte block.
/// </summary>
/// <param name="stream"></param>
public void WriteStream(Stream stream)
{
//Get all the bytes
byte[] op = BitConverter.GetBytes((uint)Opcode);
byte[] len = BitConverter.GetBytes(Length);
//Copy it all into a buffer
byte[] buff = new byte[op.Length + len.Length + Data.Length];
op.CopyTo(buff, 0);
len.CopyTo(buff, op.Length);
Data.CopyTo(buff, op.Length + len.Length);
//Write it to the stream
stream.Write(buff, 0, buff.Length);
}
}
}