QTSS_Error RedisSetDevice(Easy_DeviceInfo_Params* inParams)
{
	OSMutexLocker mutexLock(&sMutex);

	if (!RedisConnect())
	{
		return QTSS_NotConnected;
	}

	if (!inParams->serial_ || string(inParams->serial_).empty())
	{
		return QTSS_BadArgument;
	}

	QTSS_Error theRet = QTSS_NoErr;

	do
	{
		string id(QTSServerInterface::GetServer()->GetCloudServiceNodeID());
		auto hmset = Format("hmset %s:%s %s %s %s %s %s %s %s %s", string(EASY_REDIS_DEVICE), string(inParams->serial_),
			string(EASY_REDIS_DEVICE_TYPE), string(inParams->deviceType_), string(EASY_REDIS_TYPE), string(inParams->type_),
			string(EASY_REDIS_CHANNEL), string(inParams->channels_), string(EASY_REDIS_EASYCMS), id,
			string(EASY_REDIS_TOKEN), string(inParams->token_));
		auto reply = static_cast<redisReply*>(redisCommand(redisContext_, hmset.c_str()));
		RedisReplyObjectDeleter replyDeleter(reply);
		if (!reply)
		{
			theRet = QTSS_NotConnected;
			break;
		}

		if (string(reply->str) == string("OK"))
		{
			auto expire = Format("expire %s:%s 150", string(EASY_REDIS_DEVICE), string(inParams->serial_));
			auto replyExpire = static_cast<redisReply*>(redisCommand(redisContext_, expire.c_str()));
			RedisReplyObjectDeleter replyExpireDeleter(replyExpire);
			if (!replyExpire)
			{
				theRet = QTSS_NotConnected;
				break;
			}
		}
		else
		{
			theRet = QTSS_RequestFailed;
		}

	} while (0);

	if (theRet != QTSS_NoErr)
	{
		RedisErrorHandler();
	}

	return theRet;
}
QTSS_Error Initialize(QTSS_Initialize_Params* inParams)
{
	QTSSModuleUtils::Initialize(inParams->inMessages, inParams->inServer, inParams->inErrorLogStream);
	sServer = inParams->inServer;
	sServerPrefs = inParams->inPrefs;
	modulePrefs = QTSSModuleUtils::GetModulePrefsObject(inParams->inModule);

	RereadPrefs();

	RedisConnect();

	return QTSS_NoErr;
}
QTSS_Error RedisDelDevice(Easy_DeviceInfo_Params* inParams)
{
	OSMutexLocker mutexLock(&sMutex);

	if (!RedisConnect())
	{
		return QTSS_NotConnected;
	}

	if (!inParams->serial_ || string(inParams->serial_).empty())
	{
		return QTSS_BadArgument;
	}

	QTSS_Error theRet = QTSS_NoErr;

	do
	{
		auto del = Format("del %s:%s", EASY_REDIS_DEVICE, string(inParams->serial_));
		auto reply = static_cast<redisReply*>(redisCommand(redisContext_, del.c_str()));
		RedisReplyObjectDeleter replyDeleter(reply);

		if (!reply)
		{
			theRet = QTSS_NotConnected;
			break;
		}

		if (reply->integer == 0)
		{
			theRet = QTSS_RequestFailed;
		}

	} while (0);

	if (theRet != QTSS_NoErr)
	{
		RedisErrorHandler();
	}

	return theRet;
}
QTSS_Error RedisTTL()//注意当网络在一段时间很差时可能会因为超时时间达到而导致key被删除,这时应该重新设置该key
{

	OSMutexLocker mutexLock(&sMutex);

	if (RedisConnect() != QTSS_NoErr)//每一次执行命令之前都先连接redis,如果当前redis还没有成功连接
		return QTSS_NotConnected;

	char chKey[128] = { 0 };//注意128位是否足够
	sprintf(chKey, "%s:%d_Live 15", sRTSPWanIP, sRTSPWanPort);//更改超时时间

	int ret = sRedisClient->SetExpire(chKey, 15);
	if (ret == -1)//fatal error
	{
		sRedisClient->Free();
		sIfConSucess = false;
		return QTSS_NotConnected;
	}
	else if (ret == 1)
	{
		return QTSS_NoErr;
	}
	else if (ret == 0)//the key doesn't exist, reset
	{
		sprintf(chKey, "%s:%d_Live", sRTSPWanIP, sRTSPWanPort);
		int retret = sRedisClient->SetEX(chKey, 15, "1");
		if (retret == -1)//fatal error
		{
			sRedisClient->Free();
			sIfConSucess = false;
		}
		return retret;
	}
	else
	{
		return ret;
	}
}
QTSS_Error RedisGetAssociatedDarwin(QTSS_GetAssociatedDarwin_Params* inParams)
{
	OSMutexLocker mutexLock(&sMutex);

	if (!RedisConnect())
	{
		return QTSS_NotConnected;
	}

	QTSS_Error theRet = QTSS_NoErr;

	do
	{
		string exists = Format("exists %s:%s/%s", string(EASY_REDIS_LIVE), string(inParams->inSerial), string(inParams->inChannel));
		auto reply = static_cast<redisReply*>(redisCommand(redisContext_, exists.c_str()));
		RedisReplyObjectDeleter replyDeleter(reply);

		if (!reply)
		{
			theRet = QTSS_NotConnected;
			break;
		}

		if (reply->integer == 1)
		{
			string strTemp = Format("hmget %s:%s/%s %s", string(EASY_REDIS_LIVE), string(inParams->inSerial),
				string(inParams->inChannel), string(EASY_REDIS_EASYDARWIN));
			auto replyHmget = static_cast<redisReply*>(redisCommand(redisContext_, strTemp.c_str()));
			RedisReplyObjectDeleter replyHmgetDeleter(replyHmget);
			if (!replyHmget)
			{
				theRet = QTSS_NotConnected;
				break;
			}
			string easydarwin = Format("%s:", string(EASY_REDIS_EASYDARWIN));
			easydarwin += replyHmget->element[0]->str;

			strTemp = Format("hmget %s %s %s %s", easydarwin, string(EASY_REDIS_IP), string(EASY_REDIS_HTTP),
				string(EASY_REDIS_RTSP));
			auto replyHmgetEasyDarwin = static_cast<redisReply*>(redisCommand(redisContext_, strTemp.c_str()));
			RedisReplyObjectDeleter replyHmgetEasyDarwinDeleter(replyHmgetEasyDarwin);
			if (!replyHmgetEasyDarwin)
			{
				theRet = QTSS_NotConnected;
				break;
			}

			if (replyHmgetEasyDarwin->type == EASY_REDIS_REPLY_NIL)
			{
				theRet = QTSS_RequestFailed;
				break;;
			}

			if (replyHmgetEasyDarwin->type == EASY_REDIS_REPLY_ARRAY && replyHmgetEasyDarwin->elements == 3)
			{
				bool ok = true;
				for (int i = 0; i < replyHmgetEasyDarwin->elements; ++i)
				{
					if (replyHmgetEasyDarwin->element[i]->type == EASY_REDIS_REPLY_NIL)
					{
						ok = ok && false;
					}
				}

				if (ok)
				{
					string ip(replyHmgetEasyDarwin->element[0]->str);
					string httpPort(replyHmgetEasyDarwin->element[1]->str);
					string rtspPort(replyHmgetEasyDarwin->element[2]->str);
					memcpy(inParams->outDssIP, ip.c_str(), ip.size());
					memcpy(inParams->outHTTPPort, httpPort.c_str(), httpPort.size());
					memcpy(inParams->outDssPort, rtspPort.c_str(), rtspPort.size());
					inParams->isOn = true;
				}
				else
				{
					theRet = QTSS_RequestFailed;
					break;
				}
			}
		}
		else
		{
			string keys = Format("keys %s:*", string(EASY_REDIS_EASYDARWIN));
			auto replyKeys = static_cast<redisReply*>(redisCommand(redisContext_, keys.c_str()));
			RedisReplyObjectDeleter replyKeysDeleter(replyKeys);
			if (!replyKeys)
			{
				theRet = QTSS_NotConnected;
				break;
			}

			if (replyKeys->elements > 0)
			{
				int eleIndex = -1, eleLoad = 0;
				for (size_t i = 0; i < replyKeys->elements; ++i)
				{
					auto replyTemp = replyKeys->element[i];
					if (replyTemp->type == EASY_REDIS_REPLY_NIL)
					{
						continue;
					}

					string strTemp = Format("hmget %s %s %s %s %s ", string(replyTemp->str), string(EASY_REDIS_LOAD), string(EASY_REDIS_IP),
						string(EASY_REDIS_HTTP), string(EASY_REDIS_RTSP));
					auto replyHmget = static_cast<redisReply*>(redisCommand(redisContext_, strTemp.c_str()));
					RedisReplyObjectDeleter replyHmgetDeleter(replyHmget);

					if (!replyHmget)
					{
						theRet = QTSS_NotConnected;
						break;
					}

					if (replyHmget->type == EASY_REDIS_REPLY_NIL)
					{
						continue;
					}

					auto loadReply = replyHmget->element[0];
					auto ipReply = replyHmget->element[1];
					auto httpReply = replyHmget->element[2];
					auto rtspReply = replyHmget->element[3];

					auto load = stoi(loadReply->str);
					string ip(ipReply->str);
					string http(httpReply->str);
					string rtsp(rtspReply->str);

					if (eleIndex == -1)
					{
						eleIndex = i;
						eleLoad = load;
						strncpy(inParams->outDssIP, ip.c_str(), ip.size());
						strncpy(inParams->outHTTPPort, http.c_str(), http.size());
						strncpy(inParams->outDssPort, rtsp.c_str(), rtsp.size());
					}
					else
					{
						if (load < eleLoad)//find better
						{
							eleIndex = i;
							eleLoad = load;
							strncpy(inParams->outDssIP, ip.c_str(), ip.size());
							strncpy(inParams->outHTTPPort, http.c_str(), http.size());
							strncpy(inParams->outDssPort, rtsp.c_str(), rtsp.size());
						}
					}
				}

				if (eleIndex == -1)//no one live
				{
					theRet = QTSS_Unimplemented;
					break;
				}
				else
				{
					inParams->isOn = false;
				}
			}
			else
			{
				theRet = QTSS_Unimplemented;
				break;
			}
		}

	} while (0);

	if (theRet != QTSS_NoErr)
	{
		RedisErrorHandler();
	}

	return theRet;
}
QTSS_Error RedisTTL()
{
	OSMutexLocker mutexLock(&sMutex);

	QTSS_Error theRet = QTSS_NoErr;
	if (!RedisConnect())
	{
		return QTSS_NotConnected;
	}
	string server(QTSServerInterface::GetServer()->GetServerName().Ptr);
	string id(QTSServerInterface::GetServer()->GetCloudServiceNodeID());
	UInt32 load = QTSServerInterface::GetServer()->GetNumServiceSessions();

	do
	{
		string expire = Format("expire %s:%s 15", server, id);
		redisReply* reply = static_cast<redisReply*>(redisCommand(redisContext_, expire.c_str()));

		RedisReplyObjectDeleter replyDeleter(reply);
		if (!reply)
		{
			theRet = QTSS_NotConnected;
			break;
		}

		if (reply->integer == 0)
		{
			string cmsIp(QTSServerInterface::GetServer()->GetPrefs()->GetServiceWANIP());
			auto cmsPort = QTSServerInterface::GetServer()->GetPrefs()->GetServiceWANPort();
			auto hmset = Format("hmset %s:%s %s %s %s %hu %s %lu", string(EASY_REDIS_EASYCMS), id, string(EASY_REDIS_IP), cmsIp,
				string(EASY_REDIS_PORT), cmsPort, string(EASY_REDIS_LOAD), load);
			auto replyHmset = static_cast<redisReply*>(redisCommand(redisContext_, hmset.c_str()));
			RedisReplyObjectDeleter replyHmsetDeleter(replyHmset);
			if (!replyHmset)
			{
				theRet = QTSS_NotConnected;
				break;
			}

			auto replyExpire = static_cast<redisReply*>(redisCommand(redisContext_, expire.c_str()));
			RedisReplyObjectDeleter replyExpireDeleter(replyExpire);
			if (!replyExpire)
			{
				theRet = QTSS_NotConnected;
				break;
			}
		}
		else if (reply->integer == 1)
		{
			auto hset = Format("hset %s:%s %s %lu", server, id, string(EASY_REDIS_LOAD), load);
			auto replyHset = static_cast<redisReply*>(redisCommand(redisContext_, hset.c_str()));
			RedisReplyObjectDeleter replyHsetDeleter(replyHset);
			if (!replyHset)
			{
				theRet = QTSS_NotConnected;
				break;
			}
		}

	} while (0);

	if (theRet != QTSS_NoErr)
	{
		RedisErrorHandler();
	}

	return theRet;
}