Some changes
This commit is contained in:
parent
7fdd272d76
commit
7dcf4a54ef
@ -1 +1 @@
|
||||
Subproject commit 32b1ef973d44c668fc2e74735491db3896a32c2d
|
||||
Subproject commit fe633dc99a6ea91c2c0a8cb13a51a7587a54cb2e
|
@ -257,7 +257,7 @@ target_link_libraries(PermMapHelper
|
||||
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "18")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "19")
|
||||
if (BUILD_TYPE_NAME EQUAL OFF)
|
||||
SET(CPACK_PACKAGE_VERSION_DATA "beta")
|
||||
elseif (BUILD_TYPE_NAME STREQUAL "")
|
||||
|
@ -994,6 +994,10 @@ std::shared_ptr<Properties> DatabaseHelper::loadClientProperties(const std::shar
|
||||
column = "client_nickname";
|
||||
break;
|
||||
|
||||
case property::CONNECTION_CLIENT_IP:
|
||||
column = "client_ip";
|
||||
break;
|
||||
|
||||
case property::CLIENT_LASTCONNECTED:
|
||||
column = "client_last_connected";
|
||||
break;
|
||||
@ -1326,10 +1330,10 @@ void DatabaseHelper::listDatabaseClients(
|
||||
client.client_ip = values[index++];
|
||||
|
||||
assert(names[index] == "client_created");
|
||||
client.client_last_connected = values[index++];
|
||||
client.client_created = values[index++];
|
||||
|
||||
assert(names[index] == "client_last_connected");
|
||||
client.client_created = values[index++];
|
||||
client.client_last_connected = values[index++];
|
||||
|
||||
assert(names[index] == "client_total_connections");
|
||||
client.client_total_connections = values[index++];
|
||||
|
@ -36,6 +36,14 @@ ConnectedClient::~ConnectedClient() {
|
||||
memtrack::freed<ConnectedClient>(this);
|
||||
}
|
||||
|
||||
bool ConnectedClient::loadDataForCurrentServer() {
|
||||
auto result = DataClient::loadDataForCurrentServer();
|
||||
if(!result) return false;
|
||||
|
||||
this->properties()[property::CONNECTION_CLIENT_IP] = this->getLoggingPeerIp();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<ConnectionInfoData> ConnectedClient::request_connection_info(const std::shared_ptr<ConnectedClient> &receiver, bool& send_temp) {
|
||||
auto& info = this->connection_info;
|
||||
|
||||
|
@ -375,6 +375,8 @@ namespace ts {
|
||||
std::weak_ptr<MusicClient> subscribed_bot;
|
||||
std::weak_ptr<ts::music::Playlist> _subscribed_playlist{};
|
||||
|
||||
bool loadDataForCurrentServer() override;
|
||||
|
||||
virtual void tick(const std::chrono::system_clock::time_point &time);
|
||||
//Locked by everything who has something todo with command handling
|
||||
threads::Mutex command_lock; /* Note: This mutex must be recursive! */
|
||||
|
@ -124,7 +124,7 @@ enum WhisperType {
|
||||
CHANNEL_COMMANDER = 2,
|
||||
ALL = 3,
|
||||
|
||||
ECHO_TEXT = 0x10,
|
||||
ECHO = 0x10,
|
||||
};
|
||||
|
||||
enum WhisperTarget {
|
||||
@ -184,7 +184,7 @@ void SpeakingClient::handlePacketVoiceWhisper(const pipes::buffer_view& data, bo
|
||||
#endif
|
||||
|
||||
deque<shared_ptr<SpeakingClient>> available_clients;
|
||||
if(type == WhisperType::ECHO_TEXT) {
|
||||
if(type == WhisperType::ECHO) {
|
||||
available_clients.push_back(dynamic_pointer_cast<SpeakingClient>(this->ref()));
|
||||
} else {
|
||||
for(const auto& client : this->server->getClients()) {
|
||||
@ -269,7 +269,6 @@ void SpeakingClient::handlePacketVoiceWhisper(const pipes::buffer_view& data, bo
|
||||
auto speakingClient = dynamic_pointer_cast<SpeakingClient>(cl);
|
||||
return !speakingClient->shouldReceiveVoiceWhisper(self_lock);
|
||||
}), available_clients.end());
|
||||
}
|
||||
|
||||
if(available_clients.empty()) {
|
||||
if(update_whisper_error(this->speak_last_no_whisper_target)) {
|
||||
@ -278,6 +277,7 @@ void SpeakingClient::handlePacketVoiceWhisper(const pipes::buffer_view& data, bo
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(available_clients.size() > this->server->properties()[property::VIRTUALSERVER_MIN_CLIENTS_IN_CHANNEL_BEFORE_FORCED_SILENCE].as_save<size_t>()) {
|
||||
if(update_whisper_error(this->speak_last_too_many_whisper_targets)) {
|
||||
command_result result{error::whisper_too_many_targets};
|
||||
@ -285,6 +285,7 @@ void SpeakingClient::handlePacketVoiceWhisper(const pipes::buffer_view& data, bo
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Create the packet data
|
||||
char packet_buffer[OUT_WHISPER_PKT_OFFSET + data_length];
|
||||
|
@ -3,8 +3,7 @@
|
||||
#include <json/json.h>
|
||||
#include "ConnectedClient.h"
|
||||
|
||||
namespace ts {
|
||||
namespace server {
|
||||
namespace ts::server {
|
||||
class VirtualServer;
|
||||
class SpeakingClient : public ConnectedClient {
|
||||
public:
|
||||
@ -96,5 +95,4 @@ namespace ts {
|
||||
std::shared_ptr<Json::Value> identityData;
|
||||
} handshake;
|
||||
};
|
||||
}
|
||||
}
|
@ -475,6 +475,22 @@ bool QueryClient::handleMessage(const pipes::buffer_view& message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(auto non_escape{command.find_first_not_of('\r')}; non_escape == std::string::npos) {
|
||||
logTrace(LOG_QUERY, "[{}:{}] Got query idle command (\\r)", this->getLoggingPeerIp(), this->getPeerPort());
|
||||
CMD_RESET_IDLE; //if idle time over 5 min than connection drop
|
||||
return true;
|
||||
} else {
|
||||
command = command.substr(non_escape);
|
||||
}
|
||||
|
||||
if(auto non_escape{command.find_first_not_of('\n')}; non_escape == std::string::npos) {
|
||||
logTrace(LOG_QUERY, "[{}:{}] Got query idle command (\\n)", this->getLoggingPeerIp(), this->getPeerPort());
|
||||
CMD_RESET_IDLE; //if idle time over 5 min than connection drop
|
||||
return true;
|
||||
} else {
|
||||
command = command.substr(non_escape);
|
||||
}
|
||||
|
||||
if((uint8_t) command[0] == 255) {
|
||||
string commands{};
|
||||
|
||||
|
@ -145,7 +145,7 @@ std::string VoiceBridge::generate_answer() {
|
||||
}
|
||||
|
||||
void VoiceBridge::execute_tick() {
|
||||
if(!this->_voice_channel) {
|
||||
if(!this->voice_channel_) {
|
||||
if(this->offer_timestamp.time_since_epoch().count() > 0 && this->offer_timestamp + chrono::seconds{20} < chrono::system_clock::now()) {
|
||||
this->offer_timestamp = chrono::system_clock::time_point();
|
||||
this->connection->callback_setup_fail(rtc::PeerConnection::ConnectionComponent::BASE, "setup timeout");
|
||||
@ -182,26 +182,47 @@ void VoiceBridge::handle_media_stream(const std::shared_ptr<rtc::Channel> &undef
|
||||
}
|
||||
|
||||
void VoiceBridge::handle_data_channel(const std::shared_ptr<rtc::DataChannel> &channel) {
|
||||
if(channel->lable() == "main") {
|
||||
this->_voice_channel = channel;
|
||||
if(channel->lable() == "main" || channel->lable() == "voice") {
|
||||
this->voice_channel_ = channel;
|
||||
debugMessage(this->server_id(), "{} Got voice channel!", CLIENT_STR_LOG_PREFIX_(this->owner()));
|
||||
this->callback_initialized();
|
||||
}
|
||||
|
||||
weak_ptr<rtc::DataChannel> weak_channel = channel;
|
||||
channel->callback_binary = [&, weak_channel](const pipes::buffer_view& buffer) {
|
||||
if(buffer.length() < 2)
|
||||
return;
|
||||
|
||||
this->callback_voice_data(buffer.view(2), buffer[0] == 1, buffer[1] == 1); /* buffer.substr(2), buffer[0] == 1, buffer[1] == 1 */
|
||||
};
|
||||
|
||||
channel->callback_close = [&, channel] {
|
||||
if(channel == this->_voice_channel) {
|
||||
this->_voice_channel = nullptr;
|
||||
channel->callback_close = [&, weak_channel] {
|
||||
auto channel_ref = weak_channel.lock();
|
||||
if(channel_ref == this->voice_channel_) {
|
||||
this->voice_channel_ = nullptr;
|
||||
//TODO may callback?
|
||||
debugMessage(this->server_id(), "{} Voice channel disconnected!", CLIENT_STR_LOG_PREFIX_(this->owner()));
|
||||
}
|
||||
};
|
||||
} else if(channel->lable() == "voice-whisper") {
|
||||
this->voice_whisper_channel_ = channel;
|
||||
debugMessage(this->server_id(), "{} Got voice whisper channel", CLIENT_STR_LOG_PREFIX_(this->owner()));
|
||||
|
||||
weak_ptr<rtc::DataChannel> weak_channel = channel;
|
||||
channel->callback_binary = [&, weak_channel](const pipes::buffer_view& buffer) {
|
||||
if(buffer.length() < 1)
|
||||
return;
|
||||
|
||||
this->callback_voice_whisper_data(buffer.view(2), buffer[0] == 1);
|
||||
};
|
||||
|
||||
channel->callback_close = [&, weak_channel] {
|
||||
auto channel_ref = weak_channel.lock();
|
||||
if(channel_ref == this->voice_whisper_channel_) {
|
||||
this->voice_whisper_channel_ = nullptr;
|
||||
debugMessage(this->server_id(), "{} Voice whisper channel has been closed.", CLIENT_STR_LOG_PREFIX_(this->owner()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void VoiceBridge::handle_audio_data(const std::shared_ptr<rtc::MediaChannel> &channel, const pipes::buffer_view &data, size_t payload_offset) {
|
||||
|
@ -12,12 +12,14 @@ namespace ts {
|
||||
class VoiceBridge {
|
||||
public:
|
||||
typedef std::function<void(const pipes::buffer_view&, bool, bool)> cb_voice_data;
|
||||
typedef std::function<void(const pipes::buffer_view&, bool)> cb_voice_whisper_data;
|
||||
typedef std::function<void(const rtc::IceCandidate&)> cb_ice_candidate;
|
||||
typedef std::function<void(const std::string& /* sdpMid */, int /* sdpMLineIndex */)> cb_ice_candidate_finish;
|
||||
typedef std::function<void()> cb_initialized;
|
||||
typedef std::function<void()> cb_failed;
|
||||
|
||||
std::shared_ptr<rtc::DataChannel> voice_channel() { return this->_voice_channel; }
|
||||
std::shared_ptr<rtc::DataChannel> voice_channel() { return this->voice_channel_; }
|
||||
std::shared_ptr<rtc::DataChannel> voice_whisper_channel() { return this->voice_whisper_channel_; }
|
||||
|
||||
explicit VoiceBridge(const std::shared_ptr<server::WebClient>&);
|
||||
virtual ~VoiceBridge();
|
||||
@ -31,6 +33,7 @@ namespace ts {
|
||||
cb_ice_candidate callback_ice_candidate;
|
||||
cb_ice_candidate_finish callback_ice_candidate_finished;
|
||||
cb_voice_data callback_voice_data;
|
||||
cb_voice_whisper_data callback_voice_whisper_data;
|
||||
cb_initialized callback_initialized;
|
||||
cb_failed callback_failed;
|
||||
|
||||
@ -48,7 +51,10 @@ namespace ts {
|
||||
std::weak_ptr<server::WebClient> _owner;
|
||||
std::chrono::system_clock::time_point offer_timestamp;
|
||||
std::unique_ptr<rtc::PeerConnection> connection;
|
||||
std::shared_ptr<rtc::DataChannel> _voice_channel;
|
||||
|
||||
std::shared_ptr<rtc::DataChannel> voice_channel_;
|
||||
std::shared_ptr<rtc::DataChannel> voice_whisper_channel_;
|
||||
|
||||
std::weak_ptr<rtc::AudioChannel> _audio_channel;
|
||||
struct {
|
||||
uint16_t packet_id = 0;
|
||||
|
@ -156,22 +156,29 @@ void WebClient::sendJson(const Json::Value& json) {
|
||||
}
|
||||
|
||||
void WebClient::sendCommand(const ts::Command &command, bool low) {
|
||||
if(this->allow_raw_commands) {
|
||||
Json::Value value{};
|
||||
value["type"] = "command-raw";
|
||||
value["payload"] = command.build();
|
||||
this->sendJson(value);
|
||||
} else {
|
||||
Json::Value value = command.buildJson();
|
||||
value["type"] = "command";
|
||||
this->sendJson(value);
|
||||
}
|
||||
}
|
||||
|
||||
void WebClient::sendCommand(const ts::command_builder &command, bool low) {
|
||||
#if false
|
||||
if(this->allow_raw_commands) {
|
||||
Json::Value value{};
|
||||
value["type"] = "command2";
|
||||
value["type"] = "command-raw";
|
||||
value["payload"] = command.build();
|
||||
this->sendJson(value);
|
||||
#else
|
||||
} else {
|
||||
auto data = command.build();
|
||||
Command parsed_command = Command::parse(pipes::buffer_view{data.data(), data.length()}, true, false);
|
||||
this->sendCommand(parsed_command, low);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool WebClient::close_connection(const std::chrono::system_clock::time_point& timeout) {
|
||||
@ -418,7 +425,7 @@ void WebClient::disconnectFinal() {
|
||||
this->handle->unregisterConnection(static_pointer_cast<WebClient>(self_lock));
|
||||
}
|
||||
|
||||
Json::CharReaderBuilder json_reader_builder = []{
|
||||
Json::CharReaderBuilder json_reader_builder = []() noexcept {
|
||||
Json::CharReaderBuilder reader_builder;
|
||||
|
||||
return reader_builder;
|
||||
@ -432,7 +439,8 @@ void WebClient::handleMessage(const std::string &message) {
|
||||
unique_ptr<Json::CharReader> reader{json_reader_builder.newCharReader()};
|
||||
|
||||
string error_message;
|
||||
if(!reader->parse(message.data(),message.data() + message.length(), &val, &error_message)) throw Json::Exception("Could not parse payload! (" + error_message + ")");
|
||||
if(!reader->parse(message.data(),message.data() + message.length(), &val, &error_message))
|
||||
throw Json::Exception("Could not parse payload! (" + error_message + ")");
|
||||
} catch (const std::exception& ex) {
|
||||
logError(this->server->getServerId(), "Could not parse web message! Message: " + string(ex.what()));
|
||||
logTrace(this->server->getServerId(), "Payload: " + message);
|
||||
@ -458,7 +466,7 @@ void WebClient::handleMessage(const std::string &message) {
|
||||
} else if(val["type"].asString() == "WebRTC") {
|
||||
auto subType = val["request"].asString();
|
||||
if(subType == "create") {
|
||||
unique_lock voice_bridge_lock(this->voice_bridge_lock);
|
||||
std::unique_lock voice_bridge_lock_{this->voice_bridge_lock};
|
||||
if(this->voice_bridge) {
|
||||
logError(this->server->getServerId(), "[{}] Tried to register a WebRTC channel twice!", CLIENT_STR_LOG_PREFIX_(this));
|
||||
|
||||
@ -467,14 +475,19 @@ void WebClient::handleMessage(const std::string &message) {
|
||||
lock = nullptr;
|
||||
}).detach();
|
||||
}
|
||||
//TODO test if bridge already exists!
|
||||
this->voice_bridge = make_unique<web::VoiceBridge>(dynamic_pointer_cast<WebClient>(_this.lock())); //FIXME Add config
|
||||
|
||||
this->voice_bridge = make_unique<web::VoiceBridge>(dynamic_pointer_cast<WebClient>(this->ref())); //FIXME Add config
|
||||
|
||||
this->voice_bridge->callback_voice_data = [&](const pipes::buffer_view& buffer, bool a, bool b) {
|
||||
/* may somehow get the "real" packet size? */
|
||||
this->connectionStatistics->logIncomingPacket(stats::ConnectionStatistics::category::VOICE, buffer.length());
|
||||
this->handlePacketVoice(buffer, a, b);
|
||||
};
|
||||
this->voice_bridge->callback_voice_whisper_data = [&](const pipes::buffer_view& buffer, bool a) {
|
||||
/* may somehow get the "real" packet size? */
|
||||
this->connectionStatistics->logIncomingPacket(stats::ConnectionStatistics::category::VOICE, buffer.length());
|
||||
this->handlePacketVoiceWhisper(buffer, a);
|
||||
};
|
||||
this->voice_bridge->callback_initialized = [&](){
|
||||
debugMessage(this->getServerId(), "{} Voice bridge initialized!", CLIENT_STR_LOG_PREFIX);
|
||||
};
|
||||
@ -521,7 +534,7 @@ void WebClient::handleMessage(const std::string &message) {
|
||||
};
|
||||
|
||||
auto vbp = &*this->voice_bridge;
|
||||
voice_bridge_lock.unlock();
|
||||
voice_bridge_lock_.unlock();
|
||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
|
||||
if(vbp != &*this->voice_bridge) {
|
||||
@ -628,6 +641,8 @@ void WebClient::handleMessage(const std::string &message) {
|
||||
}
|
||||
this->js_ping.last_response = system_clock::now();
|
||||
this->js_ping.value = duration_cast<nanoseconds>(this->js_ping.last_response - this->js_ping.last_request);
|
||||
} else if(val["type"].asString() == "enable-raw-commands") {
|
||||
this->allow_raw_commands = true;
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
logError(this->server->getServerId(), "Could not handle json packet! Message {}", ex.what());
|
||||
@ -664,21 +679,18 @@ command_result WebClient::handleCommandClientInit(Command &command) {
|
||||
bool WebClient::shouldReceiveVoice(const std::shared_ptr<ConnectedClient> &sender) {
|
||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
if(!this->voice_bridge || !this->voice_bridge->voice_channel()) return false;
|
||||
|
||||
return SpeakingClient::shouldReceiveVoice(sender);
|
||||
}
|
||||
|
||||
void WebClient::handlePacketVoiceWhisper(const pipes::buffer_view &string, bool flag) {
|
||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
if(!this->voice_bridge || !this->voice_bridge->voice_channel()) return;
|
||||
SpeakingClient::handlePacketVoiceWhisper(string, flag);
|
||||
}
|
||||
|
||||
void WebClient::send_voice_packet(const pipes::buffer_view &view, const SpeakingClient::VoicePacketFlags &flags) {
|
||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
std::shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
if(this->voice_bridge) {
|
||||
auto channel = this->voice_bridge->voice_channel();
|
||||
if(channel) {
|
||||
channel->send(view);
|
||||
read_voice_bridge_lock.unlock();
|
||||
|
||||
/* may somehow get the "real" packet size? */
|
||||
this->connectionStatistics->logOutgoingPacket(stats::ConnectionStatistics::category::VOICE, view.length());
|
||||
}
|
||||
@ -686,6 +698,15 @@ void WebClient::send_voice_packet(const pipes::buffer_view &view, const Speaking
|
||||
}
|
||||
|
||||
void WebClient::send_voice_whisper_packet(const pipes::buffer_view &view, const SpeakingClient::VoicePacketFlags &flags) {
|
||||
logError(this->server->getServerId(), "Web client got whisper packet");
|
||||
//As well log the data!
|
||||
std::shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
||||
if(this->voice_bridge) {
|
||||
auto channel = this->voice_bridge->voice_whisper_channel();
|
||||
if(channel) {
|
||||
channel->send(view);
|
||||
read_voice_bridge_lock.unlock();
|
||||
|
||||
/* may somehow get the "real" packet size? */
|
||||
this->connectionStatistics->logOutgoingPacket(stats::ConnectionStatistics::category::VOICE, view.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
#include <json/json.h>
|
||||
#include <EventLoop.h>
|
||||
|
||||
namespace ts {
|
||||
namespace server {
|
||||
namespace ts::server {
|
||||
class WebControlServer;
|
||||
|
||||
class WebClient : public SpeakingClient {
|
||||
@ -25,7 +24,7 @@ namespace ts {
|
||||
~WebClient() override;
|
||||
|
||||
void sendJson(const Json::Value&);
|
||||
void sendCommand(const ts::Command &command, bool low = false) override;
|
||||
void sendCommand(const ts::Command &command, bool low) override;
|
||||
void sendCommand(const ts::command_builder &command, bool low) override;
|
||||
|
||||
bool disconnect(const std::string &reason) override;
|
||||
@ -33,11 +32,10 @@ namespace ts {
|
||||
|
||||
bool shouldReceiveVoice(const std::shared_ptr<ConnectedClient> &sender) override;
|
||||
|
||||
|
||||
inline std::chrono::nanoseconds client_ping() { return this->client_ping_layer_7(); }
|
||||
inline std::chrono::nanoseconds client_ping_layer_5() { return this->ping.value; }
|
||||
inline std::chrono::nanoseconds client_ping_layer_7() { return this->js_ping.value; }
|
||||
protected:
|
||||
void handlePacketVoiceWhisper(const pipes::buffer_view &string, bool) override;
|
||||
|
||||
protected:
|
||||
void tick(const std::chrono::system_clock::time_point&) override; /* Every 500ms */
|
||||
@ -83,8 +81,9 @@ namespace ts {
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
bool ssl_detected = false;
|
||||
bool ssl_encrypted = true;
|
||||
bool allow_raw_commands{false};
|
||||
bool ssl_detected{false};
|
||||
bool ssl_encrypted{true};
|
||||
pipes::SSL ssl_handler;
|
||||
pipes::WebSocket ws_handler;
|
||||
void handleMessageRead(int, short, void*);
|
||||
@ -113,6 +112,5 @@ namespace ts {
|
||||
command_result handleCommand(Command &command) override;
|
||||
command_result handleCommandClientInit(Command &command) override;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
@ -79,9 +79,19 @@ do { \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
std::string replace_all(std::string str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
inline bool execute_commands(sql::SqlManager* sql, std::string& error, const std::array<T, N>& commands) {
|
||||
std::string insert_or_ignore{sql->getType() == sql::TYPE_SQLITE ? "INSERT OR IGNORE" : "INSERT IGNORE"};
|
||||
std::string auto_increment{sql->getType() == sql::TYPE_SQLITE ? "AUTOINCREMENT" : "AUTO_INCREMENT"};
|
||||
for(const auto& cmd : commands) {
|
||||
std::string command{cmd};
|
||||
|
||||
@ -89,8 +99,8 @@ inline bool execute_commands(sql::SqlManager* sql, std::string& error, const std
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
|
||||
if(command.starts_with("[INSERT_OR_IGNORE]"))
|
||||
command = insert_or_ignore + command.substr(18);
|
||||
command = replace_all(command, "[INSERT_OR_IGNORE]", insert_or_ignore);
|
||||
command = replace_all(command, "[AUTO_INCREMENT]", auto_increment);
|
||||
|
||||
auto result = sql::command(sql, command).execute();
|
||||
if(!result) {
|
||||
@ -451,7 +461,7 @@ bool SqlDataManager::update_database(std::string &error) {
|
||||
case 12: {
|
||||
constexpr static std::string_view kCreateClientsV2{R"(
|
||||
CREATE TABLE `clients_v2` (
|
||||
`client_database_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
`client_database_id` INTEGER NOT NULL PRIMARY KEY [AUTO_INCREMENT],
|
||||
`client_unique_id` VARCHAR(40) UNIQUE,
|
||||
`client_created` BIGINT,
|
||||
`client_login_name` VARCHAR(20) UNIQUE
|
||||
@ -515,7 +525,7 @@ bool SqlDataManager::update_database(std::string &error) {
|
||||
"CREATE INDEX `idx_properties_serverid_id_value` ON `properties` (`serverId`, `id`, `key`);",
|
||||
"CREATE INDEX `idx_properties_serverid_id_type` ON `properties` (`serverId`, `id`, `type`);",
|
||||
|
||||
"CREATE TABLE `groups_v2` (`serverId` INT NOT NULL, `groupId` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `target` INT, `type` INT, `displayName` VARCHAR(128), `original_group_id` INTEGER);",
|
||||
"CREATE TABLE `groups_v2` (`serverId` INT NOT NULL, `groupId` INTEGER NOT NULL PRIMARY KEY [AUTO_INCREMENT], `target` INT, `type` INT, `displayName` VARCHAR(128), `original_group_id` INTEGER);",
|
||||
"INSERT INTO `groups_v2` (`serverId`, `groupId`, `target`, `type`, `displayName`) SELECT `serverId`, `groupId`, `target`, `type`, `displayName` FROM `groups`;",
|
||||
"DROP TABLE `groups`;",
|
||||
"ALTER TABLE `groups_v2` RENAME TO groups;",
|
||||
|
Loading…
x
Reference in New Issue
Block a user