This commit is contained in:
Philip Rosedale 2014-10-08 15:28:56 -07:00
commit cdd60dead2
35 changed files with 620 additions and 200 deletions

View file

@ -206,7 +206,7 @@ void Agent::run() {
scriptURL = QUrl(_payload); scriptURL = QUrl(_payload);
} }
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL)); QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
QNetworkDiskCache* cache = new QNetworkDiskCache(); QNetworkDiskCache* cache = new QNetworkDiskCache();

View file

@ -59,6 +59,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_POOL_OPTION = "pool";
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
Assignment::Type requestAssignmentType = Assignment::AllTypes; Assignment::Type requestAssignmentType = Assignment::AllTypes;
@ -87,17 +88,29 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
// create a NodeList as an unassigned client // create a NodeList as an unassigned client
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned);
unsigned short assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT;
// check for an overriden assignment server port
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) {
assignmentServerPort =
argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt();
}
HifiSockAddr assignmentServerSocket(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, assignmentServerPort);
// check for an overriden assignment server hostname // check for an overriden assignment server hostname
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); _assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
// set the custom assignment socket on our NodeList // change the hostname for our assignment server
HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerSocket.getPort());
nodeList->setAssignmentServerSocket(customAssignmentSocket);
} }
nodeList->setAssignmentServerSocket(assignmentServerSocket);
qDebug() << "Assignment server socket is" << assignmentServerSocket;
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
qDebug() << "Waiting for assignment -" << _requestAssignment; qDebug() << "Waiting for assignment -" << _requestAssignment;

View file

@ -940,7 +940,7 @@ void OctreeServer::run() {
qDebug("--statusHost=%s", statusHost); qDebug("--statusHost=%s", statusHost);
_statusHost = statusHost; _statusHost = statusHost;
} else { } else {
_statusHost = QHostAddress(getHostOrderLocalAddress()).toString(); _statusHost = getLocalAddress().toString();
} }
qDebug("statusHost=%s", qPrintable(_statusHost)); qDebug("statusHost=%s", qPrintable(_statusHost));

View file

@ -33,6 +33,14 @@
"label": "None: use the network information I have entered for this domain at data.highfidelity.io" "label": "None: use the network information I have entered for this domain at data.highfidelity.io"
} }
] ]
},
{
"name": "local_port",
"label": "Local UDP Port",
"help": "This is the local port your domain-server binds to for UDP connections.<br/>Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.",
"default": "40102",
"type": "int",
"advanced": true
} }
] ]
}, },
@ -51,6 +59,19 @@
"type": "password", "type": "password",
"help": "Password used for basic HTTP authentication. Leave this blank if you do not want to change it.", "help": "Password used for basic HTTP authentication. Leave this blank if you do not want to change it.",
"value-hidden": true "value-hidden": true
},
{
"name": "allowed_users",
"type": "table",
"label": "Allowed Users",
"help": "A list of usernames for the High Fidelity users you want to allow into your domain. Users not found in this list will not be allowed to connect.",
"numbered": false,
"can_add": true,
"can_delete": true,
"key": {
"name": "username",
"label": "Username"
}
} }
] ]
}, },
@ -59,10 +80,44 @@
"label": "Audio", "label": "Audio",
"assignment-types": [0], "assignment-types": [0],
"settings": [ "settings": [
{
"name": "zones",
"type": "table",
"label": "Zones",
"help": "In this table you can define a set of zones in which you can specify various audio properties.",
"numbered": false,
"can_add": true,
"can_delete": true,
"key": {
"name": "name",
"label": "Name",
"placeholder": "Zone name"
},
"columns": [
{
"name": "x_range",
"label": "X range",
"can_set": true,
"placeholder": "0-16384"
},
{
"name": "y_range",
"label": "Y range",
"can_set": true,
"placeholder": "0-16384"
},
{
"name": "z_range",
"label": "Z range",
"can_set": true,
"placeholder": "0-16384"
}
]
},
{ {
"name": "enable_filter", "name": "enable_filter",
"type": "checkbox", "type": "checkbox",
"label": "Enable Positional Filter", "label": "Positional filter",
"help": "positional audio stream uses lowpass filter", "help": "positional audio stream uses lowpass filter",
"default": true "default": true
}, },

View file

@ -74,3 +74,12 @@ span.port {
width: 100%; width: 100%;
margin-bottom: 15px; margin-bottom: 15px;
} }
td.buttons {
width: 14px;
}
td.buttons .glyphicon {
display: block;
text-align: center;
}

View file

@ -25,10 +25,12 @@ var viewHelpers = {
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>" form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>" form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
form_group += "<label for='" + setting_name + "'>" form_group += "<label for='" + setting_name + "'>"
form_group += "<input type='checkbox' name='" + setting_name + "' " + form_group += "<input type='checkbox' name='" + setting_name + "' " +
(setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>" (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
form_group += " " + setting.help + "</label>"; form_group += " " + setting.help + "</label>";
form_group += "</div>" form_group += "</div>"
} else if (setting.type === 'table') {
form_group += makeTable(setting, setting_name, setting_value);
} else { } else {
input_type = _.has(setting, 'type') ? setting.type : "text" input_type = _.has(setting, 'type') ? setting.type : "text"
@ -39,13 +41,18 @@ var viewHelpers = {
_.each(setting.options, function(option) { _.each(setting.options, function(option) {
form_group += "<option value='" + option.value + "'" + form_group += "<option value='" + option.value + "'" +
(option.value == setting_value ? 'selected' : '') + ">" + option.label + "</option>" (option.value == setting_value ? 'selected' : '') + ">" + option.label + "</option>"
}) })
form_group += "</select>" form_group += "</select>"
form_group += "<input type='hidden' name='" + setting_name + "' value='" + setting_value + "'>" form_group += "<input type='hidden' name='" + setting_name + "' value='" + setting_value + "'>"
} else { } else {
if (input_type == 'integer') {
input_type = "text"
}
form_group += "<input type='" + input_type + "' class='form-control' name='" + setting_name + form_group += "<input type='" + input_type + "' class='form-control' name='" + setting_name +
"' placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") + "' placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
"' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>" "' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>"
@ -69,17 +76,101 @@ $(document).ready(function(){
*/ */
$('[data-clampedwidth]').each(function () { $('[data-clampedwidth]').each(function () {
var elem = $(this); var elem = $(this);
var parentPanel = elem.data('clampedwidth'); var parentPanel = elem.data('clampedwidth');
var resizeFn = function () { var resizeFn = function () {
var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth')); var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth'));
elem.css('width', sideBarNavWidth); elem.css('width', sideBarNavWidth);
}; };
resizeFn(); resizeFn();
$(window).resize(resizeFn); $(window).resize(resizeFn);
}) })
$('#settings-form').on('click', '.add-row', function(){
var row = $(this).parents("tr")
var data = row.parent().children(".row-data")
// Check key spaces
var name = row.children(".key").children("input").val()
if (name.indexOf(' ') !== -1) {
showAlertMessage("Key contains spaces", false)
return
}
// Check keys with the same name
var equals = false;
_.each(data.children(".key"), function(element) {
if ($(element).text() === name) {
equals = true
return
}
})
if (equals) {
showAlertMessage("Two keys cannot be identical.", false)
return
}
// Check empty fields
var empty = false;
_.each(row.children(".row-data").children("input"), function(element) {
if ($(element).val().length === 0) {
empty = true
return
}
})
if (empty) {
showAlertMessage("Empty field(s)")
return
}
var input_clone = row.clone()
// Change input row to data row
var full_name = row.parents("table").attr("name") + "." + name
row.attr("class", "row-data")
_.each(row.children(), function(element) {
if ($(element).hasClass("number")) { // Index row
var numbers = data.children(".number")
if (numbers.length > 0) {
$(element).html(parseInt(numbers.last().text()) + 1)
} else {
$(element).html(1)
}
} else if ($(element).hasClass("buttons")) { // Change buttons
var prevSpan = $(element).parent().prev().children(".buttons").children("span")
var span = $(element).children("span")
if (prevSpan.hasClass("del-row")) {
span.removeClass("glyphicon-ok add-row")
span.addClass("glyphicon-remove del-row")
} else {
span.remove()
}
} else if ($(element).hasClass("key")) {
var input = $(element).children("input")
$(element).html(input.val())
input.remove()
} else if($(element).hasClass("row-data")) { // Hide inputs
var input = $(element).children("input")
input.attr("type", "hidden")
input.attr("name", full_name + "." + $(element).attr("name"))
input.attr("value", input.val())
input.attr("data-changed", "true")
$(element).html($(element).html() + input.val())
} else {
console.log("Unknown table element")
}
})
row.parent().append(input_clone)
showAlertMessage("Row added", true)
})
$('#settings-form').on('click', '.del-row', function(){
var row = $(this).parents("tr")
row.empty()
row.html("<input type='hidden' class='form-control' name='" + row.attr("name") + "' data-changed='true' value=''>");
})
$('#settings-form').on('change', 'input', function(){ $('#settings-form').on('change', 'input', function(){
// this input was changed, add the changed data attribute to it // this input was changed, add the changed data attribute to it
$(this).attr('data-changed', true) $(this).attr('data-changed', true)
@ -89,7 +180,7 @@ $(document).ready(function(){
$('#advanced-toggle-button').click(function(){ $('#advanced-toggle-button').click(function(){
Settings.showAdvanced = !Settings.showAdvanced Settings.showAdvanced = !Settings.showAdvanced
var advancedSelector = $('.advanced-setting') var advancedSelector = $('.advanced-setting')
if (Settings.showAdvanced) { if (Settings.showAdvanced) {
advancedSelector.show() advancedSelector.show()
@ -188,6 +279,78 @@ $('body').on('click', '.save-button', function(e){
return false; return false;
}); });
function makeTable(setting, setting_name, setting_value) {
var html = "<label class='control-label'>" + setting.label + "</label>"
html += "<span class='help-block'>" + setting.help + "</span>"
html += "<table class='table table-bordered' name='" + setting_name + "'>"
// Column names
html += "<tr class='headers'>"
if (setting.number === true) {
html += "<td class='number'><strong>#</strong></td>" // Row number
}
html += "<td class='key'><strong>" + setting.key.label + "</strong></td>" // Key
_.each(setting.columns, function(col) {
html += "<td class='data'><strong>" + col.label + "</strong></td>" // Data
})
if (setting.can_delete === true || setting.can_add === true) {
html += "<td class='buttons'><strong>+/-</strong></td>" // Buttons
}
html += "</tr>"
// Rows
var row_num = 1
_.each(setting_value, function(row, name) {
html += "<tr class='row-data' name='" + setting_name + "." + name + "'>"
if (setting.numbered === true) {
html += "<td class='numbered'>" + row_num + "</td>"
}
html += "<td class='key'>" + name + "</td>"
_.each(setting.columns, function(col) {
html += "<td class='row-data'>"
if (row.hasOwnProperty(col.name)) {
html += row[col.name]
}
html += "</td>"
})
if (setting.can_delete === true) {
html += "<td class='buttons'><span class='glyphicon glyphicon-remove del-row'></span></td>"
} else if (setting.can_add === true) {
html += "<td class='buttons'></td>"
}
html += "</tr>"
row_num++
})
// Inputs
if (setting.can_add === true) {
html += makeTableInputs(setting)
}
html += "</table>"
return html;
}
function makeTableInputs(setting) {
var html = "<tr class='inputs'>"
if (setting.numbered === true) {
html += "<td class='numbered'></td>"
}
html += "<td class='key' name='" + setting.key.name + "'>\
<input type='text' class='form-control' placeholder='" + (_.has(setting.key, 'placeholder') ? setting.key.placeholder : "") + "' value=''>\
</td>"
_.each(setting.columns, function(col) {
html += "<td class='row-data'name='" + col.name + "'>\
<input type='text' class='form-control' placeholder='" + col.placeholder + "' value=''>\
</td>"
})
html += "<td class='buttons'><span class='glyphicon glyphicon-ok add-row'></span></td>"
html += "</tr>"
return html
}
function badgeSidebarForDifferences(changedInput) { function badgeSidebarForDifferences(changedInput) {
// figure out which group this input is in // figure out which group this input is in
var panelParentID = changedInput.closest('.panel').attr('id') var panelParentID = changedInput.closest('.panel').attr('id')
@ -237,7 +400,7 @@ function showRestartModal() {
}, 1000); }, 1000);
} }
function cleanupFormValues(node) { function cleanupFormValues(node) {
if (node.type && node.type === 'checkbox') { if (node.type && node.type === 'checkbox') {
return { name: node.name, value: node.checked ? true : false }; return { name: node.name, value: node.checked ? true : false };
} else { } else {

View file

@ -57,6 +57,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
setApplicationName("domain-server"); setApplicationName("domain-server");
QSettings::setDefaultFormat(QSettings::IniFormat); QSettings::setDefaultFormat(QSettings::IniFormat);
// make sure we have a fresh AccountManager instance
// (need this since domain-server can restart itself and maintain static variables)
AccountManager::getInstance(true);
_settingsManager.setupConfigMap(arguments()); _settingsManager.setupConfigMap(arguments());
installNativeEventFilter(&_shutdownEventListener); installNativeEventFilter(&_shutdownEventListener);
@ -82,10 +86,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
void DomainServer::restart() { void DomainServer::restart() {
qDebug() << "domain-server is restarting."; qDebug() << "domain-server is restarting.";
// make sure all static instances are reset
LimitedNodeList::getInstance()->reset();
AccountManager::getInstance(true);
exit(DomainServer::EXIT_CODE_REBOOT); exit(DomainServer::EXIT_CODE_REBOOT);
} }
@ -189,17 +189,20 @@ bool DomainServer::optionallySetupOAuth() {
const QString DOMAIN_CONFIG_ID_KEY = "id"; const QString DOMAIN_CONFIG_ID_KEY = "id";
const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking";
const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full";
const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip";
const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled";
void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
const QString CUSTOM_PORT_OPTION = "port"; const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
unsigned short domainServerPort = DEFAULT_DOMAIN_SERVER_PORT;
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
unsigned short domainServerPort = (unsigned short) localPortValue.toUInt();
QVariantMap& settingsMap = _settingsManager.getSettingsMap(); QVariantMap& settingsMap = _settingsManager.getSettingsMap();
if (settingsMap.contains(CUSTOM_PORT_OPTION)) {
domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt();
}
unsigned short domainServerDTLSPort = 0; unsigned short domainServerDTLSPort = 0;
if (_isUsingDTLS) { if (_isUsingDTLS) {
@ -310,12 +313,7 @@ bool DomainServer::optionallySetupAssignmentPayment() {
return true; return true;
} }
const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full";
const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip";
const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled";
void DomainServer::setupAutomaticNetworking() { void DomainServer::setupAutomaticNetworking() {
const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking";
if (!didSetupAccountManagerWithAccessToken()) { if (!didSetupAccountManagerWithAccessToken()) {
qDebug() << "Cannot setup domain-server automatic networking without an access token."; qDebug() << "Cannot setup domain-server automatic networking without an access token.";
@ -357,7 +355,8 @@ void DomainServer::setupAutomaticNetworking() {
connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates); connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS);
// call our sendHeartbeaToIceServer immediately anytime a public address changes // call our sendHeartbeaToIceServer immediately anytime a local or public socket changes
connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer);
connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer);
// tell the data server which type of automatic networking we are using // tell the data server which type of automatic networking we are using

View file

@ -29,6 +29,7 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings
const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString DESCRIPTION_SETTINGS_KEY = "settings";
const QString SETTING_DEFAULT_KEY = "default"; const QString SETTING_DEFAULT_KEY = "default";
const QString DESCRIPTION_NAME_KEY = "name"; const QString DESCRIPTION_NAME_KEY = "name";
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
DomainServerSettingsManager::DomainServerSettingsManager() : DomainServerSettingsManager::DomainServerSettingsManager() :
_descriptionArray(), _descriptionArray(),
@ -232,63 +233,92 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty
return responseObject; return responseObject;
} }
bool DomainServerSettingsManager::settingExists(const QString& groupName, const QString& settingName,
const QJsonArray& descriptionArray, QJsonValue& settingDescription) {
foreach(const QJsonValue& groupValue, descriptionArray) {
QJsonObject groupObject = groupValue.toObject();
if (groupObject[DESCRIPTION_NAME_KEY].toString() == groupName) {
foreach(const QJsonValue& settingValue, groupObject[DESCRIPTION_SETTINGS_KEY].toArray()) {
QJsonObject settingObject = settingValue.toObject();
if (settingObject[DESCRIPTION_NAME_KEY].toString() == settingName) {
settingDescription = settingObject[SETTING_DEFAULT_KEY];
return true;
}
}
}
}
settingDescription = QJsonValue::Undefined;
return false;
}
const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
const QJsonValue& settingDescription) {
if (newValue.isString()) {
if (newValue.toString().isEmpty()) {
// this is an empty value, clear it in settings variant so the default is sent
settingMap.remove(key);
} else {
// make sure the resulting json value has the right type
const QString settingType = settingDescription.toObject()[SETTING_DESCRIPTION_TYPE_KEY].toString();
const QString INPUT_DOUBLE_TYPE = "double";
const QString INPUT_INTEGER_TYPE = "int";
if (settingType == INPUT_DOUBLE_TYPE) {
settingMap[key] = newValue.toString().toDouble();
} else if (settingType == INPUT_INTEGER_TYPE) {
settingMap[key] = newValue.toString().toInt();
} else {
settingMap[key] = newValue.toString();
}
}
} else if (newValue.isBool()) {
settingMap[key] = newValue.toBool();
} else if (newValue.isObject()) {
if (!settingMap.contains(key)) {
// we don't have a map below this key yet, so set it up now
settingMap[key] = QVariantMap();
}
QVariantMap& thisMap = *reinterpret_cast<QVariantMap*>(settingMap[key].data());
foreach(const QString childKey, newValue.toObject().keys()) {
updateSetting(childKey, newValue.toObject()[childKey], thisMap, settingDescription.toObject()[key]);
}
if (settingMap[key].toMap().isEmpty()) {
// we've cleared all of the settings below this value, so remove this one too
settingMap.remove(key);
}
}
}
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
QVariantMap& settingsVariant, QVariantMap& settingsVariant,
QJsonArray descriptionArray) { const QJsonArray& descriptionArray) {
foreach(const QString& key, postedObject.keys()) { // Iterate on the setting groups
foreach(const QString& groupKey, postedObject.keys()) {
QJsonValue groupValue = postedObject[groupKey];
QJsonValue rootValue = postedObject[key]; if (!settingsVariant.contains(groupKey)) {
// we don't have a map below this key yet, so set it up now
settingsVariant[groupKey] = QVariantMap();
}
// we don't continue if this key is not present in our descriptionObject // Iterate on the settings
foreach(const QJsonValue& groupValue, descriptionArray) { foreach(const QString& settingKey, groupValue.toObject().keys()) {
if (groupValue.toObject()[DESCRIPTION_NAME_KEY].toString() == key) { QJsonValue settingValue = groupValue.toObject()[settingKey];
QJsonObject groupObject = groupValue.toObject();
if (rootValue.isString()) { QJsonValue thisDescription;
if (rootValue.toString().isEmpty()) { if (settingExists(groupKey, settingKey, descriptionArray, thisDescription)) {
// this is an empty value, clear it in settings variant so the default is sent QVariantMap& thisMap = *reinterpret_cast<QVariantMap*>(settingsVariant[groupKey].data());
settingsVariant.remove(key); updateSetting(settingKey, settingValue, thisMap, thisDescription);
} else {
QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString();
const QString INPUT_DOUBLE_TYPE = "double";
// make sure the resulting json value has the right type
if (settingType == INPUT_DOUBLE_TYPE) {
settingsVariant[key] = rootValue.toString().toDouble();
} else {
settingsVariant[key] = rootValue.toString();
}
}
} else if (rootValue.isBool()) {
settingsVariant[key] = rootValue.toBool();
} else if (rootValue.isObject()) {
// there's a JSON Object to explore, so attempt to recurse into it
QJsonObject nextDescriptionObject = groupObject;
if (nextDescriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
if (!settingsVariant.contains(key)) {
// we don't have a map below this key yet, so set it up now
settingsVariant[key] = QVariantMap();
}
QVariantMap& thisMap = *reinterpret_cast<QVariantMap*>(settingsVariant[key].data());
recurseJSONObjectAndOverwriteSettings(rootValue.toObject(),
thisMap,
nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toArray());
if (thisMap.isEmpty()) {
// we've cleared all of the settings below this value, so remove this one too
settingsVariant.remove(key);
}
}
}
} }
} }
if (settingsVariant[groupKey].toMap().empty()) {
// we've cleared all of the settings below this value, so remove this one too
settingsVariant.remove(groupKey);
}
} }
} }

View file

@ -32,7 +32,11 @@ public:
private: private:
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant,
QJsonArray descriptionArray); const QJsonArray& descriptionArray);
bool settingExists(const QString& groupName, const QString& settingName,
const QJsonArray& descriptionArray, QJsonValue& settingDescription);
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
const QJsonValue& settingDescription);
void persistToFile(); void persistToFile();
QJsonArray _descriptionArray; QJsonArray _descriptionArray;

View file

@ -30,8 +30,6 @@ var leapHands = (function () {
CALIBRATING = 1, CALIBRATING = 1,
CALIBRATED = 2, CALIBRATED = 2,
CALIBRATION_TIME = 1000, // milliseconds CALIBRATION_TIME = 1000, // milliseconds
PI = 3.141593,
isWindows,
avatarScale, avatarScale,
avatarFaceModelURL, avatarFaceModelURL,
avatarSkeletonModelURL, avatarSkeletonModelURL,
@ -132,9 +130,6 @@ var leapHands = (function () {
if (hands[0].controller.isActive() && hands[1].controller.isActive()) { if (hands[0].controller.isActive() && hands[1].controller.isActive()) {
leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0;
// TODO: Temporary detection of Windows to work around Leap Controller problem.
isWindows = (hands[1].controller.getAbsRotation().z > (0.25 * PI));
} else { } else {
calibrationStatus = UNCALIBRATED; calibrationStatus = UNCALIBRATED;
return; return;
@ -318,11 +313,7 @@ var leapHands = (function () {
j, j,
side, side,
handOffset, handOffset,
handRoll,
handPitch,
handYaw,
handRotation, handRotation,
wristAbsRotation,
locRotation, locRotation,
cameraOrientation, cameraOrientation,
inverseAvatarOrientation; inverseAvatarOrientation;
@ -361,20 +352,22 @@ var leapHands = (function () {
handOffset.x = -handOffset.x; handOffset.x = -handOffset.x;
// Hand rotation in camera coordinates ... // Hand rotation in camera coordinates ...
// TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. handRotation = wrists[h].controller.getAbsRotation();
handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; handRotation = {
wristAbsRotation = wrists[h].controller.getAbsRotation(); x: handRotation.z,
handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; y: handRotation.y,
handYaw = 2.0 * -wristAbsRotation.y; z: handRotation.x,
// TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. w: handRotation.w
handRoll = PI + handRoll; };
if (h === 0) { if (h === 0) {
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), handRotation.x = -handRotation.x;
Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation);
} else { } else {
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), handRotation.z = -handRotation.z;
Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation);
} }
// Hand rotation in avatar coordinates ... // Hand rotation in avatar coordinates ...
@ -392,25 +385,22 @@ var leapHands = (function () {
z: hands[h].zeroPosition.z - handOffset.z z: hands[h].zeroPosition.z - handOffset.z
}; };
// TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. handRotation = wrists[h].controller.getAbsRotation();
handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; handRotation = {
wristAbsRotation = wrists[h].controller.getAbsRotation(); x: handRotation.z,
handPitch = 2.0 * -wristAbsRotation.x; y: handRotation.y,
handYaw = 2.0 * wristAbsRotation.y; z: handRotation.x,
w: handRotation.w
};
// TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down.
// Approximate fix is to add a fudge factor.
if (h === 1 && isWindows) {
handRoll = handRoll + 0.6 * PI;
}
// Hand position and orientation ...
if (h === 0) { if (h === 0) {
handRotation.x = -handRotation.x;
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }),
Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); handRotation);
} else { } else {
handRotation.z = -handRotation.z;
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }),
Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); handRotation);
} }
} }

View file

@ -169,7 +169,14 @@ SelectionDisplay = (function () {
alpha: 0.2, alpha: 0.2,
solid: true, solid: true,
visible: false, visible: false,
rotation: yawOverlayRotation rotation: yawOverlayRotation,
hasTickMarks: true,
majorTickMarksAngle: 12.5,
minorTickMarksAngle: 0,
majorTickMarksLength: -0.25,
minorTickMarksLength: 0,
majorTickMarksColor: { red: 0, green: 0, blue: 0 },
minorTickMarksColor: { red: 0, green: 0, blue: 0 },
}); });
var rotateOverlayOuter = Overlays.addOverlay("circle3d", { var rotateOverlayOuter = Overlays.addOverlay("circle3d", {
@ -179,7 +186,15 @@ SelectionDisplay = (function () {
alpha: 0.2, alpha: 0.2,
solid: true, solid: true,
visible: false, visible: false,
rotation: yawOverlayRotation rotation: yawOverlayRotation,
hasTickMarks: true,
majorTickMarksAngle: 45.0,
minorTickMarksAngle: 5,
majorTickMarksLength: 0.25,
minorTickMarksLength: 0.1,
majorTickMarksColor: { red: 0, green: 0, blue: 0 },
minorTickMarksColor: { red: 0, green: 0, blue: 0 },
}); });
var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { var rotateOverlayCurrent = Overlays.addOverlay("circle3d", {
@ -571,7 +586,7 @@ SelectionDisplay = (function () {
innerRadius: 0.9, innerRadius: 0.9,
startAt: 0, startAt: 0,
endAt: 360, endAt: 360,
alpha: outerAlpha alpha: outerAlpha,
}); });
Overlays.editOverlay(rotateOverlayCurrent, Overlays.editOverlay(rotateOverlayCurrent,
@ -584,7 +599,7 @@ SelectionDisplay = (function () {
size: outerRadius, size: outerRadius,
startAt: 0, startAt: 0,
endAt: 0, endAt: 0,
innerRadius: 0.9 innerRadius: 0.9,
}); });
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden

View file

@ -349,7 +349,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkDiskCache* cache = new QNetworkDiskCache(); QNetworkDiskCache* cache = new QNetworkDiskCache();
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
networkAccessManager.setCache(cache); networkAccessManager.setCache(cache);

View file

@ -28,7 +28,7 @@ FileLogger::FileLogger(QObject* parent) :
setExtraDebugging(false); setExtraDebugging(false);
_fileName = FileUtils::standardPath(LOGS_DIRECTORY); _fileName = FileUtils::standardPath(LOGS_DIRECTORY);
QHostAddress clientAddress = QHostAddress(getHostOrderLocalAddress()); QHostAddress clientAddress = getLocalAddress();
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
_fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); _fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT)));
} }

View file

@ -117,7 +117,7 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
} }
url.setQuery(query); url.setQuery(query);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.get(request); QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));

View file

@ -26,7 +26,7 @@ AddressBarDialog::AddressBarDialog() :
void AddressBarDialog::setupUI() { void AddressBarDialog::setupUI() {
const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;";
const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, @user, #location"; const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z";
const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;";
const int ADDRESSBAR_MIN_WIDTH = 200; const int ADDRESSBAR_MIN_WIDTH = 200;
@ -45,13 +45,6 @@ void AddressBarDialog::setupUI() {
const int DIALOG_HEIGHT = 62; const int DIALOG_HEIGHT = 62;
const int DIALOG_INITIAL_WIDTH = 560; const int DIALOG_INITIAL_WIDTH = 560;
setModal(true);
#ifndef Q_OS_MAC
setWindowModality(Qt::ApplicationModal);
#else
setWindowModality(Qt::WindowModal);
#endif
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setSizePolicy(sizePolicy); setSizePolicy(sizePolicy);
setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT)); setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT));

View file

@ -35,9 +35,6 @@ LoginDialog::LoginDialog(QWidget* parent) :
_ui->infoLabel->setVisible(false); _ui->infoLabel->setVisible(false);
_ui->errorLabel->setVisible(false); _ui->errorLabel->setVisible(false);
setModal(true);
setWindowModality(Qt::ApplicationModal);
connect(&AccountManager::getInstance(), &AccountManager::loginComplete, connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
this, &LoginDialog::handleLoginCompleted); this, &LoginDialog::handleLoginCompleted);
connect(&AccountManager::getInstance(), &AccountManager::loginFailed, connect(&AccountManager::getInstance(), &AccountManager::loginFailed,

View file

@ -48,7 +48,7 @@ enum GridPlane {
const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX); const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX);
MetavoxelEditor::MetavoxelEditor() : MetavoxelEditor::MetavoxelEditor() :
QWidget(Application::getInstance()->getGLWidget(), Qt::Tool | Qt::WindowStaysOnTopHint) { QWidget(Application::getInstance()->getGLWidget(), Qt::Tool) {
setWindowTitle("Metavoxel Editor"); setWindowTitle("Metavoxel Editor");
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);

View file

@ -221,7 +221,7 @@ void ModelHandler::update() {
} }
for (int i = 0; i < _model.rowCount(); ++i) { for (int i = 0; i < _model.rowCount(); ++i) {
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.head(request); QNetworkReply* reply = networkAccessManager.head(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
@ -272,7 +272,7 @@ void ModelHandler::queryNewFiles(QString marker) {
// Download // Download
url.setQuery(query); url.setQuery(query);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.get(request); QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));

View file

@ -150,7 +150,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished);
} }
} else { } else {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading included script at" << scriptPath; qDebug() << "Downloading included script at" << scriptPath;
QEventLoop loop; QEventLoop loop;

View file

@ -21,8 +21,15 @@ Circle3DOverlay::Circle3DOverlay() :
_startAt(0.0f), _startAt(0.0f),
_endAt(360.0f), _endAt(360.0f),
_outerRadius(1.0f), _outerRadius(1.0f),
_innerRadius(0.0f) _innerRadius(0.0f),
_hasTickMarks(false),
_majorTickMarksAngle(0.0f),
_minorTickMarksAngle(0.0f),
_majorTickMarksLength(0.0f),
_minorTickMarksLength(0.0f)
{ {
_majorTickMarksColor.red = _majorTickMarksColor.green = _majorTickMarksColor.blue = (unsigned char)0;
_minorTickMarksColor.red = _minorTickMarksColor.green = _minorTickMarksColor.blue = (unsigned char)0;
} }
Circle3DOverlay::~Circle3DOverlay() { Circle3DOverlay::~Circle3DOverlay() {
@ -142,6 +149,66 @@ void Circle3DOverlay::render() {
glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glVertex2f(lastOuterPoint.x, lastOuterPoint.y);
glEnd(); glEnd();
} }
// draw our tick marks
// for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise
// we just draw a line...
if (getHasTickMarks()) {
glBegin(GL_LINES);
// draw our major tick marks
if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) {
xColor color = getMajorTickMarksColor();
glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
float angle = startAt;
float angleInRadians = glm::radians(angle);
float tickMarkLength = getMajorTickMarksLength();
float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
float endRadius = startRadius + tickMarkLength;
while (angle <= endAt) {
angleInRadians = glm::radians(angle);
glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
glVertex2f(thisPointA.x, thisPointA.y);
glVertex2f(thisPointB.x, thisPointB.y);
angle += getMajorTickMarksAngle();
}
}
// draw our minor tick marks
if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) {
xColor color = getMinorTickMarksColor();
glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
float angle = startAt;
float angleInRadians = glm::radians(angle);
float tickMarkLength = getMinorTickMarksLength();
float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius;
float endRadius = startRadius + tickMarkLength;
while (angle <= endAt) {
angleInRadians = glm::radians(angle);
glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius);
glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius);
glVertex2f(thisPointA.x, thisPointA.y);
glVertex2f(thisPointB.x, thisPointB.y);
angle += getMinorTickMarksAngle();
}
}
glEnd();
}
glPopMatrix(); glPopMatrix();
glPopMatrix(); glPopMatrix();
@ -173,6 +240,55 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) {
if (innerRadius.isValid()) { if (innerRadius.isValid()) {
setInnerRadius(innerRadius.toVariant().toFloat()); setInnerRadius(innerRadius.toVariant().toFloat());
} }
QScriptValue hasTickMarks = properties.property("hasTickMarks");
if (hasTickMarks.isValid()) {
setHasTickMarks(hasTickMarks.toVariant().toBool());
}
QScriptValue majorTickMarksAngle = properties.property("majorTickMarksAngle");
if (majorTickMarksAngle.isValid()) {
setMajorTickMarksAngle(majorTickMarksAngle.toVariant().toFloat());
}
QScriptValue minorTickMarksAngle = properties.property("minorTickMarksAngle");
if (minorTickMarksAngle.isValid()) {
setMinorTickMarksAngle(minorTickMarksAngle.toVariant().toFloat());
}
QScriptValue majorTickMarksLength = properties.property("majorTickMarksLength");
if (majorTickMarksLength.isValid()) {
setMajorTickMarksLength(majorTickMarksLength.toVariant().toFloat());
}
QScriptValue minorTickMarksLength = properties.property("minorTickMarksLength");
if (minorTickMarksLength.isValid()) {
setMinorTickMarksLength(minorTickMarksLength.toVariant().toFloat());
}
QScriptValue majorTickMarksColor = properties.property("majorTickMarksColor");
if (majorTickMarksColor.isValid()) {
QScriptValue red = majorTickMarksColor.property("red");
QScriptValue green = majorTickMarksColor.property("green");
QScriptValue blue = majorTickMarksColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_majorTickMarksColor.red = red.toVariant().toInt();
_majorTickMarksColor.green = green.toVariant().toInt();
_majorTickMarksColor.blue = blue.toVariant().toInt();
}
}
QScriptValue minorTickMarksColor = properties.property("minorTickMarksColor");
if (minorTickMarksColor.isValid()) {
QScriptValue red = minorTickMarksColor.property("red");
QScriptValue green = minorTickMarksColor.property("green");
QScriptValue blue = minorTickMarksColor.property("blue");
if (red.isValid() && green.isValid() && blue.isValid()) {
_minorTickMarksColor.red = red.toVariant().toInt();
_minorTickMarksColor.green = green.toVariant().toInt();
_minorTickMarksColor.blue = blue.toVariant().toInt();
}
}
} }

View file

@ -26,17 +26,38 @@ public:
float getEndAt() const { return _endAt; } float getEndAt() const { return _endAt; }
float getOuterRadius() const { return _outerRadius; } float getOuterRadius() const { return _outerRadius; }
float getInnerRadius() const { return _innerRadius; } float getInnerRadius() const { return _innerRadius; }
bool getHasTickMarks() const { return _hasTickMarks; }
float getMajorTickMarksAngle() const { return _majorTickMarksAngle; }
float getMinorTickMarksAngle() const { return _minorTickMarksAngle; }
float getMajorTickMarksLength() const { return _majorTickMarksLength; }
float getMinorTickMarksLength() const { return _minorTickMarksLength; }
xColor getMajorTickMarksColor() const { return _majorTickMarksColor; }
xColor getMinorTickMarksColor() const { return _minorTickMarksColor; }
void setStartAt(float value) { _startAt = value; } void setStartAt(float value) { _startAt = value; }
void setEndAt(float value) { _endAt = value; } void setEndAt(float value) { _endAt = value; }
void setOuterRadius(float value) { _outerRadius = value; } void setOuterRadius(float value) { _outerRadius = value; }
void setInnerRadius(float value) { _innerRadius = value; } void setInnerRadius(float value) { _innerRadius = value; }
void setHasTickMarks(bool value) { _hasTickMarks = value; }
void setMajorTickMarksAngle(float value) { _majorTickMarksAngle = value; }
void setMinorTickMarksAngle(float value) { _minorTickMarksAngle = value; }
void setMajorTickMarksLength(float value) { _majorTickMarksLength = value; }
void setMinorTickMarksLength(float value) { _minorTickMarksLength = value; }
void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; }
void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; }
protected: protected:
float _startAt; float _startAt;
float _endAt; float _endAt;
float _outerRadius; float _outerRadius;
float _innerRadius; float _innerRadius;
bool _hasTickMarks;
float _majorTickMarksAngle;
float _minorTickMarksAngle;
float _majorTickMarksLength;
float _minorTickMarksLength;
xColor _majorTickMarksColor;
xColor _minorTickMarksColor;
}; };

View file

@ -37,7 +37,7 @@ ImageOverlay::~ImageOverlay() {
// TODO: handle setting image multiple times, how do we manage releasing the bound texture? // TODO: handle setting image multiple times, how do we manage releasing the bound texture?
void ImageOverlay::setImageURL(const QUrl& url) { void ImageOverlay::setImageURL(const QUrl& url) {
_isLoaded = false; _isLoaded = false;
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished);
} }

View file

@ -78,7 +78,7 @@ Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) :
// assume we have a QApplication or QCoreApplication instance and use the // assume we have a QApplication or QCoreApplication instance and use the
// QNetworkAccess manager to grab the raw audio file at the given URL // QNetworkAccess manager to grab the raw audio file at the given URL
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
qDebug() << "Requesting audio file" << sampleURL.toDisplayString(); qDebug() << "Requesting audio file" << sampleURL.toDisplayString();

View file

@ -1048,7 +1048,7 @@ void AvatarData::setBillboardFromURL(const QString &billboardURL) {
QNetworkRequest billboardRequest; QNetworkRequest billboardRequest;
billboardRequest.setUrl(QUrl(billboardURL)); billboardRequest.setUrl(QUrl(billboardURL));
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(billboardRequest); QNetworkReply* networkReply = networkAccessManager.get(billboardRequest);
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
} }
@ -1113,7 +1113,7 @@ void AvatarData::updateJointMappings() {
_jointNames.clear(); _jointNames.clear();
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL)); QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL));
connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply()));
} }

View file

@ -385,7 +385,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
// Download file if necessary // Download file if necessary
qDebug() << "Downloading recording at" << url; qDebug() << "Downloading recording at" << url;
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
QEventLoop loop; QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));

View file

@ -187,7 +187,7 @@ void AccountManager::invokedRequest(const QString& path,
const JSONCallbackParameters& callbackParams, const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest; QNetworkRequest networkRequest;
@ -359,7 +359,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken)
void AccountManager::requestAccessToken(const QString& login, const QString& password) { void AccountManager::requestAccessToken(const QString& login, const QString& password) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request; QNetworkRequest request;
@ -431,7 +431,7 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error)
} }
void AccountManager::requestProfile() { void AccountManager::requestProfile() {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QUrl profileURL = _authURL; QUrl profileURL = _authURL;
profileURL.setPath("/api/v1/users/profile"); profileURL.setPath("/api/v1/users/profile");

View file

@ -90,7 +90,7 @@ void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hos
void DomainHandler::setUUID(const QUuid& uuid) { void DomainHandler::setUUID(const QUuid& uuid) {
if (uuid != _uuid) { if (uuid != _uuid) {
_uuid = uuid; _uuid = uuid;
qDebug() << "Domain uuid changed to" << uuidStringWithoutCurlyBraces(_uuid); qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid);
} }
} }

View file

@ -90,32 +90,29 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) {
return dataStream; return dataStream;
} }
quint32 getHostOrderLocalAddress() { QHostAddress getLocalAddress() {
static int localAddress = 0; QHostAddress localAddress;
if (localAddress == 0) { foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { if (networkInterface.flags() & QNetworkInterface::IsUp
if (networkInterface.flags() & QNetworkInterface::IsUp && networkInterface.flags() & QNetworkInterface::IsRunning
&& networkInterface.flags() & QNetworkInterface::IsRunning && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) {
&& networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { // we've decided that this is the active NIC
// we've decided that this is the active NIC // enumerate it's addresses to grab the IPv4 address
// enumerate it's addresses to grab the IPv4 address foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { // make sure it's an IPv4 address that isn't the loopback
// make sure it's an IPv4 address that isn't the loopback if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
qDebug("Node's local address is %s", entry.ip().toString().toLocal8Bit().constData()); // set our localAddress and break out
localAddress = entry.ip();
// set our localAddress and break out break;
localAddress = entry.ip().toIPv4Address();
break;
}
} }
} }
}
if (localAddress != 0) {
break; if (!localAddress.isNull()) {
} break;
} }
} }

View file

@ -58,7 +58,7 @@ private:
uint qHash(const HifiSockAddr& key, uint seed); uint qHash(const HifiSockAddr& key, uint seed);
quint32 getHostOrderLocalAddress(); QHostAddress getLocalAddress();
Q_DECLARE_METATYPE(HifiSockAddr) Q_DECLARE_METATYPE(HifiSockAddr)

View file

@ -70,6 +70,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
_nodeHashMutex(QMutex::Recursive), _nodeHashMutex(QMutex::Recursive),
_nodeSocket(this), _nodeSocket(this),
_dtlsSocket(NULL), _dtlsSocket(NULL),
_localSockAddr(),
_publicSockAddr(), _publicSockAddr(),
_numCollectedPackets(0), _numCollectedPackets(0),
_numCollectedBytes(0), _numCollectedBytes(0),
@ -89,6 +90,15 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
const int LARGER_BUFFER_SIZE = 1048576; const int LARGER_BUFFER_SIZE = 1048576;
changeSocketBufferSizes(LARGER_BUFFER_SIZE); changeSocketBufferSizes(LARGER_BUFFER_SIZE);
// check for local socket updates every so often
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
QTimer* localSocketUpdate = new QTimer(this);
connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr);
localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS);
// check the local socket right now
updateLocalSockAddr();
_packetStatTimer.start(); _packetStatTimer.start();
} }
@ -570,7 +580,7 @@ void LimitedNodeList::sendSTUNRequest() {
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES); memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
// lookup the IP for the STUN server // lookup the IP for the STUN server
static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
stunSockAddr.getAddress(), stunSockAddr.getPort()); stunSockAddr.getAddress(), stunSockAddr.getPort());
@ -659,6 +669,23 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
return false; return false;
} }
void LimitedNodeList::updateLocalSockAddr() {
HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort());
if (newSockAddr != _localSockAddr) {
if (_localSockAddr.isNull()) {
qDebug() << "Local socket is" << newSockAddr;
} else {
qDebug() << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
}
_localSockAddr = newSockAddr;
emit localSockAddrChanged(_localSockAddr);
}
}
void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
QUuid headerID, const QUuid& connectionRequestID) { QUuid headerID, const QUuid& connectionRequestID) {
@ -669,7 +696,7 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock
QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); iceDataStream << _publicSockAddr << _localSockAddr;
if (!connectionRequestID.isNull()) { if (!connectionRequestID.isNull()) {
iceDataStream << connectionRequestID; iceDataStream << connectionRequestID;

View file

@ -129,11 +129,15 @@ public slots:
void removeSilentNodes(); void removeSilentNodes();
void updateLocalSockAddr();
void killNodeWithUUID(const QUuid& nodeUUID); void killNodeWithUUID(const QUuid& nodeUUID);
signals: signals:
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
void nodeAdded(SharedNodePointer); void nodeAdded(SharedNodePointer);
void nodeKilled(SharedNodePointer); void nodeKilled(SharedNodePointer);
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
protected: protected:
static std::auto_ptr<LimitedNodeList> _sharedInstance; static std::auto_ptr<LimitedNodeList> _sharedInstance;
@ -155,6 +159,7 @@ protected:
QMutex _nodeHashMutex; QMutex _nodeHashMutex;
QUdpSocket _nodeSocket; QUdpSocket _nodeSocket;
QUdpSocket* _dtlsSocket; QUdpSocket* _dtlsSocket;
HifiSockAddr _localSockAddr;
HifiSockAddr _publicSockAddr; HifiSockAddr _publicSockAddr;
int _numCollectedPackets; int _numCollectedPackets;
int _numCollectedBytes; int _numCollectedBytes;

View file

@ -13,15 +13,12 @@
#include "NetworkAccessManager.h" #include "NetworkAccessManager.h"
QThreadStorage<NetworkAccessManager*> networkAccessManagers; QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
NetworkAccessManager& NetworkAccessManager::getInstance() { QNetworkAccessManager& NetworkAccessManager::getInstance() {
if (!networkAccessManagers.hasLocalData()) { if (!networkAccessManagers.hasLocalData()) {
networkAccessManagers.setLocalData(new NetworkAccessManager()); networkAccessManagers.setLocalData(new QNetworkAccessManager());
} }
return *networkAccessManagers.localData(); return *networkAccessManagers.localData();
} }
NetworkAccessManager::NetworkAccessManager() {
}

View file

@ -15,13 +15,10 @@
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
/// Wrapper around QNetworkAccessManager to restrict at one instance by thread /// Wrapper around QNetworkAccessManager to restrict at one instance by thread
class NetworkAccessManager : public QNetworkAccessManager { class NetworkAccessManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static NetworkAccessManager& getInstance(); static QNetworkAccessManager& getInstance();
private:
NetworkAccessManager();
}; };
#endif // hifi_NetworkAccessManager_h #endif // hifi_NetworkAccessManager_h

View file

@ -302,9 +302,7 @@ void NodeList::sendDomainServerCheckIn() {
QDataStream packetStream(&domainServerPacket, QIODevice::Append); QDataStream packetStream(&domainServerPacket, QIODevice::Append);
// pack our data to send to the domain-server // pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr packetStream << _ownerType << _publicSockAddr << _localSockAddr << (quint8) _nodeTypesOfInterest.size();
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
// copy over the bytes for node types of interest, if required // copy over the bytes for node types of interest, if required
foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
@ -420,13 +418,7 @@ void NodeList::sendAssignment(Assignment& assignment) {
packetStream << assignment; packetStream << assignment;
static HifiSockAddr DEFAULT_ASSIGNMENT_SOCKET(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, DEFAULT_DOMAIN_SERVER_PORT); _nodeSocket.writeDatagram(packet, _assignmentServerSocket.getAddress(), _assignmentServerSocket.getPort());
const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull()
? &DEFAULT_ASSIGNMENT_SOCKET
: &_assignmentServerSocket;
_nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort());
} }
void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) {

View file

@ -157,7 +157,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL,
emit errorMessage("ERROR Loading file:" + fileName); emit errorMessage("ERROR Loading file:" + fileName);
} }
} else { } else {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading script at" << url; qDebug() << "Downloading script at" << url;
QEventLoop loop; QEventLoop loop;
@ -682,7 +682,7 @@ void ScriptEngine::include(const QString& includeFile) {
QString includeContents; QString includeContents;
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading included script at" << includeFile; qDebug() << "Downloading included script at" << includeFile;
QEventLoop loop; QEventLoop loop;