using HslCommunication.Core;
using HslCommunication.Core.IMessage;
using HslCommunication.Core.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.IO;
namespace HslCommunication.Enthernet.Redis
{
///
/// 这是一个redis的客户端类,支持读取,写入,发布订阅,但是不支持订阅,如果需要订阅,请使用另一个类
///
public class RedisClient : NetworkDoubleBase
{
#region Constructor
///
/// 实例化一个客户端的对象,用于和服务器通信
///
/// 服务器的ip地址
/// 服务器的端口号
/// 密码,如果服务器没有设置,密码设置为null
public RedisClient( string ipAddress, int port, string password )
{
IpAddress = ipAddress;
Port = port;
ReceiveTimeOut = 30000;
this.password = password;
}
///
/// 实例化一个客户端对象,需要手动指定Ip地址和端口
///
/// 密码,如果服务器没有设置,密码设置为null
public RedisClient( string password )
{
ReceiveTimeOut = 30000;
this.password = password;
}
#endregion
#region Override
///
/// 如果设置了密码,对密码进行验证
///
/// 网络的套接字服务
/// 是否成功的对象
protected override OperateResult InitializationOnConnect( Socket socket )
{
if (!string.IsNullOrEmpty( this.password ))
{
byte[] command = RedisHelper.PackStringCommand( new string[] { "AUTH", this.password } );
OperateResult read = ReadFromCoreServer(socket, command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
string msg = Encoding.UTF8.GetString( read.Content );
if (!msg.StartsWith( "+" )) return new OperateResult( msg );
return OperateResult.CreateSuccessResult( msg.Substring( 1 ).TrimEnd( '\r', '\n' ) );
}
return base.InitializationOnConnect( socket );
}
///
/// 在其他指定的套接字上,使用报文来通讯,传入需要发送的消息,返回一条完整的数据指令
///
/// 指定的套接字
/// 发送的完整的报文信息
///
/// 无锁的基于套接字直接进行叠加协议的操作。
///
///
/// 假设你有一个自己的socket连接了设备,本组件可以直接基于该socket实现modbus读取,三菱读取,西门子读取等等操作,前提是该服务器支持多协议,虽然这个需求听上去比较变态,但本组件支持这样的操作。
///
///
/// 接收的完整的报文信息
public override OperateResult ReadFromCoreServer( Socket socket, byte[] send )
{
OperateResult sendResult = Send( socket, send );
if (!sendResult.IsSuccess) return OperateResult.CreateFailedResult( sendResult );
string tmp = BasicFramework.SoftBasic.ByteToHexString( send, ' ' );
// 接收超时时间大于0时才允许接收远程的数据
if (ReceiveTimeOut < 0) return OperateResult.CreateSuccessResult( new byte[0] );
// 接收数据信息
return RedisHelper.ReceiveCommand( socket );
}
#endregion
#region Customer
///
/// 自定义的指令交互方法,该指令用空格分割,举例:LTRIM AAAAA 0 999 就是收缩列表,GET AAA 就是获取键值,需要对返回的数据进行二次分析
///
/// 举例:LTRIM AAAAA 0 999 就是收缩列表,GET AAA 就是获取键值
/// 从服务器返回的结果数据对象
public OperateResult ReadCustomer( string command )
{
byte[] byteCommand = RedisHelper.PackStringCommand( command.Split( ' ' ) );
OperateResult read = ReadFromCoreServer( byteCommand );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return OperateResult.CreateSuccessResult( Encoding.UTF8.GetString( read.Content ) );
}
#endregion
#region Base Operate
///
/// 向服务器请求指定,并返回数字的结果对象
///
/// 命令数组
/// 数字的结果对象
public OperateResult OperateNumberFromServer(string[] commands)
{
byte[] command = RedisHelper.PackStringCommand( commands );
OperateResult read = ReadFromCoreServer( command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
string msg = Encoding.UTF8.GetString( read.Content );
if (!msg.StartsWith( ":" )) return new OperateResult( msg );
return RedisHelper.GetNumberFromCommandLine( read.Content );
}
///
/// 向服务器请求指令,并返回long数字的结果对象
///
/// 命令数组
/// long数字的结果对象
public OperateResult OperateLongNumberFromServer(string[] commands)
{
byte[] command = RedisHelper.PackStringCommand( commands );
OperateResult read = ReadFromCoreServer( command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
string msg = Encoding.UTF8.GetString( read.Content );
if (!msg.StartsWith( ":" )) return new OperateResult( msg );
return RedisHelper.GetLongNumberFromCommandLine( read.Content );
}
///
/// 向服务器请求指令,并返回字符串的结果对象
///
/// 命令数组
/// 字符串的结果对象
public OperateResult OperateStringFromServer(string[] commands)
{
byte[] command = RedisHelper.PackStringCommand( commands );
OperateResult read = ReadFromCoreServer( command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return RedisHelper.GetStringFromCommandLine( read.Content );
}
///
/// 向服务器请求指令,并返回字符串数组的结果对象
///
/// 命令数组
/// 字符串数组的结果对象
public OperateResult OperateStringsFromServer(string[] commands)
{
byte[] command = RedisHelper.PackStringCommand( commands );
OperateResult read = ReadFromCoreServer( command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
return RedisHelper.GetStringsFromCommandLine( read.Content );
}
///
/// 向服务器请求指令,并返回状态的结果对象,通常用于写入的判断,或是请求类型的判断
///
/// 命令数组
/// 是否成功的结果对象
public OperateResult OperateStatusFromServer(string[] commands)
{
byte[] command = RedisHelper.PackStringCommand( commands );
OperateResult read = ReadFromCoreServer( command );
if (!read.IsSuccess) return OperateResult.CreateFailedResult( read );
string msg = Encoding.UTF8.GetString( read.Content );
if (!msg.StartsWith( "+" )) return new OperateResult( msg );
return OperateResult.CreateSuccessResult( msg.Substring( 1 ).TrimEnd( '\r', '\n' ) );
}
#endregion
#region Key Operate
///
/// 删除给定的一个或多个 key 。不存在的 key 会被忽略。
///
/// 关键字
/// 被删除 key 的数量。
public OperateResult DeleteKey( string[] keys )
{
List list = new List( );
list.Add( "DEL" );
list.AddRange( keys );
return OperateNumberFromServer( list.ToArray( ) );
}
///
/// 删除给定的一个或多个 key 。不存在的 key 会被忽略。
///
/// 关键字
/// 被删除 key 的数量。
public OperateResult DeleteKey( string key )
{
return DeleteKey( new string[] { key } );
}
///
/// 检查给定 key 是否存在。若 key 存在,返回 1 ,否则返回 0 。
///
/// 关键字
/// 若 key 存在,返回 1 ,否则返回 0 。
public OperateResult ExistsKey( string key )
{
return OperateNumberFromServer( new string[] { "EXISTS", key } );
}
///
/// 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。设置成功返回 1 。当 key 不存在或者不能为 key 设置生存时间时,返回 0 。
///
/// 关键字
///
/// 设置成功返回 1 。当 key 不存在或者不能为 key 设置生存时间时,返回 0 。
///
public OperateResult ExpireKey( string key )
{
return OperateNumberFromServer( new string[] { "EXPIRE", key } );
}
///
/// 查找所有符合给定模式 pattern 的 key 。
/// * 匹配数据库中所有 key。
/// h?llo 匹配 hello , hallo 和 hxllo 等。
/// h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
///
/// 给定模式
/// 符合给定模式的 key 列表。
public OperateResult ReadAllKeys( string pattern )
{
return OperateStringsFromServer( new string[] { "KEYS", pattern } );
}
///
/// 将当前数据库的 key 移动到给定的数据库 db 当中。
/// 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。
/// 因此,也可以利用这一特性,将 MOVE 当作锁(locking)原语(primitive)。
///
/// 关键字
/// 数据块
/// 是否移动成功
public OperateResult MoveKey( string key, int db )
{
return OperateStatusFromServer( new string[] { "MOVE", key, db.ToString( ) } );
}
///
/// 移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
/// 当生存时间移除成功时,返回 1 .
/// 如果 key 不存在或 key 没有设置生存时间,返回 0 。
///
/// 关键字
///
/// 当生存时间移除成功时,返回 1 .
/// 如果 key 不存在或 key 没有设置生存时间,返回 0 。
///
public OperateResult PersistKey( string key )
{
return OperateNumberFromServer( new string[] { "PERSIST", key } );
}
///
/// 从当前数据库中随机返回(不删除)一个 key 。
/// 当数据库不为空时,返回一个 key 。
/// 当数据库为空时,返回 nil 。
///
///
/// 当数据库不为空时,返回一个 key 。
/// 当数据库为空时,返回 nil 。
///
public OperateResult ReadRandomKey( )
{
return OperateStringFromServer( new string[] { "RANDOMKEY" } );
}
///
/// 将 key 改名为 newkey 。
/// 当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
/// 当 newkey 已经存在时, RENAME 命令将覆盖旧值。
///
/// 旧的key
/// 新的key
///
/// 改名成功时提示 OK ,失败时候返回一个错误。
///
public OperateResult RenameKey( string key1, string key2 )
{
return OperateStatusFromServer( new string[] { "RENAME", key1, key2 } );
}
///
/// 返回 key 所储存的值的类型。none (key不存在),string (字符串),list (列表),set (集合),zset (有序集),hash (哈希表)
///
/// 关键字
/// 类型
public OperateResult ReadKeyType( string key )
{
return OperateStatusFromServer( new string[] { "TYPE", key } );
}
#endregion
#region String Operate
///
/// 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
/// 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
/// 返回追加 value 之后, key 中字符串的长度。
///
/// 关键字
/// 数值
///
/// 追加 value 之后, key 中字符串的长度。
///
public OperateResult AppendKey( string key, string value )
{
return OperateNumberFromServer( new string[] { "APPEND", key, value } );
}
///
/// 将 key 中储存的数字值减一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
/// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
/// 本操作的值限制在 64 位(bit)有符号数字表示之内。
/// 返回执行 DECR 命令之后 key 的值。
///
/// 关键字
/// 执行 DECR 命令之后 key 的值。
public OperateResult DecrementKey( string key )
{
return OperateLongNumberFromServer( new string[] { "DECR", key } );
}
///
/// 将 key 所储存的值减去减量 decrement 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
/// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
/// 本操作的值限制在 64 位(bit)有符号数字表示之内。
/// 返回减去 decrement 之后, key 的值。
///
/// 关键字
/// 操作的值
/// 返回减去 decrement 之后, key 的值。
public OperateResult DecrementKey( string key, long value )
{
return OperateLongNumberFromServer( new string[] { "DECRBY", key, value.ToString( ) } );
}
///
/// 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。
/// 假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。
///
/// 关键字
/// 当 key 不存在时,返回 nil ,否则,返回 key 的值。
public OperateResult ReadKey( string key )
{
return OperateStringFromServer( new string[] { "GET", key } );
}
///
/// 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
/// 负数偏移量表示从字符串最后开始计数, -1 表示最后一个字符, -2 表示倒数第二个,以此类推。
/// 返回截取得出的子字符串。
///
/// 关键字
/// 截取开始的位置
/// 截取结束的位置
/// 返回截取得出的子字符串。
public OperateResult ReadKeyRange( string key, int start, int end )
{
return OperateStringFromServer( new string[] { "GETRANGE", key, start.ToString( ), end.ToString( ) } );
}
///
/// 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。
///
/// 关键字
/// 新的值
/// 返回给定 key 的旧值。当 key 没有旧值时,也即是, key 不存在时,返回 nil 。
public OperateResult ReadAndWriteKey( string key, string value )
{
return OperateStringFromServer( new string[] { "GETSET", key, value } );
}
///
/// 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
/// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
/// 返回执行 INCR 命令之后 key 的值。
///
/// 关键字
/// 返回执行 INCR 命令之后 key 的值。
public OperateResult IncrementKey( string key )
{
return OperateLongNumberFromServer( new string[] { "INCR", key } );
}
///
/// 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
/// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
///
/// 关键字
/// 增量数据
/// 加上 increment 之后, key 的值。
public OperateResult IncrementKey( string key, long value )
{
return OperateLongNumberFromServer( new string[] { "INCRBY", key, value.ToString( ) } );
}
///
/// 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBYFLOAT 操作。
/// 如果命令执行成功,那么 key 的值会被更新为(执行加法之后的)新值,并且新值会以字符串的形式返回给调用者
///
/// 关键字
/// 增量数据
/// 执行命令之后 key 的值。
public OperateResult IncrementKey( string key, float value )
{
return OperateStringFromServer( new string[] { "INCRBYFLOAT", key, value.ToString( ) } );
}
///
/// 返回所有(一个或多个)给定 key 的值。
/// 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 null 。因此,该命令永不失败。
///
/// 关键字数组
/// 一个包含所有给定 key 的值的列表。
public OperateResult ReadKey( string[] keys )
{
List list = new List( );
list.Add( "MGET" );
list.AddRange( keys );
return OperateStringsFromServer( list.ToArray( ) );
}
///
/// 同时设置一个或多个 key-value 对。
/// 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
///
/// 关键字数组
/// 值数组
/// 总是返回 OK (因为 MSET 不可能失败)
public OperateResult WriteKey( string[] keys, string[] values )
{
if (keys == null) throw new ArgumentNullException( "keys" );
if (values == null) throw new ArgumentNullException( "values" );
if (keys.Length != values.Length) throw new ArgumentException( "Two arguement not same length" );
List list = new List( );
list.Add( "MSET" );
for (int i = 0; i < keys.Length; i++)
{
list.Add( keys[i] );
list.Add( values[i] );
}
return OperateStatusFromServer( list.ToArray( ) );
}
///
/// 将字符串值 value 关联到 key 。
/// 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
/// 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
///
/// 关键字
/// 数据值
/// SET 在设置操作成功完成时,才返回 OK 。
public OperateResult WriteKey( string key, string value )
{
return OperateStatusFromServer( new string[] { "SET", key, value } );
}
///
/// 将字符串值 value 关联到 key 。并发布一个订阅的频道数据,都成功时,才返回成功
///
/// 关键字
/// 数据值
/// 是否成功的结果对象
public OperateResult WriteAndPublishKey(string key, string value )
{
OperateResult write = WriteKey( key, value );
if (!write.IsSuccess) return write;
return Publish( key, value );
}
///
/// 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX 命令将覆写旧值。
///
/// 关键字
/// 数值
/// 生存时间,单位秒
/// 设置成功时返回 OK 。当 seconds 参数不合法时,返回一个错误。
public OperateResult WriteExpireKey( string key, string value, long seconds )
{
return OperateStatusFromServer( new string[] { "SETEX", key, seconds.ToString( ), value } );
}
///
/// 将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。设置成功,返回 1 。设置失败,返回 0 。
///
/// 关键字
/// 数据值
/// 设置成功,返回 1 。设置失败,返回 0 。
public OperateResult WriteKeyIfNotExists( string key, string value )
{
return OperateNumberFromServer( new string[] { "SETNX", key, value } );
}
///
/// 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。不存在的 key 当作空白字符串处理。返回被 SETRANGE 修改之后,字符串的长度。
///
/// 关键字
/// 数值
/// 起始的偏移量
/// 被 SETRANGE 修改之后,字符串的长度。
public OperateResult WriteKeyRange( string key, string value, int offset )
{
return OperateNumberFromServer( new string[] { "SETRANGE", key, offset.ToString( ), value } );
}
///
/// 返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。返回符串值的长度。当 key 不存在时,返回 0 。
///
/// 关键字
/// 字符串值的长度。当 key 不存在时,返回 0 。
public OperateResult ReadKeyLength( string key )
{
return OperateNumberFromServer( new string[] { "STRLEN", key } );
}
#endregion
#region List Operate
///
/// 将值 value 插入到列表 key 当中,位于值 pivot 之前。
/// 当 pivot 不存在于列表 key 时,不执行任何操作。
/// 当 key 不存在时, key 被视为空列表,不执行任何操作。
/// 如果 key 不是列表类型,返回一个错误。
///
/// 关键字
/// 数值
/// 原先的值
///
/// 如果命令执行成功,返回插入操作完成之后,列表的长度。
/// 如果没有找到 pivot ,返回 -1 。
/// 如果 key 不存在或为空列表,返回 0 。
///
public OperateResult ListInsertBefore( string key, string value, string pivot )
{
return OperateNumberFromServer( new string[] { "LINSERT", key, "BEFORE", pivot, value } );
}
///
/// 将值 value 插入到列表 key 当中,位于值 pivot 之后。
/// 当 pivot 不存在于列表 key 时,不执行任何操作。
/// 当 key 不存在时, key 被视为空列表,不执行任何操作。
/// 如果 key 不是列表类型,返回一个错误。
///
/// 关键字
/// 数值
/// 原先的值
///
/// 如果命令执行成功,返回插入操作完成之后,列表的长度。
/// 如果没有找到 pivot ,返回 -1 。
/// 如果 key 不存在或为空列表,返回 0 。
///
public OperateResult ListInsertAfter( string key, string value, string pivot )
{
return OperateNumberFromServer( new string[] { "LINSERT", key, "AFTER", pivot, value } );
}
///
/// 返回列表 key 的长度。如果 key 不存在,则 key 被解释为一个空列表,返回 0 .如果 key 不是列表类型,返回一个错误。
///
/// 关键字
/// 列表 key 的长度。
public OperateResult GetListLength( string key )
{
return OperateNumberFromServer( new string[] { "LLEN", key } );
}
///
/// 返回列表 key 中,下标为 index 的元素。下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
/// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。如果 key 不是列表类型,返回一个错误。
///
/// 关键字
/// 索引位置
/// 列表中下标为 index 的元素。如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。
public OperateResult ReadListByIndex( string key, long index )
{
return OperateStringFromServer( new string[] { "LINDEX", key, index.ToString( ) } );
}
///
/// 移除并返回列表 key 的头元素。列表的头元素。当 key 不存在时,返回 nil 。
///
/// 关键字信息
/// 列表的头元素。
public OperateResult ListLeftPop( string key )
{
return OperateStringFromServer( new string[] { "LPOP", key } );
}
///
/// 将一个或多个值 value 插入到列表 key 的表头,如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。返回执行 LPUSH 命令后,列表的长度。
///
/// 关键字
/// 值
/// 执行 LPUSH 命令后,列表的长度。
public OperateResult ListLeftPush( string key, string value )
{
return ListLeftPush( key, new string[] { value } );
}
///
/// 将一个或多个值 value 插入到列表 key 的表头,如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。返回执行 LPUSH 命令后,列表的长度。
///
/// 关键字
/// 值
/// 执行 LPUSH 命令后,列表的长度。
public OperateResult ListLeftPush( string key, string[] values )
{
List list = new List( );
list.Add( "LPUSH" );
list.Add( key );
list.AddRange( values );
return OperateNumberFromServer( list.ToArray( ) );
}
///
/// 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。
/// 返回LPUSHX 命令执行之后,表的长度。
///
/// 关键字
/// 值
/// 是否插入数据成功
public OperateResult ListLeftPushX( string key, string value )
{
return OperateNumberFromServer( new string[] { "LPUSHX", key, value } );
}
///
/// 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
/// 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
/// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
/// 返回一个列表,包含指定区间内的元素。
///
/// 关键字
/// 开始的索引
/// 结束的索引
/// 返回一个列表,包含指定区间内的元素。
public OperateResult ListRange( string key, long start, long stop )
{
return OperateStringsFromServer( new string[] { "LRANGE", key, start.ToString( ), stop.ToString( ) } );
}
///
/// 根据参数 count 的值,移除列表中与参数 value 相等的元素。count 的值可以是以下几种:
/// count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
/// count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
/// count = 0 : 移除表中所有与 value 相等的值。
/// 返回被移除的数量。
///
/// 关键字
/// 移除参数
/// 匹配的值
/// 被移除元素的数量。因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0 。
public OperateResult ListRemoveElementMatch( string key, long count, string value )
{
return OperateNumberFromServer( new string[] { "LREM", key, count.ToString( ), value } );
}
///
/// 设置数组的某一个索引的数据信息,当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
///
/// 关键字
/// 索引位置
/// 值
/// 操作成功返回 ok ,否则返回错误信息。
public OperateResult ListSet( string key, long index, string value )
{
return OperateStatusFromServer( new string[] { "LSET", key.ToString( ), index.ToString( ), value } );
}
///
/// 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
/// 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
/// 下标( index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
/// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
/// 当 key 不是列表类型时,返回一个错误。
///
/// 关键字信息
/// 起始的索引信息
/// 结束的索引信息
/// 操作成功返回 ok ,否则返回错误信息。
public OperateResult ListTrim( string key, long start, long end )
{
return OperateStatusFromServer( new string[] { "LTRIM", key, start.ToString( ), end.ToString( ) } );
}
///
/// 移除并返回列表 key 的尾元素。当 key 不存在时,返回 nil 。
///
/// 关键字信息
/// 列表的尾元素。
public OperateResult ListRightPop( string key )
{
return OperateStringFromServer( new string[] { "RPOP", key } );
}
///
/// 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
/// 1. 将列表 source 中的最后一个元素( 尾元素)弹出,并返回给客户端。
/// 2. 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
/// 举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。
/// 如果 source 不存在,值 nil 被返回,并且不执行其他动作。
/// 如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转( rotation)操作。
///
/// 第一个关键字
/// 第二个关键字
/// 返回的移除的对象
public OperateResult ListRightPopLeftPush( string key1, string key2 )
{
return OperateStringFromServer( new string[] { "RPOPLPUSH", key1, key2 } );
}
///
/// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
/// 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。
///
/// 关键字
/// 值
/// 返回执行 RPUSH 操作后,表的长度。
public OperateResult ListRightPush( string key, string value )
{
return ListRightPush( key, new string[] { value } );
}
///
/// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
/// 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,
/// 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。
/// 返回执行 RPUSH 操作后,表的长度。
///
/// 关键字
/// 值
/// 返回执行 RPUSH 操作后,表的长度。
public OperateResult ListRightPush( string key, string[] values )
{
List list = new List( );
list.Add( "RPUSH" );
list.Add( key );
list.AddRange( values );
return OperateNumberFromServer( list.ToArray( ) );
}
///
/// 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
/// 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
///
/// 关键字
/// 值
/// RPUSHX 命令执行之后,表的长度。
public OperateResult ListRightPushX( string key, string value )
{
return OperateNumberFromServer( new string[] { "RPUSHX", key, value } );
}
#endregion
#region Hash Operate
///
/// 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
///
/// 关键字
/// 域
/// 被成功移除的域的数量,不包括被忽略的域。
public OperateResult DeleteHashKey( string key, string field )
{
return DeleteHashKey( key, new string[] { field } );
}
///
/// 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。返回被成功移除的域的数量,不包括被忽略的域。
///
/// 关键字
/// 所有的域
/// 返回被成功移除的域的数量,不包括被忽略的域。
public OperateResult DeleteHashKey( string key, string[] fields )
{
List list = new List( );
list.Add( "HDEL" );
list.Add( key );
list.AddRange( fields );
return OperateNumberFromServer( list.ToArray( ) );
}
///
/// 查看哈希表 key 中,给定域 field 是否存在。如果哈希表含有给定域,返回 1 。
/// 如果哈希表不含有给定域,或 key 不存在,返回 0 。
///
/// 关键字
/// 域
/// 如果哈希表含有给定域,返回 1 。如果哈希表不含有给定域,或 key 不存在,返回 0 。
public OperateResult ExistsHashKey( string key, string field )
{
return OperateNumberFromServer( new string[] { "HEXISTS", key, field } );
}
///
/// 返回哈希表 key 中给定域 field 的值。当给定域不存在或是给定 key 不存在时,返回 nil
///
/// 关键值
/// 域
///
/// 给定域的值。
/// 当给定域不存在或是给定 key 不存在时,返回 nil 。
///
public OperateResult ReadHashKey( string key, string field )
{
return OperateStringFromServer( new string[] { "HGET", key, field } );
}
///
/// 返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
///
/// 关键值
///
/// 以列表形式返回哈希表的域和域的值。
/// 若 key 不存在,返回空列表。
///
public OperateResult ReadHashKeyAll( string key )
{
return OperateStringsFromServer( new string[] { "HGETALL", key } );
}
///
/// 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。
/// 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。
///
/// 关键字
/// 域
/// 增量值
/// 返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。
public OperateResult IncrementHashKey( string key, string field, long value )
{
return OperateLongNumberFromServer( new string[] { "HINCRBY", key, field, value.ToString( ) } );
}
///
/// 为哈希表 key 中的域 field 的值加上增量 increment 。增量也可以为负数,相当于对给定域进行减法操作。
/// 如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。
///
/// 关键字
/// 域
/// 增量值
/// 返回执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。
public OperateResult IncrementHashKey( string key, string field, float value )
{
return OperateStringFromServer( new string[] { "HINCRBYFLOAT", key, field, value.ToString( ) } );
}
///
/// 返回哈希表 key 中的所有域。当 key 不存在时,返回一个空表。
///
/// 关键值
///
/// 一个包含哈希表中所有域的表。
/// 当 key 不存在时,返回一个空表。
///
public OperateResult ReadHashKeys( string key )
{
return OperateStringsFromServer( new string[] { "HKEYS", key } );
}
///
/// 返回哈希表 key 中域的数量。
///
/// 关键字
/// 哈希表中域的数量。当 key 不存在时,返回 0 。
public OperateResult ReadHashKeyLength( string key )
{
return OperateNumberFromServer( new string[] { "HLEN", key } );
}
///
/// 返回哈希表 key 中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个 nil 值。
/// 因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。
///
/// 关键值
/// 指定的域
///
/// 一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。
///
public OperateResult ReadHashKey( string key, string[] fields )
{
List list = new List( );
list.Add( "HMGET" );
list.Add( key );
list.AddRange( fields );
return OperateStringsFromServer( list.ToArray( ) );
}
///
/// 将哈希表 key 中的域 field 的值设为 value 。
/// 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
/// 如果域 field 已经存在于哈希表中,旧值将被覆盖。
/// 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。
/// 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。
///
/// 关键字
/// 域
/// 数据值
///
/// 如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。
/// 如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。
///
public OperateResult WriteHashKey( string key, string field, string value )
{
return OperateNumberFromServer( new string[] { "HSET", key, field, value } );
}
///
/// 同时将多个 field-value (域-值)对设置到哈希表 key 中。
/// 此命令会覆盖哈希表中已存在的域。
/// 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
///
/// 关键字
/// 域
/// 数据值
///
/// 如果命令执行成功,返回 OK 。
/// 当 key 不是哈希表(hash)类型时,返回一个错误
///
public OperateResult WriteHashKey( string key, string[] fields, string[] values )
{
if (fields == null) throw new ArgumentNullException( "fields" );
if (values == null) throw new ArgumentNullException( "values" );
if (fields.Length != values.Length) throw new ArgumentException( "Two arguement not same length" );
List list = new List( );
list.Add( "HMSET" );
list.Add( key );
for (int i = 0; i < fields.Length; i++)
{
list.Add( fields[i] );
list.Add( values[i] );
}
return OperateStatusFromServer( list.ToArray( ) );
}
///
/// 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。若域 field 已经存在,该操作无效。
/// 设置成功,返回 1 。如果给定域已经存在且没有操作被执行,返回 0 。
///
/// 关键字
/// 域
/// 数据值
/// 设置成功,返回 1 。如果给定域已经存在且没有操作被执行,返回 0 。
public OperateResult WriteHashKeyNx( string key, string field, string value )
{
return OperateNumberFromServer( new string[] { "HSETNX", key, field, value } );
}
///
/// 返回哈希表 key 中所有域的值。当 key 不存在时,返回一个空表。
///
/// 关键值
///
/// 返回哈希表 key 中所有域的值。
/// 当 key 不存在时,返回一个空表。
///
public OperateResult ReadHashValues( string key )
{
return OperateStringsFromServer( new string[] { "HVALS", key } );
}
#endregion
#region Server Operate
///
/// SAVE 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。
///
/// 保存成功时返回 OK 。
public OperateResult Save( )
{
return OperateStatusFromServer( new string[] { "SAVE" } );
}
///
/// 在后台异步(Asynchronously)保存当前数据库的数据到磁盘。
/// BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。
///
/// 反馈信息。
public OperateResult SaveAsync( )
{
return OperateStatusFromServer( new string[] { "BGSAVE" } );
}
///
/// 获取服务器的时间戳信息,可用于本地时间的数据同步问题
///
/// 带有服务器时间的结果对象
public OperateResult ReadServerTime( )
{
OperateResult times = OperateStringsFromServer( new string[] { "TIME" } );
if (!times.IsSuccess) return OperateResult.CreateFailedResult( times );
long timeTick = long.Parse( times.Content[0] );
DateTime dateTime = new DateTime( 1970, 1, 1, 8, 0, 0 ).AddSeconds( timeTick );
return OperateResult.CreateSuccessResult( dateTime );
}
#endregion
#region Publish
///
/// 将信息 message 发送到指定的频道 channel,返回接收到信息 message 的订阅者数量。
///
/// 频道,和关键字不是一回事
/// 消息
/// 接收到信息 message 的订阅者数量。
public OperateResult Publish( string channel, string message )
{
return OperateNumberFromServer( new string[] { "PUBLISH", channel, message } );
}
#endregion
#region DB Block
///
/// 切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。默认使用 0 号数据库。
///
/// 索引值
/// 是否切换成功
public OperateResult SelectDB( int db )
{
return OperateStatusFromServer( new string[] { "SELECT", db.ToString( ) } );
}
#endregion
#region Private Member
private string password = string.Empty; // 密码信息
#endregion
#region Object Override
///
/// 返回表示当前对象的字符串
///
/// 字符串信息
public override string ToString( )
{
return $"RedisClient[{IpAddress}:{Port}]";
}
#endregion
}
}