diff --git a/NetworkClient.cpp b/NetworkClient.cpp index a25e86d54..35c634576 100644 --- a/NetworkClient.cpp +++ b/NetworkClient.cpp @@ -44,8 +44,8 @@ NetworkClient::NetworkClient(std::vector& control) : controller server_reinitialize = false; change_in_progress = false; - ListenThread = NULL; - ConnectionThread = NULL; + ListenThread = NULL; + ConnectionThread = NULL; } NetworkClient::~NetworkClient() @@ -53,37 +53,22 @@ NetworkClient::~NetworkClient() StopClient(); } -void NetworkClient::ClearCallbacks() +/*---------------------------------------------------------*\ +| Client Information functions | +\*---------------------------------------------------------*/ +bool NetworkClient::GetConnected() { - ClientInfoChangeCallbacks.clear(); - ClientInfoChangeCallbackArgs.clear(); -} - -void NetworkClient::ClientInfoChanged() -{ - ClientInfoChangeMutex.lock(); - ControllerListMutex.lock(); - - /*---------------------------------------------------------*\ - | Client info has changed, call the callbacks | - \*---------------------------------------------------------*/ - for(unsigned int callback_idx = 0; callback_idx < ClientInfoChangeCallbacks.size(); callback_idx++) - { - ClientInfoChangeCallbacks[callback_idx](ClientInfoChangeCallbackArgs[callback_idx]); - } - - ControllerListMutex.unlock(); - ClientInfoChangeMutex.unlock(); + return(server_connected); } std::string NetworkClient::GetIP() { - return port_ip; + return(port_ip); } unsigned short NetworkClient::GetPort() { - return port_num; + return(port_num); } unsigned int NetworkClient::GetProtocolVersion() @@ -102,22 +87,19 @@ unsigned int NetworkClient::GetProtocolVersion() return(protocol_version); } -bool NetworkClient::GetConnected() -{ - return(server_connected); -} - bool NetworkClient::GetOnline() { return(server_connected && client_string_sent && protocol_initialized && server_initialized); } -void NetworkClient::RegisterClientInfoChangeCallback(NetClientCallback new_callback, void * new_callback_arg) +std::string NetworkClient::GetServerName() { - ClientInfoChangeCallbacks.push_back(new_callback); - ClientInfoChangeCallbackArgs.push_back(new_callback_arg); + return(server_name); } +/*---------------------------------------------------------*\ +| Client Control functions | +\*---------------------------------------------------------*/ void NetworkClient::SetIP(std::string new_ip) { if(server_connected == false) @@ -214,6 +196,452 @@ void NetworkClient::StopClient() ClientInfoChanged(); } +void NetworkClient::SendRequest_ControllerData(unsigned int dev_idx) +{ + NetPacketHeader request_hdr; + unsigned int protocol_version; + + controller_data_received = false; + + memcpy(request_hdr.pkt_magic, openrgb_sdk_magic, sizeof(openrgb_sdk_magic)); + + request_hdr.pkt_dev_idx = dev_idx; + request_hdr.pkt_id = NET_PACKET_ID_REQUEST_CONTROLLER_DATA; + + if(server_protocol_version == 0) + { + request_hdr.pkt_size = 0; + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); + } + else + { + request_hdr.pkt_size = sizeof(unsigned int); + + /*-------------------------------------------------------------*\ + | Limit the protocol version to the highest supported by both | + | the client and the server. | + \*-------------------------------------------------------------*/ + if(server_protocol_version > OPENRGB_SDK_PROTOCOL_VERSION) + { + protocol_version = OPENRGB_SDK_PROTOCOL_VERSION; + } + else + { + protocol_version = server_protocol_version; + } + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)&protocol_version, sizeof(unsigned int), MSG_NOSIGNAL); + send_in_progress.unlock(); + } +} + +void NetworkClient::SendRequest_RescanDevices() +{ + if(GetProtocolVersion() >= 5) + { + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_REQUEST_RESCAN_DEVICES, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); + } +} + +/*---------------------------------------------------------*\ +| Client Callback functions | +\*---------------------------------------------------------*/ +void NetworkClient::ClearCallbacks() +{ + ClientInfoChangeCallbacks.clear(); + ClientInfoChangeCallbackArgs.clear(); +} + +void NetworkClient::RegisterClientInfoChangeCallback(NetClientCallback new_callback, void * new_callback_arg) +{ + ClientInfoChangeCallbacks.push_back(new_callback); + ClientInfoChangeCallbackArgs.push_back(new_callback_arg); +} + +/*---------------------------------------------------------*\ +| ProfileManager functions | +\*---------------------------------------------------------*/ +char * NetworkClient::ProfileManager_GetProfileList() +{ + NetPacketHeader reply_hdr; + char * response_data = NULL; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); + + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + if(response_header.pkt_id == NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST && response_data_ptr != NULL) + { + response_data = response_data_ptr; + response_data_ptr = NULL; + } + + return(response_data); +} + +void NetworkClient::ProfileManager_LoadProfile(std::string profile_name) +{ + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_LOAD_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::ProfileManager_SaveProfile(std::string profile_name) +{ + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_SAVE_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::ProfileManager_DeleteProfile(std::string profile_name) +{ + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_DELETE_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::ProfileManager_UploadProfile(std::string profile_json_str) +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_UPLOAD_PROFILE, (unsigned int)strlen(profile_json_str.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_json_str.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +std::string NetworkClient::ProfileManager_DownloadProfile(std::string profile_name) +{ + NetPacketHeader request_hdr; + std::string response_string; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_name.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + if(response_header.pkt_id == NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE && response_data_ptr != NULL) + { + response_string.assign(response_data_ptr, response_header.pkt_size); + delete[] response_data_ptr; + response_data_ptr = NULL; + } + + return(response_string); +} + +std::string NetworkClient::ProfileManager_GetActiveProfile() +{ + NetPacketHeader request_hdr; + std::string response_string; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); + + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + if(response_header.pkt_id == NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE && response_data_ptr != NULL) + { + response_string.assign(response_data_ptr, response_header.pkt_size); + delete[] response_data_ptr; + response_data_ptr = NULL; + } + + return(response_string); +} + +/*---------------------------------------------------------*\ +| SettingsManager functions | +\*---------------------------------------------------------*/ +std::string NetworkClient::SettingsManager_GetSettings(std::string settings_key) +{ + NetPacketHeader request_hdr; + std::string response_string; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS, (unsigned int)strlen(settings_key.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)settings_key.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + + std::unique_lock wait_lock(waiting_on_response_mutex); + waiting_on_response_cv.wait(wait_lock); + + if(response_header.pkt_id == NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS && response_data_ptr != NULL) + { + response_string.assign(response_data_ptr, response_header.pkt_size); + delete[] response_data_ptr; + response_data_ptr = NULL; + } + + return(response_string); +} + +void NetworkClient::SettingsManager_SaveSettings() +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SettingsManager_SetSettings(std::string settings_json_str) +{ + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS, (unsigned int)strlen(settings_json_str.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)settings_json_str.c_str(), request_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +/*---------------------------------------------------------*\ +| RGBController functions | +\*---------------------------------------------------------*/ +void NetworkClient::SendRequest_RGBController_ClearSegments(unsigned int dev_idx, int zone) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + int request_data[1]; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS, sizeof(request_data)); + + request_data[0] = zone; + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)&request_data, sizeof(request_data), MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_AddSegment(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, 0); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_ResizeZone(unsigned int dev_idx, int zone, int new_size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + int request_data[2]; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE, sizeof(request_data)); + + request_data[0] = zone; + request_data[1] = new_size; + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)&request_data, sizeof(request_data), MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_UpdateLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, 0); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_UpdateZoneLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_UpdateSingleLED(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_SetCustomMode(unsigned int dev_idx) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE, 0); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_UpdateMode(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char * data, unsigned int size) +{ + if(change_in_progress) + { + return; + } + + NetPacketHeader request_hdr; + + InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SAVEMODE, size); + + send_in_progress.lock(); + send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)data, size, MSG_NOSIGNAL); + send_in_progress.unlock(); +} + +void NetworkClient::WaitOnControllerData() +{ + for(int i = 0; i < 1000; i++) + { + if(controller_data_received) + { + break; + } + std::this_thread::sleep_for(1ms); + } + + return; +} + +/*---------------------------------------------------------*\ +| Client callback signal functions | +\*---------------------------------------------------------*/ +void NetworkClient::ClientInfoChanged() +{ + ClientInfoChangeMutex.lock(); + ControllerListMutex.lock(); + + /*---------------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*---------------------------------------------------------*/ + for(unsigned int callback_idx = 0; callback_idx < ClientInfoChangeCallbacks.size(); callback_idx++) + { + ClientInfoChangeCallbacks[callback_idx](ClientInfoChangeCallbackArgs[callback_idx]); + } + + ControllerListMutex.unlock(); + ClientInfoChangeMutex.unlock(); +} + +/*---------------------------------------------------------*\ +| Client thread functions | +\*---------------------------------------------------------*/ void NetworkClient::ConnectionThreadFunction() { std::unique_lock lock(connection_mutex); @@ -413,37 +841,6 @@ void NetworkClient::ConnectionThreadFunction() } } -int NetworkClient::recv_select(SOCKET s, char *buf, int len, int flags) -{ - fd_set set; - struct timeval timeout; - - while(1) - { - timeout.tv_sec = 5; - timeout.tv_usec = 0; - - FD_ZERO(&set); - FD_SET(s, &set); - - int rv = select((int)s + 1, &set, NULL, NULL, &timeout); - - if(rv == SOCKET_ERROR || server_connected == false) - { - return 0; - } - else if(rv == 0) - { - continue; - } - else - { - return(recv(s, buf, len, flags)); - } - - } -} - void NetworkClient::ListenThreadFunction() { printf("Network client listener started\n"); @@ -456,6 +853,7 @@ void NetworkClient::ListenThreadFunction() NetPacketHeader header; int bytes_read = 0; char * data = NULL; + bool delete_data = true; for(unsigned int i = 0; i < 4; i++) { @@ -540,12 +938,40 @@ void NetworkClient::ListenThreadFunction() ProcessReply_ProtocolVersion(header.pkt_size, data); break; + case NET_PACKET_ID_SET_SERVER_NAME: + if(data == NULL) + { + break; + } + + ProcessRequest_ServerString(header.pkt_size, data); + break; + case NET_PACKET_ID_DEVICE_LIST_UPDATED: ProcessRequest_DeviceListChanged(); break; + + case NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST: + case NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE: + case NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE: + case NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS: + { + std::unique_lock lock(waiting_on_response_mutex); + + response_header = header; + response_data_ptr = data; + delete_data = false; + + lock.unlock(); + waiting_on_response_cv.notify_all(); + } + break; } - delete[] data; + if(delete_data) + { + delete[] data; + } } listen_done: @@ -592,20 +1018,9 @@ listen_done: ClientInfoChanged(); } -void NetworkClient::WaitOnControllerData() -{ - for(int i = 0; i < 1000; i++) - { - if(controller_data_received) - { - break; - } - std::this_thread::sleep_for(1ms); - } - - return; -} - +/*---------------------------------------------------------*\ +| Private Client functions | +\*---------------------------------------------------------*/ void NetworkClient::ProcessReply_ControllerCount(unsigned int data_size, char * data) { if(data_size == sizeof(unsigned int)) @@ -730,6 +1145,16 @@ void NetworkClient::ProcessRequest_DeviceListChanged() change_in_progress = false; } +void NetworkClient::ProcessRequest_ServerString(unsigned int data_size, char * data) +{ + server_name.assign(data, data_size); + + /*---------------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*---------------------------------------------------------*/ + ClientInfoChanged(); +} + void NetworkClient::SendData_ClientString() { NetPacketHeader reply_hdr; @@ -753,50 +1178,6 @@ void NetworkClient::SendRequest_ControllerCount() send_in_progress.unlock(); } -void NetworkClient::SendRequest_ControllerData(unsigned int dev_idx) -{ - NetPacketHeader request_hdr; - unsigned int protocol_version; - - controller_data_received = false; - - memcpy(request_hdr.pkt_magic, openrgb_sdk_magic, sizeof(openrgb_sdk_magic)); - - request_hdr.pkt_dev_idx = dev_idx; - request_hdr.pkt_id = NET_PACKET_ID_REQUEST_CONTROLLER_DATA; - - if(server_protocol_version == 0) - { - request_hdr.pkt_size = 0; - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send_in_progress.unlock(); - } - else - { - request_hdr.pkt_size = sizeof(unsigned int); - - /*-------------------------------------------------------------*\ - | Limit the protocol version to the highest supported by both | - | the client and the server. | - \*-------------------------------------------------------------*/ - if(server_protocol_version > OPENRGB_SDK_PROTOCOL_VERSION) - { - protocol_version = OPENRGB_SDK_PROTOCOL_VERSION; - } - else - { - protocol_version = server_protocol_version; - } - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)&protocol_version, sizeof(unsigned int), MSG_NOSIGNAL); - send_in_progress.unlock(); - } -} - void NetworkClient::SendRequest_ProtocolVersion() { NetPacketHeader request_hdr; @@ -812,226 +1193,9 @@ void NetworkClient::SendRequest_ProtocolVersion() send_in_progress.unlock(); } -void NetworkClient::SendRequest_RescanDevices() -{ - if(GetProtocolVersion() >= 5) - { - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, 0, NET_PACKET_ID_REQUEST_RESCAN_DEVICES, 0); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send_in_progress.unlock(); - } -} - -void NetworkClient::SendRequest_RGBController_ClearSegments(unsigned int dev_idx, int zone) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - int request_data[1]; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS, sizeof(request_data)); - - request_data[0] = zone; - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)&request_data, sizeof(request_data), MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_AddSegment(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, 0); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_ResizeZone(unsigned int dev_idx, int zone, int new_size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - int request_data[2]; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE, sizeof(request_data)); - - request_data[0] = zone; - request_data[1] = new_size; - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)&request_data, sizeof(request_data), MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_UpdateLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, 0); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_UpdateZoneLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_UpdateSingleLED(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_SetCustomMode(unsigned int dev_idx) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE, 0); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_UpdateMode(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char * data, unsigned int size) -{ - if(change_in_progress) - { - return; - } - - NetPacketHeader request_hdr; - - InitNetPacketHeader(&request_hdr, dev_idx, NET_PACKET_ID_RGBCONTROLLER_SAVEMODE, size); - - send_in_progress.lock(); - send(client_sock, (char *)&request_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)data, size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_LoadProfile(std::string profile_name) -{ - NetPacketHeader reply_hdr; - - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_LOAD_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); - - send_in_progress.lock(); - send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_SaveProfile(std::string profile_name) -{ - NetPacketHeader reply_hdr; - - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_SAVE_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); - - send_in_progress.lock(); - send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_DeleteProfile(std::string profile_name) -{ - NetPacketHeader reply_hdr; - - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_DELETE_PROFILE, (unsigned int)strlen(profile_name.c_str()) + 1); - - send_in_progress.lock(); - send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send(client_sock, (char *)profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); - send_in_progress.unlock(); -} - -void NetworkClient::SendRequest_GetProfileList() -{ - NetPacketHeader reply_hdr; - - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_PROFILE_LIST, 0); - - send_in_progress.lock(); - send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); - send_in_progress.unlock(); -} - +/*---------------------------------------------------------*\ +| Private ProfileManager functions | +\*---------------------------------------------------------*/ std::vector * NetworkClient::ProcessReply_ProfileList(unsigned int data_size, char * data) { std::vector * profile_list; @@ -1071,3 +1235,37 @@ std::vector * NetworkClient::ProcessReply_ProfileList(unsigned int return profile_list; } + +/*---------------------------------------------------------*\ +| Private helper functions | +\*---------------------------------------------------------*/ +int NetworkClient::recv_select(SOCKET s, char *buf, int len, int flags) +{ + fd_set set; + struct timeval timeout; + + while(1) + { + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + FD_ZERO(&set); + FD_SET(s, &set); + + int rv = select((int)s + 1, &set, NULL, NULL, &timeout); + + if(rv == SOCKET_ERROR || server_connected == false) + { + return 0; + } + else if(rv == 0) + { + continue; + } + else + { + return(recv(s, buf, len, flags)); + } + + } +} diff --git a/NetworkClient.h b/NetworkClient.h index c8c7e8764..bac86106b 100644 --- a/NetworkClient.h +++ b/NetworkClient.h @@ -11,6 +11,7 @@ #pragma once +#include #include #include #include @@ -26,104 +27,165 @@ public: NetworkClient(std::vector& control); ~NetworkClient(); - void ClientInfoChanged(); + /*-----------------------------------------------------*\ + | Client Information functions | + \*-----------------------------------------------------*/ + bool GetConnected(); + std::string GetIP(); + unsigned short GetPort(); + unsigned int GetProtocolVersion(); + bool GetOnline(); + std::string GetServerName(); - bool GetConnected(); - std::string GetIP(); - unsigned short GetPort(); - unsigned int GetProtocolVersion(); - bool GetOnline(); + /*-----------------------------------------------------*\ + | Client Control functions | + \*-----------------------------------------------------*/ + void SetIP(std::string new_ip); + void SetName(std::string new_name); + void SetPort(unsigned short new_port); - void ClearCallbacks(); - void RegisterClientInfoChangeCallback(NetClientCallback new_callback, void * new_callback_arg); + void StartClient(); + void StopClient(); - void SetIP(std::string new_ip); - void SetName(std::string new_name); - void SetPort(unsigned short new_port); + void SendRequest_ControllerData(unsigned int dev_idx); + void SendRequest_RescanDevices(); - void StartClient(); - void StopClient(); + /*-----------------------------------------------------*\ + | Client Callback functions | + \*-----------------------------------------------------*/ + void ClearCallbacks(); + void RegisterClientInfoChangeCallback(NetClientCallback new_callback, void * new_callback_arg); - void ConnectionThreadFunction(); - void ListenThreadFunction(); + /*-----------------------------------------------------*\ + | ProfileManager functions | + \*-----------------------------------------------------*/ + char * ProfileManager_GetProfileList(); + void ProfileManager_LoadProfile(std::string profile_name); + void ProfileManager_SaveProfile(std::string profile_name); + void ProfileManager_DeleteProfile(std::string profile_name); + void ProfileManager_UploadProfile(std::string profile_json_str); + std::string ProfileManager_DownloadProfile(std::string profile_name); + std::string ProfileManager_GetActiveProfile(); - void WaitOnControllerData(); + /*-----------------------------------------------------*\ + | SettingsManager functions | + \*-----------------------------------------------------*/ + std::string SettingsManager_GetSettings(std::string settings_key); + void SettingsManager_SaveSettings(); + void SettingsManager_SetSettings(std::string settings_json_str); - void ProcessReply_ControllerCount(unsigned int data_size, char * data); - void ProcessReply_ControllerData(unsigned int data_size, char * data, unsigned int dev_idx); - void ProcessReply_ProtocolVersion(unsigned int data_size, char * data); + /*-----------------------------------------------------*\ + | RGBController functions | + \*-----------------------------------------------------*/ + void SendRequest_RGBController_ClearSegments(unsigned int dev_idx, int zone); + void SendRequest_RGBController_AddSegment(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_ResizeZone(unsigned int dev_idx, int zone, int new_size); - void ProcessRequest_DeviceListChanged(); + void SendRequest_RGBController_UpdateLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_UpdateZoneLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_UpdateSingleLED(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendData_ClientString(); + void SendRequest_RGBController_SetCustomMode(unsigned int dev_idx); - void SendRequest_ControllerCount(); - void SendRequest_ControllerData(unsigned int dev_idx); - void SendRequest_ProtocolVersion(); + void SendRequest_RGBController_UpdateMode(unsigned int dev_idx, unsigned char * data, unsigned int size); + void SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendRequest_RescanDevices(); - - void SendRequest_RGBController_ClearSegments(unsigned int dev_idx, int zone); - void SendRequest_RGBController_AddSegment(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendRequest_RGBController_ResizeZone(unsigned int dev_idx, int zone, int new_size); - - void SendRequest_RGBController_UpdateLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendRequest_RGBController_UpdateZoneLEDs(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendRequest_RGBController_UpdateSingleLED(unsigned int dev_idx, unsigned char * data, unsigned int size); - - void SendRequest_RGBController_SetCustomMode(unsigned int dev_idx); - - void SendRequest_RGBController_UpdateMode(unsigned int dev_idx, unsigned char * data, unsigned int size); - void SendRequest_RGBController_SaveMode(unsigned int dev_idx, unsigned char * data, unsigned int size); - - - std::vector * ProcessReply_ProfileList(unsigned int data_size, char * data); - - void SendRequest_GetProfileList(); - void SendRequest_LoadProfile(std::string profile_name); - void SendRequest_SaveProfile(std::string profile_name); - void SendRequest_DeleteProfile(std::string profile_name); - - std::vector server_controllers; - - std::mutex ControllerListMutex; - -protected: - std::vector& controllers; + void WaitOnControllerData(); + std::vector server_controllers; private: - SOCKET client_sock; - std::string client_name; - net_port port; - std::string port_ip; - unsigned short port_num; - std::atomic client_active; - bool client_string_sent; - bool controller_data_received; - bool controller_data_requested; - bool protocol_initialized; - bool server_connected; - bool server_initialized; - bool server_reinitialize; - unsigned int server_controller_count; - bool server_controller_count_requested; - bool server_controller_count_received; - unsigned int server_protocol_version; - bool server_protocol_version_received; - bool change_in_progress; - unsigned int requested_controllers; - std::mutex send_in_progress; + /*-----------------------------------------------------*\ + | Client state variables | + \*-----------------------------------------------------*/ + std::atomic client_active; + bool client_string_sent; + bool controller_data_received; + bool controller_data_requested; + bool protocol_initialized; + bool change_in_progress; + unsigned int requested_controllers; + std::mutex send_in_progress; - std::mutex connection_mutex; - std::condition_variable connection_cv; + NetPacketHeader response_header; + char * response_data_ptr; + std::mutex waiting_on_response_mutex; + std::condition_variable waiting_on_response_cv; - std::thread * ConnectionThread; - std::thread * ListenThread; + /*-----------------------------------------------------*\ + | Client information | + \*-----------------------------------------------------*/ + std::string client_name; + SOCKET client_sock; + net_port port; + std::string port_ip; + unsigned short port_num; + /*-----------------------------------------------------*\ + | Server information | + \*-----------------------------------------------------*/ + std::string server_name; + bool server_connected; + bool server_initialized; + bool server_reinitialize; + unsigned int server_controller_count; + bool server_controller_count_requested; + bool server_controller_count_received; + unsigned int server_protocol_version; + bool server_protocol_version_received; + + /*-----------------------------------------------------*\ + | Client threads | + \*-----------------------------------------------------*/ + std::mutex connection_mutex; + std::condition_variable connection_cv; + std::thread * ConnectionThread; + std::thread * ListenThread; + + /*-----------------------------------------------------*\ + | Callbacks | + \*-----------------------------------------------------*/ std::mutex ClientInfoChangeMutex; std::vector ClientInfoChangeCallbacks; std::vector ClientInfoChangeCallbackArgs; - int recv_select(SOCKET s, char *buf, int len, int flags); + /*-----------------------------------------------------*\ + | Controller list | + \*-----------------------------------------------------*/ + std::mutex ControllerListMutex; + std::vector& controllers; + + /*-----------------------------------------------------*\ + | Client callback signal functions | + \*-----------------------------------------------------*/ + void ClientInfoChanged(); + + /*-----------------------------------------------------*\ + | Client thread functions | + \*-----------------------------------------------------*/ + void ConnectionThreadFunction(); + void ListenThreadFunction(); + + /*-----------------------------------------------------*\ + | Private Client functions | + \*-----------------------------------------------------*/ + void ProcessReply_ControllerCount(unsigned int data_size, char * data); + void ProcessReply_ControllerData(unsigned int data_size, char * data, unsigned int dev_idx); + void ProcessReply_ProtocolVersion(unsigned int data_size, char * data); + void ProcessRequest_DeviceListChanged(); + void ProcessRequest_ServerString(unsigned int data_size, char * data); + + void SendData_ClientString(); + void SendRequest_ControllerCount(); + void SendRequest_ProtocolVersion(); + + /*-----------------------------------------------------*\ + | Private ProfileManager functions | + \*-----------------------------------------------------*/ + std::vector * ProcessReply_ProfileList(unsigned int data_size, char * data); + + /*-----------------------------------------------------*\ + | Private helper functions | + \*-----------------------------------------------------*/ + int recv_select(SOCKET s, char *buf, int len, int flags); }; diff --git a/NetworkProtocol.h b/NetworkProtocol.h index b44dfa650..03e1708cc 100644 --- a/NetworkProtocol.h +++ b/NetworkProtocol.h @@ -61,33 +61,50 @@ enum NET_PACKET_ID_REQUEST_PROTOCOL_VERSION = 40, /* Request OpenRGB SDK protocol version from server */ NET_PACKET_ID_SET_CLIENT_NAME = 50, /* Send client name string to server */ + NET_PACKET_ID_SET_SERVER_NAME = 51, /* Send server name string to client */ NET_PACKET_ID_DEVICE_LIST_UPDATED = 100, /* Indicate to clients that device list has updated */ NET_PACKET_ID_REQUEST_RESCAN_DEVICES = 140, /* Request rescan of devices */ - NET_PACKET_ID_REQUEST_PROFILE_LIST = 150, /* Request profile list */ - NET_PACKET_ID_REQUEST_SAVE_PROFILE = 151, /* Save current configuration in a new profile */ - NET_PACKET_ID_REQUEST_LOAD_PROFILE = 152, /* Load a given profile */ - NET_PACKET_ID_REQUEST_DELETE_PROFILE = 153, /* Delete a given profile */ - - NET_PACKET_ID_REQUEST_PLUGIN_LIST = 200, /* Request list of plugins */ - NET_PACKET_ID_PLUGIN_SPECIFIC = 201, /* Interact with a plugin */ + /*----------------------------------------------------------------------------------------------------------*\ + | ProfileManager functions | + \*----------------------------------------------------------------------------------------------------------*/ + NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST = 150, /* Get profile list */ + NET_PACKET_ID_PROFILEMANAGER_SAVE_PROFILE = 151, /* Save current configuration in a new profile */ + NET_PACKET_ID_PROFILEMANAGER_LOAD_PROFILE = 152, /* Load a given profile */ + NET_PACKET_ID_PROFILEMANAGER_DELETE_PROFILE = 153, /* Delete a given profile */ + NET_PACKET_ID_PROFILEMANAGER_UPLOAD_PROFILE = 154, /* Upload a profile to the server in JSON format */ + NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE = 155, /* Download a profile from the server in JSON format*/ + NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE = 156, /* Get the active profile name */ /*----------------------------------------------------------------------------------------------------------*\ - | RGBController class functions | + | PluginManager functions | \*----------------------------------------------------------------------------------------------------------*/ - NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE = 1000, /* RGBController::ResizeZone() */ - NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS = 1001, /* RGBController::ClearSegments() */ - NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT = 1002, /* RGBController::AddSegment() */ + NET_PACKET_ID_PLUGINMANAGER_GET_PLUGIN_LIST = 200, /* Get list of plugins */ + NET_PACKET_ID_PLUGINMANAGER_PLUGIN_SPECIFIC = 201, /* Interact with a plugin */ - NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS = 1050, /* RGBController::UpdateLEDs() */ - NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS = 1051, /* RGBController::UpdateZoneLEDs() */ - NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED = 1052, /* RGBController::UpdateSingleLED() */ + /*----------------------------------------------------------------------------------------------------------*\ + | SettingsManager functions | + \*----------------------------------------------------------------------------------------------------------*/ + NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS = 250, /* Get settings for a given key in JSON format */ + NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS = 251, /* Set settings for a given key in JSON format */ + NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS = 252, /* Save settings */ - NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE = 1100, /* RGBController::SetCustomMode() */ - NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE = 1101, /* RGBController::UpdateMode() */ - NET_PACKET_ID_RGBCONTROLLER_SAVEMODE = 1102, /* RGBController::SaveMode() */ + /*----------------------------------------------------------------------------------------------------------*\ + | RGBController functions | + \*----------------------------------------------------------------------------------------------------------*/ + NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE = 1000, /* RGBController::ResizeZone() */ + NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS = 1001, /* RGBController::ClearSegments() */ + NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT = 1002, /* RGBController::AddSegment() */ + + NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS = 1050, /* RGBController::UpdateLEDs() */ + NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS = 1051, /* RGBController::UpdateZoneLEDs() */ + NET_PACKET_ID_RGBCONTROLLER_UPDATESINGLELED = 1052, /* RGBController::UpdateSingleLED() */ + + NET_PACKET_ID_RGBCONTROLLER_SETCUSTOMMODE = 1100, /* RGBController::SetCustomMode() */ + NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE = 1101, /* RGBController::UpdateMode() */ + NET_PACKET_ID_RGBCONTROLLER_SAVEMODE = 1102, /* RGBController::SaveMode() */ }; void InitNetPacketHeader diff --git a/NetworkServer.cpp b/NetworkServer.cpp index 456189ee0..848e06473 100644 --- a/NetworkServer.cpp +++ b/NetworkServer.cpp @@ -10,10 +10,11 @@ \*---------------------------------------------------------*/ #include +#include #include "NetworkServer.h" #include "LogManager.h" -#ifndef WIN32 +#ifndef _WIN32 #include #include #include @@ -28,8 +29,9 @@ const char yes = 1; -#ifdef WIN32 +#ifdef _WIN32 #include +#define MSG_NOSIGNAL 0 #else #include #endif @@ -71,6 +73,7 @@ NetworkServer::NetworkServer(std::vector& control) : controller plugin_manager = nullptr; profile_manager = nullptr; + settings_manager = nullptr; } NetworkServer::~NetworkServer() @@ -78,48 +81,9 @@ NetworkServer::~NetworkServer() StopServer(); } -void NetworkServer::ClientInfoChanged() -{ - ClientInfoChangeMutex.lock(); - - /*---------------------------------------------------------*\ - | Client info has changed, call the callbacks | - \*---------------------------------------------------------*/ - for(unsigned int callback_idx = 0; callback_idx < ClientInfoChangeCallbacks.size(); callback_idx++) - { - ClientInfoChangeCallbacks[callback_idx](ClientInfoChangeCallbackArgs[callback_idx]); - } - - ClientInfoChangeMutex.unlock(); -} - -void NetworkServer::DeviceListChanged() -{ - /*---------------------------------------------------------*\ - | Indicate to the clients that the controller list has | - | changed | - \*---------------------------------------------------------*/ - for(unsigned int client_idx = 0; client_idx < ServerClients.size(); client_idx++) - { - SendRequest_DeviceListChanged(ServerClients[client_idx]->client_sock); - } -} - -void NetworkServer::ServerListeningChanged() -{ - ServerListeningChangeMutex.lock(); - - /*---------------------------------------------------------*\ - | Server state has changed, call the callbacks | - \*---------------------------------------------------------*/ - for(unsigned int callback_idx = 0; callback_idx < ServerListeningChangeCallbacks.size(); callback_idx++) - { - ServerListeningChangeCallbacks[callback_idx](ServerListeningChangeCallbackArgs[callback_idx]); - } - - ServerListeningChangeMutex.unlock(); -} - +/*---------------------------------------------------------*\ +| Server Information functions | +\*---------------------------------------------------------*/ std::string NetworkServer::GetHost() { return host; @@ -205,6 +169,21 @@ unsigned int NetworkServer::GetClientProtocolVersion(unsigned int client_num) return result; } +/*---------------------------------------------------------*\ +| Callback functions | +\*---------------------------------------------------------*/ +void NetworkServer::DeviceListChanged() +{ + /*-----------------------------------------------------*\ + | Indicate to the clients that the controller list has | + | changed | + \*-----------------------------------------------------*/ + for(unsigned int client_idx = 0; client_idx < ServerClients.size(); client_idx++) + { + SendRequest_DeviceListChanged(ServerClients[client_idx]->client_sock); + } +} + void NetworkServer::RegisterClientInfoChangeCallback(NetServerCallback new_callback, void * new_callback_arg) { ClientInfoChangeCallbacks.push_back(new_callback); @@ -217,6 +196,9 @@ void NetworkServer::RegisterServerListeningChangeCallback(NetServerCallback new_ ServerListeningChangeCallbackArgs.push_back(new_callback_arg); } +/*---------------------------------------------------------*\ +| Server Configuration functions | +\*---------------------------------------------------------*/ void NetworkServer::SetHost(std::string new_host) { if(server_online == false) @@ -230,6 +212,22 @@ void NetworkServer::SetLegacyWorkaroundEnable(bool enable) legacy_workaround_enabled = enable; } +void NetworkServer::SetName(std::string new_name) +{ + /*-----------------------------------------------------*\ + | Store the server name | + \*-----------------------------------------------------*/ + server_name = new_name; + + /*-----------------------------------------------------*\ + | Send server name to all clients | + \*-----------------------------------------------------*/ + for(std::size_t client_idx = 0; client_idx < ServerClients.size(); client_idx++) + { + SendReply_ServerString(ServerClients[client_idx]->client_sock); + } +} + void NetworkServer::SetPort(unsigned short new_port) { if(server_online == false) @@ -238,22 +236,25 @@ void NetworkServer::SetPort(unsigned short new_port) } } +/*---------------------------------------------------------*\ +| Server Control functions | +\*---------------------------------------------------------*/ void NetworkServer::StartServer() { int err; struct addrinfo hints, *res, *result; - /*---------------------------------------------------------*\ - | Start a TCP server and launch threads | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Start a TCP server and launch threads | + \*-----------------------------------------------------*/ char port_str[6]; snprintf(port_str, 6, "%d", port_num); socket_count = 0; - /*---------------------------------------------------------*\ - | Windows requires WSAStartup before using sockets | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Windows requires WSAStartup before using sockets | + \*-----------------------------------------------------*/ #ifdef WIN32 if(WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR) { @@ -275,9 +276,9 @@ void NetworkServer::StartServer() return; } - /*---------------------------------------------------------*\ - | Create a server socket for each address returned. | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Create a server socket for each address returned. | + \*-----------------------------------------------------*/ for(res = result; res && socket_count < MAXSOCK; res = res->ai_next) { server_sock[socket_count] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); @@ -289,14 +290,14 @@ void NetworkServer::StartServer() return; } - /*---------------------------------------------------------*\ - | Set socket options - reuse addr | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Set socket options - reuse addr | + \*-------------------------------------------------*/ setsockopt(server_sock[socket_count], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - /*---------------------------------------------------------*\ - | Bind the server socket | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Bind the server socket | + \*-------------------------------------------------*/ if(bind(server_sock[socket_count], res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) { if(errno == EADDRINUSE) @@ -332,9 +333,9 @@ void NetworkServer::StartServer() return; } - /*---------------------------------------------------------*\ - | Set socket options - no delay | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Set socket options - no delay | + \*-------------------------------------------------*/ setsockopt(server_sock[socket_count], IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); socket_count += 1; @@ -343,9 +344,9 @@ void NetworkServer::StartServer() freeaddrinfo(result); server_online = true; - /*---------------------------------------------------------*\ - | Start the connection thread | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Start the connection thread | + \*-----------------------------------------------------*/ for(int curr_socket = 0; curr_socket < socket_count; curr_socket++) { ConnectionThread[curr_socket] = new std::thread(&NetworkServer::ConnectionThreadFunction, this, curr_socket); @@ -386,24 +387,78 @@ void NetworkServer::StopServer() socket_count = 0; - /*---------------------------------------------------------*\ - | Client info has changed, call the callbacks | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*-----------------------------------------------------*/ ClientInfoChanged(); } +/*---------------------------------------------------------*\ +| Server Interface functions | +\*---------------------------------------------------------*/ +void NetworkServer::SetPluginManager(PluginManagerInterface* plugin_manager_pointer) +{ + plugin_manager = plugin_manager_pointer; +} + +void NetworkServer::SetProfileManager(ProfileManagerInterface* profile_manager_pointer) +{ + profile_manager = profile_manager_pointer; +} + +void NetworkServer::SetSettingsManager(SettingsManagerInterface* settings_manager_pointer) +{ + settings_manager = settings_manager_pointer; +} + +/*---------------------------------------------------------*\ +| Server callback signal functions | +\*---------------------------------------------------------*/ +void NetworkServer::ClientInfoChanged() +{ + ClientInfoChangeMutex.lock(); + + /*-----------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*-----------------------------------------------------*/ + for(unsigned int callback_idx = 0; callback_idx < ClientInfoChangeCallbacks.size(); callback_idx++) + { + ClientInfoChangeCallbacks[callback_idx](ClientInfoChangeCallbackArgs[callback_idx]); + } + + ClientInfoChangeMutex.unlock(); +} + +void NetworkServer::ServerListeningChanged() +{ + ServerListeningChangeMutex.lock(); + + /*-----------------------------------------------------*\ + | Server state has changed, call the callbacks | + \*-----------------------------------------------------*/ + for(unsigned int callback_idx = 0; callback_idx < ServerListeningChangeCallbacks.size(); callback_idx++) + { + ServerListeningChangeCallbacks[callback_idx](ServerListeningChangeCallbackArgs[callback_idx]); + } + + ServerListeningChangeMutex.unlock(); +} + +/*---------------------------------------------------------*\ +| Server Thread functions | +\*---------------------------------------------------------*/ void NetworkServer::ConnectionThreadFunction(int socket_idx) { - /*---------------------------------------------------------*\ - | This thread handles client connections | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | This thread handles client connections | + \*-----------------------------------------------------*/ LOG_INFO("[NetworkServer] Network connection thread started on port %hu", GetPort()); while(server_online == true) { - /*---------------------------------------------------------*\ - | Create new socket for client connection | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Create new socket for client connection | + \*-------------------------------------------------*/ NetworkClientInfo * client_info = new NetworkClientInfo(); /*---------------------------------------------------------*\ @@ -422,9 +477,9 @@ void NetworkServer::ConnectionThreadFunction(int socket_idx) server_listening = true; ServerListeningChanged(); - /*---------------------------------------------------------*\ - | Accept the client connection | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Accept the client connection | + \*-------------------------------------------------*/ client_info->client_sock = accept_select((int)server_sock[socket_idx]); if(client_info->client_sock < 0) @@ -446,9 +501,9 @@ void NetworkServer::ConnectionThreadFunction(int socket_idx) ioctlsocket(client_info->client_sock, FIONBIO, &arg); setsockopt(client_info->client_sock, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); - /*---------------------------------------------------------*\ - | Discover the remote hosts IP | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Discover the remote hosts IP | + \*-------------------------------------------------*/ struct sockaddr_storage tmp_addr; char ipstr[INET6_ADDRSTRLEN]; socklen_t len; @@ -482,9 +537,9 @@ void NetworkServer::ConnectionThreadFunction(int socket_idx) ServerClients.push_back(client_info); ServerClientsMutex.unlock(); - /*---------------------------------------------------------*\ - | Client info has changed, call the callbacks | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*-------------------------------------------------*/ ClientInfoChanged(); } @@ -494,62 +549,52 @@ void NetworkServer::ConnectionThreadFunction(int socket_idx) ServerListeningChanged(); } -int NetworkServer::accept_select(int sockfd) +void NetworkServer::ControllerListenThread(NetworkServerControllerThread * this_thread) { - fd_set set; - struct timeval timeout; - - while(1) + while(this_thread->online == true) { - timeout.tv_sec = TCP_TIMEOUT_SECONDS; - timeout.tv_usec = 0; + std::unique_lock start_lock(this_thread->start_mutex); + this_thread->start_cv.wait(start_lock); - FD_ZERO(&set); - FD_SET(sockfd, &set); - - int rv = select(sockfd + 1, &set, NULL, NULL, &timeout); - - if(rv == SOCKET_ERROR || server_online == false) + while(this_thread->queue.size() > 0) { - return -1; - } - else if(rv == 0) - { - continue; - } - else - { - return(accept((int)sockfd, NULL, NULL)); - } - } -} + NetworkServerControllerThreadQueueEntry queue_entry; -int NetworkServer::recv_select(SOCKET s, char *buf, int len, int flags) -{ - fd_set set; - struct timeval timeout; + this_thread->queue_mutex.lock(); + queue_entry = this_thread->queue.front(); + this_thread->queue.pop(); + this_thread->queue_mutex.unlock(); - while(1) - { - timeout.tv_sec = TCP_TIMEOUT_SECONDS; - timeout.tv_usec = 0; + switch(queue_entry.id) + { + case NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS: + controllers[this_thread->index]->SetColorDescription((unsigned char *)queue_entry.data); + controllers[this_thread->index]->UpdateLEDs(); + break; - FD_ZERO(&set); - FD_SET(s, &set); + case NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS: + { + int zone; - int rv = select((int)s + 1, &set, NULL, NULL, &timeout); + memcpy(&zone, &queue_entry.data[sizeof(unsigned int)], sizeof(int)); - if(rv == SOCKET_ERROR || server_online == false) - { - return 0; - } - else if(rv == 0) - { - continue; - } - else - { - return(recv(s, buf, len, flags)); + controllers[this_thread->index]->SetZoneColorDescription((unsigned char *)queue_entry.data); + controllers[this_thread->index]->UpdateZoneLEDs(zone); + } + break; + + case NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE: + controllers[this_thread->index]->SetModeDescription((unsigned char *)queue_entry.data, queue_entry.client_protocol_version); + controllers[this_thread->index]->UpdateMode(); + break; + + case NET_PACKET_ID_RGBCONTROLLER_SAVEMODE: + controllers[this_thread->index]->SetModeDescription((unsigned char *)queue_entry.data, queue_entry.client_protocol_version); + controllers[this_thread->index]->SaveMode(); + break; + } + + delete[] queue_entry.data; } } } @@ -560,20 +605,21 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) LOG_INFO("[NetworkServer] Network server started"); - /*---------------------------------------------------------*\ - | This thread handles messages received from clients | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | This thread handles messages received from clients | + \*-----------------------------------------------------*/ while(server_online == true) { NetPacketHeader header; int bytes_read = 0; char * data = NULL; + bool delete_data = true; for(unsigned int i = 0; i < 4; i++) { - /*---------------------------------------------------------*\ - | Read byte of magic | - \*---------------------------------------------------------*/ + /*---------------------------------------------*\ + | Read byte of magic | + \*---------------------------------------------*/ bytes_read = recv_select(client_sock, &header.pkt_magic[i], 1, 0); if(bytes_read <= 0) @@ -582,9 +628,9 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) goto listen_done; } - /*---------------------------------------------------------*\ - | Test characters of magic "ORGB" | - \*---------------------------------------------------------*/ + /*---------------------------------------------*\ + | Test characters of magic "ORGB" | + \*---------------------------------------------*/ if(header.pkt_magic[i] != openrgb_sdk_magic[i]) { LOG_ERROR("[NetworkServer] Invalid magic received"); @@ -592,10 +638,10 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) } } - /*---------------------------------------------------------*\ - | If we get to this point, the magic is correct. Read the | - | rest of the header | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | If we get to this point, the magic is correct. | + | Read the rest of the header | + \*-------------------------------------------------*/ bytes_read = 0; do { @@ -613,9 +659,9 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) } while(bytes_read != sizeof(header) - sizeof(header.pkt_magic)); - /*---------------------------------------------------------*\ - | Header received, now receive the data | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Header received, now receive the data | + \*-------------------------------------------------*/ bytes_read = 0; if(header.pkt_size > 0) { @@ -637,12 +683,15 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) } while ((unsigned int)bytes_read < header.pkt_size); } - /*---------------------------------------------------------*\ - | Entire request received, select functionality based on | - | request ID | - \*---------------------------------------------------------*/ + /*-------------------------------------------------*\ + | Entire request received, select functionality | + | based on request ID | + \*-------------------------------------------------*/ switch(header.pkt_id) { + /*-------------------------------------------------*\ + | Network requests | + \*-------------------------------------------------*/ case NET_PACKET_ID_REQUEST_CONTROLLER_COUNT: SendReply_ControllerCount(client_sock); break; @@ -661,8 +710,9 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) break; case NET_PACKET_ID_REQUEST_PROTOCOL_VERSION: - SendReply_ProtocolVersion(client_sock); ProcessRequest_ClientProtocolVersion(client_sock, header.pkt_size, data); + SendReply_ProtocolVersion(client_sock); + SendReply_ServerString(client_sock); break; case NET_PACKET_ID_SET_CLIENT_NAME: @@ -678,6 +728,189 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) ProcessRequest_RescanDevices(); break; + /*-------------------------------------------------*\ + | ProfileManager functions | + \*-------------------------------------------------*/ + case NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST: + SendReply_ProfileList(client_sock); + break; + + case NET_PACKET_ID_PROFILEMANAGER_SAVE_PROFILE: + if(data == NULL) + { + break; + } + + if(profile_manager) + { + std::string profile_name; + profile_name.assign(data, header.pkt_size); + + profile_manager->SaveProfile(profile_name); + } + break; + + case NET_PACKET_ID_PROFILEMANAGER_LOAD_PROFILE: + if(data == NULL) + { + break; + } + + if(profile_manager) + { + std::string profile_name; + profile_name.assign(data, header.pkt_size); + + profile_manager->LoadProfile(profile_name); + } + break; + + case NET_PACKET_ID_PROFILEMANAGER_DELETE_PROFILE: + if(data == NULL) + { + break; + } + + if(profile_manager) + { + std::string profile_name; + profile_name.assign(data, header.pkt_size); + + profile_manager->DeleteProfile(profile_name); + } + break; + + case NET_PACKET_ID_PROFILEMANAGER_UPLOAD_PROFILE: + if(data == NULL) + { + break; + } + + if(profile_manager) + { + std::string profile_json_string; + profile_json_string.assign(data, header.pkt_size); + + nlohmann::json profile_json = nlohmann::json::parse(profile_json_string); + + profile_manager->SaveProfileFromJSON(profile_json); + } + break; + + case NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE: + if(data == NULL) + { + break; + } + + if(profile_manager) + { + std::string profile_name; + profile_name.assign(data, header.pkt_size); + + std::string profile_json_string = profile_manager->ReadProfileJSON(profile_name).dump(); + + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_DOWNLOAD_PROFILE, (unsigned int)strlen(profile_json_string.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)profile_json_string.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + } + break; + + case NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE: + { + std::string active_profile_name = profile_manager->GetActiveProfile(); + + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_GET_ACTIVE_PROFILE, (unsigned int)strlen(active_profile_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)active_profile_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + } + break; + + /*-------------------------------------------------*\ + | PluginManager functions | + \*-------------------------------------------------*/ + case NET_PACKET_ID_PLUGINMANAGER_GET_PLUGIN_LIST: + SendReply_PluginList(client_sock); + break; + + case NET_PACKET_ID_PLUGINMANAGER_PLUGIN_SPECIFIC: + if(plugin_manager) + { + unsigned int plugin_pkt_id = *((unsigned int*)(data)); + unsigned int plugin_pkt_size = header.pkt_size - (sizeof(unsigned int)); + unsigned char* plugin_data = (unsigned char*)(data + sizeof(unsigned int)); + unsigned char* output = plugin_manager->OnSDKCommand(header.pkt_dev_idx, plugin_pkt_id, plugin_data, &plugin_pkt_size); + + if(output != nullptr) + { + SendReply_PluginSpecific(client_sock, plugin_pkt_id, output, plugin_pkt_size); + } + } + break; + + /*-------------------------------------------------*\ + | SettingsManager functions | + \*-------------------------------------------------*/ + case NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS: + if(data == NULL) + { + break; + } + + if(settings_manager != NULL) + { + std::string settings_key; + settings_key.assign(data, header.pkt_size); + + nlohmann::json settings_json = settings_manager->GetSettings(settings_key); + std::string settings_json_str = settings_json.dump(); + + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_SETTINGSMANAGER_GET_SETTINGS, (unsigned int)strlen(settings_json_str.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)settings_json_str.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + } + break; + + case NET_PACKET_ID_SETTINGSMANAGER_SET_SETTINGS: + if(data == NULL) + { + break; + } + + if(settings_manager != NULL) + { + std::string settings_json_str; + settings_json_str.assign(data, header.pkt_size); + + settings_manager->SetSettingsFromJsonString(settings_json_str); + } + break; + + case NET_PACKET_ID_SETTINGSMANAGER_SAVE_SETTINGS: + if(settings_manager != NULL) + { + settings_manager->SaveSettings(); + } + break; + + /*-------------------------------------------------*\ + | RGBController functions | + \*-------------------------------------------------*/ case NET_PACKET_ID_RGBCONTROLLER_RESIZEZONE: if(data == NULL) { @@ -698,71 +931,63 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) break; case NET_PACKET_ID_RGBCONTROLLER_UPDATELEDS: - if(data == NULL) - { - break; - } - - /*---------------------------------------------------------*\ - | Verify the color description size (first 4 bytes of data) | - | matches the packet size in the header | - | | - | If protocol version is 4 or below and the legacy SDK | - | compatibility workaround is enabled, ignore this check. | - | This allows backwards compatibility with old versions of | - | SDK applications that didn't properly implement the size | - | field. | - \*---------------------------------------------------------*/ - if((header.pkt_size == *((unsigned int*)data)) - || ((client_info->client_protocol_version <= 4) - && (legacy_workaround_enabled))) - { - if(header.pkt_dev_idx < controllers.size()) - { - controllers[header.pkt_dev_idx]->SetColorDescription((unsigned char *)data); - controllers[header.pkt_dev_idx]->UpdateLEDs(); - } - } - else - { - LOG_ERROR("[NetworkServer] UpdateLEDs packet has invalid size. Packet size: %d, Data size: %d", header.pkt_size, *((unsigned int*)data)); - goto listen_done; - } - break; - case NET_PACKET_ID_RGBCONTROLLER_UPDATEZONELEDS: + case NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE: + case NET_PACKET_ID_RGBCONTROLLER_SAVEMODE: if(data == NULL) { break; } - /*---------------------------------------------------------*\ - | Verify the color description size (first 4 bytes of data) | - | matches the packet size in the header | - | | - | If protocol version is 4 or below and the legacy SDK | - | compatibility workaround is enabled, ignore this check. | - | This allows backwards compatibility with old versions of | - | SDK applications that didn't properly implement the size | - | field. | - \*---------------------------------------------------------*/ + /*-----------------------------------------*\ + | Verify the color description size (first | + | 4 bytes of data) matches the packet size | + | in the header | + | | + | If protocol version is 4 or below and the | + | legacy SDK compatibility workaround is | + | enabled, ignore this check. This allows | + | backwards compatibility with old versions | + | of SDK applications that didn't properly | + | implement the size field. | + \*-----------------------------------------*/ if((header.pkt_size == *((unsigned int*)data)) || ((client_info->client_protocol_version <= 4) && (legacy_workaround_enabled))) { if(header.pkt_dev_idx < controllers.size()) { - int zone; + if(controller_threads.size() < controllers.size()) + { + for(std::size_t controller_idx = controller_threads.size(); controller_idx < controllers.size(); controller_idx++) + { + NetworkServerControllerThread * new_controller_thread = new NetworkServerControllerThread; - memcpy(&zone, &data[sizeof(unsigned int)], sizeof(int)); + new_controller_thread->index = controller_idx; + new_controller_thread->online = true; + new_controller_thread->thread = new std::thread(&NetworkServer::ControllerListenThread, this, new_controller_thread); - controllers[header.pkt_dev_idx]->SetZoneColorDescription((unsigned char *)data); - controllers[header.pkt_dev_idx]->UpdateZoneLEDs(zone); + controller_threads.push_back(new_controller_thread); + } + } + + controller_threads[header.pkt_dev_idx]->queue_mutex.lock(); + NetworkServerControllerThreadQueueEntry new_entry; + new_entry.data = data; + new_entry.id = header.pkt_id; + new_entry.size = header.pkt_size; + new_entry.client_protocol_version = client_info->client_protocol_version; + controller_threads[header.pkt_dev_idx]->queue.push(new_entry); + controller_threads[header.pkt_dev_idx]->queue_mutex.unlock(); + + controller_threads[header.pkt_dev_idx]->start_cv.notify_all(); + + delete_data = false; } } else { - LOG_ERROR("[NetworkServer] UpdateZoneLEDs packet has invalid size. Packet size: %d, Data size: %d", header.pkt_size, *((unsigned int*)data)); + LOG_ERROR("[NetworkServer] RGBController packet with ID %d has invalid size. Packet size: %d, Data size: %d", header.pkt_id, header.pkt_size, *((unsigned int*)data)); goto listen_done; } break; @@ -773,10 +998,11 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) break; } - /*---------------------------------------------------------*\ - | Verify the single LED color description size (8 bytes) | - | matches the packet size in the header | - \*---------------------------------------------------------*/ + /*-----------------------------------------*\ + | Verify the single LED color description | + | size (8 bytes) matches the packet size in | + | the header | + \*-----------------------------------------*/ if(header.pkt_size == (sizeof(int) + sizeof(RGBColor))) { if(header.pkt_dev_idx < controllers.size()) @@ -803,138 +1029,6 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) } break; - case NET_PACKET_ID_RGBCONTROLLER_UPDATEMODE: - if(data == NULL) - { - break; - } - - /*---------------------------------------------------------*\ - | Verify the mode description size (first 4 bytes of data) | - | matches the packet size in the header | - | | - | If protocol version is 4 or below and the legacy SDK | - | compatibility workaround is enabled, ignore this check. | - | This allows backwards compatibility with old versions of | - | SDK applications that didn't properly implement the size | - | field. | - \*---------------------------------------------------------*/ - if((header.pkt_size == *((unsigned int*)data)) - || ((client_info->client_protocol_version <= 4) - && (legacy_workaround_enabled))) - { - if(header.pkt_dev_idx < controllers.size()) - { - controllers[header.pkt_dev_idx]->SetModeDescription((unsigned char *)data, client_info->client_protocol_version); - controllers[header.pkt_dev_idx]->UpdateMode(); - } - } - else - { - LOG_ERROR("[NetworkServer] UpdateMode packet has invalid size. Packet size: %d, Data size: %d", header.pkt_size, *((unsigned int*)data)); - goto listen_done; - } - break; - - case NET_PACKET_ID_RGBCONTROLLER_SAVEMODE: - if(data == NULL) - { - break; - } - - /*---------------------------------------------------------*\ - | Verify the mode description size (first 4 bytes of data) | - | matches the packet size in the header | - | | - | If protocol version is 4 or below and the legacy SDK | - | compatibility workaround is enabled, ignore this check. | - | This allows backwards compatibility with old versions of | - | SDK applications that didn't properly implement the size | - | field. | - \*---------------------------------------------------------*/ - if((header.pkt_size == *((unsigned int*)data)) - || ((client_info->client_protocol_version <= 4) - && (legacy_workaround_enabled))) - { - if(header.pkt_dev_idx < controllers.size()) - { - controllers[header.pkt_dev_idx]->SetModeDescription((unsigned char *)data, client_info->client_protocol_version); - controllers[header.pkt_dev_idx]->SaveMode(); - } - } - break; - - case NET_PACKET_ID_REQUEST_PROFILE_LIST: - SendReply_ProfileList(client_sock); - break; - - case NET_PACKET_ID_REQUEST_SAVE_PROFILE: - if(data == NULL) - { - break; - } - - if(profile_manager) - { - std::string profile_name; - profile_name.assign(data, header.pkt_size); - - profile_manager->SaveProfile(profile_name); - } - - break; - - case NET_PACKET_ID_REQUEST_LOAD_PROFILE: - if(data == NULL) - { - break; - } - - if(profile_manager) - { - std::string profile_name; - profile_name.assign(data, header.pkt_size); - - profile_manager->LoadProfile(profile_name); - } - - break; - - case NET_PACKET_ID_REQUEST_DELETE_PROFILE: - if(data == NULL) - { - break; - } - - if(profile_manager) - { - std::string profile_name; - profile_name.assign(data, header.pkt_size); - - profile_manager->DeleteProfile(profile_name); - } - - break; - - case NET_PACKET_ID_REQUEST_PLUGIN_LIST: - SendReply_PluginList(client_sock); - break; - - case NET_PACKET_ID_PLUGIN_SPECIFIC: - if(plugin_manager) - { - unsigned int plugin_pkt_id = *((unsigned int*)(data)); - unsigned int plugin_pkt_size = header.pkt_size - (sizeof(unsigned int)); - unsigned char* plugin_data = (unsigned char*)(data + sizeof(unsigned int)); - unsigned char* output = plugin_manager->OnSDKCommand(header.pkt_dev_idx, plugin_pkt_id, plugin_data, &plugin_pkt_size); - - if(output != nullptr) - { - SendReply_PluginSpecific(client_sock, plugin_pkt_id, output, plugin_pkt_size); - } - } - break; - case NET_PACKET_ID_RGBCONTROLLER_CLEARSEGMENTS: if(data == NULL) { @@ -954,10 +1048,11 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) case NET_PACKET_ID_RGBCONTROLLER_ADDSEGMENT: { - /*---------------------------------------------------------*\ - | Verify the segment description size (first 4 bytes of | - | data) matches the packet size in the header | - \*---------------------------------------------------------*/ + /*-------------------------------------*\ + | Verify the segment description size | + | (first 4 bytes of data) matches the | + | packet size in the header | + \*-------------------------------------*/ if(header.pkt_size == *((unsigned int*)data)) { if(header.pkt_dev_idx < controllers.size()) @@ -970,7 +1065,10 @@ void NetworkServer::ListenThreadFunction(NetworkClientInfo * client_info) break; } - delete[] data; + if(delete_data) + { + delete[] data; + } } listen_done: @@ -991,12 +1089,15 @@ listen_done: ServerClientsMutex.unlock(); - /*---------------------------------------------------------*\ - | Client info has changed, call the callbacks | - \*---------------------------------------------------------*/ + /*-----------------------------------------------------*\ + | Client info has changed, call the callbacks | + \*-----------------------------------------------------*/ ClientInfoChanged(); } +/*---------------------------------------------------------*\ +| Server Protocol functions | +\*---------------------------------------------------------*/ void NetworkServer::ProcessRequest_ClientProtocolVersion(SOCKET client_sock, unsigned int data_size, char * data) { unsigned int protocol_version = 0; @@ -1039,6 +1140,7 @@ void NetworkServer::ProcessRequest_ClientString(SOCKET client_sock, unsigned int break; } } + ServerClientsMutex.unlock(); /*---------------------------------------------------------*\ @@ -1103,6 +1205,33 @@ void NetworkServer::SendReply_ProtocolVersion(SOCKET client_sock) send_in_progress.unlock(); } +void NetworkServer::SendReply_ServerString(SOCKET client_sock) +{ + /*---------------------------------------------------------*\ + | Send server string to client only if protocol is 5 or | + | greater | + \*---------------------------------------------------------*/ + ServerClientsMutex.lock(); + for(unsigned int this_idx = 0; this_idx < ServerClients.size(); this_idx++) + { + if(ServerClients[this_idx]->client_sock == client_sock) + { + if(ServerClients[this_idx]->client_protocol_version >= 5) + { + NetPacketHeader reply_hdr; + + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_SET_SERVER_NAME, (unsigned int)strlen(server_name.c_str()) + 1); + + send_in_progress.lock(); + send(client_sock, (char *)&reply_hdr, sizeof(NetPacketHeader), MSG_NOSIGNAL); + send(client_sock, (char *)server_name.c_str(), reply_hdr.pkt_size, MSG_NOSIGNAL); + send_in_progress.unlock(); + } + } + } + ServerClientsMutex.unlock(); +} + void NetworkServer::SendRequest_DeviceListChanged(SOCKET client_sock) { NetPacketHeader pkt_hdr; @@ -1127,7 +1256,7 @@ void NetworkServer::SendReply_ProfileList(SOCKET client_sock) memcpy(&reply_size, reply_data, sizeof(reply_size)); - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_PROFILE_LIST, reply_size); + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PROFILEMANAGER_GET_PROFILE_LIST, reply_size); send_in_progress.lock(); send(client_sock, (const char *)&reply_hdr, sizeof(NetPacketHeader), 0); @@ -1228,7 +1357,7 @@ void NetworkServer::SendReply_PluginList(SOCKET client_sock) memcpy(&reply_size, data_buf, sizeof(reply_size)); - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_REQUEST_PLUGIN_LIST, reply_size); + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PLUGINMANAGER_GET_PLUGIN_LIST, reply_size); send_in_progress.lock(); send(client_sock, (const char *)&reply_hdr, sizeof(NetPacketHeader), 0); @@ -1242,7 +1371,7 @@ void NetworkServer::SendReply_PluginSpecific(SOCKET client_sock, unsigned int pk { NetPacketHeader reply_hdr; - InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PLUGIN_SPECIFIC, data_size + sizeof(pkt_id)); + InitNetPacketHeader(&reply_hdr, 0, NET_PACKET_ID_PLUGINMANAGER_PLUGIN_SPECIFIC, data_size + sizeof(pkt_id)); send_in_progress.lock(); send(client_sock, (const char *)&reply_hdr, sizeof(NetPacketHeader), 0); @@ -1253,12 +1382,65 @@ void NetworkServer::SendReply_PluginSpecific(SOCKET client_sock, unsigned int pk delete [] data; } -void NetworkServer::SetPluginManager(PluginManagerInterface* plugin_manager_pointer) +/*---------------------------------------------------------*\ +| Private helper functions | +\*---------------------------------------------------------*/ +int NetworkServer::accept_select(int sockfd) { - plugin_manager = plugin_manager_pointer; + fd_set set; + struct timeval timeout; + + while(1) + { + timeout.tv_sec = TCP_TIMEOUT_SECONDS; + timeout.tv_usec = 0; + + FD_ZERO(&set); + FD_SET(sockfd, &set); + + int rv = select(sockfd + 1, &set, NULL, NULL, &timeout); + + if(rv == SOCKET_ERROR || server_online == false) + { + return -1; + } + else if(rv == 0) + { + continue; + } + else + { + return(accept((int)sockfd, NULL, NULL)); + } + } } -void NetworkServer::SetProfileManager(ProfileManagerInterface* profile_manager_pointer) +int NetworkServer::recv_select(SOCKET s, char *buf, int len, int flags) { - profile_manager = profile_manager_pointer; + fd_set set; + struct timeval timeout; + + while(1) + { + timeout.tv_sec = TCP_TIMEOUT_SECONDS; + timeout.tv_usec = 0; + + FD_ZERO(&set); + FD_SET(s, &set); + + int rv = select((int)s + 1, &set, NULL, NULL, &timeout); + + if(rv == SOCKET_ERROR || server_online == false) + { + return 0; + } + else if(rv == 0) + { + continue; + } + else + { + return(recv(s, buf, len, flags)); + } + } } diff --git a/NetworkServer.h b/NetworkServer.h index 96eff12d2..6814fce06 100644 --- a/NetworkServer.h +++ b/NetworkServer.h @@ -11,21 +11,44 @@ #pragma once +#include +#include +#include #include #include -#include +#include #include "RGBController.h" #include "NetworkProtocol.h" #include "net_port.h" #include "PluginManagerInterface.h" #include "ProfileManager.h" #include "ResourceManager.h" +#include "SettingsManager.h" #define MAXSOCK 32 #define TCP_TIMEOUT_SECONDS 5 typedef void (*NetServerCallback)(void *); +typedef struct +{ + char * data; + unsigned int id; + unsigned int size; + unsigned int client_protocol_version; +} NetworkServerControllerThreadQueueEntry; + +typedef struct +{ + unsigned int index; + std::queue queue; + std::mutex queue_mutex; + std::mutex start_mutex; + std::condition_variable start_cv; + std::thread * thread; + std::atomic online; +} NetworkServerControllerThread; + class NetworkClientInfo { public: @@ -45,6 +68,9 @@ public: NetworkServer(std::vector& control); ~NetworkServer(); + /*-----------------------------------------------------*\ + | Server Information functions | + \*-----------------------------------------------------*/ std::string GetHost(); unsigned short GetPort(); bool GetOnline(); @@ -54,23 +80,106 @@ public: const char * GetClientIP(unsigned int client_num); unsigned int GetClientProtocolVersion(unsigned int client_num); - void ClientInfoChanged(); + /*-----------------------------------------------------*\ + | Callback functions | + \*-----------------------------------------------------*/ void DeviceListChanged(); void RegisterClientInfoChangeCallback(NetServerCallback, void * new_callback_arg); - - void ServerListeningChanged(); void RegisterServerListeningChangeCallback(NetServerCallback, void * new_callback_arg); + /*-----------------------------------------------------*\ + | Server Configuration functions | + \*-----------------------------------------------------*/ void SetHost(std::string host); void SetLegacyWorkaroundEnable(bool enable); + void SetName(std::string new_name); void SetPort(unsigned short new_port); + /*-----------------------------------------------------*\ + | Server Control functions | + \*-----------------------------------------------------*/ void StartServer(); void StopServer(); + /*-----------------------------------------------------*\ + | Server Interface functions | + \*-----------------------------------------------------*/ + void SetPluginManager(PluginManagerInterface* plugin_manager_pointer); + void SetProfileManager(ProfileManagerInterface* profile_manager_pointer); + void SetSettingsManager(SettingsManagerInterface* settings_manager_pointer); + +private: + /*-----------------------------------------------------*\ + | Server variables | + \*-----------------------------------------------------*/ + std::string host; + bool legacy_workaround_enabled; + unsigned short port_num; + std::mutex send_in_progress; + std::string server_name; + std::atomic server_online; + std::atomic server_listening; + SOCKET server_sock[MAXSOCK]; + int socket_count; + + /*-----------------------------------------------------*\ + | Server controller list | + \*-----------------------------------------------------*/ + std::vector& controllers; + std::vector controller_threads; + + /*-----------------------------------------------------*\ + | Server clients | + \*-----------------------------------------------------*/ + std::mutex ServerClientsMutex; + std::vector ServerClients; + std::thread * ConnectionThread[MAXSOCK]; + + /*-----------------------------------------------------*\ + | Client information change callbacks | + \*-----------------------------------------------------*/ + std::mutex ClientInfoChangeMutex; + std::vector ClientInfoChangeCallbacks; + std::vector ClientInfoChangeCallbackArgs; + + /*-----------------------------------------------------*\ + | Server listening change callbacks | + \*-----------------------------------------------------*/ + std::mutex ServerListeningChangeMutex; + std::vector ServerListeningChangeCallbacks; + std::vector ServerListeningChangeCallbackArgs; + + /*-----------------------------------------------------*\ + | Pointers to components that integrate with server | + \*-----------------------------------------------------*/ + PluginManagerInterface* plugin_manager; + ProfileManagerInterface* profile_manager; + SettingsManagerInterface* settings_manager; + +private: +#ifdef WIN32 + /*-----------------------------------------------------*\ + | Windows-specific WSA data | + \*-----------------------------------------------------*/ + WSADATA wsa; +#endif + + /*-----------------------------------------------------*\ + | Server callback signal functions | + \*-----------------------------------------------------*/ + void ClientInfoChanged(); + void ServerListeningChanged(); + + /*-----------------------------------------------------*\ + | Server Thread functions | + \*-----------------------------------------------------*/ void ConnectionThreadFunction(int socket_idx); + void ControllerListenThread(NetworkServerControllerThread * this_thread); void ListenThreadFunction(NetworkClientInfo * client_sock); + /*-----------------------------------------------------*\ + | Server Protocol functions | + \*-----------------------------------------------------*/ void ProcessRequest_ClientProtocolVersion(SOCKET client_sock, unsigned int data_size, char * data); void ProcessRequest_ClientString(SOCKET client_sock, unsigned int data_size, char * data); void ProcessRequest_RescanDevices(); @@ -78,49 +187,16 @@ public: void SendReply_ControllerCount(SOCKET client_sock); void SendReply_ControllerData(SOCKET client_sock, unsigned int dev_idx, unsigned int protocol_version); void SendReply_ProtocolVersion(SOCKET client_sock); + void SendReply_ServerString(SOCKET client_sock); void SendRequest_DeviceListChanged(SOCKET client_sock); void SendReply_ProfileList(SOCKET client_sock); void SendReply_PluginList(SOCKET client_sock); void SendReply_PluginSpecific(SOCKET client_sock, unsigned int pkt_type, unsigned char* data, unsigned int data_size); - void SetPluginManager(PluginManagerInterface* plugin_manager_pointer); - void SetProfileManager(ProfileManagerInterface* profile_manager_pointer); - -protected: - std::string host; - unsigned short port_num; - std::atomic server_online; - std::atomic server_listening; - - std::vector& controllers; - - std::mutex ServerClientsMutex; - std::vector ServerClients; - std::thread * ConnectionThread[MAXSOCK]; - - std::mutex ClientInfoChangeMutex; - std::vector ClientInfoChangeCallbacks; - std::vector ClientInfoChangeCallbackArgs; - - std::mutex ServerListeningChangeMutex; - std::vector ServerListeningChangeCallbacks; - std::vector ServerListeningChangeCallbackArgs; - - PluginManagerInterface* plugin_manager; - ProfileManagerInterface* profile_manager; - - std::mutex send_in_progress; - -private: -#ifdef WIN32 - WSADATA wsa; -#endif - - bool legacy_workaround_enabled; - int socket_count; - SOCKET server_sock[MAXSOCK]; - - int accept_select(int sockfd); - int recv_select(SOCKET s, char *buf, int len, int flags); + /*-----------------------------------------------------*\ + | Private helper functions | + \*-----------------------------------------------------*/ + int accept_select(int sockfd); + int recv_select(SOCKET s, char *buf, int len, int flags); }; diff --git a/ProfileManager.cpp b/ProfileManager.cpp index 772bbfd22..8eb5f0dd0 100644 --- a/ProfileManager.cpp +++ b/ProfileManager.cpp @@ -97,12 +97,22 @@ ProfileManager::~ProfileManager() void ProfileManager::DeleteProfile(std::string profile_name) { + /*-----------------------------------------------------*\ + | Clean up the profile name | + \*-----------------------------------------------------*/ profile_name = StringUtils::remove_null_terminating_chars(profile_name); - filesystem::path filename = profile_directory / profile_name; - filename.concat(".json"); + if(ResourceManager::get()->IsLocalClient()) + { + ResourceManager::get()->GetLocalClient()->ProfileManager_DeleteProfile(profile_name); + } + else + { + filesystem::path filename = profile_directory / profile_name; + filename.concat(".json"); - filesystem::remove(filename); + filesystem::remove(filename); + } UpdateProfileList(); } @@ -230,22 +240,31 @@ bool ProfileManager::LoadProfile(std::string profile_name) nlohmann::json ProfileManager::ReadProfileJSON(std::string profile_name) { + nlohmann::json profile_json; + /*-----------------------------------------------------*\ | Clean up the profile name | \*-----------------------------------------------------*/ profile_name = StringUtils::remove_null_terminating_chars(profile_name); - /*-----------------------------------------------------*\ - | File extension for v6+ profiles is .json | - \*-----------------------------------------------------*/ - profile_name += ".json"; + if(ResourceManager::get()->IsLocalClient()) + { + profile_json = nlohmann::json::parse(ResourceManager::get()->GetLocalClient()->ProfileManager_DownloadProfile(profile_name)); + } + else + { + /*-------------------------------------------------*\ + | File extension for v6+ profiles is .json | + \*-------------------------------------------------*/ + profile_name += ".json"; - /*-----------------------------------------------------*\ - | Read the profile JSON from the file | - \*-----------------------------------------------------*/ - filesystem::path profile_path = profile_directory / filesystem::u8path(profile_name); + /*-------------------------------------------------*\ + | Read the profile JSON from the file | + \*-------------------------------------------------*/ + filesystem::path profile_path = profile_directory / filesystem::u8path(profile_name); - nlohmann::json profile_json = ReadProfileFileJSON(profile_path); + profile_json = ReadProfileFileJSON(profile_path); + } return(profile_json); } @@ -299,15 +318,25 @@ bool ProfileManager::SaveProfile(std::string profile_name) profile_json["plugins"] = plugin_manager->OnProfileSave(); } - /*-------------------------------------------------*\ - | Save the profile to file from the JSON | - \*-------------------------------------------------*/ - SaveProfileFromJSON(profile_json); + if(ResourceManager::get()->IsLocalClient()) + { + /*---------------------------------------------*\ + | Upload the profile to the server | + \*---------------------------------------------*/ + ResourceManager::get()->GetLocalClient()->ProfileManager_UploadProfile(profile_json.dump()); - /*-------------------------------------------------*\ - | Update the profile list | - \*-------------------------------------------------*/ - UpdateProfileList(); + /*---------------------------------------------*\ + | Update the profile list | + \*---------------------------------------------*/ + UpdateProfileList(); + } + else + { + /*---------------------------------------------*\ + | Save the profile to file from the JSON | + \*---------------------------------------------*/ + SaveProfileFromJSON(profile_json); + } return(true); } @@ -341,6 +370,11 @@ bool ProfileManager::SaveProfileFromJSON(nlohmann::json profile_json) \*-------------------------------------------------*/ profile_file.close(); + /*-------------------------------------------------*\ + | Update the profile list | + \*-------------------------------------------------*/ + UpdateProfileList(); + return(true); } else @@ -447,29 +481,42 @@ void ProfileManager::UpdateProfileList() { profile_list.clear(); - /*-----------------------------------------------------*\ - | Load profiles by looking for .json files in profile | - | directory | - \*-----------------------------------------------------*/ - for(const filesystem::directory_entry &entry : filesystem::directory_iterator(profile_directory)) + if(ResourceManager::get()->IsLocalClient()) { - std::string filename = entry.path().filename().string(); + char * profile_data = ResourceManager::get()->GetLocalClient()->ProfileManager_GetProfileList(); - if(filename.find(".json") != std::string::npos) + if(profile_data != NULL) { - LOG_INFO("[ProfileManager] Found file: %s attempting to validate header", filename.c_str()); + SetProfileListFromDescription(profile_data); + delete[] profile_data; + } + } + else + { + /*-------------------------------------------------*\ + | Load profiles by looking for .json files in | + | profile directory | + \*-------------------------------------------------*/ + for(const filesystem::directory_entry &entry : filesystem::directory_iterator(profile_directory)) + { + std::string filename = entry.path().filename().string(); - /*---------------------------------------------*\ - | Open input file in binary mode | - \*---------------------------------------------*/ - filesystem::path file_path = profile_directory; - file_path.append(filename); - - nlohmann::json profile_json = ReadProfileFileJSON(file_path); - - if(!profile_json.empty()) + if(filename.find(".json") != std::string::npos) { - profile_list.push_back(filename.erase(filename.length() - 5)); + LOG_INFO("[ProfileManager] Found file: %s attempting to validate header", filename.c_str()); + + /*-----------------------------------------*\ + | Open input file in binary mode | + \*-----------------------------------------*/ + filesystem::path file_path = profile_directory; + file_path.append(filename); + + nlohmann::json profile_json = ReadProfileFileJSON(file_path); + + if(!profile_json.empty()) + { + profile_list.push_back(filename.erase(filename.length() - 5)); + } } } } diff --git a/ResourceManager.cpp b/ResourceManager.cpp index f2b09e3ed..e1626cb0b 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -194,6 +194,15 @@ ResourceManager::ResourceManager() server = new NetworkServer(rgb_controllers_hw); } + /*-----------------------------------------------------*\ + | Set server name | + \*-----------------------------------------------------*/ + std::string titleString = "OpenRGB "; + titleString.append(VERSION_STRING); + + server->SetName(titleString); + server->SetSettingsManager(settings_manager); + /*-----------------------------------------------------*\ | Enable legacy SDK workaround in server if configured | \*-----------------------------------------------------*/ @@ -1797,6 +1806,7 @@ void ResourceManager::InitCoroutine() | detection if the local server was connected | \*---------------------------------------------*/ auto_connection_active = true; + profile_manager->UpdateProfileList(); DisableDetection(); } @@ -2123,3 +2133,13 @@ bool ResourceManager::IsAnyDimmDetectorEnabled(json &detector_settings) } return false; } + +bool ResourceManager::IsLocalClient() +{ + return(auto_connection_active); +} + +NetworkClient* ResourceManager::GetLocalClient() +{ + return(auto_connection_client); +} diff --git a/ResourceManager.h b/ResourceManager.h index 208e1b5d4..43b5cbf04 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -199,6 +199,9 @@ public: void WaitForInitialization(); void WaitForDeviceDetection(); + bool IsLocalClient(); + NetworkClient* GetLocalClient(); + private: void UpdateDetectorSettings(); void SetupConfigurationDirectory(); diff --git a/SettingsManager.cpp b/SettingsManager.cpp index 640302b95..ba086618e 100644 --- a/SettingsManager.cpp +++ b/SettingsManager.cpp @@ -13,8 +13,22 @@ #include #include -#include "SettingsManager.h" #include "LogManager.h" +#include "NetworkClient.h" +#include "ResourceManager.h" +#include "SettingsManager.h" +#include "StringUtils.h" + +static const std::string ui_settings_keys[7] = +{ + "UserInterface", + "AutoStart", + "Theme", + "Plugins", + "Client", + "LogManager", + "Server" +}; SettingsManager::SettingsManager() { @@ -28,31 +42,113 @@ SettingsManager::~SettingsManager() json SettingsManager::GetSettings(std::string settings_key) { - /*-----------------------------------------------------*\ - | Check to see if the key exists in the settings store | - | and return the settings associated with the key if it | - | exists. We lock the mutex to protect the value from | - | changing while data is being read and copy before | - | unlocking. | - \*-----------------------------------------------------*/ json result; + bool ui_settings_key = false; - mutex.lock(); - if(settings_data.contains(settings_key)) + /*-----------------------------------------------------*\ + | Remove any excess null termination from settings key | + \*-----------------------------------------------------*/ + settings_key = StringUtils::remove_null_terminating_chars(settings_key); + + for(std::size_t settings_key_idx = 0; settings_key_idx < 7; settings_key_idx++) { - result = settings_data[settings_key]; + if(settings_key == ui_settings_keys[settings_key_idx]) + { + ui_settings_key = true; + break; + } } - mutex.unlock(); + if(!ui_settings_key && ResourceManager::get()->IsLocalClient()) + { + /*-------------------------------------------------*\ + | If this is a local client, request the settings | + | from the server | + \*-------------------------------------------------*/ + try + { + result = nlohmann::json::parse(ResourceManager::get()->GetLocalClient()->SettingsManager_GetSettings(settings_key)); + } + catch(...) + { + + } + } + else + { + /*-------------------------------------------------*\ + | Check to see if the key exists in the settings | + | store and return the settings associated with the | + | key if it exists. We lock the mutex to protect | + | the value from changing while data is being read | + | and copy before unlocking. | + \*-------------------------------------------------*/ + mutex.lock(); + if(settings_data.contains(settings_key)) + { + result = settings_data[settings_key]; + } + mutex.unlock(); + } return result; } void SettingsManager::SetSettings(std::string settings_key, json new_settings) { - mutex.lock(); - settings_data[settings_key] = new_settings; - mutex.unlock(); + bool ui_settings_key = false; + + /*-----------------------------------------------------*\ + | Remove any excess null termination from settings key | + \*-----------------------------------------------------*/ + settings_key = StringUtils::remove_null_terminating_chars(settings_key); + + for(std::size_t settings_key_idx = 0; settings_key_idx < 7; settings_key_idx++) + { + if(settings_key == ui_settings_keys[settings_key_idx]) + { + ui_settings_key = true; + break; + } + } + + if(!ui_settings_key && ResourceManager::get()->IsLocalClient()) + { + /*-------------------------------------------------*\ + | If this is a local client, request the settings | + | from the server | + \*-------------------------------------------------*/ + nlohmann::json settings_json; + + settings_json[settings_key] = new_settings; + + ResourceManager::get()->GetLocalClient()->SettingsManager_SetSettings(settings_json.dump()); + } + else + { + mutex.lock(); + settings_data[settings_key] = new_settings; + mutex.unlock(); + } +} + +void SettingsManager::SetSettingsFromJsonString(std::string settings_json_str) +{ + /*-----------------------------------------------------*\ + | Parse the JSON string | + \*-----------------------------------------------------*/ + nlohmann::json settings_json = nlohmann::json::parse(settings_json_str); + + /*-----------------------------------------------------*\ + | Get key/value pairs from JSON, call SetSettings for | + | each key. This use of `auto` is acceptable due to | + | how the JSON library implements iterators, the type | + | would change based on the library version. | + \*-----------------------------------------------------*/ + for(auto& element : settings_json.items()) + { + SetSettings(element.key(), element.value()); + } } void SettingsManager::LoadSettings(const filesystem::path& filename) @@ -109,6 +205,15 @@ void SettingsManager::LoadSettings(const filesystem::path& filename) void SettingsManager::SaveSettings() { + if(ResourceManager::get()->IsLocalClient()) + { + /*-------------------------------------------------*\ + | If this is a local client, save the settings on | + | the server | + \*-------------------------------------------------*/ + ResourceManager::get()->GetLocalClient()->SettingsManager_SaveSettings(); + } + mutex.lock(); std::ofstream settings_file(settings_filename, std::ios::out | std::ios::binary); diff --git a/SettingsManager.h b/SettingsManager.h index 0f4b991f7..db48af344 100644 --- a/SettingsManager.h +++ b/SettingsManager.h @@ -24,6 +24,7 @@ class SettingsManagerInterface public: virtual json GetSettings(std::string settings_key) = 0; virtual void SetSettings(std::string settings_key, json new_settings) = 0; + virtual void SetSettingsFromJsonString(std::string settings_json_str) = 0; virtual void LoadSettings(const filesystem::path& filename) = 0; virtual void SaveSettings() = 0; @@ -40,6 +41,7 @@ public: json GetSettings(std::string settings_key) override; void SetSettings(std::string settings_key, json new_settings) override; + void SetSettingsFromJsonString(std::string settings_json_str) override; void LoadSettings(const filesystem::path& filename) override; void SaveSettings() override; diff --git a/qt/OpenRGBClientInfoPage/OpenRGBClientInfoPage.cpp b/qt/OpenRGBClientInfoPage/OpenRGBClientInfoPage.cpp index c7a45940e..2ad42176e 100644 --- a/qt/OpenRGBClientInfoPage/OpenRGBClientInfoPage.cpp +++ b/qt/OpenRGBClientInfoPage/OpenRGBClientInfoPage.cpp @@ -131,11 +131,29 @@ void OpenRGBClientInfoPage::UpdateInfo() } /*-----------------------------------------------------*\ - | Create the top level tree widget items and display the| - | client IP addresses and protocol versions in them | + | Create the top level tree widget items | \*-----------------------------------------------------*/ QTreeWidgetItem* new_top_item = new QTreeWidgetItem(ui->ClientTree); - new_top_item->setText(0, QString::fromStdString(ResourceManager::get()->GetClients()[client_idx]->GetIP())); + + /*-----------------------------------------------------*\ + | First column, display the server IP and optionally | + | the server name if it exists | + \*-----------------------------------------------------*/ + std::string server_name = ResourceManager::get()->GetClients()[client_idx]->GetServerName(); + std::string ip = ResourceManager::get()->GetClients()[client_idx]->GetIP(); + + if(server_name == "") + { + new_top_item->setText(0, QString::fromStdString(ip)); + } + else + { + new_top_item->setText(0, QString::fromStdString(ip + ": " + server_name)); + } + + /*-----------------------------------------------------*\ + | Second column, display the protocol version | + \*-----------------------------------------------------*/ new_top_item->setText(1, QString::number(ResourceManager::get()->GetClients()[client_idx]->GetProtocolVersion())); /*-----------------------------------------------------*\ diff --git a/startup/startup.cpp b/startup/startup.cpp index 46f48af50..000d2c14a 100644 --- a/startup/startup.cpp +++ b/startup/startup.cpp @@ -52,6 +52,12 @@ int startup(int argc, char* argv[], unsigned int ret_flags) \*-----------------------------------------------------*/ int exitval = EXIT_SUCCESS; + /*-----------------------------------------------------*\ + | Before opening GUI, wait for automatic connection so | + | that settings and profiles can be updated from server | + \*-----------------------------------------------------*/ + ResourceManager::get()->WaitForInitialization(); + /*-----------------------------------------------------*\ | If the command line parser indicates that the GUI | | should run, or if there were no command line |