You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

952 lines
30 KiB

  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Net.Sockets;
  5. using System.Diagnostics;
  6. namespace Apewer.Source
  7. {
  8. /// <summary></summary>
  9. public class Redis : IDisposable
  10. {
  11. Socket socket;
  12. BufferedStream bstream;
  13. int db = 0;
  14. /// <summary>连接指定主机。</summary>
  15. public Redis(string host, int port = 6379, string password = null)
  16. {
  17. Host = string.IsNullOrEmpty(host) ? "localhost" : host;
  18. Port = (port < 1 || port > 65535) ? 6379 : port;
  19. Password = password;
  20. SendTimeout = -1;
  21. }
  22. /// <summary>连接 localhost 的指定端口。</summary>
  23. public Redis(int port, string host = "localhost", string password = null) : this(host, port, password) { }
  24. /// <summary>连接 localhost 的 6379 端口。</summary>
  25. public Redis() : this("localhost", 6379, null) { }
  26. /// <summary>主机。</summary>
  27. public string Host { get; private set; }
  28. /// <summary>端口。</summary>
  29. public int Port { get; private set; }
  30. /// <summary>重试超时。</summary>
  31. public int RetryTimeout { get; set; }
  32. /// <summary>重试次数。</summary>
  33. public int RetryCount { get; set; }
  34. /// <summary>Socket 发送超时。</summary>
  35. public int SendTimeout { get; set; }
  36. /// <summary>密码。</summary>
  37. public string Password { get; set; }
  38. /// <summary>设置要日志输出。</summary>
  39. public Action<string> Log { get; set; }
  40. /// <summary>数据库编号,默认为 0。</summary>
  41. public int Db
  42. {
  43. get { return db; }
  44. set
  45. {
  46. db = value;
  47. SendExpectSuccess("SELECT", db);
  48. }
  49. }
  50. /// <summary>获取或设置文本。</summary>
  51. public string this[string key]
  52. {
  53. get { return GetString(key); }
  54. set { Set(key, value); }
  55. }
  56. /// <summary>设置 UTF-8 文本。返回错误信息。</summary>
  57. public string Set(string key, string value, bool ifNotExist = false)
  58. {
  59. if (key == null) return "Key 无效。";
  60. if (value == null) return "Value 无效";
  61. var bytes = value.Length < 1 ? new byte[0] : GetBytes(value);
  62. return Set(key, bytes, ifNotExist);
  63. }
  64. /// <summary>设置字节数组,Bytes 最大长度为 1073741824。返回错误信息。</summary>
  65. public string Set(string key, byte[] bytes, bool ifNotExist = false)
  66. {
  67. if (key == null) return "Key 无效。";
  68. if (bytes == null) return "Bytes 无效";
  69. if (bytes.Length > 1073741824) return "Value[] 长度超出限制。";
  70. var cmd = ifNotExist ? "SETNX" : "SET";
  71. var success = SendDataCommand(bytes, cmd, key);
  72. if (!success) return "设置失败。";
  73. return ExpectSuccess();
  74. }
  75. /// <summary>设置多个值。返回错误信息。</summary>
  76. public string Set(IDictionary<string, string> dict)
  77. {
  78. if (dict == null) return "字典无效。";
  79. var newDict = new Dictionary<string, byte[]>();
  80. foreach (var i in dict) newDict.Add(i.Key, GetBytes(i.Value));
  81. return Set(newDict);
  82. // return Set(dict.ToDictionary(k => k.Key, v => GetBytes(v.Value)));
  83. }
  84. /// <summary>设置多个值。返回错误信息。</summary>
  85. public string Set(IDictionary<string, byte[]> dict)
  86. {
  87. if (dict == null) return "字典无效。";
  88. var keys = new List<string>();
  89. var values = new List<byte[]>();
  90. foreach (var i in dict)
  91. {
  92. keys.Add(i.Key);
  93. values.Add(i.Value);
  94. }
  95. return Set(keys.ToArray(), values.ToArray());
  96. //return Set(dict.Keys.ToArray(), dict.Values.ToArray());
  97. }
  98. /// <summary>设置多个值。返回错误信息。</summary>
  99. public string Set(string[] keys, byte[][] values)
  100. {
  101. if (keys == null) return "Keys 无效。";
  102. if (values == null) return "Values 无效";
  103. if (keys.Length != values.Length) return "Keys 和 Values 的长度不相等";
  104. byte[] nl = GetBytes("\r\n");
  105. var ms = new MemoryStream();
  106. for (int i = 0; i < keys.Length; i++)
  107. {
  108. byte[] key = GetBytes(keys[i]);
  109. byte[] val = values[i];
  110. byte[] kLength = GetBytes("$" + key.Length + "\r\n");
  111. byte[] k = GetBytes(keys[i] + "\r\n");
  112. byte[] vLength = GetBytes("$" + val.Length + "\r\n");
  113. ms.Write(kLength, 0, kLength.Length);
  114. ms.Write(k, 0, k.Length);
  115. ms.Write(vLength, 0, vLength.Length);
  116. ms.Write(val, 0, val.Length);
  117. ms.Write(nl, 0, nl.Length);
  118. }
  119. SendDataRESP(ms.ToArray(), "*" + (keys.Length * 2 + 1) + "\r\n$4\r\nMSET\r\n");
  120. return ExpectSuccess();
  121. }
  122. /// <summary>获取值。Key 无效时获取 NULL 值。</summary>
  123. public byte[] Get(string key)
  124. {
  125. if (key == null) return null;
  126. return SendExpectData("GET", key);
  127. }
  128. /// <summary>获取值。Key 无效时获取 NULL 值。</summary>
  129. public string GetString(string key)
  130. {
  131. if (key == null) return null;
  132. var bytes = Get(key);
  133. if (bytes == null) return null;
  134. return GetString(bytes);
  135. }
  136. /// <summary>排序。</summary>
  137. public byte[][] Sort(string key = null, string storeInKey = null, bool descending = false, bool lexographically = false, int lowerLimit = 0, int upperLimit = 0, string by = null, string get = null
  138. )
  139. {
  140. var args = new System.Collections.ArrayList();
  141. if (lowerLimit != 0 || upperLimit != 0)
  142. {
  143. args.Add("LIMIT");
  144. args.Add(lowerLimit);
  145. args.Add(upperLimit);
  146. }
  147. if (lexographically) args.Add("ALPHA");
  148. if (!string.IsNullOrEmpty(by))
  149. {
  150. args.Add("BY");
  151. args.Add(by);
  152. }
  153. if (!string.IsNullOrEmpty(get))
  154. {
  155. args.Add("GET");
  156. args.Add(get);
  157. }
  158. var argsArray = args.ToArray();
  159. return Sort(key, storeInKey, argsArray);
  160. }
  161. // public byte[][] Sort(RedisSortOptions options)
  162. // {
  163. // return Sort(options.Key, options.StoreInKey, options.ToArgs());
  164. // }
  165. /// <summary>排序。Key 无效时返回 NULL 值。</summary>
  166. public byte[][] Sort(string key, string destination, params object[] options)
  167. {
  168. if (key == null) return null; // throw new ArgumentNullException("key");
  169. int offset = string.IsNullOrEmpty(destination) ? 1 : 3;
  170. object[] args = new object[offset + options.Length];
  171. args[0] = key;
  172. Array.Copy(options, 0, args, offset, options.Length);
  173. if (offset == 1)
  174. {
  175. return SendExpectDataArray("SORT", args);
  176. }
  177. else
  178. {
  179. args[1] = "STORE";
  180. args[2] = destination;
  181. int n = SendExpectInt("SORT", args);
  182. return new byte[n][];
  183. }
  184. }
  185. /// <summary>获取集合。获取失败时返回 NULL 值。</summary>
  186. public byte[] GetSet(string key, byte[] value)
  187. {
  188. if (key == null) return null; // throw new ArgumentNullException("key");
  189. if (value == null) return null; // throw new ArgumentNullException("value");
  190. if (value.Length > 1073741824) return null; // throw new ArgumentException("value exceeds 1G", "value");
  191. if (!SendDataCommand(value, "GETSET", key)) return null; // throw new Exception("Unable to connect");
  192. return ReadData();
  193. }
  194. /// <summary>获取集合。获取失败时返回 NULL 值。</summary>
  195. public string GetSet(string key, string value)
  196. {
  197. if (key == null) return null; // throw new ArgumentNullException("key");
  198. if (value == null) return null; // throw new ArgumentNullException("value");
  199. return GetString(GetSet(key, GetBytes(value)));
  200. }
  201. string ReadLine()
  202. {
  203. var sb = new System.Text.StringBuilder();
  204. int c;
  205. while ((c = bstream.ReadByte()) != -1)
  206. {
  207. if (c == '\r')
  208. continue;
  209. if (c == '\n')
  210. break;
  211. sb.Append((char)c);
  212. }
  213. return sb.ToString();
  214. }
  215. string Connect()
  216. {
  217. try
  218. {
  219. socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  220. socket.NoDelay = true;
  221. socket.SendTimeout = SendTimeout;
  222. socket.Connect(Host, Port);
  223. if (!socket.Connected)
  224. {
  225. socket.Close();
  226. socket = null;
  227. return "连接失败。";
  228. }
  229. bstream = new BufferedStream(new NetworkStream(socket), 16 * 1024);
  230. if (Password != null) return SendExpectSuccess("AUTH", Password);
  231. return null;
  232. }
  233. catch (Exception ex)
  234. {
  235. var error = ex.GetType().Name + ": " + ex.Message;
  236. return error;
  237. }
  238. }
  239. byte[] end_data = new byte[] { (byte)'\r', (byte)'\n' };
  240. bool SendDataCommand(byte[] data, string cmd, params object[] args)
  241. {
  242. string resp = "*" + (1 + args.Length + 1).ToString() + "\r\n";
  243. resp += "$" + cmd.Length + "\r\n" + cmd + "\r\n";
  244. foreach (object arg in args)
  245. {
  246. string argStr = arg.ToString();
  247. int argStrLength = GetByteCount(argStr);
  248. resp += "$" + argStrLength + "\r\n" + argStr + "\r\n";
  249. }
  250. resp += "$" + data.Length + "\r\n";
  251. return SendDataRESP(data, resp);
  252. }
  253. bool SendDataRESP(byte[] data, string resp)
  254. {
  255. if (socket == null)
  256. Connect();
  257. if (socket == null)
  258. return false;
  259. byte[] r = GetBytes(resp);
  260. try
  261. {
  262. ShowLog("C", resp);
  263. socket.Send(r);
  264. if (data != null)
  265. {
  266. socket.Send(data);
  267. socket.Send(end_data);
  268. }
  269. }
  270. catch (SocketException)
  271. {
  272. // timeout;
  273. socket.Close();
  274. socket = null;
  275. return false;
  276. }
  277. return true;
  278. }
  279. bool SendCommand(string cmd, params object[] args)
  280. {
  281. if (socket == null)
  282. Connect();
  283. if (socket == null)
  284. return false;
  285. string resp = "*" + (1 + args.Length).ToString() + "\r\n";
  286. resp += "$" + cmd.Length + "\r\n" + cmd + "\r\n";
  287. foreach (object arg in args)
  288. {
  289. string argStr = arg.ToString();
  290. int argStrLength = GetByteCount(argStr);
  291. resp += "$" + argStrLength + "\r\n" + argStr + "\r\n";
  292. }
  293. byte[] r = GetBytes(resp);
  294. try
  295. {
  296. ShowLog("C", resp);
  297. socket.Send(r);
  298. }
  299. catch (SocketException)
  300. {
  301. // timeout;
  302. socket.Close();
  303. socket = null;
  304. return false;
  305. }
  306. return true;
  307. }
  308. [Conditional("DEBUG")]
  309. void ShowLog(string id, string message)
  310. {
  311. Log?.Invoke(id + ": " + message.Trim().Replace("\r\n", " "));
  312. }
  313. string ExpectSuccess()
  314. {
  315. int c = bstream.ReadByte();
  316. if (c == -1) return "没有更多字节。";
  317. string s = ReadLine();
  318. ShowLog("S", (char)c + s);
  319. if (c == '-') return s.StartsWith("ERR ") ? s.Substring(4) : s;
  320. return null;
  321. }
  322. string SendExpectSuccess(string cmd, params object[] args)
  323. {
  324. if (!SendCommand(cmd, args)) return "无法连接。"; // throw new Exception("Unable to connect");
  325. return ExpectSuccess();
  326. }
  327. int SendDataExpectInt(byte[] data, string cmd, params object[] args)
  328. {
  329. if (!SendDataCommand(data, cmd, args)) return 0; // throw new Exception("Unable to connect");
  330. int c = bstream.ReadByte();
  331. if (c == -1) return 0; // throw new ResponseException("No more data");
  332. string s = ReadLine();
  333. ShowLog("S", (char)c + s);
  334. if (c == '-') return 0; // throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s);
  335. if (c == ':')
  336. {
  337. int i;
  338. if (int.TryParse(s, out i)) return i;
  339. }
  340. return 0; // throw new ResponseException("Unknown reply on integer request: " + c + s);
  341. }
  342. int SendExpectInt(string cmd, params object[] args)
  343. {
  344. if (!SendCommand(cmd, args)) return 0; // throw new Exception("Unable to connect");
  345. int c = bstream.ReadByte();
  346. if (c == -1) return 0; // throw new ResponseException("No more data");
  347. string s = ReadLine();
  348. ShowLog("S", (char)c + s);
  349. if (c == '-') return 0; // throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s);
  350. if (c == ':')
  351. {
  352. int i;
  353. if (int.TryParse(s, out i)) return i;
  354. }
  355. return 0; // throw new ResponseException("Unknown reply on integer request: " + c + s);
  356. }
  357. string SendExpectString(string cmd, params object[] args)
  358. {
  359. if (!SendCommand(cmd, args)) return null; // throw new Exception("Unable to connect");
  360. int c = bstream.ReadByte();
  361. if (c == -1) return null; // throw new ResponseException("No more data");
  362. string s = ReadLine();
  363. ShowLog("S", (char)c + s);
  364. if (c == '-') return null; // throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s);
  365. if (c == '+') return s;
  366. return null; // throw new ResponseException("Unknown reply on integer request: " + c + s);
  367. }
  368. string SendGetString(string cmd, params object[] args)
  369. {
  370. if (!SendCommand(cmd, args)) return null; // 连接失败时返回 NULL 值。
  371. return ReadLine();
  372. }
  373. byte[] SendExpectData(string cmd, params object[] args)
  374. {
  375. if (!SendCommand(cmd, args)) return null; // 连接失败时返回 NULL 值。
  376. return ReadData();
  377. }
  378. byte[] ReadData()
  379. {
  380. string s = ReadLine();
  381. ShowLog("S", s);
  382. if (s.Length == 0) return null; // 失败时返回 NULL 值。不 Throw 异常。
  383. char c = s[0];
  384. if (c == '-') return null; // throw new ResponseException(s.StartsWith("-ERR ") ? s.Substring(5) : s.Substring(1));
  385. if (c == '$')
  386. {
  387. if (s == "$-1")
  388. return null;
  389. int n;
  390. if (Int32.TryParse(s.Substring(1), out n))
  391. {
  392. byte[] retbuf = new byte[n];
  393. int bytesRead = 0;
  394. do
  395. {
  396. int read = bstream.Read(retbuf, bytesRead, n - bytesRead);
  397. if (read < 1) return null; // throw new ResponseException("Invalid termination mid stream");
  398. bytesRead += read;
  399. }
  400. while (bytesRead < n);
  401. if (bstream.ReadByte() != '\r' || bstream.ReadByte() != '\n') return null; // throw new ResponseException("Invalid termination");
  402. return retbuf;
  403. }
  404. return null; // throw new ResponseException("Invalid length");
  405. }
  406. /* don't treat arrays here because only one element works -- use DataArray!
  407. //returns the number of matches
  408. if (c == '*') {
  409. int n;
  410. if (Int32.TryParse(s.Substring(1), out n))
  411. return n <= 0 ? new byte [0] : ReadData();
  412. throw new ResponseException ("Unexpected length parameter" + r);
  413. }
  414. */
  415. return null; // throw new ResponseException("Unexpected reply: " + s);
  416. }
  417. /// <summary></summary>
  418. public bool ContainsKey(string key)
  419. {
  420. if (key == null) return false; // throw new ArgumentNullException("key");
  421. return SendExpectInt("EXISTS", key) == 1;
  422. }
  423. /// <summary></summary>
  424. public bool Remove(string key)
  425. {
  426. if (key == null) return false; // throw new ArgumentNullException("key");
  427. return SendExpectInt("DEL", key) == 1;
  428. }
  429. /// <summary></summary>
  430. public int Remove(params string[] args)
  431. {
  432. if (args == null) return 0; // throw new ArgumentNullException("args");
  433. return SendExpectInt("DEL", args);
  434. }
  435. /// <summary></summary>
  436. public int Increment(string key)
  437. {
  438. if (key == null) return 0; // throw new ArgumentNullException("key");
  439. return SendExpectInt("INCR", key);
  440. }
  441. /// <summary></summary>
  442. public int Increment(string key, int count)
  443. {
  444. if (key == null) return 0; // throw new ArgumentNullException("key");
  445. return SendExpectInt("INCRBY", key, count);
  446. }
  447. /// <summary></summary>
  448. public int Decrement(string key)
  449. {
  450. if (key == null) return 0; // throw new ArgumentNullException("key");
  451. return SendExpectInt("DECR", key);
  452. }
  453. /// <summary></summary>
  454. public int Decrement(string key, int count)
  455. {
  456. if (key == null) return 0; // throw new ArgumentNullException("key");
  457. return SendExpectInt("DECRBY", key, count);
  458. }
  459. /// <summary>获取 Key 的值类型,正确类型为 none | string | set | list。</summary>
  460. public string TypeOf(string key)
  461. {
  462. if (key == null) return "";
  463. return SendExpectString("TYPE", key);
  464. }
  465. /// <summary></summary>
  466. public string RandomKey()
  467. {
  468. return SendExpectString("RANDOMKEY");
  469. }
  470. /// <summary></summary>
  471. public bool Rename(string oldKeyname, string newKeyname)
  472. {
  473. if (oldKeyname == null) return false; // throw new ArgumentNullException("oldKeyname");
  474. if (newKeyname == null) return false; // throw new ArgumentNullException("newKeyname");
  475. return SendGetString("RENAME", oldKeyname, newKeyname)[0] == '+';
  476. }
  477. /// <summary></summary>
  478. public bool Expire(string key, int seconds)
  479. {
  480. if (key == null) return false; // throw new ArgumentNullException("key");
  481. return SendExpectInt("EXPIRE", key, seconds) == 1;
  482. }
  483. /// <summary></summary>
  484. public bool ExpireAt(string key, int time)
  485. {
  486. if (key == null) return false;// throw new ArgumentNullException("key");
  487. return SendExpectInt("EXPIREAT", key, time) == 1;
  488. }
  489. /// <summary></summary>
  490. public int TimeToLive(string key)
  491. {
  492. if (key == null) return 0; // throw new ArgumentNullException("key");
  493. return SendExpectInt("TTL", key);
  494. }
  495. /// <summary></summary>
  496. public int DbSize
  497. {
  498. get { return SendExpectInt("DBSIZE"); }
  499. }
  500. /// <summary></summary>
  501. public void Save()
  502. {
  503. SendExpectSuccess("SAVE");
  504. }
  505. /// <summary></summary>
  506. public void BackgroundSave()
  507. {
  508. SendExpectSuccess("BGSAVE");
  509. }
  510. /// <summary></summary>
  511. public void Shutdown()
  512. {
  513. SendCommand("SHUTDOWN");
  514. try
  515. {
  516. // the server may return an error
  517. string s = ReadLine();
  518. ShowLog("S", s);
  519. if (s.Length == 0) return; // throw new ResponseException("Zero length respose");
  520. // throw new ResponseException(s.StartsWith("-ERR ") ? s.Substring(5) : s.Substring(1));
  521. }
  522. catch (IOException)
  523. {
  524. // this is the expected good result
  525. socket.Close();
  526. socket = null;
  527. }
  528. }
  529. /// <summary></summary>
  530. public void FlushAll()
  531. {
  532. SendExpectSuccess("FLUSHALL");
  533. }
  534. /// <summary></summary>
  535. public void FlushDb()
  536. {
  537. SendExpectSuccess("FLUSHDB");
  538. }
  539. const long UnixEpoch = 621355968000000000L;
  540. /// <summary></summary>
  541. public DateTime LastSave
  542. {
  543. get
  544. {
  545. int t = SendExpectInt("LASTSAVE");
  546. return new DateTime(UnixEpoch) + TimeSpan.FromSeconds(t);
  547. }
  548. }
  549. /// <summary></summary>
  550. public Dictionary<string, string> GetInfo()
  551. {
  552. byte[] r = SendExpectData("INFO");
  553. var dict = new Dictionary<string, string>();
  554. foreach (var line in GetString(r).Split('\n'))
  555. {
  556. int p = line.IndexOf(':');
  557. if (p == -1)
  558. continue;
  559. dict.Add(line.Substring(0, p), line.Substring(p + 1));
  560. }
  561. return dict;
  562. }
  563. /// <summary></summary>
  564. public string[] Keys
  565. {
  566. get
  567. {
  568. return GetKeys("*");
  569. }
  570. }
  571. /// <summary></summary>
  572. public string[] GetKeys(string pattern)
  573. {
  574. if (pattern == null) return null; // throw new ArgumentNullException("pattern");
  575. return SendExpectStringArray("KEYS", pattern);
  576. }
  577. /// <summary></summary>
  578. public byte[][] MGet(params string[] keys)
  579. {
  580. if (keys == null) return null; // throw new ArgumentNullException("keys");
  581. if (keys.Length == 0) return null; // throw new ArgumentException("keys");
  582. return SendExpectDataArray("MGET", keys);
  583. }
  584. /// <summary></summary>
  585. public string[] SendExpectStringArray(string cmd, params object[] args)
  586. {
  587. byte[][] reply = SendExpectDataArray(cmd, args);
  588. string[] keys = new string[reply.Length];
  589. for (int i = 0; i < reply.Length; i++)
  590. keys[i] = GetString(reply[i]);
  591. return keys;
  592. }
  593. /// <summary></summary>
  594. public byte[][] SendExpectDataArray(string cmd, params object[] args)
  595. {
  596. if (!SendCommand(cmd, args)) return null; // throw new Exception("Unable to connect");
  597. int c = bstream.ReadByte();
  598. if (c == -1) return null; // throw new ResponseException("No more data");
  599. string s = ReadLine();
  600. ShowLog("S", (char)c + s);
  601. if (c == '-') return null; // throw new ResponseException(s.StartsWith("ERR ") ? s.Substring(4) : s);
  602. if (c == '*')
  603. {
  604. int count;
  605. if (int.TryParse(s, out count))
  606. {
  607. byte[][] result = new byte[count][];
  608. for (int i = 0; i < count; i++) result[i] = ReadData();
  609. return result;
  610. }
  611. }
  612. return null; // throw new ResponseException("Unknown reply on multi-request: " + c + s);
  613. }
  614. #region List commands
  615. /// <summary></summary>
  616. public byte[][] ListRange(string key, int start, int end)
  617. {
  618. return SendExpectDataArray("LRANGE", key, start, end);
  619. }
  620. /// <summary></summary>
  621. public void LeftPush(string key, string value)
  622. {
  623. LeftPush(key, GetBytes(value));
  624. }
  625. /// <summary></summary>
  626. public void LeftPush(string key, byte[] value)
  627. {
  628. SendDataCommand(value, "LPUSH", key);
  629. ExpectSuccess();
  630. }
  631. /// <summary></summary>
  632. public void RightPush(string key, string value)
  633. {
  634. RightPush(key, GetBytes(value));
  635. }
  636. /// <summary></summary>
  637. public void RightPush(string key, byte[] value)
  638. {
  639. SendDataCommand(value, "RPUSH", key);
  640. ExpectSuccess();
  641. }
  642. /// <summary></summary>
  643. public int ListLength(string key)
  644. {
  645. return SendExpectInt("LLEN", key);
  646. }
  647. /// <summary></summary>
  648. public byte[] ListIndex(string key, int index)
  649. {
  650. SendCommand("LINDEX", key, index);
  651. return ReadData();
  652. }
  653. /// <summary></summary>
  654. public byte[] LeftPop(string key)
  655. {
  656. SendCommand("LPOP", key);
  657. return ReadData();
  658. }
  659. /// <summary></summary>
  660. public byte[] RightPop(string key)
  661. {
  662. SendCommand("RPOP", key);
  663. return ReadData();
  664. }
  665. #endregion
  666. #region Set commands
  667. /// <summary></summary>
  668. public bool AddToSet(string key, byte[] member)
  669. {
  670. return SendDataExpectInt(member, "SADD", key) > 0;
  671. }
  672. /// <summary></summary>
  673. public bool AddToSet(string key, string member)
  674. {
  675. return AddToSet(key, GetBytes(member));
  676. }
  677. /// <summary></summary>
  678. public int CardinalityOfSet(string key)
  679. {
  680. return SendExpectInt("SCARD", key);
  681. }
  682. /// <summary></summary>
  683. public bool IsMemberOfSet(string key, byte[] member)
  684. {
  685. return SendDataExpectInt(member, "SISMEMBER", key) > 0;
  686. }
  687. /// <summary></summary>
  688. public bool IsMemberOfSet(string key, string member)
  689. {
  690. return IsMemberOfSet(key, GetBytes(member));
  691. }
  692. /// <summary></summary>
  693. public byte[][] GetMembersOfSet(string key)
  694. {
  695. return SendExpectDataArray("SMEMBERS", key);
  696. }
  697. /// <summary></summary>
  698. public byte[] GetRandomMemberOfSet(string key)
  699. {
  700. return SendExpectData("SRANDMEMBER", key);
  701. }
  702. /// <summary></summary>
  703. public byte[] PopRandomMemberOfSet(string key)
  704. {
  705. return SendExpectData("SPOP", key);
  706. }
  707. /// <summary></summary>
  708. public bool RemoveFromSet(string key, byte[] member)
  709. {
  710. return SendDataExpectInt(member, "SREM", key) > 0;
  711. }
  712. /// <summary></summary>
  713. public bool RemoveFromSet(string key, string member)
  714. {
  715. return RemoveFromSet(key, GetBytes(member));
  716. }
  717. /// <summary></summary>
  718. public byte[][] GetUnionOfSets(params string[] keys)
  719. {
  720. if (keys == null) return null; // throw new ArgumentNullException();
  721. return SendExpectDataArray("SUNION", keys);
  722. }
  723. void StoreSetCommands(string cmd, params string[] keys)
  724. {
  725. if (String.IsNullOrEmpty(cmd)) return; // throw new ArgumentNullException("cmd");
  726. if (keys == null) return; // throw new ArgumentNullException("keys");
  727. SendExpectSuccess(cmd, keys);
  728. }
  729. /// <summary></summary>
  730. public void StoreUnionOfSets(params string[] keys)
  731. {
  732. StoreSetCommands("SUNIONSTORE", keys);
  733. }
  734. /// <summary></summary>
  735. public byte[][] GetIntersectionOfSets(params string[] keys)
  736. {
  737. if (keys == null) return null; // throw new ArgumentNullException();
  738. return SendExpectDataArray("SINTER", keys);
  739. }
  740. /// <summary></summary>
  741. public void StoreIntersectionOfSets(params string[] keys)
  742. {
  743. StoreSetCommands("SINTERSTORE", keys);
  744. }
  745. /// <summary></summary>
  746. public byte[][] GetDifferenceOfSets(params string[] keys)
  747. {
  748. if (keys == null) return null; // throw new ArgumentNullException();
  749. return SendExpectDataArray("SDIFF", keys);
  750. }
  751. /// <summary></summary>
  752. public void StoreDifferenceOfSets(params string[] keys)
  753. {
  754. StoreSetCommands("SDIFFSTORE", keys);
  755. }
  756. /// <summary></summary>
  757. public bool MoveMemberToSet(string srcKey, string destKey, byte[] member)
  758. {
  759. return SendDataExpectInt(member, "SMOVE", srcKey, destKey) > 0;
  760. }
  761. #endregion
  762. /// <summary></summary>
  763. public void Dispose()
  764. {
  765. Dispose(true);
  766. GC.SuppressFinalize(this);
  767. }
  768. /// <summary></summary>
  769. ~Redis()
  770. {
  771. Dispose(false);
  772. }
  773. /// <summary></summary>
  774. protected virtual void Dispose(bool disposing)
  775. {
  776. if (disposing)
  777. {
  778. SendCommand("QUIT");
  779. ExpectSuccess();
  780. socket.Close();
  781. socket = null;
  782. }
  783. }
  784. private static byte[] GetBytes(string text)
  785. {
  786. if (string.IsNullOrEmpty(text)) return new byte[0];
  787. return System.Text.Encoding.UTF8.GetBytes(text);
  788. }
  789. private static string GetString(byte[] bytes)
  790. {
  791. if (bytes != null && bytes.Length > 0)
  792. {
  793. try
  794. {
  795. return System.Text.Encoding.UTF8.GetString(bytes);
  796. }
  797. catch { }
  798. }
  799. return "";
  800. }
  801. private static int GetByteCount(string text)
  802. {
  803. if (string.IsNullOrEmpty(text)) return 0;
  804. return System.Text.Encoding.UTF8.GetByteCount(text);
  805. }
  806. }
  807. }