mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-07-08 04:14:50 -04:00
1165 lines
42 KiB
C++
1165 lines
42 KiB
C++
/*---------------------------------------------------------*\
|
|
| ResourceManager.cpp |
|
|
| |
|
|
| OpenRGB Resource Manager controls access to application |
|
|
| components including RGBControllers, I2C interfaces, |
|
|
| and network SDK components |
|
|
| |
|
|
| Adam Honse (CalcProgrammer1) 27 Sep 2020 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#ifdef _WIN32
|
|
#include <codecvt>
|
|
#include <locale>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include "cli.h"
|
|
#include "DetectionManager.h"
|
|
#include "ResourceManager.h"
|
|
#include "ProfileManager.h"
|
|
#include "LogManager.h"
|
|
#include "serial_port.h"
|
|
#include "SettingsManager.h"
|
|
#include "StringUtils.h"
|
|
#include "NetworkClient.h"
|
|
#include "NetworkServer.h"
|
|
#include "filesystem.h"
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Put these last to avoid some include order issues |
|
|
\*---------------------------------------------------------*/
|
|
#include <hidapi.h>
|
|
#include <libusb.h>
|
|
|
|
#ifdef __linux__
|
|
#include <sys/resource.h>
|
|
#endif
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
/*---------------------------------------------------------*\
|
|
| ResourceManager Callback Functions |
|
|
\*---------------------------------------------------------*/
|
|
static void ResourceManagerDetectionCallback(void * this_ptr, unsigned int update_reason)
|
|
{
|
|
ResourceManager* this_obj = (ResourceManager *)this_ptr;
|
|
|
|
switch(update_reason)
|
|
{
|
|
case DETECTIONMANAGER_UPDATE_REASON_I2C_BUS_REGISTERED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_I2C_BUS_LIST_UPDATED);
|
|
break;
|
|
|
|
case DETECTIONMANAGER_UPDATE_REASON_DETECTION_STARTED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_STARTED);
|
|
break;
|
|
|
|
case DETECTIONMANAGER_UPDATE_REASON_RGBCONTROLLER_REGISTERED:
|
|
case DETECTIONMANAGER_UPDATE_REASON_RGBCONTROLLER_UNREGISTERED:
|
|
case DETECTIONMANAGER_UPDATE_REASON_RGBCONTROLLER_LIST_CLEARED:
|
|
this_obj->UpdateDeviceList();
|
|
break;
|
|
|
|
case DETECTIONMANAGER_UPDATE_REASON_DETECTION_PROGRESS_CHANGED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_PROGRESS_CHANGED);
|
|
break;
|
|
|
|
case DETECTIONMANAGER_UPDATE_REASON_DETECTION_COMPLETE:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_COMPLETE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ResourceManagerNetworkClientCallback(void* this_ptr, unsigned int update_reason)
|
|
{
|
|
ResourceManager* this_obj = (ResourceManager*)this_ptr;
|
|
|
|
switch(update_reason)
|
|
{
|
|
case NETWORKCLIENT_UPDATE_REASON_DEVICE_LIST_UPDATED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_CLIENT_INFO_UPDATED);
|
|
this_obj->UpdateDeviceList();
|
|
break;
|
|
|
|
case NETWORKCLIENT_UPDATE_REASON_DETECTION_STARTED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_STARTED);
|
|
break;
|
|
|
|
case NETWORKCLIENT_UPDATE_REASON_DETECTION_PROGRESS_CHANGED:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_PROGRESS_CHANGED);
|
|
break;
|
|
|
|
case NETWORKCLIENT_UPDATE_REASON_DETECTION_COMPLETE:
|
|
this_obj->SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DETECTION_COMPLETE);
|
|
break;
|
|
|
|
case NETWORKCLIENT_UPDATE_REASON_PROFILEMANAGER_PROFILE_LIST_UPDATED:
|
|
this_obj->GetProfileManager()->SignalProfileManagerUpdate(PROFILEMANAGER_UPDATE_REASON_PROFILE_LIST_UPDATED);
|
|
break;
|
|
|
|
case NETWORKCLIENT_UPDATE_REASON_PROFILEMANAGER_ACTIVE_PROFILE_CHANGED:
|
|
this_obj->GetProfileManager()->SignalProfileManagerUpdate(PROFILEMANAGER_UPDATE_REASON_ACTIVE_PROFILE_CHANGED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| ResourceManager name for log entries |
|
|
\*---------------------------------------------------------*/
|
|
const char* RESOURCEMANAGER = "ResourceManager";
|
|
|
|
/*---------------------------------------------------------*\
|
|
| ResourceManager Global Instance Pointer |
|
|
\*---------------------------------------------------------*/
|
|
ResourceManager* ResourceManager::instance;
|
|
|
|
ResourceManager::ResourceManager()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Initialize global instance pointer the when created |
|
|
| There should only ever be one instance of |
|
|
| ResourceManager |
|
|
\*-----------------------------------------------------*/
|
|
if(!instance)
|
|
{
|
|
instance = this;
|
|
}
|
|
/*-----------------------------------------------------*\
|
|
| If, for whatever reason, ResourceManager already |
|
|
| exists, delete this instance as only one should exist |
|
|
\*-----------------------------------------------------*/
|
|
else
|
|
{
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Initialize Detection Variables |
|
|
\*-----------------------------------------------------*/
|
|
auto_connection_client = NULL;
|
|
auto_connection_active = false;
|
|
default_server_host = "";
|
|
default_server_port = 0;
|
|
detection_enabled = true;
|
|
init_finished = false;
|
|
plugin_manager = NULL;
|
|
server = NULL;
|
|
|
|
SetupConfigurationDirectory();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Load settings from file |
|
|
\*-----------------------------------------------------*/
|
|
settings_manager = new SettingsManager();
|
|
|
|
settings_manager->LoadSettings(GetConfigurationDirectory() / "OpenRGB.json");
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Create Detection settings schema |
|
|
\*-----------------------------------------------------*/
|
|
json detection_settings_schema;
|
|
|
|
detection_settings_schema["hid_safe_mode"]["title"] = QT_TRANSLATE_NOOP("Settings", "HID Safe Mode");
|
|
detection_settings_schema["hid_safe_mode"]["type"] = "bool";
|
|
detection_settings_schema["hid_safe_mode"]["description"] = QT_TRANSLATE_NOOP("Settings", "Use an alternate method for detecting HID devices");
|
|
|
|
detection_settings_schema["initial_detection_delay_ms"]["title"] = QT_TRANSLATE_NOOP("Settings", "Initial Detection Delay (ms)");
|
|
detection_settings_schema["initial_detection_delay_ms"]["type"] = "integer";
|
|
detection_settings_schema["initial_detection_delay_ms"]["description"] = QT_TRANSLATE_NOOP("Settings", "Amount of time, in milliseconds, to wait before detecting devices when started");
|
|
|
|
settings_manager->RegisterSettingsSchema("Detectors", QT_TRANSLATE_NOOP("Settings", "Detection"), detection_settings_schema);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Create LogManager settings schema |
|
|
\*-----------------------------------------------------*/
|
|
json logmanager_settings_schema;
|
|
|
|
logmanager_settings_schema["log_console"]["title"] = QT_TRANSLATE_NOOP("Settings", "Enable Log Console");
|
|
logmanager_settings_schema["log_console"]["type"] = "bool";
|
|
|
|
logmanager_settings_schema["log_file"]["title"] = QT_TRANSLATE_NOOP("Settings", "Enable Log File");
|
|
logmanager_settings_schema["log_file"]["type"] = "bool";
|
|
logmanager_settings_schema["log_file"]["default"] = true;
|
|
|
|
logmanager_settings_schema["loglevel"]["title"] = QT_TRANSLATE_NOOP("Settings", "Log Level");
|
|
logmanager_settings_schema["loglevel"]["type"] = "integer";
|
|
logmanager_settings_schema["loglevel"]["default"] = 3;
|
|
logmanager_settings_schema["loglevel"]["enum"][0] = 0;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][0] = "Fatal";
|
|
logmanager_settings_schema["loglevel"]["enum"][1] = 1;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][1] = "Error";
|
|
logmanager_settings_schema["loglevel"]["enum"][2] = 2;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][2] = "Warning";
|
|
logmanager_settings_schema["loglevel"]["enum"][3] = 3;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][3] = "Info";
|
|
logmanager_settings_schema["loglevel"]["enum"][4] = 4;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][4] = "Verbose";
|
|
logmanager_settings_schema["loglevel"]["enum"][5] = 5;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][5] = "Debug";
|
|
logmanager_settings_schema["loglevel"]["enum"][6] = 6;
|
|
logmanager_settings_schema["loglevel"]["enumNames"][6] = "Trace";
|
|
|
|
logmanager_settings_schema["file_count_limit"]["title"] = QT_TRANSLATE_NOOP("Settings", "Log File Count Limit");
|
|
logmanager_settings_schema["file_count_limit"]["type"] = "integer";
|
|
logmanager_settings_schema["file_count_limit"]["description"] = QT_TRANSLATE_NOOP("Settings", "Maximum number of log files to keep, 0 for no limit");
|
|
logmanager_settings_schema["file_count_limit"]["default"] = 10;
|
|
logmanager_settings_schema["file_count_limit"]["minimum"] = 0;
|
|
|
|
settings_manager->RegisterSettingsSchema("LogManager", QT_TRANSLATE_NOOP("Settings", "Log Manager"), logmanager_settings_schema);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Create Server settings schema |
|
|
\*-----------------------------------------------------*/
|
|
json server_settings_schema;
|
|
|
|
server_settings_schema["all_controllers"]["title"] = QT_TRANSLATE_NOOP("Settings", "Serve All Controllers");
|
|
server_settings_schema["all_controllers"]["type"] = "bool";
|
|
server_settings_schema["all_controllers"]["description"] = QT_TRANSLATE_NOOP("Settings", "Include controllers provided by client connections and plugins");
|
|
|
|
server_settings_schema["default_host"]["title"] = QT_TRANSLATE_NOOP("Settings", "Default Host");
|
|
server_settings_schema["default_host"]["type"] = "string";
|
|
server_settings_schema["default_host"]["default"] = OPENRGB_SDK_HOST;
|
|
|
|
server_settings_schema["default_port"]["title"] = QT_TRANSLATE_NOOP("Settings", "Default Port");
|
|
server_settings_schema["default_port"]["type"] = "integer";
|
|
server_settings_schema["default_port"]["default"] = OPENRGB_SDK_PORT;
|
|
server_settings_schema["default_port"]["minimum"] = 0;
|
|
server_settings_schema["default_port"]["maximum"] = 65535;
|
|
|
|
server_settings_schema["legacy_workaround"]["title"] = QT_TRANSLATE_NOOP("Settings", "Legacy Workaround");
|
|
server_settings_schema["legacy_workaround"]["type"] = "bool";
|
|
server_settings_schema["legacy_workaround"]["description"] = QT_TRANSLATE_NOOP("Settings", "Workaround for some older SDK implementations that sent incorrect packet size for certain packets");
|
|
|
|
settings_manager->RegisterSettingsSchema("Server", QT_TRANSLATE_NOOP("Settings", "Server"), server_settings_schema);
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Configure the log manager |
|
|
\*-----------------------------------------------------*/
|
|
LogManager::get()->Configure(settings_manager->GetSettings("LogManager"), GetConfigurationDirectory());
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Load sizes list from file |
|
|
\*-----------------------------------------------------*/
|
|
profile_manager = new ProfileManager(GetConfigurationDirectory());
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If configured, lower process priority to potentially |
|
|
| reduce interference with other programs. Positive |
|
|
| nice values decrease priority on Linux and MacOS. |
|
|
\*-----------------------------------------------------*/
|
|
json general_settings = settings_manager->GetSettings("General");
|
|
bool low_priority = false;
|
|
|
|
if(general_settings.contains("low_priority"))
|
|
{
|
|
low_priority = general_settings["low_priority"];
|
|
}
|
|
|
|
if(low_priority)
|
|
{
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
setpriority(PRIO_PROCESS, 0, 10);
|
|
#endif
|
|
#ifdef _WIN32
|
|
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ResourceManager::~ResourceManager()
|
|
{
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| ResourceManager Global Instance Accessor |
|
|
\*---------------------------------------------------------*/
|
|
ResourceManager* ResourceManager::get()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| If ResourceManager does not exist yet, create it |
|
|
\*-----------------------------------------------------*/
|
|
if(!instance)
|
|
{
|
|
instance = new ResourceManager();
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Resource Accessors |
|
|
\*---------------------------------------------------------*/
|
|
std::vector<NetworkClient*>& ResourceManager::GetClients()
|
|
{
|
|
return(clients);
|
|
}
|
|
|
|
filesystem::path ResourceManager::GetConfigurationDirectory()
|
|
{
|
|
return(config_dir);
|
|
}
|
|
|
|
std::string ResourceManager::GetDefaultServerHost()
|
|
{
|
|
return(default_server_host);
|
|
}
|
|
|
|
unsigned short ResourceManager::GetDefaultServerPort()
|
|
{
|
|
return(default_server_port);
|
|
}
|
|
|
|
std::vector<HIDDeviceInfo> ResourceManager::GetHIDDeviceInfo()
|
|
{
|
|
if(IsLocalClient())
|
|
{
|
|
return(GetLocalClient()->GetHIDDeviceInfo());
|
|
}
|
|
else
|
|
{
|
|
hid_device_info* hid_devices;
|
|
std::vector<HIDDeviceInfo> hid_info;
|
|
|
|
hid_devices = hid_enumerate(0,0);
|
|
|
|
while(hid_devices)
|
|
{
|
|
HIDDeviceInfo hid_device_info;
|
|
|
|
hid_device_info.vendor_id = hid_devices->vendor_id;
|
|
hid_device_info.product_id = hid_devices->product_id;
|
|
hid_device_info.release_number = hid_devices->release_number;
|
|
hid_device_info.usage_page = hid_devices->usage_page;
|
|
hid_device_info.usage = hid_devices->usage;
|
|
hid_device_info.interface_number = hid_devices->interface_number;
|
|
hid_device_info.serial_number = StringUtils::wchar_to_string(hid_devices->serial_number);
|
|
hid_device_info.manufacturer_string = StringUtils::wchar_to_string(hid_devices->manufacturer_string);
|
|
hid_device_info.product_string = StringUtils::wchar_to_string(hid_devices->product_string);
|
|
hid_device_info.path = hid_devices->path;
|
|
|
|
hid_info.push_back(hid_device_info);
|
|
|
|
hid_devices = hid_devices->next;
|
|
}
|
|
|
|
return(hid_info);
|
|
}
|
|
}
|
|
|
|
std::vector<i2c_smbus_interface*> & ResourceManager::GetI2CBuses()
|
|
{
|
|
return DetectionManager::get()->GetI2CBuses();
|
|
}
|
|
|
|
std::vector<i2c_smbus_info> ResourceManager::GetI2CBusInfo()
|
|
{
|
|
if(IsLocalClient())
|
|
{
|
|
return(GetLocalClient()->GetI2CBusInfo());
|
|
}
|
|
else
|
|
{
|
|
std::vector<i2c_smbus_info> bus_info;
|
|
std::vector<i2c_smbus_interface*> buses = GetI2CBuses();
|
|
|
|
for(std::size_t bus_idx = 0; bus_idx < buses.size(); bus_idx++)
|
|
{
|
|
bus_info.push_back(buses[bus_idx]->info);
|
|
}
|
|
|
|
return(bus_info);
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> ResourceManager::GetSerialPorts()
|
|
{
|
|
if(IsLocalClient())
|
|
{
|
|
return(GetLocalClient()->GetSerialPorts());
|
|
}
|
|
else
|
|
{
|
|
return(serial_port::getSerialPorts());
|
|
}
|
|
}
|
|
|
|
std::vector<SerialDeviceInfo> ResourceManager::GetUSBSerialPorts()
|
|
{
|
|
if(IsLocalClient())
|
|
{
|
|
return(find_usb_serial_ports());
|
|
}
|
|
else
|
|
{
|
|
return(find_usb_serial_ports());
|
|
}
|
|
}
|
|
|
|
std::vector<USBDeviceInfo> ResourceManager::GetUSBDeviceInfo()
|
|
{
|
|
if(IsLocalClient())
|
|
{
|
|
return(GetLocalClient()->GetUSBDeviceInfo());
|
|
}
|
|
else
|
|
{
|
|
std::size_t usb_device_count;
|
|
libusb_device** usb_devices;
|
|
std::vector<USBDeviceInfo> usb_info;
|
|
|
|
if(libusb_init(NULL) >= 0)
|
|
{
|
|
usb_device_count = libusb_get_device_list(NULL, &usb_devices);
|
|
|
|
for(std::size_t usb_device_idx = 0; usb_device_idx < usb_device_count; usb_device_idx++)
|
|
{
|
|
libusb_device_descriptor usb_desc;
|
|
libusb_device_handle* usb_handle;
|
|
|
|
if(libusb_get_device_descriptor(usb_devices[usb_device_idx], &usb_desc) >= 0)
|
|
{
|
|
USBDeviceInfo usb_device_info;
|
|
char usb_descriptor_buf[256];
|
|
|
|
usb_device_info.vendor_id = usb_desc.idVendor;
|
|
usb_device_info.product_id = usb_desc.idProduct;
|
|
|
|
if(libusb_open(usb_devices[usb_device_idx], &usb_handle) >= 0)
|
|
{
|
|
if(usb_desc.iSerialNumber)
|
|
{
|
|
libusb_get_string_descriptor_ascii(usb_handle, usb_desc.iSerialNumber, (unsigned char*)usb_descriptor_buf, sizeof(usb_descriptor_buf));
|
|
usb_device_info.serial_number.assign(usb_descriptor_buf);
|
|
}
|
|
|
|
if(usb_desc.iManufacturer)
|
|
{
|
|
libusb_get_string_descriptor_ascii(usb_handle, usb_desc.iManufacturer, (unsigned char*)usb_descriptor_buf, sizeof(usb_descriptor_buf));
|
|
usb_device_info.manufacturer_string.assign(usb_descriptor_buf);
|
|
}
|
|
|
|
if(usb_desc.iProduct)
|
|
{
|
|
libusb_get_string_descriptor_ascii(usb_handle, usb_desc.iProduct, (unsigned char*)usb_descriptor_buf, sizeof(usb_descriptor_buf));
|
|
usb_device_info.product_string.assign(usb_descriptor_buf);
|
|
}
|
|
|
|
libusb_close(usb_handle);
|
|
}
|
|
|
|
usb_info.push_back(usb_device_info);
|
|
}
|
|
}
|
|
|
|
libusb_free_device_list(usb_devices, 1);
|
|
}
|
|
|
|
return(usb_info);
|
|
}
|
|
}
|
|
|
|
LogManager* ResourceManager::GetLogManager()
|
|
{
|
|
return LogManager::get();
|
|
}
|
|
|
|
PluginManagerInterface* ResourceManager::GetPluginManager()
|
|
{
|
|
return(plugin_manager);
|
|
}
|
|
|
|
ProfileManager* ResourceManager::GetProfileManager()
|
|
{
|
|
return(profile_manager);
|
|
}
|
|
|
|
std::vector<RGBController*>& ResourceManager::GetRGBControllers()
|
|
{
|
|
return(rgb_controllers);
|
|
}
|
|
|
|
std::vector<RGBControllerInterface*>& ResourceManager::GetRGBControllerInterfaces()
|
|
{
|
|
return(rgb_controller_interfaces);
|
|
}
|
|
|
|
NetworkServer* ResourceManager::GetServer()
|
|
{
|
|
return(server);
|
|
}
|
|
|
|
SettingsManager* ResourceManager::GetSettingsManager()
|
|
{
|
|
return(settings_manager);
|
|
}
|
|
|
|
void ResourceManager::SetConfigurationDirectory(const filesystem::path &directory)
|
|
{
|
|
config_dir = directory;
|
|
settings_manager->LoadSettings(directory / "OpenRGB.json");
|
|
LogManager::get()->Configure(settings_manager->GetSettings("LogManager"), GetConfigurationDirectory());
|
|
profile_manager->SetConfigurationDirectory(directory);
|
|
}
|
|
|
|
void ResourceManager::SetDefaultServerHost(std::string new_server_host)
|
|
{
|
|
default_server_host = new_server_host;
|
|
}
|
|
|
|
void ResourceManager::SetDefaultServerPort(unsigned short new_server_port)
|
|
{
|
|
default_server_port = new_server_port;
|
|
}
|
|
|
|
void ResourceManager::SetPluginManager(PluginManagerInterface* plugin_manager_ptr)
|
|
{
|
|
plugin_manager = plugin_manager_ptr;
|
|
|
|
if(server)
|
|
{
|
|
server->SetPluginManager(plugin_manager);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Network Client Registration |
|
|
\*---------------------------------------------------------*/
|
|
void ResourceManager::RegisterNetworkClient(NetworkClient* new_client)
|
|
{
|
|
new_client->RegisterNetworkClientCallback(ResourceManagerNetworkClientCallback, this);
|
|
|
|
clients.push_back(new_client);
|
|
}
|
|
|
|
void ResourceManager::UnregisterNetworkClient(NetworkClient* network_client)
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Stop the disconnecting client |
|
|
\*-----------------------------------------------------*/
|
|
network_client->StopClient();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Clear callbacks from the client before removal |
|
|
\*-----------------------------------------------------*/
|
|
network_client->ClearCallbacks();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Find the client to remove and remove it from the |
|
|
| clients list |
|
|
\*-----------------------------------------------------*/
|
|
std::vector<NetworkClient*>::iterator client_it = std::find(clients.begin(), clients.end(), network_client);
|
|
|
|
if(client_it != clients.end())
|
|
{
|
|
clients.erase(client_it);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Delete the client |
|
|
\*-----------------------------------------------------*/
|
|
delete network_client;
|
|
|
|
UpdateDeviceList();
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Local Client Accessors |
|
|
\*---------------------------------------------------------*/
|
|
NetworkClient* ResourceManager::GetLocalClient()
|
|
{
|
|
return(auto_connection_client);
|
|
}
|
|
|
|
unsigned int ResourceManager::GetLocalClientProtocolVersion()
|
|
{
|
|
return(auto_connection_client->GetProtocolVersion());
|
|
}
|
|
|
|
bool ResourceManager::IsLocalClient()
|
|
{
|
|
return(auto_connection_active && (auto_connection_client != NULL) && auto_connection_client->GetLocal());
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Callback Registration Functions |
|
|
\*---------------------------------------------------------*/
|
|
void ResourceManager::RegisterResourceManagerCallback(ResourceManagerCallback new_callback, void * new_callback_arg)
|
|
{
|
|
ResourceManagerCallbackMutex.lock();
|
|
|
|
for(size_t idx = 0; idx < ResourceManagerCallbacks.size(); idx++)
|
|
{
|
|
if(ResourceManagerCallbacks[idx] == new_callback && ResourceManagerCallbackArgs[idx] == new_callback_arg)
|
|
{
|
|
ResourceManagerCallbackMutex.unlock();
|
|
|
|
LOG_TRACE("[%s] Tried to register an already registered ResourceManager callback, skipping. Total callbacks registered: %d", RESOURCEMANAGER, ResourceManagerCallbacks.size());
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
ResourceManagerCallbacks.push_back(new_callback);
|
|
ResourceManagerCallbackArgs.push_back(new_callback_arg);
|
|
|
|
ResourceManagerCallbackMutex.unlock();
|
|
|
|
LOG_TRACE("[%s] Registered ResourceManager callback. Total callbacks registered: %d", RESOURCEMANAGER, ResourceManagerCallbacks.size());
|
|
}
|
|
|
|
void ResourceManager::UnregisterResourceManagerCallback(ResourceManagerCallback callback, void * callback_arg)
|
|
{
|
|
ResourceManagerCallbackMutex.lock();
|
|
|
|
for(size_t idx = 0; idx < ResourceManagerCallbacks.size(); idx++)
|
|
{
|
|
if(ResourceManagerCallbacks[idx] == callback && ResourceManagerCallbackArgs[idx] == callback_arg)
|
|
{
|
|
ResourceManagerCallbacks.erase(ResourceManagerCallbacks.begin() + idx);
|
|
ResourceManagerCallbackArgs.erase(ResourceManagerCallbackArgs.begin() + idx);
|
|
}
|
|
}
|
|
|
|
ResourceManagerCallbackMutex.unlock();
|
|
|
|
LOG_TRACE("[%s] Unregistered ResourceManager callback. Total callbacks registered: %d", RESOURCEMANAGER, ResourceManagerCallbackArgs.size());
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Functions to manage detection |
|
|
\*---------------------------------------------------------*/
|
|
|
|
bool ResourceManager::GetDetectionEnabled()
|
|
{
|
|
return(detection_enabled);
|
|
}
|
|
|
|
unsigned int ResourceManager::GetDetectionPercent()
|
|
{
|
|
if(auto_connection_active && (auto_connection_client != NULL) && auto_connection_client->GetLocal())
|
|
{
|
|
return auto_connection_client->DetectionManager_GetDetectionPercent();
|
|
}
|
|
else
|
|
{
|
|
return DetectionManager::get()->GetDetectionPercent();
|
|
}
|
|
}
|
|
|
|
std::string ResourceManager::GetDetectionString()
|
|
{
|
|
if(auto_connection_active && (auto_connection_client != NULL) && auto_connection_client->GetLocal())
|
|
{
|
|
return auto_connection_client->DetectionManager_GetDetectionString();
|
|
}
|
|
else
|
|
{
|
|
return DetectionManager::get()->GetDetectionString();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::RescanDevices()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| If automatic local connection is active, the primary |
|
|
| instance is the local server, so send rescan requests |
|
|
| to the automatic local connection client |
|
|
\*-----------------------------------------------------*/
|
|
if(auto_connection_active && (auto_connection_client != NULL) && auto_connection_client->GetLocal())
|
|
{
|
|
auto_connection_client->SendRequest_RescanDevices();
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If detection is disabled and there is exactly one |
|
|
| client, the primary instance is the connected server, |
|
|
| so send rescan requests to the first (and only) |
|
|
| client |
|
|
\*-----------------------------------------------------*/
|
|
else if(!detection_enabled && clients.size() == 1)
|
|
{
|
|
clients[0]->SendRequest_RescanDevices();
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If detection is enabled, start detection |
|
|
\*-----------------------------------------------------*/
|
|
if(detection_enabled)
|
|
{
|
|
DetectionManager::get()->BeginDetection();
|
|
}
|
|
}
|
|
|
|
void ResourceManager::StopDeviceDetection()
|
|
{
|
|
//TODO: Call DetectionManager::AbortDetection() or send SDK command if local client
|
|
}
|
|
|
|
void ResourceManager::UpdateDeviceList()
|
|
{
|
|
DeviceListChangeMutex.lock();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Clear the controller list |
|
|
\*-----------------------------------------------------*/
|
|
rgb_controllers.clear();
|
|
rgb_controller_interfaces.clear();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Insert hardware controllers into controller list |
|
|
\*-----------------------------------------------------*/
|
|
rgb_controllers_hw = DetectionManager::get()->GetRGBControllers();
|
|
|
|
for(std::size_t rgb_controller_idx = 0; rgb_controller_idx < rgb_controllers_hw.size(); rgb_controller_idx++)
|
|
{
|
|
rgb_controllers.push_back(rgb_controllers_hw[rgb_controller_idx]);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Insert plugin controllers into controller list |
|
|
\*-----------------------------------------------------*/
|
|
if(plugin_manager)
|
|
{
|
|
std::vector<RGBController*> rgb_controllers_plugins = plugin_manager->GetRGBControllers();
|
|
|
|
for(std::size_t rgb_controller_idx = 0; rgb_controller_idx < rgb_controllers_plugins.size(); rgb_controller_idx++)
|
|
{
|
|
rgb_controllers.push_back(rgb_controllers_plugins[rgb_controller_idx]);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Insert client controllers into controller list |
|
|
\*-----------------------------------------------------*/
|
|
for(std::size_t client_idx = 0; client_idx < clients.size(); client_idx++)
|
|
{
|
|
std::vector<RGBController*> rgb_controllers_client = clients[client_idx]->GetRGBControllers();
|
|
|
|
for(std::size_t rgb_controller_idx = 0; rgb_controller_idx < rgb_controllers_client.size(); rgb_controller_idx++)
|
|
{
|
|
rgb_controllers.push_back(rgb_controllers_client[rgb_controller_idx]);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Update server list |
|
|
\*-----------------------------------------------------*/
|
|
if(server)
|
|
{
|
|
json server_settings = settings_manager->GetSettings("Server");
|
|
bool all_controllers = false;
|
|
|
|
if(server_settings.contains("all_controllers"))
|
|
{
|
|
all_controllers = server_settings["all_controllers"];
|
|
}
|
|
|
|
if(all_controllers)
|
|
{
|
|
server->SetControllers(rgb_controllers);
|
|
}
|
|
else
|
|
{
|
|
server->SetControllers(rgb_controllers_hw);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Synchronize interfaces with controllers |
|
|
\*-----------------------------------------------------*/
|
|
rgb_controller_interfaces.reserve(rgb_controllers.size());
|
|
|
|
for(RGBController* rgb_controller : rgb_controllers)
|
|
{
|
|
rgb_controller_interfaces.push_back((RGBControllerInterface*)rgb_controller);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Signal list has changed |
|
|
\*-----------------------------------------------------*/
|
|
DeviceListChangeMutex.unlock();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Signal device list update |
|
|
\*-----------------------------------------------------*/
|
|
SignalResourceManagerUpdate(RESOURCEMANAGER_UPDATE_REASON_DEVICE_LIST_UPDATED);
|
|
}
|
|
|
|
void ResourceManager::WaitForDetection()
|
|
{
|
|
DetectionManager::get()->WaitForDetection();
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Function to signal update callbacks |
|
|
\*---------------------------------------------------------*/
|
|
void ResourceManager::SignalResourceManagerUpdate(unsigned int update_reason)
|
|
{
|
|
if(server)
|
|
{
|
|
server->SignalResourceManagerUpdate(update_reason);
|
|
}
|
|
|
|
ResourceManagerCallbackMutex.lock();
|
|
|
|
for(std::size_t callback_idx = 0; callback_idx < ResourceManagerCallbacks.size(); callback_idx++)
|
|
{
|
|
ResourceManagerCallbacks[callback_idx](ResourceManagerCallbackArgs[callback_idx], update_reason);
|
|
}
|
|
|
|
ResourceManagerCallbackMutex.unlock();
|
|
|
|
LOG_TRACE("[%s] ResourceManager update signalled: %d", RESOURCEMANAGER, update_reason);
|
|
}
|
|
|
|
void ResourceManager::SetupConfigurationDirectory()
|
|
{
|
|
config_dir.clear();
|
|
#ifdef _WIN32
|
|
const wchar_t* appdata = _wgetenv(L"APPDATA");
|
|
if(appdata != NULL)
|
|
{
|
|
config_dir = appdata;
|
|
}
|
|
#else
|
|
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
|
|
const char* home = getenv("HOME");
|
|
/*-----------------------------------------------------*\
|
|
| Check both XDG_CONFIG_HOME and APPDATA environment |
|
|
| variables. If neither exist, use current directory |
|
|
\*-----------------------------------------------------*/
|
|
if(xdg_config_home != NULL)
|
|
{
|
|
config_dir = xdg_config_home;
|
|
}
|
|
else if(home != NULL)
|
|
{
|
|
config_dir = home;
|
|
config_dir /= ".config";
|
|
}
|
|
#endif
|
|
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If a configuration directory was found, append OpenRGB|
|
|
\*-----------------------------------------------------*/
|
|
if(config_dir != "")
|
|
{
|
|
config_dir.append("OpenRGB");
|
|
|
|
/*-------------------------------------------------*\
|
|
| Create OpenRGB configuration directory if it |
|
|
| doesn't exist |
|
|
\*-------------------------------------------------*/
|
|
filesystem::create_directories(config_dir);
|
|
}
|
|
else
|
|
{
|
|
config_dir = "./";
|
|
}
|
|
}
|
|
|
|
bool ResourceManager::AttemptLocalConnection()
|
|
{
|
|
LOG_DEBUG("[%s] Attempting local server connection...", RESOURCEMANAGER);
|
|
|
|
bool success = false;
|
|
|
|
auto_connection_client = new NetworkClient();
|
|
|
|
std::string titleString = "OpenRGB ";
|
|
titleString.append(VERSION_STRING);
|
|
|
|
auto_connection_client->RequestLocalClient(true);
|
|
auto_connection_client->SetName(titleString.c_str());
|
|
auto_connection_client->StartClient();
|
|
|
|
for(int timeout = 0; timeout < 10; timeout++)
|
|
{
|
|
if(auto_connection_client->GetConnected())
|
|
{
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(5ms);
|
|
}
|
|
|
|
if(!auto_connection_client->GetConnected())
|
|
{
|
|
LOG_TRACE("[%s] Client failed to connect", RESOURCEMANAGER);
|
|
auto_connection_client->StopClient();
|
|
LOG_TRACE("[%s] Client stopped", RESOURCEMANAGER);
|
|
|
|
delete auto_connection_client;
|
|
|
|
auto_connection_client = NULL;
|
|
}
|
|
else
|
|
{
|
|
ResourceManager::get()->RegisterNetworkClient(auto_connection_client);
|
|
LOG_TRACE("[%s] Registered network client", RESOURCEMANAGER);
|
|
|
|
success = true;
|
|
|
|
/*-------------------------------------------------*\
|
|
| Wait up to 5 seconds for the client connection to |
|
|
| retrieve all controllers |
|
|
\*-------------------------------------------------*/
|
|
for(int timeout = 0; timeout < 1000; timeout++)
|
|
{
|
|
if(auto_connection_client->GetOnline())
|
|
{
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(5ms);
|
|
}
|
|
|
|
/*-------------------------------------------------*\
|
|
| If local client, set local log level to server's |
|
|
| log level and download log entries |
|
|
\*-------------------------------------------------*/
|
|
if(auto_connection_client->GetLocal() && auto_connection_client->GetSupportsLogManagerAPI())
|
|
{
|
|
unsigned int log_level = auto_connection_client->LogManager_GetLogLevel();
|
|
LogManager::get()->SetLogLevel(log_level, true);
|
|
auto_connection_client->LogManager_GetLogBuffer();
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void ResourceManager::Initialize(bool tryConnect, bool detectDevices, bool startServer, bool applyPostOptions)
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Cache the parameters |
|
|
| TODO: Possibly cache them in the CLI file somewhere |
|
|
\*-----------------------------------------------------*/
|
|
tryAutoConnect = tryConnect;
|
|
detection_enabled = detectDevices;
|
|
start_server = startServer;
|
|
apply_post_options = applyPostOptions;
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If enabled, try connecting to local server instead of |
|
|
| detecting devices from this instance of OpenRGB |
|
|
\*-----------------------------------------------------*/
|
|
if(tryAutoConnect)
|
|
{
|
|
/*-------------------------------------------------*\
|
|
| Attempt connection to local server |
|
|
\*-------------------------------------------------*/
|
|
if(AttemptLocalConnection())
|
|
{
|
|
LOG_DEBUG("[%s] Local OpenRGB server connected, running in client mode", RESOURCEMANAGER);
|
|
|
|
/*---------------------------------------------*\
|
|
| Set auto connection active flag and disable |
|
|
| detection if the local server was connected |
|
|
\*---------------------------------------------*/
|
|
auto_connection_active = true;
|
|
detection_enabled = false;
|
|
|
|
profile_manager->UpdateProfileList();
|
|
}
|
|
|
|
tryAutoConnect = false;
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Initialize Saved Client Connections |
|
|
\*-----------------------------------------------------*/
|
|
json client_settings = settings_manager->GetSettings("Client");
|
|
|
|
if(client_settings.contains("clients"))
|
|
{
|
|
for(unsigned int client_idx = 0; client_idx < client_settings["clients"].size(); client_idx++)
|
|
{
|
|
NetworkClient * client = new NetworkClient();
|
|
|
|
std::string titleString = "OpenRGB ";
|
|
titleString.append(VERSION_STRING);
|
|
|
|
std::string client_ip = client_settings["clients"][client_idx]["ip"];
|
|
unsigned short client_port = client_settings["clients"][client_idx]["port"];
|
|
|
|
client->SetIP(client_ip.c_str());
|
|
client->SetName(titleString.c_str());
|
|
client->SetPort(client_port);
|
|
|
|
client->StartClient();
|
|
|
|
for(int timeout = 0; timeout < 100; timeout++)
|
|
{
|
|
if(client->GetConnected())
|
|
{
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(10ms);
|
|
}
|
|
|
|
RegisterNetworkClient(client);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If the server host and port have been set on the CLI, |
|
|
| use those values. Otherwise, get default server host |
|
|
| and port from settings if configured. |
|
|
\*-----------------------------------------------------*/
|
|
json server_settings = settings_manager->GetSettings("Server");
|
|
|
|
if(default_server_host == "")
|
|
{
|
|
if(server_settings.contains("default_host"))
|
|
{
|
|
default_server_host = server_settings["default_host"];
|
|
}
|
|
else
|
|
{
|
|
default_server_host = OPENRGB_SDK_HOST;
|
|
}
|
|
}
|
|
|
|
if(default_server_port == 0)
|
|
{
|
|
if(server_settings.contains("default_port"))
|
|
{
|
|
default_server_port = server_settings["default_port"];
|
|
}
|
|
else
|
|
{
|
|
default_server_port = OPENRGB_SDK_PORT;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Start server if requested |
|
|
\*-----------------------------------------------------*/
|
|
if(start_server)
|
|
{
|
|
InitializeServer();
|
|
server->StartServer();
|
|
if(!server->GetOnline())
|
|
{
|
|
LOG_DEBUG("[%s] Server failed to start", RESOURCEMANAGER);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Perform actual detection if enabled |
|
|
\*-----------------------------------------------------*/
|
|
if(detection_enabled)
|
|
{
|
|
LOG_DEBUG("[%s] Local OpenRGB server not found, running in standalone mode", RESOURCEMANAGER);
|
|
|
|
DetectionManager::get()->RegisterDetectionCallback(ResourceManagerDetectionCallback, this);
|
|
DetectionManager::get()->BeginDetection();
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| Process command line arguments after detection only |
|
|
| if the pre-detection parsing indicated it should be |
|
|
| run |
|
|
\*-----------------------------------------------------*/
|
|
if(apply_post_options)
|
|
{
|
|
cli_post_detection();
|
|
}
|
|
|
|
init_finished = true;
|
|
}
|
|
|
|
void ResourceManager::InitializeServer()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| Initialize Server Instance |
|
|
| If configured, pass through full controller list |
|
|
| including clients. Otherwise, pass only local |
|
|
| hardware controllers |
|
|
\*-----------------------------------------------------*/
|
|
json server_settings = settings_manager->GetSettings("Server");
|
|
bool legacy_workaround = false;
|
|
|
|
server = new NetworkServer();
|
|
|
|
/*-----------------------------------------------------*\
|
|
| 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 |
|
|
\*-----------------------------------------------------*/
|
|
if(server_settings.contains("legacy_workaround"))
|
|
{
|
|
legacy_workaround = server_settings["legacy_workaround"];
|
|
}
|
|
|
|
if(legacy_workaround)
|
|
{
|
|
server->SetLegacyWorkaroundEnable(true);
|
|
}
|
|
|
|
server->SetProfileManager(profile_manager);
|
|
|
|
if(plugin_manager)
|
|
{
|
|
server->SetPluginManager(plugin_manager);
|
|
}
|
|
|
|
bool all_controllers = false;
|
|
|
|
if(server_settings.contains("all_controllers"))
|
|
{
|
|
all_controllers = server_settings["all_controllers"];
|
|
}
|
|
|
|
if(all_controllers)
|
|
{
|
|
server->SetControllers(rgb_controllers);
|
|
}
|
|
else
|
|
{
|
|
server->SetControllers(rgb_controllers_hw);
|
|
}
|
|
|
|
/*-----------------------------------------------------*\
|
|
| If the server host and port have been set on the CLI, |
|
|
| use those values. Otherwise, get default server host |
|
|
| and port from settings if configured. |
|
|
\*-----------------------------------------------------*/
|
|
if(default_server_host != "")
|
|
{
|
|
server->SetHost(default_server_host);
|
|
}
|
|
|
|
if(default_server_port != 0)
|
|
{
|
|
server->SetPort(default_server_port);
|
|
}
|
|
}
|
|
|
|
void ResourceManager::WaitForInitialization()
|
|
{
|
|
/*-----------------------------------------------------*\
|
|
| A reliable sychronization of this kind is impossible |
|
|
| without the use of a `barrier` implementation, which |
|
|
| is only introduced in C++20 |
|
|
\*-----------------------------------------------------*/
|
|
while(!init_finished)
|
|
{
|
|
std::this_thread::sleep_for(1ms);
|
|
};
|
|
}
|