bool is_db_updated() {
		AUTO_LOG_FUNCTION;
		alarm_center_video::request request;
		alarm_center_video::reply reply;
		grpc::ClientContext context;

		auto status = stub_->is_db_updated(&context, request, &reply);
		if (status.ok()) {
			JLOGA("is_db_updated: ", reply.place_holder().c_str());
			return reply.place_holder() == "true";
		}

		return false;
	}
CRect CVideoPlayerCtrl::GetRealRect() const {
	AUTO_LOG_FUNCTION;
	CRect rc = { 0 };
	GetClientRect(rc);
	rc.DeflateRect(1, 1, 1, 1);

	//if (real_player) {
	//	real_player->MoveWindow(rc);
	//	real_player->GetClientRect(&rc);
	//	real_player->ClientToScreen(&rc);
	//}
	ClientToScreen(rc);
	
	JLOGA("%d %d %d %d %dX%d", rc.left, rc.top, rc.right, rc.bottom, rc.Width(), rc.Height());
	return rc;
}
BOOL CAlarmMachine::SendType()
{
	AUTO_LOG_FUNCTION;
	USES_CONVERSION;

	char buff[BFSZ] = { 0 };
	AdemcoPacket packet1;
	int len = packet1.Make(buff, BFSZ, AID_HB, 0, /*GetDeviceIDA(),*/
						   NULL, _ademco_id, EVENT_I_AM_EXPRESSED_GPRS_2050_MACHINE, 0, 0);
	Send(buff, len);
	m_dwLastTimeSendLinkTest = GetTickCount();

	char txt[BFSZ] = { 0 };
	sprintf_s(txt, "I am netmodule.");
	JLOGA(txt);
	CAlarmMachineExDlg *dlg = static_cast<CAlarmMachineExDlg*>(AfxGetApp()->m_pMainWnd);
	dlg->AddListSend(A2W(txt));

	return TRUE;
}
BOOL CClient::Connect(const std::string& server_ip, unsigned int server_port)
{
    AUTO_LOG_FUNCTION;
    if (m_bConnectionEstablished)
        return TRUE;
    do {
        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip.c_str());
        server_addr.sin_port = htons(static_cast<u_short>(server_port));

        if ((m_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
            JLOG(_T("socket failed\n"));
            JLOG(FormatWSAError(WSAGetLastError()));
            break;
        }

        // set the socket in non-blocking mode.
        unsigned long non_blocking_mode = 1;
        int result = ioctlsocket(m_socket, FIONBIO, &non_blocking_mode);
        if (result != NO_ERROR) {
            JLOG(_T("ioctlsocket failed : %d\n"), result);
            JLOG(FormatWSAError(WSAGetLastError()));
            CLOSESOCKET(m_socket);
            break;
        }

        int ret = connect(m_socket, (struct sockaddr *) &server_addr,
                          sizeof(struct sockaddr));

        if (ret != -1) {
            JLOGA("connect to %s:%d failed\n", server_ip.c_str(), server_port);
            JLOG(FormatWSAError(WSAGetLastError()));
            CLOSESOCKET(m_socket);
            break;
        }

        TIMEVAL tm;
        tm.tv_sec = 3;
        tm.tv_usec = 0;
        fd_set fdset;
        FD_ZERO(&fdset);
        FD_SET(m_socket, &fdset);
        if (select(m_socket + 1, nullptr, &fdset, nullptr, &tm) <= 0) {
            CLOSESOCKET(m_socket);
            break;
        }

        int error, len;
        len = sizeof(int);
        getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
        if (error != NO_ERROR) {
            JLOGA("connect to %s:%d failed\n", server_ip.c_str(), server_port);
            JLOG(FormatWSAError(WSAGetLastError()));
            CLOSESOCKET(m_socket);
            break;
        }

        // set the socket in blocking mode.
        non_blocking_mode = 0;
        result = ioctlsocket(m_socket, FIONBIO, &non_blocking_mode);
        if (result != NO_ERROR) {
            JLOG(_T("ioctlsocket failed : %d\n"), result);
            JLOG(FormatWSAError(WSAGetLastError()));
            CLOSESOCKET(m_socket);
            break;
        }


        m_bConnectionEstablished = TRUE;
        m_buff.Clear();
        last_recv_time_ = COleDateTime::GetTickCount();
        last_send_link_test_time_ = COleDateTime::GetTickCount();

        return TRUE;
    } while (0);


    return FALSE;
}
void alarm_center_video_client::worker()
{
	AUTO_LOG_FUNCTION;
	auto last_time_insert_histories = std::chrono::steady_clock::now();
	auto last_time_get_alarm_devs = std::chrono::steady_clock::now();
	auto last_time_check_is_db_updated = std::chrono::steady_clock::now();
	auto last_time_check_has_device_waiting_to_play = std::chrono::steady_clock::now();
	auto last_time_check_delete_camera = std::chrono::steady_clock::now();

	while (running_) {
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
		if (!running_)break;

		// insert buffered histories per 3s
		{
			auto now = std::chrono::steady_clock::now();
			auto diff = now - last_time_insert_histories;
			if (std::chrono::duration_cast<std::chrono::seconds>(diff).count() >= 3) {

				range_log log("insert buffered histories per 3s");

				std::vector<history> histories;
				{
					std::lock_guard<std::mutex> lg(mutex_);

					JLOGA("histories_.size = %d", histories_.size());
					if (!histories_.empty()) {
						std::copy(histories_.begin(), histories_.end(), std::back_inserter(histories));
						histories_.clear();
					}
				}

				JLOGA("histories.size = %d", histories.size());
				if (!histories.empty()) {
					client_->histories_ = histories;
					client_->insert_histories();
				}

				last_time_insert_histories = std::chrono::steady_clock::now();
			}
		}

		// check need update db per 1s
		{
			if (db_refreshed_) {
				client_->refresh_db();
				db_refreshed_ = false;
			}
		}

		// check if alarm center updated db per 3s
		{
			auto now = std::chrono::steady_clock::now();
			auto diff = now - last_time_check_is_db_updated;
			if (std::chrono::duration_cast<std::chrono::seconds>(diff).count() >= 3) {

				range_log log("insert buffered histories per 3s");

				if (client_->is_db_updated()) {
					video::video_manager::get_instance()->LoadFromDB(false);
					notify_observers(0);
				}

				last_time_check_is_db_updated = std::chrono::steady_clock::now();
			}
			
		}

		// check if there are devices waiting to play per 2s
		{
			auto now = std::chrono::steady_clock::now();
			auto diff = now - last_time_check_has_device_waiting_to_play;
			if (std::chrono::duration_cast<std::chrono::seconds>(diff).count() >= 2) {

				range_log log("get_wait_to_play_devices per 2s");

				client_->get_wait_to_play_devices();

				last_time_check_has_device_waiting_to_play = std::chrono::steady_clock::now();
			}
		}


		// check if there are cameras waiting for been deleted per 3s
		{
			auto now = std::chrono::steady_clock::now();
			auto diff = now - last_time_check_delete_camera;
			if (std::chrono::duration_cast<std::chrono::seconds>(diff).count() >= 3) {
				range_log log("delete_camera per 2s");

				std::vector<alarm_center_video::camera_info> cameras_waiting_to_delete;

				{
					std::lock_guard<std::mutex> lg(mutex_for_cameras_waiting_to_delete_);
					if (!cameras_waiting_to_delete_.empty()) {
						cameras_waiting_to_delete = cameras_waiting_to_delete_;
						cameras_waiting_to_delete_.clear();
					}
				}

				if (!cameras_waiting_to_delete.empty()) {
					client_->cameras_waiting_to_delete_ = cameras_waiting_to_delete;
					client_->delete_camera();
				}
				
				last_time_check_delete_camera = std::chrono::steady_clock::now();
			}
		}
	}
}
std::string get_domain_ip(const std::string& domain) {
	AUTO_LOG_FUNCTION;
	struct addrinfo *result = nullptr;
	struct addrinfo *ptr = nullptr;
	struct addrinfo hints;

	struct sockaddr_in  *sockaddr_ipv4;
	//    struct sockaddr_in6 *sockaddr_ipv6;
	LPSOCKADDR sockaddr_ip;

	char ipstringbuffer[46];
	DWORD ipbufferlength = 46;

	//--------------------------------
	// Setup the hints address info structure
	// which is passed to the getaddrinfo() function
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	std::string ip;

	do {

		//--------------------------------
		// Call getaddrinfo(). If the call succeeds,
		// the result variable will hold a linked list
		// of addrinfo structures containing response
		// information
		DWORD dwRetval = getaddrinfo(domain.c_str(), "0", &hints, &result);
		if (dwRetval != 0) {
			JLOGA("getaddrinfo failed with error: %d\n", dwRetval);
			break;
		}

		JLOGA("getaddrinfo returned success\n");

		// Retrieve each address and print out the hex bytes
		int i = 0;
		int iRetval = 0;
		bool ok = false;
		for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
			JLOGA("getaddrinfo response %d\n", i++);
			JLOGA("\tFlags: 0x%x\n", ptr->ai_flags);
			JLOGA("\tFamily: ");
			switch (ptr->ai_family) {
			case AF_UNSPEC:
				JLOGA("Unspecified\n");
				break;
			case AF_INET:
				JLOGA("AF_INET (IPv4)\n");
				sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
				ip = inet_ntoa(sockaddr_ipv4->sin_addr);
				JLOGA("\tIPv4 address %s\n", ip.c_str());
				ok = true;
				break;
			case AF_INET6:
				JLOGA("AF_INET6 (IPv6)\n");
				// the InetNtop function is available on Windows Vista and later
				// sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
				// printf("\tIPv6 address %s\n",
				//    InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46) );

				// We use WSAAddressToString since it is supported on Windows XP and later
				sockaddr_ip = (LPSOCKADDR)ptr->ai_addr;
				// The buffer length is changed by each call to WSAAddresstoString
				// So we need to set it for each iteration through the loop for safety
				ipbufferlength = 46;
				iRetval = WSAAddressToStringA(sockaddr_ip, (DWORD)ptr->ai_addrlen, nullptr,
											  ipstringbuffer, &ipbufferlength);
				if (iRetval)
					JLOGA("WSAAddressToString failed with %u\n", WSAGetLastError());
				else
					JLOGA("\tIPv6 address %s\n", ipstringbuffer);
				break;
			case AF_NETBIOS:
				JLOGA("AF_NETBIOS (NetBIOS)\n");
				break;
			default:
				JLOGA("Other %ld\n", ptr->ai_family);
				break;
			}
			JLOGA("\tSocket type: ");
			switch (ptr->ai_socktype) {
			case 0:
				JLOGA("Unspecified\n");
				break;
			case SOCK_STREAM:
				JLOGA("SOCK_STREAM (stream)\n");
				break;
			case SOCK_DGRAM:
				JLOGA("SOCK_DGRAM (datagram) \n");
				break;
			case SOCK_RAW:
				JLOGA("SOCK_RAW (raw) \n");
				break;
			case SOCK_RDM:
				JLOGA("SOCK_RDM (reliable message datagram)\n");
				break;
			case SOCK_SEQPACKET:
				JLOGA("SOCK_SEQPACKET (pseudo-stream packet)\n");
				break;
			default:
				JLOGA("Other %ld\n", ptr->ai_socktype);
				break;
			}
			JLOGA("\tProtocol: ");
			switch (ptr->ai_protocol) {
			case 0:
				JLOGA("Unspecified\n");
				break;
			case IPPROTO_TCP:
				JLOGA("IPPROTO_TCP (TCP)\n");
				break;
			case IPPROTO_UDP:
				JLOGA("IPPROTO_UDP (UDP) \n");
				break;
			default:
				JLOGA("Other %ld\n", ptr->ai_protocol);
				break;
			}
			JLOGA("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
			JLOGA("\tCanonical name: %s\n", ptr->ai_canonname);

			if (ok) {
				break;
			}
		}

		freeaddrinfo(result);

		if (ok) {
			return ip;
		}
	} while (false);

	return "";
}