Merge branch 'master' of git://github.com/highfidelity/hifi into 19779

Conflicts:
	interface/src/location/LocationManager.cpp
This commit is contained in:
Ryan Huffman 2014-06-16 11:35:55 -07:00
commit a13810bd72
17 changed files with 605 additions and 495 deletions

View file

@ -15,6 +15,7 @@
#include <AccountManager.h> #include <AccountManager.h>
#include <Assignment.h> #include <Assignment.h>
#include <HifiConfigVariantMap.h>
#include <Logging.h> #include <Logging.h>
#include <NodeList.h> #include <NodeList.h>
#include <PacketHeaders.h> #include <PacketHeaders.h>
@ -41,73 +42,65 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
setOrganizationDomain("highfidelity.io"); setOrganizationDomain("highfidelity.io");
setApplicationName("assignment-client"); setApplicationName("assignment-client");
QSettings::setDefaultFormat(QSettings::IniFormat); QSettings::setDefaultFormat(QSettings::IniFormat);
QStringList argumentList = arguments();
// register meta type is required for queued invoke method on Assignment subclasses
// set the logging target to the the CHILD_TARGET_NAME // set the logging target to the the CHILD_TARGET_NAME
Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
const QString ASSIGNMENT_TYPE_OVVERIDE_OPTION = "-t"; const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
int argumentIndex = argumentList.indexOf(ASSIGNMENT_TYPE_OVVERIDE_OPTION);
const QString ASSIGNMENT_TYPE_OVERRIDE_OPTION = "t";
const QString ASSIGNMENT_POOL_OPTION = "pool";
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
Assignment::Type requestAssignmentType = Assignment::AllTypes; Assignment::Type requestAssignmentType = Assignment::AllTypes;
if (argumentIndex != -1) { // check for an assignment type passed on the command line or in the config
requestAssignmentType = (Assignment::Type) argumentList[argumentIndex + 1].toInt(); if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
} }
const QString ASSIGNMENT_POOL_OPTION = "--pool";
argumentIndex = argumentList.indexOf(ASSIGNMENT_POOL_OPTION);
QString assignmentPool; QString assignmentPool;
if (argumentIndex != -1) { // check for an assignment pool passed on the command line or in the config
assignmentPool = argumentList[argumentIndex + 1]; if (argumentVariantMap.contains(ASSIGNMENT_POOL_OPTION)) {
assignmentPool = argumentVariantMap.value(ASSIGNMENT_POOL_OPTION).toString();
} }
// setup our _requestAssignment member variable from the passed arguments // setup our _requestAssignment member variable from the passed arguments
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool); _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);
// check if we were passed a wallet UUID on the command line // check for a wallet UUID on the command line or in the config
// this would represent where the user running AC wants funds sent to // this would represent where the user running AC wants funds sent to
if (argumentVariantMap.contains(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) {
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "--wallet"; QUuid walletUUID = argumentVariantMap.value(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION).toString();
if ((argumentIndex = argumentList.indexOf(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION)) != -1) {
QUuid walletUUID = QString(argumentList[argumentIndex + 1]);
qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
_requestAssignment.setWalletUUID(walletUUID); _requestAssignment.setWalletUUID(walletUUID);
} }
// 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);
// check for an overriden assignment server hostname // check for an overriden assignment server hostname
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "-a"; if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
argumentIndex = argumentList.indexOf(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
if (argumentIndex != -1) {
_assignmentServerHostname = argumentList[argumentIndex + 1];
// set the custom assignment socket on our NodeList // set the custom assignment socket on our NodeList
HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT);
nodeList->setAssignmentServerSocket(customAssignmentSocket); nodeList->setAssignmentServerSocket(customAssignmentSocket);
} }
// 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;
QTimer* timer = new QTimer(this); QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); connect(timer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS); timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
// connect our readPendingDatagrams method to the readyRead() signal of the socket // connect our readPendingDatagrams method to the readyRead() signal of the socket
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
// connections to AccountManager for authentication // connections to AccountManager for authentication
connect(&AccountManager::getInstance(), &AccountManager::authRequired, connect(&AccountManager::getInstance(), &AccountManager::authRequired,
this, &AssignmentClient::handleAuthenticationRequest); this, &AssignmentClient::handleAuthenticationRequest);
@ -121,49 +114,49 @@ void AssignmentClient::sendAssignmentRequest() {
void AssignmentClient::readPendingDatagrams() { void AssignmentClient::readPendingDatagrams() {
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
QByteArray receivedPacket; QByteArray receivedPacket;
HifiSockAddr senderSockAddr; HifiSockAddr senderSockAddr;
while (nodeList->getNodeSocket().hasPendingDatagrams()) { while (nodeList->getNodeSocket().hasPendingDatagrams()) {
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize()); receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(), nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
if (nodeList->packetVersionAndHashMatch(receivedPacket)) { if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) { if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
// construct the deployed assignment from the packet data // construct the deployed assignment from the packet data
_currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket)); _currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket));
if (_currentAssignment) { if (_currentAssignment) {
qDebug() << "Received an assignment -" << *_currentAssignment; qDebug() << "Received an assignment -" << *_currentAssignment;
// switch our DomainHandler hostname and port to whoever sent us the assignment // switch our DomainHandler hostname and port to whoever sent us the assignment
nodeList->getDomainHandler().setSockAddr(senderSockAddr, _assignmentServerHostname); nodeList->getDomainHandler().setSockAddr(senderSockAddr, _assignmentServerHostname);
nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID()); nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID());
qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
// start the deployed assignment // start the deployed assignment
AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this); AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this);
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run); connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit); connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit);
connect(_currentAssignment.data(), &ThreadedAssignment::finished, connect(_currentAssignment.data(), &ThreadedAssignment::finished,
this, &AssignmentClient::assignmentCompleted); this, &AssignmentClient::assignmentCompleted);
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
_currentAssignment->moveToThread(workerThread); _currentAssignment->moveToThread(workerThread);
// move the NodeList to the thread used for the _current assignment // move the NodeList to the thread used for the _current assignment
nodeList->moveToThread(workerThread); nodeList->moveToThread(workerThread);
// let the assignment handle the incoming datagrams for its duration // let the assignment handle the incoming datagrams for its duration
disconnect(&nodeList->getNodeSocket(), 0, this, 0); disconnect(&nodeList->getNodeSocket(), 0, this, 0);
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(), connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(),
&ThreadedAssignment::readPendingDatagrams); &ThreadedAssignment::readPendingDatagrams);
// Starts an event loop, and emits workerThread->started() // Starts an event loop, and emits workerThread->started()
workerThread->start(); workerThread->start();
} else { } else {
@ -180,15 +173,15 @@ void AssignmentClient::readPendingDatagrams() {
void AssignmentClient::handleAuthenticationRequest() { void AssignmentClient::handleAuthenticationRequest() {
const QString DATA_SERVER_USERNAME_ENV = "HIFI_AC_USERNAME"; const QString DATA_SERVER_USERNAME_ENV = "HIFI_AC_USERNAME";
const QString DATA_SERVER_PASSWORD_ENV = "HIFI_AC_PASSWORD"; const QString DATA_SERVER_PASSWORD_ENV = "HIFI_AC_PASSWORD";
// this node will be using an authentication server, let's make sure we have a username/password // this node will be using an authentication server, let's make sure we have a username/password
QProcessEnvironment sysEnvironment = QProcessEnvironment::systemEnvironment(); QProcessEnvironment sysEnvironment = QProcessEnvironment::systemEnvironment();
QString username = sysEnvironment.value(DATA_SERVER_USERNAME_ENV); QString username = sysEnvironment.value(DATA_SERVER_USERNAME_ENV);
QString password = sysEnvironment.value(DATA_SERVER_PASSWORD_ENV); QString password = sysEnvironment.value(DATA_SERVER_PASSWORD_ENV);
AccountManager& accountManager = AccountManager::getInstance(); AccountManager& accountManager = AccountManager::getInstance();
if (!username.isEmpty() && !password.isEmpty()) { if (!username.isEmpty() && !password.isEmpty()) {
// ask the account manager to log us in from the env variables // ask the account manager to log us in from the env variables
accountManager.requestAccessToken(username, password); accountManager.requestAccessToken(username, password);
@ -196,7 +189,7 @@ void AssignmentClient::handleAuthenticationRequest() {
qDebug() << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString()) qDebug() << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString())
<< "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV) << "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV)
<< "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate."; << "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate.";
return; return;
} }
} }
@ -204,15 +197,15 @@ void AssignmentClient::handleAuthenticationRequest() {
void AssignmentClient::assignmentCompleted() { void AssignmentClient::assignmentCompleted() {
// reset the logging target to the the CHILD_TARGET_NAME // reset the logging target to the the CHILD_TARGET_NAME
Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
qDebug("Assignment finished or never started - waiting for new assignment."); qDebug("Assignment finished or never started - waiting for new assignment.");
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
// have us handle incoming NodeList datagrams again // have us handle incoming NodeList datagrams again
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0); disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0);
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
// clear our current assignment shared pointer now that we're done with it // clear our current assignment shared pointer now that we're done with it
// if the assignment thread is still around it has its own shared pointer to the assignment // if the assignment thread is still around it has its own shared pointer to the assignment
_currentAssignment.clear(); _currentAssignment.clear();

File diff suppressed because it is too large Load diff

View file

@ -691,6 +691,10 @@ function rayPlaneIntersection(pickRay, point, normal) {
} }
function mousePressEvent(event) { function mousePressEvent(event) {
if (altIsPressed) {
return;
}
mouseLastPosition = { x: event.x, y: event.y }; mouseLastPosition = { x: event.x, y: event.y };
modelSelected = false; modelSelected = false;
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
@ -790,6 +794,10 @@ var oldModifier = 0;
var modifier = 0; var modifier = 0;
var wasShifted = false; var wasShifted = false;
function mouseMoveEvent(event) { function mouseMoveEvent(event) {
if (altIsPressed) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
if (!modelSelected) { if (!modelSelected) {
@ -894,6 +902,10 @@ function mouseMoveEvent(event) {
} }
function mouseReleaseEvent(event) { function mouseReleaseEvent(event) {
if (altIsPressed) {
return;
}
modelSelected = false; modelSelected = false;
glowedModelID.id = -1; glowedModelID.id = -1;
@ -962,4 +974,16 @@ Menu.menuItemEvent.connect(function(menuItem){
} }
}); });
// handling of inspect.js concurrence
altIsPressed = false;
Controller.keyPressEvent.connect(function(event) {
if (event.text == "ALT") {
altIsPressed = true;
}
});
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "ALT") {
altIsPressed = false;
}
});

View file

@ -177,30 +177,45 @@ function keyReleaseEvent(event) {
function mousePressEvent(event) { function mousePressEvent(event) {
if (alt && !isActive) { if (alt && !isActive) {
isActive = true;
mouseLastX = event.x; mouseLastX = event.x;
mouseLastY = event.y; mouseLastY = event.y;
// Compute trajectories related values // Compute trajectories related values
var pickRay = Camera.computePickRay(mouseLastX, mouseLastY); var pickRay = Camera.computePickRay(mouseLastX, mouseLastY);
var intersection = Voxels.findRayIntersection(pickRay); var voxelIntersection = Voxels.findRayIntersection(pickRay);
var modelIntersection = Models.findRayIntersection(pickRay);
position = Camera.getPosition(); position = Camera.getPosition();
avatarTarget = MyAvatar.getTargetAvatarPosition(); var avatarTarget = MyAvatar.getTargetAvatarPosition();
voxelTarget = intersection.intersection; var voxelTarget = voxelIntersection.intersection;
if (Vec3.length(Vec3.subtract(avatarTarget, position)) < Vec3.length(Vec3.subtract(voxelTarget, position))) {
if (avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0) {
center = avatarTarget; var distance = -1;
} else { var string;
center = voxelTarget;
} if (modelIntersection.intersects && modelIntersection.accurate) {
} else { distance = modelIntersection.distance;
if (voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0) { center = modelIntersection.modelProperties.position;
center = voxelTarget; string = "Inspecting model";
} else { }
center = avatarTarget;
} if ((distance == -1 || Vec3.length(Vec3.subtract(avatarTarget, position)) < distance) &&
(avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0)) {
distance = Vec3.length(Vec3.subtract(avatarTarget, position));
center = avatarTarget;
string = "Inspecting avatar";
}
if ((distance == -1 || Vec3.length(Vec3.subtract(voxelTarget, position)) < distance) &&
(voxelTarget.x != 0 || voxelTarget.y != 0 || voxelTarget.z != 0)) {
distance = Vec3.length(Vec3.subtract(voxelTarget, position));
center = voxelTarget;
string = "Inspecting voxel";
}
if (distance == -1) {
return;
} }
vector = Vec3.subtract(position, center); vector = Vec3.subtract(position, center);
@ -209,6 +224,8 @@ function mousePressEvent(event) {
altitude = Math.asin(vector.y / Vec3.length(vector)); altitude = Math.asin(vector.y / Vec3.length(vector));
Camera.keepLookingAt(center); Camera.keepLookingAt(center);
print(string);
isActive = true;
} }
} }

View file

@ -1379,6 +1379,9 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) {
resizeGL(_glWidget->width(),_glWidget->height()); resizeGL(_glWidget->width(),_glWidget->height());
} }
void Application::setEnableVRMode(bool enableVRMode) {
resizeGL(_glWidget->width(), _glWidget->height());
}
void Application::setRenderVoxels(bool voxelRender) { void Application::setRenderVoxels(bool voxelRender) {
_voxelEditSender.setShouldSend(voxelRender); _voxelEditSender.setShouldSend(voxelRender);

View file

@ -346,6 +346,7 @@ private slots:
void setFullscreen(bool fullscreen); void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode); void setEnable3DTVMode(bool enable3DTVMode);
void setEnableVRMode(bool enableVRMode);
void cameraMenuChanged(); void cameraMenuChanged();
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);

View file

@ -127,7 +127,7 @@ Menu::Menu() :
toggleLoginMenuItem(); toggleLoginMenuItem();
// connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item // connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item
connect(&accountManager, &AccountManager::accessTokenChanged, this, &Menu::toggleLoginMenuItem); connect(&accountManager, &AccountManager::profileChanged, this, &Menu::toggleLoginMenuItem);
connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem); connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem);
addDisabledActionAndSeparator(fileMenu, "Scripts"); addDisabledActionAndSeparator(fileMenu, "Scripts");
@ -256,6 +256,11 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
appInstance, SLOT(cameraMenuChanged())); appInstance, SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0,
false,
appInstance,
SLOT(setEnableVRMode(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0,
false, false,
appInstance, appInstance,
@ -323,7 +328,7 @@ Menu::Menu() :
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
@ -404,7 +409,7 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false);
addDisabledActionAndSeparator(developerMenu, "Testing"); addDisabledActionAndSeparator(developerMenu, "Testing");
QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools");
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
@ -459,7 +464,7 @@ Menu::Menu() :
false, false,
appInstance->getAudio(), appInstance->getAudio(),
SLOT(toggleToneInjection())); SLOT(toggleToneInjection()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope,
Qt::CTRL | Qt::Key_P, false, Qt::CTRL | Qt::Key_P, false,
appInstance->getAudio(), appInstance->getAudio(),
SLOT(toggleScope())); SLOT(toggleScope()));
@ -1772,4 +1777,3 @@ QString Menu::getSnapshotsLocation() const {
} }
return _snapshotsLocation; return _snapshotsLocation;
} }

View file

@ -336,6 +336,7 @@ namespace MenuOption {
const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoLocalAudio = "Echo Local Audio";
const QString EchoServerAudio = "Echo Server Audio"; const QString EchoServerAudio = "Echo Server Audio";
const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString Enable3DTVMode = "Enable 3DTV Mode";
const QString EnableVRMode = "Enable VR Mode";
const QString ExpandMiscAvatarTiming = "Expand Misc MyAvatar Timing"; const QString ExpandMiscAvatarTiming = "Expand Misc MyAvatar Timing";
const QString ExpandAvatarUpdateTiming = "Expand MyAvatar update Timing"; const QString ExpandAvatarUpdateTiming = "Expand MyAvatar update Timing";
const QString ExpandAvatarSimulateTiming = "Expand MyAvatar simulate Timing"; const QString ExpandAvatarSimulateTiming = "Expand MyAvatar simulate Timing";

View file

@ -23,7 +23,7 @@ XmppClient::XmppClient() :
_xmppMUCManager() _xmppMUCManager()
{ {
AccountManager& accountManager = AccountManager::getInstance(); AccountManager& accountManager = AccountManager::getInstance();
connect(&accountManager, SIGNAL(accessTokenChanged()), this, SLOT(connectToServer())); connect(&accountManager, SIGNAL(profileChanged()), this, SLOT(connectToServer()));
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer())); connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
} }

View file

@ -72,6 +72,14 @@ void OculusManager::connect() {
#endif #endif
} }
bool OculusManager::isConnected() {
#ifdef HAVE_LIBOVR
return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode);
#else
return false;
#endif
}
void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) {
#ifdef HAVE_LIBOVR #ifdef HAVE_LIBOVR
_stereoConfig.SetFullViewport(Viewport(0, 0, screenWidth, screenHeight)); _stereoConfig.SetFullViewport(Viewport(0, 0, screenWidth, screenHeight));

View file

@ -27,7 +27,7 @@ class OculusManager {
public: public:
static void connect(); static void connect();
static bool isConnected() { return _isConnected; } static bool isConnected();
static void configureCamera(Camera& camera, int screenWidth, int screenHeight); static void configureCamera(Camera& camera, int screenWidth, int screenHeight);

View file

@ -76,6 +76,7 @@ void LocationManager::goTo(QString destination) {
// go to coordinate destination or to Username // go to coordinate destination or to Username
if (!goToDestination(destination)) { if (!goToDestination(destination)) {
destination = QString(QUrl::toPercentEncoding(destination)); destination = QString(QUrl::toPercentEncoding(destination));
JSONCallbackParameters callbackParams; JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this; callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "goToAddressFromResponse"; callbackParams.jsonCallbackMethod = "goToAddressFromResponse";

View file

@ -55,13 +55,13 @@ AccountManager::AccountManager() :
{ {
qRegisterMetaType<OAuthAccessToken>("OAuthAccessToken"); qRegisterMetaType<OAuthAccessToken>("OAuthAccessToken");
qRegisterMetaTypeStreamOperators<OAuthAccessToken>("OAuthAccessToken"); qRegisterMetaTypeStreamOperators<OAuthAccessToken>("OAuthAccessToken");
qRegisterMetaType<DataServerAccountInfo>("DataServerAccountInfo"); qRegisterMetaType<DataServerAccountInfo>("DataServerAccountInfo");
qRegisterMetaTypeStreamOperators<DataServerAccountInfo>("DataServerAccountInfo"); qRegisterMetaTypeStreamOperators<DataServerAccountInfo>("DataServerAccountInfo");
qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation"); qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation");
qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters"); qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters");
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
} }
@ -70,18 +70,18 @@ const QString DOUBLE_SLASH_SUBSTITUTE = "slashslash";
void AccountManager::logout() { void AccountManager::logout() {
// a logout means we want to delete the DataServerAccountInfo we currently have for this URL, in-memory and in file // a logout means we want to delete the DataServerAccountInfo we currently have for this URL, in-memory and in file
_accountInfo = DataServerAccountInfo(); _accountInfo = DataServerAccountInfo();
emit balanceChanged(0); emit balanceChanged(0);
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
QSettings settings; QSettings settings;
settings.beginGroup(ACCOUNTS_GROUP); settings.beginGroup(ACCOUNTS_GROUP);
QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE)); QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE));
settings.remove(keyURLString); settings.remove(keyURLString);
qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file"; qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file";
emit logoutComplete(); emit logoutComplete();
// the username has changed to blank // the username has changed to blank
emit usernameChanged(QString()); emit usernameChanged(QString());
@ -93,7 +93,7 @@ void AccountManager::updateBalance() {
JSONCallbackParameters callbackParameters; JSONCallbackParameters callbackParameters;
callbackParameters.jsonCallbackReceiver = &_accountInfo; callbackParameters.jsonCallbackReceiver = &_accountInfo;
callbackParameters.jsonCallbackMethod = "setBalanceFromJSON"; callbackParameters.jsonCallbackMethod = "setBalanceFromJSON";
authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters); authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters);
} }
} }
@ -105,28 +105,33 @@ void AccountManager::accountInfoBalanceChanged(qint64 newBalance) {
void AccountManager::setAuthURL(const QUrl& authURL) { void AccountManager::setAuthURL(const QUrl& authURL) {
if (_authURL != authURL) { if (_authURL != authURL) {
_authURL = authURL; _authURL = authURL;
qDebug() << "URL for node authentication has been changed to" << qPrintable(_authURL.toString()); qDebug() << "URL for node authentication has been changed to" << qPrintable(_authURL.toString());
qDebug() << "Re-setting authentication flow."; qDebug() << "Re-setting authentication flow.";
// check if there are existing access tokens to load from settings // check if there are existing access tokens to load from settings
QSettings settings; QSettings settings;
settings.beginGroup(ACCOUNTS_GROUP); settings.beginGroup(ACCOUNTS_GROUP);
foreach(const QString& key, settings.allKeys()) { foreach(const QString& key, settings.allKeys()) {
// take a key copy to perform the double slash replacement // take a key copy to perform the double slash replacement
QString keyCopy(key); QString keyCopy(key);
QUrl keyURL(keyCopy.replace("slashslash", "//")); QUrl keyURL(keyCopy.replace("slashslash", "//"));
if (keyURL == _authURL) { if (keyURL == _authURL) {
// pull out the stored access token and store it in memory // pull out the stored access token and store it in memory
_accountInfo = settings.value(key).value<DataServerAccountInfo>(); _accountInfo = settings.value(key).value<DataServerAccountInfo>();
qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString()); qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString());
emit accessTokenChanged(); // profile info isn't guaranteed to be saved too
if (_accountInfo.hasProfile()) {
emit profileChanged();
} else {
requestProfile();
}
} }
} }
// tell listeners that the auth endpoint has changed // tell listeners that the auth endpoint has changed
emit authEndpointChanged(); emit authEndpointChanged();
} }
@ -147,36 +152,36 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan
void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams, const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
if (!_networkAccessManager) { if (!_networkAccessManager) {
_networkAccessManager = new QNetworkAccessManager(this); _networkAccessManager = new QNetworkAccessManager(this);
} }
if (hasValidAccessToken()) { if (hasValidAccessToken()) {
QNetworkRequest authenticatedRequest; QNetworkRequest authenticatedRequest;
QUrl requestURL = _authURL; QUrl requestURL = _authURL;
if (path.startsWith("/")) { if (path.startsWith("/")) {
requestURL.setPath(path); requestURL.setPath(path);
} else { } else {
requestURL.setPath("/" + path); requestURL.setPath("/" + path);
} }
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
authenticatedRequest.setUrl(requestURL); authenticatedRequest.setUrl(requestURL);
if (VERBOSE_HTTP_REQUEST_DEBUGGING) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString()); qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString());
if (!dataByteArray.isEmpty()) { if (!dataByteArray.isEmpty()) {
qDebug() << "The POST/PUT body -" << QString(dataByteArray); qDebug() << "The POST/PUT body -" << QString(dataByteArray);
} }
} }
QNetworkReply* networkReply = NULL; QNetworkReply* networkReply = NULL;
switch (operation) { switch (operation) {
case QNetworkAccessManager::GetOperation: case QNetworkAccessManager::GetOperation:
networkReply = _networkAccessManager->get(authenticatedRequest); networkReply = _networkAccessManager->get(authenticatedRequest);
@ -198,24 +203,24 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray);
} }
} }
break; break;
default: default:
// other methods not yet handled // other methods not yet handled
break; break;
} }
if (networkReply) { if (networkReply) {
if (!callbackParams.isEmpty()) { if (!callbackParams.isEmpty()) {
// if we have information for a callback, insert the callbackParams into our local map // if we have information for a callback, insert the callbackParams into our local map
_pendingCallbackMap.insert(networkReply, callbackParams); _pendingCallbackMap.insert(networkReply, callbackParams);
if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) { if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) {
callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)), callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)),
callbackParams.updateSlot.toStdString().c_str()); callbackParams.updateSlot.toStdString().c_str());
} }
} }
// if we ended up firing of a request, hook up to it now // if we ended up firing of a request, hook up to it now
connect(networkReply, SIGNAL(finished()), SLOT(processReply())); connect(networkReply, SIGNAL(finished()), SLOT(processReply()));
} }
@ -224,7 +229,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::
void AccountManager::processReply() { void AccountManager::processReply() {
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender()); QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
if (requestReply->error() == QNetworkReply::NoError) { if (requestReply->error() == QNetworkReply::NoError) {
passSuccessToCallback(requestReply); passSuccessToCallback(requestReply);
} else { } else {
@ -235,17 +240,17 @@ void AccountManager::processReply() {
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply); JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
if (callbackParams.jsonCallbackReceiver) { if (callbackParams.jsonCallbackReceiver) {
// invoke the right method on the callback receiver // invoke the right method on the callback receiver
QMetaObject::invokeMethod(callbackParams.jsonCallbackReceiver, qPrintable(callbackParams.jsonCallbackMethod), QMetaObject::invokeMethod(callbackParams.jsonCallbackReceiver, qPrintable(callbackParams.jsonCallbackMethod),
Q_ARG(const QJsonObject&, jsonResponse.object())); Q_ARG(const QJsonObject&, jsonResponse.object()));
// remove the related reply-callback group from the map // remove the related reply-callback group from the map
_pendingCallbackMap.remove(requestReply); _pendingCallbackMap.remove(requestReply);
} else { } else {
if (VERBOSE_HTTP_REQUEST_DEBUGGING) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "Received JSON response from data-server that has no matching callback."; qDebug() << "Received JSON response from data-server that has no matching callback.";
@ -256,13 +261,13 @@ void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply); JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
if (callbackParams.errorCallbackReceiver) { if (callbackParams.errorCallbackReceiver) {
// invoke the right method on the callback receiver // invoke the right method on the callback receiver
QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod), QMetaObject::invokeMethod(callbackParams.errorCallbackReceiver, qPrintable(callbackParams.errorCallbackMethod),
Q_ARG(QNetworkReply::NetworkError, requestReply->error()), Q_ARG(QNetworkReply::NetworkError, requestReply->error()),
Q_ARG(const QString&, requestReply->errorString())); Q_ARG(const QString&, requestReply->errorString()));
// remove the related reply-callback group from the map // remove the related reply-callback group from the map
_pendingCallbackMap.remove(requestReply); _pendingCallbackMap.remove(requestReply);
} else { } else {
@ -274,12 +279,12 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
} }
bool AccountManager::hasValidAccessToken() { bool AccountManager::hasValidAccessToken() {
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) { if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
if (VERBOSE_HTTP_REQUEST_DEBUGGING) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "An access token is required for requests to" << qPrintable(_authURL.toString()); qDebug() << "An access token is required for requests to" << qPrintable(_authURL.toString());
} }
return false; return false;
} else { } else {
return true; return true;
@ -288,12 +293,12 @@ bool AccountManager::hasValidAccessToken() {
bool AccountManager::checkAndSignalForAccessToken() { bool AccountManager::checkAndSignalForAccessToken() {
bool hasToken = hasValidAccessToken(); bool hasToken = hasValidAccessToken();
if (!hasToken) { if (!hasToken) {
// emit a signal so somebody can call back to us and request an access token given a username and password // emit a signal so somebody can call back to us and request an access token given a username and password
emit authRequired(); emit authRequired();
} }
return hasToken; return hasToken;
} }
@ -304,36 +309,36 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
} }
QNetworkRequest request; QNetworkRequest request;
QUrl grantURL = _authURL; QUrl grantURL = _authURL;
grantURL.setPath("/oauth/token"); grantURL.setPath("/oauth/token");
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner"; const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
QByteArray postData; QByteArray postData;
postData.append("grant_type=password&"); postData.append("grant_type=password&");
postData.append("username=" + login + "&"); postData.append("username=" + login + "&");
postData.append("password=" + QUrl::toPercentEncoding(password) + "&"); postData.append("password=" + QUrl::toPercentEncoding(password) + "&");
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE); postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
request.setUrl(grantURL); request.setUrl(grantURL);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply* requestReply = _networkAccessManager->post(request, postData); QNetworkReply* requestReply = _networkAccessManager->post(request, postData);
connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestFinished); connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished);
connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError)));
} }
void AccountManager::requestFinished() { void AccountManager::requestAccessTokenFinished() {
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender()); QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
const QJsonObject& rootObject = jsonResponse.object(); const QJsonObject& rootObject = jsonResponse.object();
if (!rootObject.contains("error")) { if (!rootObject.contains("error")) {
// construct an OAuthAccessToken from the json object // construct an OAuthAccessToken from the json object
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in") if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|| !rootObject.contains("token_type")) { || !rootObject.contains("token_type")) {
// TODO: error handling - malformed token response // TODO: error handling - malformed token response
@ -342,23 +347,21 @@ void AccountManager::requestFinished() {
// clear the path from the response URL so we have the right root URL for this access token // clear the path from the response URL so we have the right root URL for this access token
QUrl rootURL = requestReply->url(); QUrl rootURL = requestReply->url();
rootURL.setPath(""); rootURL.setPath("");
qDebug() << "Storing an account with access-token for" << qPrintable(rootURL.toString()); qDebug() << "Storing an account with access-token for" << qPrintable(rootURL.toString());
_accountInfo = DataServerAccountInfo(rootObject); _accountInfo = DataServerAccountInfo();
_accountInfo.setAccessTokenFromJSON(rootObject);
emit loginComplete(rootURL); emit loginComplete(rootURL);
// the username has changed to whatever came back
emit usernameChanged(_accountInfo.getUsername());
// we have found or requested an access token
emit accessTokenChanged();
// store this access token into the local settings // store this access token into the local settings
QSettings localSettings; QSettings localSettings;
localSettings.beginGroup(ACCOUNTS_GROUP); localSettings.beginGroup(ACCOUNTS_GROUP);
localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE), localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
QVariant::fromValue(_accountInfo)); QVariant::fromValue(_accountInfo));
requestProfile();
} }
} else { } else {
// TODO: error handling // TODO: error handling
@ -367,7 +370,53 @@ void AccountManager::requestFinished() {
} }
} }
void AccountManager::requestError(QNetworkReply::NetworkError error) { void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) {
// TODO: error handling // TODO: error handling
qDebug() << "AccountManager requestError - " << error; qDebug() << "AccountManager requestError - " << error;
} }
void AccountManager::requestProfile() {
if (!_networkAccessManager) {
_networkAccessManager = new QNetworkAccessManager(this);
}
QUrl profileURL = _authURL;
profileURL.setPath("/api/v1/users/profile");
profileURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL));
connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished);
connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError)));
}
void AccountManager::requestProfileFinished() {
QNetworkReply* profileReply = reinterpret_cast<QNetworkReply*>(sender());
QJsonDocument jsonResponse = QJsonDocument::fromJson(profileReply->readAll());
const QJsonObject& rootObject = jsonResponse.object();
if (rootObject.contains("status") && rootObject["status"].toString() == "success") {
_accountInfo.setProfileInfoFromJSON(rootObject);
emit profileChanged();
// the username has changed to whatever came back
emit usernameChanged(_accountInfo.getUsername());
// store the whole profile into the local settings
QUrl rootURL = profileReply->url();
rootURL.setPath("");
QSettings localSettings;
localSettings.beginGroup(ACCOUNTS_GROUP);
localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
QVariant::fromValue(_accountInfo));
} else {
// TODO: error handling
qDebug() << "Error in response for profile";
}
}
void AccountManager::requestProfileError(QNetworkReply::NetworkError error) {
// TODO: error handling
qDebug() << "AccountManager requestProfileError - " << error;
}

View file

@ -23,9 +23,9 @@
class JSONCallbackParameters { class JSONCallbackParameters {
public: public:
JSONCallbackParameters(); JSONCallbackParameters();
bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; } bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; }
QObject* jsonCallbackReceiver; QObject* jsonCallbackReceiver;
QString jsonCallbackMethod; QString jsonCallbackMethod;
QObject* errorCallbackReceiver; QObject* errorCallbackReceiver;
@ -38,30 +38,33 @@ class AccountManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static AccountManager& getInstance(); static AccountManager& getInstance();
void authenticatedRequest(const QString& path, void authenticatedRequest(const QString& path,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(), const QByteArray& dataByteArray = QByteArray(),
QHttpMultiPart* dataMultiPart = NULL); QHttpMultiPart* dataMultiPart = NULL);
const QUrl& getAuthURL() const { return _authURL; } const QUrl& getAuthURL() const { return _authURL; }
void setAuthURL(const QUrl& authURL); void setAuthURL(const QUrl& authURL);
bool hasAuthEndpoint() { return !_authURL.isEmpty(); } bool hasAuthEndpoint() { return !_authURL.isEmpty(); }
bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); } bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); }
bool hasValidAccessToken(); bool hasValidAccessToken();
Q_INVOKABLE bool checkAndSignalForAccessToken(); Q_INVOKABLE bool checkAndSignalForAccessToken();
void requestAccessToken(const QString& login, const QString& password); void requestAccessToken(const QString& login, const QString& password);
void requestProfile();
const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; } const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; }
void destroy() { delete _networkAccessManager; } void destroy() { delete _networkAccessManager; }
public slots: public slots:
void requestFinished(); void requestAccessTokenFinished();
void requestError(QNetworkReply::NetworkError error); void requestProfileFinished();
void requestAccessTokenError(QNetworkReply::NetworkError error);
void requestProfileError(QNetworkReply::NetworkError error);
void logout(); void logout();
void updateBalance(); void updateBalance();
void accountInfoBalanceChanged(qint64 newBalance); void accountInfoBalanceChanged(qint64 newBalance);
@ -69,7 +72,7 @@ signals:
void authRequired(); void authRequired();
void authEndpointChanged(); void authEndpointChanged();
void usernameChanged(const QString& username); void usernameChanged(const QString& username);
void accessTokenChanged(); void profileChanged();
void loginComplete(const QUrl& authURL); void loginComplete(const QUrl& authURL);
void loginFailed(); void loginFailed();
void logoutComplete(); void logoutComplete();
@ -80,19 +83,19 @@ private:
AccountManager(); AccountManager();
AccountManager(AccountManager const& other); // not implemented AccountManager(AccountManager const& other); // not implemented
void operator=(AccountManager const& other); // not implemented void operator=(AccountManager const& other); // not implemented
void passSuccessToCallback(QNetworkReply* reply); void passSuccessToCallback(QNetworkReply* reply);
void passErrorToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply);
Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams, const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart); QHttpMultiPart* dataMultiPart);
QUrl _authURL; QUrl _authURL;
QNetworkAccessManager* _networkAccessManager; QNetworkAccessManager* _networkAccessManager;
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap; QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;
DataServerAccountInfo _accountInfo; DataServerAccountInfo _accountInfo;
}; };

View file

@ -21,20 +21,7 @@ DataServerAccountInfo::DataServerAccountInfo() :
_balance(0), _balance(0),
_hasBalance(false) _hasBalance(false)
{ {
}
DataServerAccountInfo::DataServerAccountInfo(const QJsonObject& jsonObject) :
_accessToken(jsonObject),
_username(),
_xmppPassword(),
_balance(0),
_hasBalance(false)
{
QJsonObject userJSONObject = jsonObject["user"].toObject();
setUsername(userJSONObject["username"].toString());
setXMPPPassword(userJSONObject["xmpp_password"].toString());
setDiscourseApiKey(userJSONObject["discourse_api_key"].toString());
} }
DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) { DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) {
@ -54,7 +41,7 @@ DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountI
void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
using std::swap; using std::swap;
swap(_accessToken, otherInfo._accessToken); swap(_accessToken, otherInfo._accessToken);
swap(_username, otherInfo._username); swap(_username, otherInfo._username);
swap(_xmppPassword, otherInfo._xmppPassword); swap(_xmppPassword, otherInfo._xmppPassword);
@ -63,10 +50,14 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
swap(_hasBalance, otherInfo._hasBalance); swap(_hasBalance, otherInfo._hasBalance);
} }
void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
_accessToken = OAuthAccessToken(jsonObject);
}
void DataServerAccountInfo::setUsername(const QString& username) { void DataServerAccountInfo::setUsername(const QString& username) {
if (_username != username) { if (_username != username) {
_username = username; _username = username;
qDebug() << "Username changed to" << username; qDebug() << "Username changed to" << username;
} }
} }
@ -87,7 +78,7 @@ void DataServerAccountInfo::setBalance(qint64 balance) {
if (!_hasBalance || _balance != balance) { if (!_hasBalance || _balance != balance) {
_balance = balance; _balance = balance;
_hasBalance = true; _hasBalance = true;
emit balanceChanged(_balance); emit balanceChanged(_balance);
} }
} }
@ -99,6 +90,17 @@ void DataServerAccountInfo::setBalanceFromJSON(const QJsonObject& jsonObject) {
} }
} }
bool DataServerAccountInfo::hasProfile() const {
return _username.length() > 0;
}
void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject) {
QJsonObject user = jsonObject["data"].toObject()["user"].toObject();
setUsername(user["username"].toString());
setXMPPPassword(user["xmpp_password"].toString());
setDiscourseApiKey(user["discourse_api_key"].toString());
}
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;
return out; return out;

View file

@ -22,12 +22,12 @@ class DataServerAccountInfo : public QObject {
Q_OBJECT Q_OBJECT
public: public:
DataServerAccountInfo(); DataServerAccountInfo();
DataServerAccountInfo(const QJsonObject& jsonObject);
DataServerAccountInfo(const DataServerAccountInfo& otherInfo); DataServerAccountInfo(const DataServerAccountInfo& otherInfo);
DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo); DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo);
const OAuthAccessToken& getAccessToken() const { return _accessToken; } const OAuthAccessToken& getAccessToken() const { return _accessToken; }
void setAccessTokenFromJSON(const QJsonObject& jsonObject);
const QString& getUsername() const { return _username; } const QString& getUsername() const { return _username; }
void setUsername(const QString& username); void setUsername(const QString& username);
@ -36,20 +36,24 @@ public:
const QString& getDiscourseApiKey() const { return _discourseApiKey; } const QString& getDiscourseApiKey() const { return _discourseApiKey; }
void setDiscourseApiKey(const QString& discourseApiKey); void setDiscourseApiKey(const QString& discourseApiKey);
qint64 getBalance() const { return _balance; } qint64 getBalance() const { return _balance; }
void setBalance(qint64 balance); void setBalance(qint64 balance);
bool hasBalance() const { return _hasBalance; } bool hasBalance() const { return _hasBalance; }
void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; } void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; }
Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject); Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject);
bool hasProfile() const;
void setProfileInfoFromJSON(const QJsonObject& jsonObject);
friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info); friend QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info);
friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info); friend QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info);
signals: signals:
qint64 balanceChanged(qint64 newBalance); qint64 balanceChanged(qint64 newBalance);
private: private:
void swap(DataServerAccountInfo& otherInfo); void swap(DataServerAccountInfo& otherInfo);
OAuthAccessToken _accessToken; OAuthAccessToken _accessToken;
QString _username; QString _username;
QString _xmppPassword; QString _xmppPassword;

View file

@ -19,71 +19,70 @@
#include "HifiConfigVariantMap.h" #include "HifiConfigVariantMap.h"
QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) { QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) {
QVariantMap mergedMap; QVariantMap mergedMap;
// Add anything in the CL parameter list to the variant map. // Add anything in the CL parameter list to the variant map.
// Take anything with a dash in it as a key, and the values after it as the value. // Take anything with a dash in it as a key, and the values after it as the value.
const QString DASHED_KEY_REGEX_STRING = "(^-{1,2})([\\w-]+)"; const QString DASHED_KEY_REGEX_STRING = "(^-{1,2})([\\w-]+)";
QRegExp dashedKeyRegex(DASHED_KEY_REGEX_STRING); QRegExp dashedKeyRegex(DASHED_KEY_REGEX_STRING);
int keyIndex = argumentList.indexOf(dashedKeyRegex); int keyIndex = argumentList.indexOf(dashedKeyRegex);
int nextKeyIndex = 0; int nextKeyIndex = 0;
// check if there is a config file to read where we can pull config info not passed on command line // check if there is a config file to read where we can pull config info not passed on command line
const QString CONFIG_FILE_OPTION = "--config"; const QString CONFIG_FILE_OPTION = "--config";
while (keyIndex != -1) { while (keyIndex != -1) {
if (argumentList[keyIndex] != CONFIG_FILE_OPTION) { if (argumentList[keyIndex] != CONFIG_FILE_OPTION) {
// we have a key - look forward to see how many values associate to it // we have a key - look forward to see how many values associate to it
QString key = dashedKeyRegex.cap(2); QString key = dashedKeyRegex.cap(2);
nextKeyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1); nextKeyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1);
if (nextKeyIndex == keyIndex + 1 || keyIndex == argumentList.size() - 1) { if (nextKeyIndex == keyIndex + 1 || keyIndex == argumentList.size() - 1) {
// there's no value associated with this option, it's a boolean // this option is simply a switch, so add it to the map with a value of `true`
// so add it to the variant map with NULL as value mergedMap.insertMulti(key, QVariant(true));
mergedMap.insertMulti(key, QVariant());
} else { } else {
int maxIndex = (nextKeyIndex == -1) ? argumentList.size() - 1: nextKeyIndex; int maxIndex = (nextKeyIndex == -1) ? argumentList.size() : nextKeyIndex;
// there's at least one value associated with the option // there's at least one value associated with the option
// pull the first value to start // pull the first value to start
QString value = argumentList[keyIndex + 1]; QString value = argumentList[keyIndex + 1];
// for any extra values, append them, with a space, to the value string // for any extra values, append them, with a space, to the value string
for (int i = keyIndex + 2; i <= maxIndex; i++) { for (int i = keyIndex + 2; i < maxIndex; i++) {
value += " " + argumentList[i]; value += " " + argumentList[i];
} }
// add the finalized value to the merged map // add the finalized value to the merged map
mergedMap.insert(key, value); mergedMap.insert(key, value);
} }
keyIndex = nextKeyIndex; keyIndex = nextKeyIndex;
} else { } else {
keyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1); keyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1);
} }
} }
int configIndex = argumentList.indexOf(CONFIG_FILE_OPTION); int configIndex = argumentList.indexOf(CONFIG_FILE_OPTION);
if (configIndex != -1) { if (configIndex != -1) {
// we have a config file - try and read it // we have a config file - try and read it
QString configFilePath = argumentList[configIndex + 1]; QString configFilePath = argumentList[configIndex + 1];
QFile configFile(configFilePath); QFile configFile(configFilePath);
if (configFile.exists()) { if (configFile.exists()) {
qDebug() << "Reading JSON config file at" << configFilePath; qDebug() << "Reading JSON config file at" << configFilePath;
configFile.open(QIODevice::ReadOnly); configFile.open(QIODevice::ReadOnly);
QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll()); QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll());
QJsonObject rootObject = configDocument.object(); QJsonObject rootObject = configDocument.object();
// enumerate the keys of the configDocument object // enumerate the keys of the configDocument object
foreach(const QString& key, rootObject.keys()) { foreach(const QString& key, rootObject.keys()) {
if (!mergedMap.contains(key)) { if (!mergedMap.contains(key)) {
// no match in existing list, add it // no match in existing list, add it
mergedMap.insert(key, QVariant(rootObject[key])); mergedMap.insert(key, QVariant(rootObject[key]));
@ -93,6 +92,6 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL
qDebug() << "Could not find JSON config file at" << configFilePath; qDebug() << "Could not find JSON config file at" << configFilePath;
} }
} }
return mergedMap; return mergedMap;
} }