From f4911431d5a405e864b10b9819ffe8e9824e1b7f Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Fri, 28 Apr 2017 18:00:16 +0300
Subject: [PATCH] Request, parse and apply phone.getCallConfig.

---
 Telegram/SourceFiles/calls/calls_call.cpp     |  4 ++
 Telegram/SourceFiles/calls/calls_call.h       |  2 +
 Telegram/SourceFiles/calls/calls_instance.cpp | 68 +++++++++++++++++++
 Telegram/SourceFiles/calls/calls_instance.h   |  7 +-
 4 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp
index 0c73952f2..5c19916e2 100644
--- a/Telegram/SourceFiles/calls/calls_call.cpp
+++ b/Telegram/SourceFiles/calls/calls_call.cpp
@@ -530,4 +530,8 @@ Call::~Call() {
 	}
 }
 
+void UpdateConfig(const std::map<std::string, std::string> &data) {
+	tgvoip::ServerConfig::GetSharedInstance()->Update(data);
+}
+
 } // namespace Calls
diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h
index 829619e41..184d28776 100644
--- a/Telegram/SourceFiles/calls/calls_call.h
+++ b/Telegram/SourceFiles/calls/calls_call.h
@@ -152,4 +152,6 @@ private:
 
 };
 
+void UpdateConfig(const std::map<std::string, std::string> &data);
+
 } // namespace Calls
diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp
index bd44aaaca..547ee78f8 100644
--- a/Telegram/SourceFiles/calls/calls_instance.cpp
+++ b/Telegram/SourceFiles/calls/calls_instance.cpp
@@ -26,6 +26,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "calls/calls_panel.h"
 
 namespace Calls {
+namespace {
+
+constexpr auto kServerConfigUpdateTimeoutMs = 24 * 3600 * TimeMs(1000);
+
+} // namespace
 
 Instance::Instance() = default;
 
@@ -57,6 +62,7 @@ void Instance::createCall(gsl::not_null<UserData*> user, Call::Type type) {
 	_currentCall = std::make_unique<Call>(getCallDelegate(), user, type);
 	_currentCallPanel = std::make_unique<Panel>(_currentCall.get());
 	_currentCallChanged.notify(_currentCall.get(), true);
+	refreshServerConfig();
 	refreshDhConfig();
 }
 
@@ -105,7 +111,69 @@ void Instance::refreshDhConfig() {
 		}
 		callFailed(call.get());
 	}).send();
+}
 
+void Instance::refreshServerConfig() {
+	if (_serverConfigRequestId) {
+		return;
+	}
+	if (_lastServerConfigUpdateTime && (getms(true) - _lastServerConfigUpdateTime) < kServerConfigUpdateTimeoutMs) {
+		return;
+	}
+	_serverConfigRequestId = request(MTPphone_GetCallConfig()).done([this](const MTPDataJSON &result) {
+		_serverConfigRequestId = 0;
+		_lastServerConfigUpdateTime = getms(true);
+
+		auto configUpdate = std::map<std::string, std::string>();
+		auto bytes = bytesFromMTP(result.c_dataJSON().vdata);
+		auto error = QJsonParseError { 0, QJsonParseError::NoError };
+		auto document = QJsonDocument::fromJson(QByteArray::fromRawData(reinterpret_cast<const char*>(bytes.data()), bytes.size()), &error);
+		if (error.error != QJsonParseError::NoError) {
+			LOG(("API Error: Faild to parse call config JSON, error: %1").arg(error.errorString()));
+			return;
+		} else if (!document.isObject()) {
+			LOG(("API Error: Not an object received in call config JSON."));
+			return;
+		}
+
+		auto parseValue = [](QJsonValueRef data) -> std::string {
+			switch (data.type()) {
+			case QJsonValue::String: return data.toString().toStdString();
+			case QJsonValue::Double: return QString::number(data.toDouble(), 'f').toStdString();
+			case QJsonValue::Bool: return data.toBool() ? "true" : "false";
+			case QJsonValue::Null: {
+				LOG(("API Warning: null field in call config JSON."));
+			} return "null";
+			case QJsonValue::Undefined: {
+				LOG(("API Warning: undefined field in call config JSON."));
+			} return "undefined";
+			case QJsonValue::Object:
+			case QJsonValue::Array: {
+				LOG(("API Warning: complex field in call config JSON."));
+				QJsonDocument serializer;
+				if (data.isArray()) {
+					serializer.setArray(data.toArray());
+				} else {
+					serializer.setObject(data.toObject());
+				}
+				auto byteArray = serializer.toJson(QJsonDocument::Compact);
+				return std::string(byteArray.constData(), byteArray.size());
+			} break;
+			}
+			Unexpected("Type in Json parse.");
+		};
+
+		auto object = document.object();
+		for (auto i = object.begin(), e = object.end(); i != e; ++i) {
+			auto key = i.key().toStdString();
+			auto value = parseValue(i.value());
+			configUpdate[key] = value;
+		}
+
+		UpdateConfig(configUpdate);
+	}).fail([this](const RPCError &error) {
+		_serverConfigRequestId = 0;
+	}).send();
 }
 
 void Instance::handleUpdate(const MTPDupdatePhoneCall& update) {
diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h
index f0155f132..ae5b21e58 100644
--- a/Telegram/SourceFiles/calls/calls_instance.h
+++ b/Telegram/SourceFiles/calls/calls_instance.h
@@ -55,13 +55,18 @@ private:
 	void callFinished(gsl::not_null<Call*> call) override;
 	void callFailed(gsl::not_null<Call*> call) override;
 	void createCall(gsl::not_null<UserData*> user, Call::Type type);
-	void refreshDhConfig();
 	void destroyCall(gsl::not_null<Call*> call);
 
+	void refreshDhConfig();
+	void refreshServerConfig();
+
 	void handleCallUpdate(const MTPPhoneCall &call);
 
 	DhConfig _dhConfig;
 
+	TimeMs _lastServerConfigUpdateTime = 0;
+	mtpRequestId _serverConfigRequestId = 0;
+
 	std::unique_ptr<Call> _currentCall;
 	std::unique_ptr<Panel> _currentCallPanel;
 	base::Observable<Call*> _currentCallChanged;