mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 04:37:48 +02:00
Merge pull request #8098 from zzmp/feat/temp-domain-heartbeats
add heartbeats to metaverse for temporary domains
This commit is contained in:
commit
4510bb1674
7 changed files with 194 additions and 100 deletions
|
@ -457,6 +457,8 @@ function disonnectHighFidelityAccount() {
|
||||||
}, function(){
|
}, function(){
|
||||||
// we need to post to settings to clear the access-token
|
// we need to post to settings to clear the access-token
|
||||||
$(Settings.ACCESS_TOKEN_SELECTOR).val('').change();
|
$(Settings.ACCESS_TOKEN_SELECTOR).val('').change();
|
||||||
|
// reset the domain id to get a new temporary name
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).val('').change();
|
||||||
saveSettings();
|
saveSettings();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -555,7 +557,7 @@ function createNewDomainID(description, justConnected) {
|
||||||
// get the JSON object ready that we'll use to create a new domain
|
// get the JSON object ready that we'll use to create a new domain
|
||||||
var domainJSON = {
|
var domainJSON = {
|
||||||
"domain": {
|
"domain": {
|
||||||
"description": description
|
"private_description": description
|
||||||
},
|
},
|
||||||
"access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val()
|
"access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val()
|
||||||
}
|
}
|
||||||
|
@ -748,8 +750,8 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
||||||
_.each(data.data.domains, function(domain){
|
_.each(data.data.domains, function(domain){
|
||||||
var domainString = "";
|
var domainString = "";
|
||||||
|
|
||||||
if (domain.description) {
|
if (domain.private_description) {
|
||||||
domainString += '"' + domain.description + '" - ';
|
domainString += '"' + domain.private_description + '" - ';
|
||||||
}
|
}
|
||||||
|
|
||||||
domainString += domain.id;
|
domainString += domain.id;
|
||||||
|
|
|
@ -76,6 +76,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
setApplicationVersion(BuildInfo::VERSION);
|
setApplicationVersion(BuildInfo::VERSION);
|
||||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||||
|
|
||||||
|
qDebug() << "Setting up domain-server";
|
||||||
|
|
||||||
// make sure we have a fresh AccountManager instance
|
// make sure we have a fresh AccountManager instance
|
||||||
// (need this since domain-server can restart itself and maintain static variables)
|
// (need this since domain-server can restart itself and maintain static variables)
|
||||||
DependencyManager::set<AccountManager>();
|
DependencyManager::set<AccountManager>();
|
||||||
|
@ -104,23 +106,31 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions,
|
connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions,
|
||||||
&_gatekeeper, &DomainGatekeeper::updateNodePermissions);
|
&_gatekeeper, &DomainGatekeeper::updateNodePermissions);
|
||||||
|
|
||||||
if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) {
|
// if we were given a certificate/private key or oauth credentials they must succeed
|
||||||
// we either read a certificate and private key or were not passed one
|
if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) {
|
||||||
// and completed login or did not need to
|
return;
|
||||||
|
|
||||||
qDebug() << "Setting up LimitedNodeList and assignments.";
|
|
||||||
setupNodeListAndAssignments();
|
|
||||||
|
|
||||||
// setup automatic networking settings with data server
|
|
||||||
setupAutomaticNetworking();
|
|
||||||
|
|
||||||
// preload some user public keys so they can connect on first request
|
|
||||||
_gatekeeper.preloadAllowedUserPublicKeys();
|
|
||||||
|
|
||||||
optionallyGetTemporaryName(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupNodeListAndAssignments();
|
||||||
|
setupAutomaticNetworking();
|
||||||
|
if (!getID().isNull()) {
|
||||||
|
setupHeartbeatToMetaverse();
|
||||||
|
// send the first heartbeat immediately
|
||||||
|
sendHeartbeatToMetaverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for the temporary name parameter
|
||||||
|
const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name";
|
||||||
|
if (args.contains(GET_TEMPORARY_NAME_SWITCH)) {
|
||||||
|
getTemporaryName();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request
|
||||||
|
|
||||||
_metadata = new DomainMetadata(this);
|
_metadata = new DomainMetadata(this);
|
||||||
|
|
||||||
|
|
||||||
|
qDebug() << "domain-server is running";
|
||||||
}
|
}
|
||||||
|
|
||||||
DomainServer::~DomainServer() {
|
DomainServer::~DomainServer() {
|
||||||
|
@ -148,6 +158,10 @@ void DomainServer::restart() {
|
||||||
exit(DomainServer::EXIT_CODE_REBOOT);
|
exit(DomainServer::EXIT_CODE_REBOOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUuid& DomainServer::getID() {
|
||||||
|
return DependencyManager::get<LimitedNodeList>()->getSessionUUID();
|
||||||
|
}
|
||||||
|
|
||||||
bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
||||||
const QString X509_CERTIFICATE_OPTION = "cert";
|
const QString X509_CERTIFICATE_OPTION = "cert";
|
||||||
const QString X509_PRIVATE_KEY_OPTION = "key";
|
const QString X509_PRIVATE_KEY_OPTION = "key";
|
||||||
|
@ -233,34 +247,26 @@ bool DomainServer::optionallySetupOAuth() {
|
||||||
|
|
||||||
static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
||||||
|
|
||||||
void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
|
void DomainServer::getTemporaryName(bool force) {
|
||||||
// check for the temporary name parameter
|
// check if we already have a domain ID
|
||||||
const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name";
|
const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||||
|
|
||||||
if (arguments.contains(GET_TEMPORARY_NAME_SWITCH)) {
|
qInfo() << "Requesting temporary domain name";
|
||||||
|
if (idValueVariant) {
|
||||||
// make sure we don't already have a domain ID
|
qDebug() << "A domain ID is already present in domain-server settings:" << idValueVariant->toString();
|
||||||
const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH);
|
if (force) {
|
||||||
if (idValueVariant) {
|
qDebug() << "Requesting temporary domain name to replace current ID:" << getID();
|
||||||
qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."
|
} else {
|
||||||
<< "Will not request temporary name.";
|
qInfo() << "Abandoning request of temporary domain name.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we've been asked to grab a temporary name from the API
|
|
||||||
// so fire off that request now
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
|
||||||
|
|
||||||
// get callbacks for temporary domain result
|
|
||||||
JSONCallbackParameters callbackParameters;
|
|
||||||
callbackParameters.jsonCallbackReceiver = this;
|
|
||||||
callbackParameters.jsonCallbackMethod = "handleTempDomainSuccess";
|
|
||||||
callbackParameters.errorCallbackReceiver = this;
|
|
||||||
callbackParameters.errorCallbackMethod = "handleTempDomainError";
|
|
||||||
|
|
||||||
accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
|
|
||||||
QNetworkAccessManager::PostOperation, callbackParameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// request a temporary name from the metaverse
|
||||||
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
JSONCallbackParameters callbackParameters { this, "handleTempDomainSuccess", this, "handleTempDomainError" };
|
||||||
|
accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
|
||||||
|
QNetworkAccessManager::PostOperation, callbackParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||||
|
@ -271,11 +277,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||||
static const QString DOMAIN_KEY = "domain";
|
static const QString DOMAIN_KEY = "domain";
|
||||||
static const QString ID_KEY = "id";
|
static const QString ID_KEY = "id";
|
||||||
static const QString NAME_KEY = "name";
|
static const QString NAME_KEY = "name";
|
||||||
|
static const QString KEY_KEY = "api_key";
|
||||||
|
|
||||||
auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject();
|
auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject();
|
||||||
if (!domainObject.isEmpty()) {
|
if (!domainObject.isEmpty()) {
|
||||||
auto id = domainObject[ID_KEY].toString();
|
auto id = domainObject[ID_KEY].toString();
|
||||||
auto name = domainObject[NAME_KEY].toString();
|
auto name = domainObject[NAME_KEY].toString();
|
||||||
|
auto key = domainObject[KEY_KEY].toString();
|
||||||
|
|
||||||
qInfo() << "Received new temporary domain name" << name;
|
qInfo() << "Received new temporary domain name" << name;
|
||||||
qDebug() << "The temporary domain ID is" << id;
|
qDebug() << "The temporary domain ID is" << id;
|
||||||
|
@ -291,9 +299,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||||
// change our domain ID immediately
|
// change our domain ID immediately
|
||||||
DependencyManager::get<LimitedNodeList>()->setSessionUUID(QUuid { id });
|
DependencyManager::get<LimitedNodeList>()->setSessionUUID(QUuid { id });
|
||||||
|
|
||||||
// change our automatic networking settings so that we're communicating with the ICE server
|
// store the new token to the account info
|
||||||
setupICEHeartbeatForFullNetworking();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
|
accountManager->setTemporaryDomain(id, key);
|
||||||
|
|
||||||
|
// update our heartbeats to use the correct id
|
||||||
|
setupICEHeartbeatForFullNetworking();
|
||||||
|
setupHeartbeatToMetaverse();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again"
|
qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again"
|
||||||
<< "via domain-server relaunch or from the domain-server settings.";
|
<< "via domain-server relaunch or from the domain-server settings.";
|
||||||
|
@ -332,8 +344,7 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
void DomainServer::setupNodeListAndAssignments() {
|
||||||
|
|
||||||
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
||||||
|
|
||||||
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
||||||
|
@ -458,29 +469,23 @@ bool DomainServer::resetAccountManagerAccessToken() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::setupAutomaticNetworking() {
|
void DomainServer::setupAutomaticNetworking() {
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting;
|
||||||
|
|
||||||
|
resetAccountManagerAccessToken();
|
||||||
|
|
||||||
_automaticNetworkingSetting =
|
_automaticNetworkingSetting =
|
||||||
_settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString();
|
_settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString();
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
const QUuid& domainID = getID();
|
||||||
|
|
||||||
if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
||||||
setupICEHeartbeatForFullNetworking();
|
setupICEHeartbeatForFullNetworking();
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasAccessToken = resetAccountManagerAccessToken();
|
|
||||||
|
|
||||||
if (!_hasAccessToken) {
|
|
||||||
qDebug() << "Will not send heartbeat to Metaverse API without an access token.";
|
|
||||||
qDebug() << "If this is not a temporary domain add an access token to your config file or via the web interface.";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE ||
|
if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE ||
|
||||||
_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) {
|
||||||
|
|
||||||
const QUuid& domainID = nodeList->getSessionUUID();
|
|
||||||
|
|
||||||
if (!domainID.isNull()) {
|
if (!domainID.isNull()) {
|
||||||
qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID"
|
qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID"
|
||||||
<< uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString();
|
<< uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString();
|
||||||
|
@ -492,9 +497,6 @@ void DomainServer::setupAutomaticNetworking() {
|
||||||
|
|
||||||
// have the LNL enable public socket updating via STUN
|
// have the LNL enable public socket updating via STUN
|
||||||
nodeList->startSTUNPublicSocketUpdate();
|
nodeList->startSTUNPublicSocketUpdate();
|
||||||
} else {
|
|
||||||
// send our heartbeat to data server so it knows what our network settings are
|
|
||||||
sendHeartbeatToMetaverse();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
|
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
|
||||||
|
@ -502,18 +504,20 @@ void DomainServer::setupAutomaticNetworking() {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sendHeartbeatToMetaverse();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting;
|
void DomainServer::setupHeartbeatToMetaverse() {
|
||||||
|
// heartbeat to the data-server every 15s
|
||||||
// no matter the auto networking settings we should heartbeat to the data-server every 15s
|
|
||||||
const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000;
|
const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000;
|
||||||
|
|
||||||
QTimer* dataHeartbeatTimer = new QTimer(this);
|
if (!_metaverseHeartbeatTimer) {
|
||||||
connect(dataHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse()));
|
// setup a timer to heartbeat with the metaverse-server
|
||||||
dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS);
|
_metaverseHeartbeatTimer = new QTimer { this };
|
||||||
|
connect(_metaverseHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse()));
|
||||||
|
// do not send a heartbeat immediately - this avoids flooding if the heartbeat fails with a 401
|
||||||
|
_metaverseHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::setupICEHeartbeatForFullNetworking() {
|
void DomainServer::setupICEHeartbeatForFullNetworking() {
|
||||||
|
@ -532,22 +536,21 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
|
||||||
limitedNodeList->startSTUNPublicSocketUpdate();
|
limitedNodeList->startSTUNPublicSocketUpdate();
|
||||||
|
|
||||||
// to send ICE heartbeats we'd better have a private key locally with an uploaded public key
|
// to send ICE heartbeats we'd better have a private key locally with an uploaded public key
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
|
||||||
auto domainID = accountManager->getAccountInfo().getDomainID();
|
|
||||||
|
|
||||||
// if we have an access token and we don't have a private key or the current domain ID has changed
|
// if we have an access token and we don't have a private key or the current domain ID has changed
|
||||||
// we should generate a new keypair
|
// we should generate a new keypair
|
||||||
if (!accountManager->getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
|
if (!accountManager->getAccountInfo().hasPrivateKey() || accountManager->getAccountInfo().getDomainID() != getID()) {
|
||||||
|
accountManager->generateNewDomainKeypair(getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
// hookup to the signal from account manager that tells us when keypair is available
|
// hookup to the signal from account manager that tells us when keypair is available
|
||||||
connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
|
connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
|
||||||
|
|
||||||
if (!_iceHeartbeatTimer) {
|
if (!_iceHeartbeatTimer) {
|
||||||
// setup a timer to heartbeat with the ice-server every so often
|
// setup a timer to heartbeat with the ice-server
|
||||||
_iceHeartbeatTimer = new QTimer { this };
|
_iceHeartbeatTimer = new QTimer { this };
|
||||||
connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer);
|
connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer);
|
||||||
|
sendHeartbeatToIceServer();
|
||||||
_iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
_iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1075,9 +1078,6 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
|
||||||
const QUuid& domainID = nodeList->getSessionUUID();
|
|
||||||
|
|
||||||
// Setup the domain object to send to the data server
|
// Setup the domain object to send to the data server
|
||||||
QJsonObject domainObject;
|
QJsonObject domainObject;
|
||||||
|
|
||||||
|
@ -1096,6 +1096,13 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
||||||
NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous);
|
NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous);
|
||||||
domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain;
|
domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain;
|
||||||
|
|
||||||
|
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
|
||||||
|
if (!temporaryDomainKey.isEmpty()) {
|
||||||
|
// add the temporary domain token
|
||||||
|
const QString KEY_KEY = "api_key";
|
||||||
|
domainObject[KEY_KEY] = temporaryDomainKey;
|
||||||
|
}
|
||||||
|
|
||||||
if (_metadata) {
|
if (_metadata) {
|
||||||
// Add the metadata to the heartbeat
|
// Add the metadata to the heartbeat
|
||||||
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
|
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
|
||||||
|
@ -1105,18 +1112,60 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
||||||
QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact)));
|
QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact)));
|
||||||
|
|
||||||
static const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
|
static const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
|
||||||
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
|
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())),
|
||||||
AccountManagerAuth::Required,
|
AccountManagerAuth::Optional,
|
||||||
QNetworkAccessManager::PutOperation,
|
QNetworkAccessManager::PutOperation,
|
||||||
JSONCallbackParameters(),
|
JSONCallbackParameters(nullptr, QString(), this, "handleMetaverseHeartbeatError"),
|
||||||
domainUpdateJSON.toUtf8());
|
domainUpdateJSON.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) {
|
||||||
|
if (!_metaverseHeartbeatTimer) {
|
||||||
|
// avoid rehandling errors from the same issue
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we need to force a new temporary domain name
|
||||||
|
switch (requestReply.error()) {
|
||||||
|
// if we have a temporary domain with a bad token, we get a 401
|
||||||
|
case QNetworkReply::NetworkError::AuthenticationRequiredError: {
|
||||||
|
static const QString DATA_KEY = "data";
|
||||||
|
static const QString TOKEN_KEY = "api_key";
|
||||||
|
|
||||||
|
QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
|
||||||
|
auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY];
|
||||||
|
|
||||||
|
if (!tokenFailure.isNull()) {
|
||||||
|
qWarning() << "Temporary domain name lacks a valid API key, and is being reset.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// if the domain does not (or no longer) exists, we get a 404
|
||||||
|
case QNetworkReply::NetworkError::ContentNotFoundError:
|
||||||
|
qWarning() << "Domain not found, getting a new temporary domain.";
|
||||||
|
break;
|
||||||
|
// otherwise, we erred on something else, and should not force a temporary domain
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// halt heartbeats until we have a token
|
||||||
|
_metaverseHeartbeatTimer->deleteLater();
|
||||||
|
_metaverseHeartbeatTimer = nullptr;
|
||||||
|
|
||||||
|
// give up eventually to avoid flooding traffic
|
||||||
|
static const int MAX_ATTEMPTS = 5;
|
||||||
|
static int attempt = 0;
|
||||||
|
if (++attempt < MAX_ATTEMPTS) {
|
||||||
|
// get a new temporary name and token
|
||||||
|
getTemporaryName(true);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Already attempted too many temporary domain requests. Please set a domain ID manually or restart.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
||||||
if (!_iceServerSocket.isNull()) {
|
if (!_iceServerSocket.isNull()) {
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
|
||||||
const QUuid& domainID = nodeList->getSessionUUID();
|
|
||||||
|
|
||||||
const QString ICE_SERVER_ADDRESS = "ice_server_address";
|
const QString ICE_SERVER_ADDRESS = "ice_server_address";
|
||||||
|
|
||||||
QJsonObject domainObject;
|
QJsonObject domainObject;
|
||||||
|
@ -1124,6 +1173,13 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
||||||
// we're using full automatic networking and we have a current ice-server socket, use that now
|
// we're using full automatic networking and we have a current ice-server socket, use that now
|
||||||
domainObject[ICE_SERVER_ADDRESS] = _iceServerSocket.getAddress().toString();
|
domainObject[ICE_SERVER_ADDRESS] = _iceServerSocket.getAddress().toString();
|
||||||
|
|
||||||
|
const auto& temporaryDomainKey = DependencyManager::get<AccountManager>()->getTemporaryDomainKey(getID());
|
||||||
|
if (!temporaryDomainKey.isEmpty()) {
|
||||||
|
// add the temporary domain token
|
||||||
|
const QString KEY_KEY = "api_key";
|
||||||
|
domainObject[KEY_KEY] = temporaryDomainKey;
|
||||||
|
}
|
||||||
|
|
||||||
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
|
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
|
||||||
|
|
||||||
// make sure we hear about failure so we can retry
|
// make sure we hear about failure so we can retry
|
||||||
|
@ -1135,7 +1191,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
||||||
|
|
||||||
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
|
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
|
||||||
|
|
||||||
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
|
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())),
|
||||||
AccountManagerAuth::Optional,
|
AccountManagerAuth::Optional,
|
||||||
QNetworkAccessManager::PutOperation,
|
QNetworkAccessManager::PutOperation,
|
||||||
callbackParameters,
|
callbackParameters,
|
||||||
|
|
|
@ -80,6 +80,8 @@ private slots:
|
||||||
void handleTempDomainSuccess(QNetworkReply& requestReply);
|
void handleTempDomainSuccess(QNetworkReply& requestReply);
|
||||||
void handleTempDomainError(QNetworkReply& requestReply);
|
void handleTempDomainError(QNetworkReply& requestReply);
|
||||||
|
|
||||||
|
void handleMetaverseHeartbeatError(QNetworkReply& requestReply);
|
||||||
|
|
||||||
void queuedQuit(QString quitMessage, int exitCode);
|
void queuedQuit(QString quitMessage, int exitCode);
|
||||||
|
|
||||||
void handleKeypairChange();
|
void handleKeypairChange();
|
||||||
|
@ -96,11 +98,13 @@ signals:
|
||||||
void userDisconnected();
|
void userDisconnected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
const QUuid& getID();
|
||||||
|
|
||||||
|
void setupNodeListAndAssignments();
|
||||||
bool optionallySetupOAuth();
|
bool optionallySetupOAuth();
|
||||||
bool optionallyReadX509KeyAndCertificate();
|
bool optionallyReadX509KeyAndCertificate();
|
||||||
|
|
||||||
void optionallyGetTemporaryName(const QStringList& arguments);
|
void getTemporaryName(bool force = false);
|
||||||
|
|
||||||
static bool packetVersionMatch(const udt::Packet& packet);
|
static bool packetVersionMatch(const udt::Packet& packet);
|
||||||
|
|
||||||
|
@ -108,6 +112,7 @@ private:
|
||||||
|
|
||||||
void setupAutomaticNetworking();
|
void setupAutomaticNetworking();
|
||||||
void setupICEHeartbeatForFullNetworking();
|
void setupICEHeartbeatForFullNetworking();
|
||||||
|
void setupHeartbeatToMetaverse();
|
||||||
void sendHeartbeatToMetaverse(const QString& networkAddress);
|
void sendHeartbeatToMetaverse(const QString& networkAddress);
|
||||||
|
|
||||||
void randomizeICEServerAddress(bool shouldTriggerHostLookup);
|
void randomizeICEServerAddress(bool shouldTriggerHostLookup);
|
||||||
|
@ -178,6 +183,7 @@ private:
|
||||||
// These will be parented to this, they are not dangling
|
// These will be parented to this, they are not dangling
|
||||||
DomainMetadata* _metadata { nullptr };
|
DomainMetadata* _metadata { nullptr };
|
||||||
QTimer* _iceHeartbeatTimer { nullptr };
|
QTimer* _iceHeartbeatTimer { nullptr };
|
||||||
|
QTimer* _metaverseHeartbeatTimer { nullptr };
|
||||||
|
|
||||||
QList<QHostAddress> _iceServerAddresses;
|
QList<QHostAddress> _iceServerAddresses;
|
||||||
QSet<QHostAddress> _failedIceServerAddresses;
|
QSet<QHostAddress> _failedIceServerAddresses;
|
||||||
|
@ -186,8 +192,6 @@ private:
|
||||||
int _numHeartbeatDenials { 0 };
|
int _numHeartbeatDenials { 0 };
|
||||||
bool _connectedToICEServer { false };
|
bool _connectedToICEServer { false };
|
||||||
|
|
||||||
bool _hasAccessToken { false };
|
|
||||||
|
|
||||||
friend class DomainGatekeeper;
|
friend class DomainGatekeeper;
|
||||||
friend class DomainMetadata;
|
friend class DomainMetadata;
|
||||||
};
|
};
|
||||||
|
|
|
@ -474,6 +474,11 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken)
|
||||||
persistAccountToFile();
|
persistAccountToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AccountManager::setTemporaryDomain(const QUuid& domainID, const QString& key) {
|
||||||
|
_accountInfo.setTemporaryDomain(domainID, key);
|
||||||
|
persistAccountToFile();
|
||||||
|
}
|
||||||
|
|
||||||
void AccountManager::requestAccessToken(const QString& login, const QString& password) {
|
void AccountManager::requestAccessToken(const QString& login, const QString& password) {
|
||||||
|
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
@ -650,22 +655,33 @@ void AccountManager::processGeneratedKeypair() {
|
||||||
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key";
|
||||||
|
|
||||||
QString uploadPath;
|
QString uploadPath;
|
||||||
if (keypairGenerator->getDomainID().isNull()) {
|
const auto& domainID = keypairGenerator->getDomainID();
|
||||||
|
if (domainID.isNull()) {
|
||||||
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
|
||||||
} else {
|
} else {
|
||||||
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(keypairGenerator->getDomainID()));
|
uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup a multipart upload to send up the public key
|
// setup a multipart upload to send up the public key
|
||||||
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||||
|
|
||||||
QHttpPart keyPart;
|
QHttpPart publicKeyPart;
|
||||||
keyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||||
keyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
|
||||||
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
|
||||||
keyPart.setBody(keypairGenerator->getPublicKey());
|
|
||||||
|
|
||||||
requestMultiPart->append(keyPart);
|
publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||||
|
QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
|
||||||
|
publicKeyPart.setBody(keypairGenerator->getPublicKey());
|
||||||
|
requestMultiPart->append(publicKeyPart);
|
||||||
|
|
||||||
|
if (!domainID.isNull()) {
|
||||||
|
const auto& key = getTemporaryDomainKey(domainID);
|
||||||
|
QHttpPart apiKeyPart;
|
||||||
|
publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||||
|
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||||
|
QVariant("form-data; name=\"api_key\""));
|
||||||
|
apiKeyPart.setBody(key.toUtf8());
|
||||||
|
requestMultiPart->append(apiKeyPart);
|
||||||
|
}
|
||||||
|
|
||||||
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
// setup callback parameters so we know once the keypair upload has succeeded or failed
|
||||||
JSONCallbackParameters callbackParameters;
|
JSONCallbackParameters callbackParameters;
|
||||||
|
|
|
@ -89,6 +89,9 @@ public:
|
||||||
QUuid getSessionID() const { return _sessionID; }
|
QUuid getSessionID() const { return _sessionID; }
|
||||||
void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; }
|
void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; }
|
||||||
|
|
||||||
|
void setTemporaryDomain(const QUuid& domainID, const QString& key);
|
||||||
|
const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestAccessToken(const QString& login, const QString& password);
|
void requestAccessToken(const QString& login, const QString& password);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const QString DataServerAccountInfo::EMPTY_KEY = QString();
|
||||||
|
|
||||||
DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() {
|
DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() {
|
||||||
_accessToken = otherInfo._accessToken;
|
_accessToken = otherInfo._accessToken;
|
||||||
_username = otherInfo._username;
|
_username = otherInfo._username;
|
||||||
|
@ -33,6 +35,8 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI
|
||||||
_walletID = otherInfo._walletID;
|
_walletID = otherInfo._walletID;
|
||||||
_privateKey = otherInfo._privateKey;
|
_privateKey = otherInfo._privateKey;
|
||||||
_domainID = otherInfo._domainID;
|
_domainID = otherInfo._domainID;
|
||||||
|
_temporaryDomainID = otherInfo._temporaryDomainID;
|
||||||
|
_temporaryDomainApiKey = otherInfo._temporaryDomainApiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) {
|
DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) {
|
||||||
|
@ -51,6 +55,8 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
|
||||||
swap(_walletID, otherInfo._walletID);
|
swap(_walletID, otherInfo._walletID);
|
||||||
swap(_privateKey, otherInfo._privateKey);
|
swap(_privateKey, otherInfo._privateKey);
|
||||||
swap(_domainID, otherInfo._domainID);
|
swap(_domainID, otherInfo._domainID);
|
||||||
|
swap(_temporaryDomainID, otherInfo._temporaryDomainID);
|
||||||
|
swap(_temporaryDomainApiKey, otherInfo._temporaryDomainApiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
||||||
|
@ -145,13 +151,14 @@ QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) {
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
|
||||||
out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey
|
out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey
|
||||||
<< info._walletID << info._privateKey << info._domainID;
|
<< info._walletID << info._privateKey << info._domainID
|
||||||
|
<< info._temporaryDomainID << info._temporaryDomainApiKey;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) {
|
QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) {
|
||||||
in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey
|
in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey
|
||||||
>> info._walletID >> info._privateKey >> info._domainID;
|
>> info._walletID >> info._privateKey >> info._domainID
|
||||||
|
>> info._temporaryDomainID >> info._temporaryDomainApiKey;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ const float SATOSHIS_PER_CREDIT = 100000000.0f;
|
||||||
|
|
||||||
class DataServerAccountInfo : public QObject {
|
class DataServerAccountInfo : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
const static QString EMPTY_KEY;
|
||||||
public:
|
public:
|
||||||
DataServerAccountInfo() {};
|
DataServerAccountInfo() {};
|
||||||
DataServerAccountInfo(const DataServerAccountInfo& otherInfo);
|
DataServerAccountInfo(const DataServerAccountInfo& otherInfo);
|
||||||
|
@ -52,6 +53,9 @@ public:
|
||||||
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
|
void setDomainID(const QUuid& domainID) { _domainID = domainID; }
|
||||||
const QUuid& getDomainID() const { return _domainID; }
|
const QUuid& getDomainID() const { return _domainID; }
|
||||||
|
|
||||||
|
void setTemporaryDomain(const QUuid& domainID, const QString& key) { _temporaryDomainID = domainID; _temporaryDomainApiKey = key; }
|
||||||
|
const QString& getTemporaryDomainKey(const QUuid& domainID) { return domainID == _temporaryDomainID ? _temporaryDomainApiKey : EMPTY_KEY; }
|
||||||
|
|
||||||
bool hasProfile() const;
|
bool hasProfile() const;
|
||||||
|
|
||||||
void setProfileInfoFromJSON(const QJsonObject& jsonObject);
|
void setProfileInfoFromJSON(const QJsonObject& jsonObject);
|
||||||
|
@ -67,7 +71,9 @@ private:
|
||||||
QString _xmppPassword;
|
QString _xmppPassword;
|
||||||
QString _discourseApiKey;
|
QString _discourseApiKey;
|
||||||
QUuid _walletID;
|
QUuid _walletID;
|
||||||
QUuid _domainID; // if this holds account info for a domain, this holds the ID of that domain
|
QUuid _domainID;
|
||||||
|
QUuid _temporaryDomainID;
|
||||||
|
QString _temporaryDomainApiKey;
|
||||||
QByteArray _privateKey;
|
QByteArray _privateKey;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue