· 6 years ago · Apr 25, 2019, 09:48 AM
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Net;
6using System.Text;
7using System.Threading.Tasks;
8using Newtonsoft;
9using Newtonsoft.Json;
10using Newtonsoft.Json.Linq;
11
12namespace YandexEat.Post
13{
14 public class HelperPOST<T> where T: class
15 {
16 private Dictionary<string, object> _properties = new Dictionary<string, object>();
17 private string _actionName;
18 private string _apiKey;
19 private string _initError;
20
21 private const string Protocol = "https";
22 private const string Host = "delivery.yandex.ru";
23 private const string ContentType = "application/x-www-form-urlencoded";
24 private const string PostActionPrefix = "api/last";
25
26 public delegate void Complite(ResponseResult<T> result);
27 public event Complite OnComplite;
28
29
30 public HelperPOST(string actionName, string yandex_api_keys, string yandex_user_info)
31 {
32 _actionName = actionName;
33
34 if (string.IsNullOrEmpty(yandex_api_keys) || string.IsNullOrEmpty(yandex_user_info))
35 {
36 _initError = "[YandexPostHelper] Api keys OR user info is empty";
37 return;
38 }
39
40 try
41 {
42 var yandexKeysObject = JObject.Parse(yandex_api_keys);
43 var yandexUserInfoObject = JObject.Parse(yandex_user_info);
44
45 var clientId = int.Parse(yandexUserInfoObject["client"]["id"].ToString());
46 var senderId = int.Parse((yandexUserInfoObject["senders"] as JArray).FirstOrDefault()["id"].ToString());
47
48 _apiKey = yandexKeysObject[_actionName].ToString();
49
50 AddProperty("client_id", clientId);
51 AddProperty("sender_id", senderId);
52 }
53 catch (Exception exception)
54 {
55 _initError = $"[YandexPostHelper] Ошибка параметров json: {exception.Message}";
56 }
57 }
58
59
60 #region Open functions
61
62 public void AddProperty(string name, object value)
63 {
64 _properties.Add(name, value);
65 }
66
67 public async void SendAsync()
68 {
69 var result = new ResponseResult<T>();
70
71 if (!string.IsNullOrEmpty(_initError))
72 {
73 result.Error = _initError;
74 Console.WriteLine(result.Error);
75 }
76
77 AddSecretKey();
78 var data = GetJson();
79 var dataBytes = System.Text.Encoding.UTF8.GetBytes(data);
80 var dataLength = dataBytes.Length;
81
82 #region Request
83 WebRequest request = WebRequest.Create($"{Protocol}://{Host}/{PostActionPrefix}/{_actionName}");
84
85 request.Method = "POST";
86 request.ContentType = ContentType;
87 request.ContentLength = dataLength;
88
89 using (Stream dataStream = request.GetRequestStream())
90 {
91 dataStream.Write(dataBytes, 0, dataLength);
92 }
93 #endregion Request
94
95 #region Response
96 WebResponse webResponse = await request.GetResponseAsync();
97 var responseJson = string.Empty;
98 using (Stream stream = webResponse.GetResponseStream())
99 {
100 using (StreamReader reader = new StreamReader(stream))
101 {
102 responseJson = reader.ReadToEnd();
103 }
104 }
105 webResponse.Dispose();
106 #endregion Response
107
108 var responseBase = JsonConvert.DeserializeObject<Response>(responseJson);
109 switch (responseBase.Status)
110 {
111 case "ok":
112 var responseObject = JsonConvert.DeserializeObject<Response<T>>(responseJson);
113 result.Data = responseObject.Data;
114 break;
115 case "error":
116 var errorResult = JsonConvert.DeserializeObject<Response<JObject>>(responseJson);
117 result.Error = errorResult.Data;
118 break;
119 default:
120 Console.WriteLine(responseBase.Status);
121 break;
122 }
123
124 OnComplite?.Invoke(result);
125 }
126
127 public ResponseResult<T> Send()
128 {
129 var result = new ResponseResult<T>();
130
131 if (!string.IsNullOrEmpty(_initError))
132 {
133 result.Error = _initError;
134 Console.WriteLine(result.Error);
135 return result;
136 }
137
138 AddSecretKey();
139 var data = GetJson();
140 var dataBytes = Encoding.UTF8.GetBytes(data);
141 var dataLength = dataBytes.Length;
142
143 #region Request
144 WebRequest request = WebRequest.Create($"{Protocol}://{Host}/{PostActionPrefix}/{_actionName}");
145
146 request.Method = "POST";
147 request.ContentType = ContentType;
148 request.ContentLength = dataLength;
149
150 using (Stream dataStream = request.GetRequestStream())
151 {
152 dataStream.Write(dataBytes, 0, dataLength);
153 }
154 #endregion Request
155
156 #region Response
157 WebResponse webResponse = request.GetResponse();
158 var responseJson = string.Empty;
159 using (Stream stream = webResponse.GetResponseStream())
160 {
161 using (StreamReader reader = new StreamReader(stream))
162 {
163 responseJson = reader.ReadToEnd();
164 }
165 }
166 webResponse.Dispose();
167 #endregion Response
168
169 var responseBase = JsonConvert.DeserializeObject<Response>(responseJson);
170 switch (responseBase.Status)
171 {
172 case "ok":
173 var responseObject = JsonConvert.DeserializeObject<Response<T>>(responseJson);
174 result.Data = responseObject.Data;
175 break;
176 case "error":
177 var errorResult = JsonConvert.DeserializeObject<Response<JObject>>(responseJson);
178 result.Error = errorResult.Data;
179 Console.WriteLine($"[YandexPostHelper] Response error: \r\n{result.Error}");
180 break;
181 default:
182 Console.WriteLine($"[YandexPostHelper] Unrecognized status: {responseBase.Status}");
183 break;
184 }
185
186 return result;
187 }
188
189 #endregion Open functions
190
191
192 #region Helpers
193
194 /// <summary>
195 /// Компонует <see cref="_properties"/> в json.
196 /// </summary>
197 /// <returns></returns>
198 private string GetJson()
199 {
200 var result = new JObject();
201 var props = _properties.OrderBy(x => x.Key);
202
203 foreach (var prop in props)
204 {
205 var jProp = new JProperty(prop.Key, prop.Value);
206 result.Add(jProp);
207 }
208
209 return result.ToString();
210 }
211
212 private const string _keySecretKey = "secret_key";
213 private void AddSecretKey()
214 {
215 // Мы не можем Ñоздать объект из Dictionary, поÑтому пихаем вÑÑ‘ в json => json в jObject => jObject Ñортируем
216 var json = GetJson();
217 var jObject = (JObject)JsonConvert.DeserializeObject(json);
218 SortJObject(jObject);
219 // И получаем Ñтроку из значений
220 var sortedValuesStr = GetValuesString(jObject);
221 var secretKey = $"{sortedValuesStr}{_apiKey}";
222
223 secretKey = MD5(secretKey);
224
225 if (!_properties.ContainsKey(_keySecretKey))
226 {
227 AddProperty(_keySecretKey, secretKey);
228 }
229 else
230 {
231 _properties[_keySecretKey] = secretKey;
232 }
233 }
234
235 private string MD5(string input)
236 {
237 var md5 = System.Security.Cryptography.MD5.Create();
238 var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
239 var result = BitConverter.ToString(hash).Replace("-", "").ToLower();
240
241 return result;
242 }
243
244 /// <summary>
245 /// Сортирует jObject по имени параметров.
246 /// </summary>
247 /// <param name="jObj"></param>
248 private void SortJObject(JObject jObj)
249 {
250 var props = jObj.Properties().ToList();
251 foreach (var prop in props)
252 {
253 prop.Remove();
254 }
255
256 foreach (var prop in props.OrderBy(p => p.Name))
257 {
258 jObj.Add(prop);
259 if (prop.Value is JObject)
260 {
261 SortJObject((JObject)prop.Value);
262 }
263 }
264 }
265
266 /// <summary>
267 /// Ð”Ð»Ñ Ñ€Ð°Ñчёта Ñекретного ключа.
268 /// Строка из отправлÑемых значений без ключей и разделителей.
269 /// </summary>
270 /// <param name="jObject"></param>
271 /// <returns></returns>
272 private string GetValuesString(JObject jObject)
273 {
274 var resultArray = new List<string>();
275 var props = jObject.Properties().Where(x => x.Name != _keySecretKey).ToList();
276
277 foreach (var prop in props.OrderBy(p => p.Name))
278 {
279 if (prop.Value is JObject)
280 {
281 resultArray.Add(GetValuesString((JObject)prop.Value));
282 }
283 else
284 {
285 resultArray.Add(prop.Value.ToString());
286 }
287 }
288
289 return string.Join("", resultArray);
290 }
291
292
293 #endregion Helpers
294 }
295}