mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 18:30:42 +02:00
merge with master and try to fix opacity mode stuff
This commit is contained in:
commit
1e100a672e
1614 changed files with 60652 additions and 9556 deletions
|
@ -71,9 +71,13 @@ RUN mkdir "$HIFI_BASE" && \
|
||||||
mkdir "$HIFI_VCPKG_BASE" && \
|
mkdir "$HIFI_VCPKG_BASE" && \
|
||||||
mkdir "$HIFI_ANDROID_PRECOMPILED"
|
mkdir "$HIFI_ANDROID_PRECOMPILED"
|
||||||
|
|
||||||
RUN git clone https://github.com/jherico/hifi.git && \
|
# Checkout a relatively recent commit from the main repository and use it to cache the
|
||||||
|
# gradle and vcpkg dependencies
|
||||||
|
# This commit ID should be updated whenever someone changes the dependency list
|
||||||
|
# in cmake/ports
|
||||||
|
RUN git clone https://github.com/highfidelity/hifi.git && \
|
||||||
cd ~/hifi && \
|
cd ~/hifi && \
|
||||||
git checkout quest/build
|
git checkout 796bfb5d6715ff14c2e60f3ee8fac1465b7578c6
|
||||||
|
|
||||||
WORKDIR /home/jenkins/hifi
|
WORKDIR /home/jenkins/hifi
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) :
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||||
|
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<PluginManager>();
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ void Agent::executeScript() {
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
||||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &player, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||||
if (_shouldMuteRecordingAudio) {
|
if (_shouldMuteRecordingAudio) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -442,9 +442,18 @@ void Agent::executeScript() {
|
||||||
|
|
||||||
QByteArray audio(frame->data);
|
QByteArray audio(frame->data);
|
||||||
|
|
||||||
|
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
|
||||||
|
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||||
|
|
||||||
|
auto volume = player->getVolume();
|
||||||
|
if (volume >= 0.0f && volume < 1.0f) {
|
||||||
|
int32_t fract = (int32_t)(volume * (float)(1 << 16)); // Q16
|
||||||
|
for (int i = 0; i < numSamples; i++) {
|
||||||
|
samples[i] = (fract * (int32_t)samples[i]) >> 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_isNoiseGateEnabled) {
|
if (_isNoiseGateEnabled) {
|
||||||
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
|
|
||||||
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
|
||||||
_audioGate.render(samples, samples, numSamples);
|
_audioGate.render(samples, samples, numSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,6 +520,7 @@ void Agent::executeScript() {
|
||||||
|
|
||||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||||
|
|
||||||
|
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_scriptEngine);
|
||||||
_scriptEngine->run();
|
_scriptEngine->run();
|
||||||
|
|
||||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <AddressManager.h>
|
#include <AddressManager.h>
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
|
#include <CrashAnnotations.h>
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <LogUtils.h>
|
#include <LogUtils.h>
|
||||||
#include <LimitedNodeList.h>
|
#include <LimitedNodeList.h>
|
||||||
|
@ -81,6 +82,9 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
||||||
}
|
}
|
||||||
|
|
||||||
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
_assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
|
||||||
|
if (_assignmentServerSocket.isNull()) {
|
||||||
|
qCCritical(assignment_client) << "PAGE: Couldn't resolve domain server address" << _assignmentServerHostname;
|
||||||
|
}
|
||||||
_assignmentServerSocket.setObjectName("AssignmentServer");
|
_assignmentServerSocket.setObjectName("AssignmentServer");
|
||||||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
|
|
||||||
|
@ -144,6 +148,7 @@ AssignmentClient::~AssignmentClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClient::aboutToQuit() {
|
void AssignmentClient::aboutToQuit() {
|
||||||
|
crash::annotations::setShutdownState(true);
|
||||||
stopAssignmentClient();
|
stopAssignmentClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +178,7 @@ void AssignmentClient::sendStatusPacketToACM() {
|
||||||
|
|
||||||
void AssignmentClient::sendAssignmentRequest() {
|
void AssignmentClient::sendAssignmentRequest() {
|
||||||
if (!_currentAssignment && !_isAssigned) {
|
if (!_currentAssignment && !_isAssigned) {
|
||||||
|
crash::annotations::setShutdownState(false);
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
@ -180,16 +186,21 @@ void AssignmentClient::sendAssignmentRequest() {
|
||||||
// we want to check again for the local domain-server port in case the DS has restarted
|
// we want to check again for the local domain-server port in case the DS has restarted
|
||||||
quint16 localAssignmentServerPort;
|
quint16 localAssignmentServerPort;
|
||||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) {
|
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) {
|
||||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
if (localAssignmentServerPort == 0) {
|
||||||
qCDebug(assignment_client) << "Port for local assignment server read from shared memory is"
|
qCWarning(assignment_client) << "ALERT: Server port from shared memory is 0";
|
||||||
<< localAssignmentServerPort;
|
} else {
|
||||||
|
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||||
|
qCDebug(assignment_client) << "Port for local assignment server read from shared memory is"
|
||||||
|
<< localAssignmentServerPort;
|
||||||
|
|
||||||
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
||||||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(assignment_client) << "Failed to read local assignment server port from shared memory"
|
qCWarning(assignment_client) << "ALERT: Failed to read local assignment server port from shared memory ("
|
||||||
<< "- will send assignment request to previous assignment server socket.";
|
<< DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY
|
||||||
|
<< ")- will send assignment request to previous assignment server socket.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +258,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer<ReceivedMessa
|
||||||
// Starts an event loop, and emits workerThread->started()
|
// Starts an event loop, and emits workerThread->started()
|
||||||
workerThread->start();
|
workerThread->start();
|
||||||
} else {
|
} else {
|
||||||
qCWarning(assignment_client) << "Received an assignment that could not be unpacked. Re-requesting.";
|
qCWarning(assignment_client) << "ALERT: Received an assignment that could not be unpacked. Re-requesting.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +300,8 @@ void AssignmentClient::handleAuthenticationRequest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentClient::assignmentCompleted() {
|
void AssignmentClient::assignmentCompleted() {
|
||||||
|
crash::annotations::setShutdownState(true);
|
||||||
|
|
||||||
// we expect that to be here the previous assignment has completely cleaned up
|
// we expect that to be here the previous assignment has completely cleaned up
|
||||||
assert(_currentAssignment.isNull());
|
assert(_currentAssignment.isNull());
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <HifiConfigVariantMap.h>
|
#include <HifiConfigVariantMap.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <ShutdownEventListener.h>
|
#include <ShutdownEventListener.h>
|
||||||
|
#include <shared/ScriptInitializerMixin.h>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
#include "AssignmentClient.h"
|
#include "AssignmentClient.h"
|
||||||
|
@ -239,7 +240,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
QThread::currentThread()->setObjectName("main thread");
|
QThread::currentThread()->setObjectName("main thread");
|
||||||
|
|
||||||
|
LogHandler::getInstance().moveToThread(thread());
|
||||||
|
LogHandler::getInstance().setupRepeatedMessageFlusher();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
|
DependencyManager::set<ScriptInitializers>();
|
||||||
|
|
||||||
if (numForks || minForks || maxForks) {
|
if (numForks || minForks || maxForks) {
|
||||||
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||||
|
|
|
@ -33,7 +33,7 @@ const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor
|
||||||
const int WAIT_FOR_CHILD_MSECS = 1000;
|
const int WAIT_FOR_CHILD_MSECS = 1000;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
HANDLE PROCESS_GROUP = createProcessGroup();
|
void* PROCESS_GROUP = createProcessGroup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmentClientForks,
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(ReceivedMessage& message) {
|
ThreadedAssignment* AssignmentFactory::unpackAssignment(ReceivedMessage& message) {
|
||||||
|
|
||||||
quint8 packedType;
|
quint8 packedType;
|
||||||
message.peekPrimitive(&packedType);
|
if (message.peekPrimitive(&packedType) != sizeof(packedType)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Assignment::Type unpackedType = (Assignment::Type) packedType;
|
Assignment::Type unpackedType = (Assignment::Type) packedType;
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||||
packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket");
|
packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket");
|
||||||
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
|
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
|
||||||
this, "handleOctreePacket");
|
this, "handleOctreePacket");
|
||||||
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "handleChallengeOwnership");
|
packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "queueIncomingPacket");
|
||||||
|
|
||||||
packetReceiver.registerListenerForTypes({
|
packetReceiver.registerListenerForTypes({
|
||||||
PacketType::ReplicatedAvatarIdentity,
|
PacketType::ReplicatedAvatarIdentity,
|
||||||
|
@ -499,6 +499,8 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) {
|
||||||
} else {
|
} else {
|
||||||
_sessionDisplayNames.erase(displayNameIter);
|
_sessionDisplayNames.erase(displayNameIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeData->getAvatar().stopChallengeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<NLPacket> killPacket;
|
std::unique_ptr<NLPacket> killPacket;
|
||||||
|
@ -1136,16 +1138,6 @@ void AvatarMixer::entityChange() {
|
||||||
_dirtyHeroStatus = true;
|
_dirtyHeroStatus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarMixer::handleChallengeOwnership(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
|
||||||
if (senderNode->getType() == NodeType::Agent && senderNode->getLinkedData()) {
|
|
||||||
auto clientData = static_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
|
||||||
auto avatar = clientData->getAvatarSharedPointer();
|
|
||||||
if (avatar) {
|
|
||||||
avatar->handleChallengeResponse(message.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvatarMixer::aboutToFinish() {
|
void AvatarMixer::aboutToFinish() {
|
||||||
DependencyManager::destroy<ResourceManager>();
|
DependencyManager::destroy<ResourceManager>();
|
||||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||||
|
|
|
@ -65,7 +65,6 @@ private slots:
|
||||||
void domainSettingsRequestComplete();
|
void domainSettingsRequestComplete();
|
||||||
void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID);
|
void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID);
|
||||||
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||||
void handleChallengeOwnership(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -74,6 +74,9 @@ int AvatarMixerClientData::processPackets(const SlaveSharedData& slaveSharedData
|
||||||
case PacketType::BulkAvatarTraitsAck:
|
case PacketType::BulkAvatarTraitsAck:
|
||||||
processBulkAvatarTraitsAckMessage(*packet);
|
processBulkAvatarTraitsAckMessage(*packet);
|
||||||
break;
|
break;
|
||||||
|
case PacketType::ChallengeOwnership:
|
||||||
|
_avatar->processChallengeResponse(*packet);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,7 +265,7 @@ static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||||
void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
quint64 start = usecTimestampNow();
|
quint64 start = usecTimestampNow();
|
||||||
|
|
||||||
if (node->getType() == NodeType::Agent && node->getLinkedData() && node->getActiveSocket() && !node->isUpstream()) {
|
if ((node->getType() == NodeType::Agent || node->getType() == NodeType::EntityScriptServer) && node->getLinkedData() && node->getActiveSocket() && !node->isUpstream()) {
|
||||||
broadcastAvatarDataToAgent(node);
|
broadcastAvatarDataToAgent(node);
|
||||||
} else if (node->getType() == NodeType::DownstreamAvatarMixer) {
|
} else if (node->getType() == NodeType::DownstreamAvatarMixer) {
|
||||||
broadcastAvatarDataToDownstreamMixer(node);
|
broadcastAvatarDataToDownstreamMixer(node);
|
||||||
|
@ -448,13 +448,6 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
// or that somehow we haven't sent
|
// or that somehow we haven't sent
|
||||||
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
||||||
++numAvatarsHeldBack;
|
++numAvatarsHeldBack;
|
||||||
|
|
||||||
// BUGZ-781 verbose debugging:
|
|
||||||
auto usecLastTimeSent = destinationNodeData->getLastOtherAvatarEncodeTime(sourceAvatarNodeData->getNodeLocalID());
|
|
||||||
if (usecLastTimeSent != 0 && startIgnoreCalculation - usecLastTimeSent > 10 * USECS_PER_SECOND) {
|
|
||||||
qCDebug(avatars) << "Not sent avatar" << *sourceAvatarNode << "to Node" << *destinationNode << "in > 10 s";
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAvatar = false;
|
sendAvatar = false;
|
||||||
} else if (lastSeqFromSender == 0) {
|
} else if (lastSeqFromSender == 0) {
|
||||||
// We have have not yet received any data about this avatar. Ignore it for now
|
// We have have not yet received any data about this avatar. Ignore it for now
|
||||||
|
|
|
@ -27,13 +27,33 @@
|
||||||
#include "ClientTraitsHandler.h"
|
#include "ClientTraitsHandler.h"
|
||||||
#include "AvatarLogging.h"
|
#include "AvatarLogging.h"
|
||||||
|
|
||||||
MixerAvatar::~MixerAvatar() {
|
MixerAvatar::MixerAvatar() {
|
||||||
if (_challengeTimeout) {
|
static constexpr int CHALLENGE_TIMEOUT_MS = 10 * 1000; // 10 s
|
||||||
_challengeTimeout->deleteLater();
|
|
||||||
}
|
_challengeTimer.setSingleShot(true);
|
||||||
|
_challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS);
|
||||||
|
|
||||||
|
_challengeTimer.callOnTimeout(this, [this]() {
|
||||||
|
if (_verifyState == challengeClient) {
|
||||||
|
_pendingEvent = false;
|
||||||
|
_verifyState = verificationFailed;
|
||||||
|
_needsIdentityUpdate = true;
|
||||||
|
qCDebug(avatars) << "Dynamic verification TIMED-OUT for" << getDisplayName() << getSessionUUID();
|
||||||
|
} else {
|
||||||
|
qCDebug(avatars) << "Ignoring timeout of avatar challenge";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* MixerAvatar::stateToName(VerifyState state) {
|
||||||
|
return QMetaEnum::fromType<VerifyState>().valueToKey(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixerAvatar::fetchAvatarFST() {
|
void MixerAvatar::fetchAvatarFST() {
|
||||||
|
if (_verifyState >= requestingFST && _verifyState <= challengeClient) {
|
||||||
|
qCDebug(avatars) << "WARNING: Avatar verification restarted; old state:" << stateToName(_verifyState);
|
||||||
|
}
|
||||||
_verifyState = nonCertified;
|
_verifyState = nonCertified;
|
||||||
|
|
||||||
_pendingEvent = false;
|
_pendingEvent = false;
|
||||||
|
@ -80,7 +100,7 @@ void MixerAvatar::fetchAvatarFST() {
|
||||||
void MixerAvatar::fstRequestComplete() {
|
void MixerAvatar::fstRequestComplete() {
|
||||||
ResourceRequest* fstRequest = static_cast<ResourceRequest*>(QObject::sender());
|
ResourceRequest* fstRequest = static_cast<ResourceRequest*>(QObject::sender());
|
||||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||||
if (fstRequest == _avatarRequest) {
|
if (_verifyState == requestingFST && fstRequest == _avatarRequest) {
|
||||||
auto result = fstRequest->getResult();
|
auto result = fstRequest->getResult();
|
||||||
if (result != ResourceRequest::Success) {
|
if (result != ResourceRequest::Success) {
|
||||||
_verifyState = error;
|
_verifyState = error;
|
||||||
|
@ -90,11 +110,11 @@ void MixerAvatar::fstRequestComplete() {
|
||||||
_verifyState = receivedFST;
|
_verifyState = receivedFST;
|
||||||
_pendingEvent = true;
|
_pendingEvent = true;
|
||||||
}
|
}
|
||||||
_avatarRequest->deleteLater();
|
|
||||||
_avatarRequest = nullptr;
|
_avatarRequest = nullptr;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(avatars) << "Incorrect request for" << getDisplayName();
|
qCDebug(avatars) << "Incorrect or outdated FST request for" << getDisplayName();
|
||||||
}
|
}
|
||||||
|
fstRequest->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MixerAvatar::generateFSTHash() {
|
bool MixerAvatar::generateFSTHash() {
|
||||||
|
@ -108,7 +128,7 @@ bool MixerAvatar::generateFSTHash() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MixerAvatar::validateFSTHash(const QString& publicKey) {
|
bool MixerAvatar::validateFSTHash(const QString& publicKey) const {
|
||||||
// Guess we should refactor this stuff into a Authorization namespace ...
|
// Guess we should refactor this stuff into a Authorization namespace ...
|
||||||
return EntityItemProperties::verifySignature(publicKey, _certificateHash,
|
return EntityItemProperties::verifySignature(publicKey, _certificateHash,
|
||||||
QByteArray::fromBase64(_certificateIdFromFST.toUtf8()));
|
QByteArray::fromBase64(_certificateIdFromFST.toUtf8()));
|
||||||
|
@ -171,7 +191,9 @@ void MixerAvatar::ownerRequestComplete() {
|
||||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||||
QNetworkReply* networkReply = static_cast<QNetworkReply*>(QObject::sender());
|
QNetworkReply* networkReply = static_cast<QNetworkReply*>(QObject::sender());
|
||||||
|
|
||||||
if (networkReply->error() == QNetworkReply::NoError) {
|
if (_verifyState != requestingOwner) {
|
||||||
|
qCDebug(avatars) << "WARNING: outdated avatar-owner information received in state" << stateToName(_verifyState);
|
||||||
|
} else if (networkReply->error() == QNetworkReply::NoError) {
|
||||||
_dynamicMarketResponse = networkReply->readAll();
|
_dynamicMarketResponse = networkReply->readAll();
|
||||||
_verifyState = ownerResponse;
|
_verifyState = ownerResponse;
|
||||||
_pendingEvent = true;
|
_pendingEvent = true;
|
||||||
|
@ -259,60 +281,27 @@ void MixerAvatar::processCertifyEvents() {
|
||||||
}
|
}
|
||||||
sendOwnerChallenge();
|
sendOwnerChallenge();
|
||||||
_verifyState = challengeClient;
|
_verifyState = challengeClient;
|
||||||
_pendingEvent = true;
|
|
||||||
} else {
|
} else {
|
||||||
_verifyState = error;
|
_verifyState = error;
|
||||||
qCDebug(avatars) << "Get owner status - couldn't parse response for" << getSessionUUID()
|
qCDebug(avatars) << "Get owner status - couldn't parse response for" << getSessionUUID()
|
||||||
<< ":" << _dynamicMarketResponse;
|
<< ":" << _dynamicMarketResponse;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(avatars) << "Get owner status failed for " << getDisplayName() << _marketplaceIdFromURL <<
|
qCDebug(avatars) << "Get owner status failed for" << getDisplayName() << _marketplaceIdFromURL <<
|
||||||
"message:" << responseJson["message"].toString();
|
"message:" << responseJson["message"].toString();
|
||||||
_verifyState = error;
|
_verifyState = error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case challengeResponse:
|
|
||||||
{
|
|
||||||
if (_challengeResponse.length() < 8) {
|
|
||||||
_verifyState = error;
|
|
||||||
_pendingEvent = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int avatarIDLength;
|
|
||||||
int signedNonceLength;
|
|
||||||
{
|
|
||||||
QDataStream responseStream(_challengeResponse);
|
|
||||||
responseStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
responseStream >> avatarIDLength >> signedNonceLength;
|
|
||||||
}
|
|
||||||
QByteArray avatarID(_challengeResponse.data() + 2 * sizeof(int), avatarIDLength);
|
|
||||||
QByteArray signedNonce(_challengeResponse.data() + 2 * sizeof(int) + avatarIDLength, signedNonceLength);
|
|
||||||
|
|
||||||
bool challengeResult = EntityItemProperties::verifySignature(_ownerPublicKey, _challengeNonceHash,
|
|
||||||
QByteArray::fromBase64(signedNonce));
|
|
||||||
_verifyState = challengeResult ? verificationSucceeded : verificationFailed;
|
|
||||||
_needsIdentityUpdate = true;
|
|
||||||
if (_verifyState == verificationFailed) {
|
|
||||||
qCDebug(avatars) << "Dynamic verification FAILED for " << getDisplayName() << getSessionUUID();
|
|
||||||
} else {
|
|
||||||
qCDebug(avatars) << "Dynamic verification SUCCEEDED for " << getDisplayName() << getSessionUUID();
|
|
||||||
}
|
|
||||||
_pendingEvent = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case requestingOwner:
|
case requestingOwner:
|
||||||
case challengeClient:
|
|
||||||
{ // Qt networking done on this thread:
|
{ // Qt networking done on this thread:
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qCDebug(avatars) << "Unexpected verify state" << _verifyState;
|
qCDebug(avatars) << "Unexpected verify state" << stateToName(_verifyState);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} // close switch
|
} // close switch
|
||||||
|
@ -334,32 +323,53 @@ void MixerAvatar::sendOwnerChallenge() {
|
||||||
QCryptographicHash nonceHash(QCryptographicHash::Sha256);
|
QCryptographicHash nonceHash(QCryptographicHash::Sha256);
|
||||||
nonceHash.addData(nonce);
|
nonceHash.addData(nonce);
|
||||||
_challengeNonceHash = nonceHash.result();
|
_challengeNonceHash = nonceHash.result();
|
||||||
|
_pendingEvent = false;
|
||||||
static constexpr int CHALLENGE_TIMEOUT_MS = 10 * 1000; // 10 s
|
|
||||||
if (_challengeTimeout) {
|
// QTimer::start is a set of overloaded functions.
|
||||||
_challengeTimeout->deleteLater();
|
QMetaObject::invokeMethod(&_challengeTimer, static_cast<void(QTimer::*)()>(&QTimer::start));
|
||||||
}
|
|
||||||
_challengeTimeout = new QTimer();
|
|
||||||
_challengeTimeout->setInterval(CHALLENGE_TIMEOUT_MS);
|
|
||||||
_challengeTimeout->setSingleShot(true);
|
|
||||||
_challengeTimeout->connect(_challengeTimeout, &QTimer::timeout, this, [this]() {
|
|
||||||
if (_verifyState == challengeClient) {
|
|
||||||
_pendingEvent = false;
|
|
||||||
_verifyState = verificationFailed;
|
|
||||||
_needsIdentityUpdate = true;
|
|
||||||
qCDebug(avatars) << "Dynamic verification TIMED-OUT for " << getDisplayName() << getSessionUUID();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_challengeTimeout->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MixerAvatar::handleChallengeResponse(ReceivedMessage* response) {
|
void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
|
||||||
QByteArray avatarID;
|
QByteArray avatarID;
|
||||||
QByteArray encryptedNonce;
|
|
||||||
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
QMutexLocker certifyLocker(&_avatarCertifyLock);
|
||||||
|
stopChallengeTimer();
|
||||||
if (_verifyState == challengeClient) {
|
if (_verifyState == challengeClient) {
|
||||||
_challengeResponse = response->readAll();
|
QByteArray responseData = response.readAll();
|
||||||
_verifyState = challengeResponse;
|
if (responseData.length() < 8) {
|
||||||
_pendingEvent = true;
|
_verifyState = error;
|
||||||
|
qCDebug(avatars) << "Avatar challenge response packet too small, length:" << responseData.length();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avatarIDLength;
|
||||||
|
int signedNonceLength;
|
||||||
|
{
|
||||||
|
QDataStream responseStream(responseData);
|
||||||
|
responseStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
responseStream >> avatarIDLength >> signedNonceLength;
|
||||||
|
}
|
||||||
|
QByteArray avatarID(responseData.data() + 2 * sizeof(int), avatarIDLength);
|
||||||
|
QByteArray signedNonce(responseData.data() + 2 * sizeof(int) + avatarIDLength, signedNonceLength);
|
||||||
|
|
||||||
|
bool challengeResult = EntityItemProperties::verifySignature(_ownerPublicKey, _challengeNonceHash,
|
||||||
|
QByteArray::fromBase64(signedNonce));
|
||||||
|
_verifyState = challengeResult ? verificationSucceeded : verificationFailed;
|
||||||
|
_needsIdentityUpdate = true;
|
||||||
|
if (_verifyState == verificationFailed) {
|
||||||
|
qCDebug(avatars) << "Dynamic verification FAILED for" << getDisplayName() << getSessionUUID();
|
||||||
|
} else {
|
||||||
|
qCDebug(avatars) << "Dynamic verification SUCCEEDED for" << getDisplayName() << getSessionUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
qCDebug(avatars) << "WARNING: Unexpected avatar challenge-response in state" << stateToName(_verifyState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MixerAvatar::stopChallengeTimer() {
|
||||||
|
if (QThread::currentThread() == thread()) {
|
||||||
|
_challengeTimer.stop();
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
// Avatar class for use within the avatar mixer - encapsulates data required only for
|
// Avatar class for use within the avatar mixer - includes avatar-verification state.
|
||||||
// sorting priorities within the mixer.
|
|
||||||
|
|
||||||
#ifndef hifi_MixerAvatar_h
|
#ifndef hifi_MixerAvatar_h
|
||||||
#define hifi_MixerAvatar_h
|
#define hifi_MixerAvatar_h
|
||||||
|
@ -20,8 +19,10 @@
|
||||||
class ResourceRequest;
|
class ResourceRequest;
|
||||||
|
|
||||||
class MixerAvatar : public AvatarData {
|
class MixerAvatar : public AvatarData {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
~MixerAvatar();
|
MixerAvatar();
|
||||||
|
|
||||||
bool getNeedsHeroCheck() const { return _needsHeroCheck; }
|
bool getNeedsHeroCheck() const { return _needsHeroCheck; }
|
||||||
void setNeedsHeroCheck(bool needsHeroCheck = true) { _needsHeroCheck = needsHeroCheck; }
|
void setNeedsHeroCheck(bool needsHeroCheck = true) { _needsHeroCheck = needsHeroCheck; }
|
||||||
|
|
||||||
|
@ -31,15 +32,20 @@ public:
|
||||||
void setNeedsIdentityUpdate(bool value = true) { _needsIdentityUpdate = value; }
|
void setNeedsIdentityUpdate(bool value = true) { _needsIdentityUpdate = value; }
|
||||||
|
|
||||||
void processCertifyEvents();
|
void processCertifyEvents();
|
||||||
void handleChallengeResponse(ReceivedMessage* response);
|
void processChallengeResponse(ReceivedMessage& response);
|
||||||
|
|
||||||
|
void stopChallengeTimer();
|
||||||
|
|
||||||
|
// Avatar certification/verification:
|
||||||
|
enum VerifyState {
|
||||||
|
nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse,
|
||||||
|
challengeClient, verified, verificationFailed, verificationSucceeded, error
|
||||||
|
};
|
||||||
|
Q_ENUM(VerifyState)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _needsHeroCheck { false };
|
bool _needsHeroCheck { false };
|
||||||
|
static const char* stateToName(VerifyState state);
|
||||||
// Avatar certification/verification:
|
|
||||||
enum VerifyState { nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse,
|
|
||||||
challengeClient, challengeResponse, verified, verificationFailed, verificationSucceeded, error };
|
|
||||||
Q_ENUM(VerifyState);
|
|
||||||
VerifyState _verifyState { nonCertified };
|
VerifyState _verifyState { nonCertified };
|
||||||
std::atomic<bool> _pendingEvent { false };
|
std::atomic<bool> _pendingEvent { false };
|
||||||
QMutex _avatarCertifyLock;
|
QMutex _avatarCertifyLock;
|
||||||
|
@ -53,12 +59,11 @@ private:
|
||||||
QString _dynamicMarketResponse;
|
QString _dynamicMarketResponse;
|
||||||
QString _ownerPublicKey;
|
QString _ownerPublicKey;
|
||||||
QByteArray _challengeNonceHash;
|
QByteArray _challengeNonceHash;
|
||||||
QByteArray _challengeResponse;
|
QTimer _challengeTimer;
|
||||||
QTimer* _challengeTimeout { nullptr };
|
|
||||||
bool _needsIdentityUpdate { false };
|
bool _needsIdentityUpdate { false };
|
||||||
|
|
||||||
bool generateFSTHash();
|
bool generateFSTHash();
|
||||||
bool validateFSTHash(const QString& publicKey);
|
bool validateFSTHash(const QString& publicKey) const;
|
||||||
QByteArray canonicalJson(const QString fstFile);
|
QByteArray canonicalJson(const QString fstFile);
|
||||||
void sendOwnerChallenge();
|
void sendOwnerChallenge();
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include <EntityTree.h>
|
#include <EntityTree.h>
|
||||||
#include <SimpleEntitySimulation.h>
|
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
#include <ScriptCache.h>
|
#include <ScriptCache.h>
|
||||||
|
#include <plugins/PluginManager.h>
|
||||||
#include <EntityEditFilters.h>
|
#include <EntityEditFilters.h>
|
||||||
#include <NetworkingConstants.h>
|
#include <NetworkingConstants.h>
|
||||||
#include <hfm/ModelFormatRegistry.h>
|
#include <hfm/ModelFormatRegistry.h>
|
||||||
|
@ -36,12 +36,13 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
|
||||||
|
|
||||||
EntityServer::EntityServer(ReceivedMessage& message) :
|
EntityServer::EntityServer(ReceivedMessage& message) :
|
||||||
OctreeServer(message),
|
OctreeServer(message),
|
||||||
_entitySimulation(NULL),
|
_entitySimulation(nullptr),
|
||||||
_dynamicDomainVerificationTimer(this)
|
_dynamicDomainVerificationTimer(this)
|
||||||
{
|
{
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<ResourceCacheSharedItems>();
|
DependencyManager::set<ResourceCacheSharedItems>();
|
||||||
DependencyManager::set<ScriptCache>();
|
DependencyManager::set<ScriptCache>();
|
||||||
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||||
DependencyManager::set<AssignmentDynamicFactory>();
|
DependencyManager::set<AssignmentDynamicFactory>();
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "EntityItem.h"
|
#include <EntityItem.h>
|
||||||
|
#include <EntityTree.h>
|
||||||
|
#include <SimpleEntitySimulation.h>
|
||||||
|
|
||||||
#include "EntityServerConsts.h"
|
#include "EntityServerConsts.h"
|
||||||
#include "EntityTree.h"
|
|
||||||
|
|
||||||
/// Handles assignments of type EntityServer - sending entities to various clients.
|
/// Handles assignments of type EntityServer - sending entities to various clients.
|
||||||
|
|
||||||
|
@ -27,9 +29,6 @@ struct ViewerSendingStats {
|
||||||
quint64 lastEdited;
|
quint64 lastEdited;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleEntitySimulation;
|
|
||||||
using SimpleEntitySimulationPointer = std::shared_ptr<SimpleEntitySimulation>;
|
|
||||||
|
|
||||||
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* The <code>EntityViewer</code> API provides a headless viewer for assignment client scripts, so that they can "see" entities
|
||||||
|
* in order for them to be available in the {@link Entities} API.
|
||||||
|
*
|
||||||
* @namespace EntityViewer
|
* @namespace EntityViewer
|
||||||
*
|
*
|
||||||
* @hifi-assignment-client
|
* @hifi-assignment-client
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Updates the entities currently in view.
|
||||||
* @function EntityViewer.queryOctree
|
* @function EntityViewer.queryOctree
|
||||||
*/
|
*/
|
||||||
void queryOctree();
|
void queryOctree();
|
||||||
|
@ -36,26 +37,30 @@ public slots:
|
||||||
// setters for camera attributes
|
// setters for camera attributes
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Sets the position of the view frustum.
|
||||||
* @function EntityViewer.setPosition
|
* @function EntityViewer.setPosition
|
||||||
* @param {Vec3} position
|
* @param {Vec3} position - The position of the view frustum.
|
||||||
*/
|
*/
|
||||||
void setPosition(const glm::vec3& position) { _hasViewFrustum = true; _viewFrustum.setPosition(position); }
|
void setPosition(const glm::vec3& position) { _hasViewFrustum = true; _viewFrustum.setPosition(position); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Sets the orientation of the view frustum.
|
||||||
* @function EntityViewer.setOrientation
|
* @function EntityViewer.setOrientation
|
||||||
* @param {Quat} orientation
|
* @param {Quat} orientation - The orientation of the view frustum.
|
||||||
*/
|
*/
|
||||||
void setOrientation(const glm::quat& orientation) { _hasViewFrustum = true; _viewFrustum.setOrientation(orientation); }
|
void setOrientation(const glm::quat& orientation) { _hasViewFrustum = true; _viewFrustum.setOrientation(orientation); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Sets the radius of the center "keyhole" in the view frustum.
|
||||||
* @function EntityViewer.setCenterRadius
|
* @function EntityViewer.setCenterRadius
|
||||||
* @param {number} radius
|
* @param {number} radius - The radius of the center "keyhole" in the view frustum.
|
||||||
*/
|
*/
|
||||||
void setCenterRadius(float radius) { _hasViewFrustum = true; _viewFrustum.setCenterRadius(radius); }
|
void setCenterRadius(float radius) { _hasViewFrustum = true; _viewFrustum.setCenterRadius(radius); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Sets the radius of the center "keyhole" in the view frustum.
|
||||||
* @function EntityViewer.setKeyholeRadius
|
* @function EntityViewer.setKeyholeRadius
|
||||||
* @param {number} radius
|
* @param {number} radius - The radius of the center "keyhole" in the view frustum.
|
||||||
* @deprecated This function is deprecated and will be removed. Use {@link EntityViewer.setCenterRadius|setCenterRadius}
|
* @deprecated This function is deprecated and will be removed. Use {@link EntityViewer.setCenterRadius|setCenterRadius}
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
|
@ -66,33 +71,38 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function EntityViewer.setVoxelSizeScale
|
* @function EntityViewer.setVoxelSizeScale
|
||||||
* @param {number} sizeScale
|
* @param {number} sizeScale - The voxel size scale.
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
void setVoxelSizeScale(float sizeScale) { _octreeQuery.setOctreeSizeScale(sizeScale) ; }
|
void setVoxelSizeScale(float sizeScale) { _octreeQuery.setOctreeSizeScale(sizeScale) ; }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function EntityViewer.setBoundaryLevelAdjust
|
* @function EntityViewer.setBoundaryLevelAdjust
|
||||||
* @param {number} boundaryLevelAdjust
|
* @param {number} boundaryLevelAdjust - The boundary level adjust factor.
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _octreeQuery.setBoundaryLevelAdjust(boundaryLevelAdjust); }
|
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _octreeQuery.setBoundaryLevelAdjust(boundaryLevelAdjust); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Sets the maximum number of entity packets to receive from the domain server per second.
|
||||||
* @function EntityViewer.setMaxPacketsPerSecond
|
* @function EntityViewer.setMaxPacketsPerSecond
|
||||||
* @param {number} maxPacketsPerSecond
|
* @param {number} maxPacketsPerSecond - The maximum number of entity packets to receive per second.
|
||||||
*/
|
*/
|
||||||
void setMaxPacketsPerSecond(int maxPacketsPerSecond) { _octreeQuery.setMaxQueryPacketsPerSecond(maxPacketsPerSecond); }
|
void setMaxPacketsPerSecond(int maxPacketsPerSecond) { _octreeQuery.setMaxQueryPacketsPerSecond(maxPacketsPerSecond); }
|
||||||
|
|
||||||
// getters for camera attributes
|
// getters for camera attributes
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Gets the position of the view frustum.
|
||||||
* @function EntityViewer.getPosition
|
* @function EntityViewer.getPosition
|
||||||
* @returns {Vec3}
|
* @returns {Vec3} The position of the view frustum.
|
||||||
*/
|
*/
|
||||||
const glm::vec3& getPosition() const { return _viewFrustum.getPosition(); }
|
const glm::vec3& getPosition() const { return _viewFrustum.getPosition(); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Gets the orientation of the view frustum.
|
||||||
* @function EntityViewer.getOrientation
|
* @function EntityViewer.getOrientation
|
||||||
* @returns {Quat}
|
* @returns {Quat} The orientation of the view frustum.
|
||||||
*/
|
*/
|
||||||
const glm::quat& getOrientation() const { return _viewFrustum.getOrientation(); }
|
const glm::quat& getOrientation() const { return _viewFrustum.getOrientation(); }
|
||||||
|
|
||||||
|
@ -101,26 +111,30 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function EntityViewer.getVoxelSizeScale
|
* @function EntityViewer.getVoxelSizeScale
|
||||||
* @returns {number}
|
* @returns {number} The voxel size scale.
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
float getVoxelSizeScale() const { return _octreeQuery.getOctreeSizeScale(); }
|
float getVoxelSizeScale() const { return _octreeQuery.getOctreeSizeScale(); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function EntityViewer.getBoundaryLevelAdjust
|
* @function EntityViewer.getBoundaryLevelAdjust
|
||||||
* @returns {number}
|
* @returns {number} The boundary level adjust factor.
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
int getBoundaryLevelAdjust() const { return _octreeQuery.getBoundaryLevelAdjust(); }
|
int getBoundaryLevelAdjust() const { return _octreeQuery.getBoundaryLevelAdjust(); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Gets the maximum number of entity packets to receive from the domain server per second.
|
||||||
* @function EntityViewer.getMaxPacketsPerSecond
|
* @function EntityViewer.getMaxPacketsPerSecond
|
||||||
* @returns {number}
|
* @returns {number} The maximum number of entity packets to receive per second.
|
||||||
*/
|
*/
|
||||||
int getMaxPacketsPerSecond() const { return _octreeQuery.getMaxQueryPacketsPerSecond(); }
|
int getMaxPacketsPerSecond() const { return _octreeQuery.getMaxQueryPacketsPerSecond(); }
|
||||||
|
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Gets the number of nodes in the octree.
|
||||||
* @function EntityViewer.getOctreeElementsCount
|
* @function EntityViewer.getOctreeElementsCount
|
||||||
* @returns {number}
|
* @returns {number} The number of nodes in the octree.
|
||||||
*/
|
*/
|
||||||
unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); }
|
unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); }
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
||||||
DependencyManager::set<ResourceScriptingInterface>();
|
DependencyManager::set<ResourceScriptingInterface>();
|
||||||
|
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<PluginManager>();
|
DependencyManager::set<PluginManager>()->instantiate();
|
||||||
|
|
||||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||||
|
|
||||||
|
@ -86,8 +86,6 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
||||||
this, "handleOctreePacket");
|
this, "handleOctreePacket");
|
||||||
packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
|
packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
|
||||||
|
|
||||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
|
||||||
|
|
||||||
packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket");
|
packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket");
|
||||||
packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket");
|
packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket");
|
||||||
packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket");
|
packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket");
|
||||||
|
@ -255,6 +253,7 @@ void EntityScriptServer::handleEntityScriptCallMethodPacket(QSharedPointer<Recei
|
||||||
void EntityScriptServer::run() {
|
void EntityScriptServer::run() {
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
|
||||||
DependencyManager::set<EntityScriptServerServices>();
|
DependencyManager::set<EntityScriptServerServices>();
|
||||||
|
DependencyManager::set<AvatarHashMap>();
|
||||||
|
|
||||||
// make sure we request our script once the agent connects to the domain
|
// make sure we request our script once the agent connects to the domain
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -301,10 +300,17 @@ void EntityScriptServer::run() {
|
||||||
|
|
||||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||||
|
|
||||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
auto treePtr = _entityViewer.getTree();
|
||||||
|
DependencyManager::set<AssignmentParentFinder>(treePtr);
|
||||||
|
|
||||||
|
if (!_entitySimulation) {
|
||||||
|
SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
|
||||||
|
simpleSimulation->setEntityTree(treePtr);
|
||||||
|
treePtr->setSimulation(simpleSimulation);
|
||||||
|
_entitySimulation = simpleSimulation;
|
||||||
|
}
|
||||||
|
|
||||||
auto tree = _entityViewer.getTree().get();
|
auto tree = treePtr.get();
|
||||||
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
|
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
|
||||||
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
|
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
|
||||||
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
|
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
|
||||||
|
@ -441,6 +447,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
||||||
newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
||||||
|
|
||||||
newEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
|
newEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
|
||||||
|
newEngine->registerGlobalObject("AvatarList", DependencyManager::get<AvatarHashMap>().data());
|
||||||
|
|
||||||
// connect this script engines printedMessage signal to the global ScriptEngines these various messages
|
// connect this script engines printedMessage signal to the global ScriptEngines these various messages
|
||||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||||
|
@ -451,10 +458,11 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
||||||
|
|
||||||
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
|
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
|
||||||
_entityViewer.queryOctree();
|
_entityViewer.queryOctree();
|
||||||
|
_entityViewer.getTree()->preUpdate();
|
||||||
_entityViewer.getTree()->update();
|
_entityViewer.getTree()->update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scriptEngines->runScriptInitializers(newEngine);
|
||||||
newEngine->runInThread();
|
newEngine->runInThread();
|
||||||
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
||||||
|
@ -548,7 +556,51 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptServer::sendStatsPacket() {
|
void EntityScriptServer::sendStatsPacket() {
|
||||||
|
QJsonObject statsObject;
|
||||||
|
|
||||||
|
QJsonObject octreeStats;
|
||||||
|
octreeStats["elementCount"] = (double)OctreeElement::getNodeCount();
|
||||||
|
octreeStats["internalElementCount"] = (double)OctreeElement::getInternalNodeCount();
|
||||||
|
octreeStats["leafElementCount"] = (double)OctreeElement::getLeafNodeCount();
|
||||||
|
statsObject["octree_stats"] = octreeStats;
|
||||||
|
|
||||||
|
QJsonObject scriptEngineStats;
|
||||||
|
int numberRunningScripts = 0;
|
||||||
|
const auto scriptEngine = _entitiesScriptEngine;
|
||||||
|
if (scriptEngine) {
|
||||||
|
numberRunningScripts = scriptEngine->getNumRunningEntityScripts();
|
||||||
|
}
|
||||||
|
scriptEngineStats["number_running_scripts"] = numberRunningScripts;
|
||||||
|
statsObject["script_engine_stats"] = scriptEngineStats;
|
||||||
|
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
QJsonObject nodesObject;
|
||||||
|
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||||
|
QJsonObject clientStats;
|
||||||
|
const QString uuidString(uuidStringWithoutCurlyBraces(node->getUUID()));
|
||||||
|
clientStats["node_type"] = NodeType::getNodeTypeName(node->getType());
|
||||||
|
auto& nodeStats = node->getConnectionStats();
|
||||||
|
|
||||||
|
static const QString NODE_OUTBOUND_KBPS_STAT_KEY("outbound_kbit/s");
|
||||||
|
static const QString NODE_INBOUND_KBPS_STAT_KEY("inbound_kbit/s");
|
||||||
|
|
||||||
|
// add the key to ask the domain-server for a username replacement, if it has it
|
||||||
|
clientStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuidString;
|
||||||
|
|
||||||
|
clientStats[NODE_OUTBOUND_KBPS_STAT_KEY] = node->getOutboundKbps();
|
||||||
|
clientStats[NODE_INBOUND_KBPS_STAT_KEY] = node->getInboundKbps();
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
const float statsPeriod = duration<float, seconds::period>(nodeStats.endTime - nodeStats.startTime).count();
|
||||||
|
clientStats["unreliable_packet/s"] = (nodeStats.sentUnreliablePackets + nodeStats.receivedUnreliablePackets) / statsPeriod;
|
||||||
|
clientStats["reliable_packet/s"] = (nodeStats.sentPackets + nodeStats.receivedPackets) / statsPeriod;
|
||||||
|
|
||||||
|
nodesObject[uuidString] = clientStats;
|
||||||
|
});
|
||||||
|
|
||||||
|
statsObject["nodes"] = nodesObject;
|
||||||
|
addPacketStatsAndSendStatsPacket(statsObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
|
#include <SimpleEntitySimulation.h>
|
||||||
#include <ThreadedAssignment.h>
|
#include <ThreadedAssignment.h>
|
||||||
#include "../entities/EntityTreeHeadlessViewer.h"
|
#include "../entities/EntityTreeHeadlessViewer.h"
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ private:
|
||||||
|
|
||||||
static int _entitiesScriptEngineCount;
|
static int _entitiesScriptEngineCount;
|
||||||
ScriptEnginePointer _entitiesScriptEngine;
|
ScriptEnginePointer _entitiesScriptEngine;
|
||||||
|
SimpleEntitySimulationPointer _entitySimulation;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
EntityTreeHeadlessViewer _entityViewer;
|
EntityTreeHeadlessViewer _entityViewer;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ if (WIN32)
|
||||||
list(APPEND CMAKE_PREFIX_PATH "${WINDOW_SDK_PATH}")
|
list(APPEND CMAKE_PREFIX_PATH "${WINDOW_SDK_PATH}")
|
||||||
|
|
||||||
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
|
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${HIFI_MAX_BUILD_CORES} /wd4351")
|
||||||
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
|
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
|
||||||
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
|
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
|
||||||
# TODO: Remove when building 64-bit.
|
# TODO: Remove when building 64-bit.
|
||||||
|
|
4
cmake/externals/wasapi/CMakeLists.txt
vendored
4
cmake/externals/wasapi/CMakeLists.txt
vendored
|
@ -6,8 +6,8 @@ if (WIN32)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL https://public.highfidelity.com/dependencies/qtaudio_wasapi11.zip
|
URL https://public.highfidelity.com/dependencies/qtaudio_wasapi13.zip
|
||||||
URL_MD5 d0eb8489455e7f79d59155535a2c8861
|
URL_MD5 aa56a45f19c18caee13d29a40d1d7d28
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
|
|
@ -38,7 +38,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(BUILD_ORGANIZATION "High Fidelity")
|
set(BUILD_ORGANIZATION "High Fidelity")
|
||||||
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
set(HIGH_FIDELITY_PROTOCOL "hifi")
|
||||||
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
|
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface")
|
set(INTERFACE_ICON_PREFIX "interface")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
@ -61,7 +61,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(PR_BUILD 1)
|
set(PR_BUILD 1)
|
||||||
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
|
||||||
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
|
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
@ -70,7 +70,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
set(DEV_BUILD 1)
|
set(DEV_BUILD 1)
|
||||||
set(BUILD_VERSION "dev")
|
set(BUILD_VERSION "dev")
|
||||||
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
|
||||||
set(INTERFACE_BUNDLE_NAME "Interface")
|
set(INTERFACE_BUNDLE_NAME "interface")
|
||||||
set(INTERFACE_ICON_PREFIX "interface-beta")
|
set(INTERFACE_ICON_PREFIX "interface-beta")
|
||||||
|
|
||||||
# add definition for this release type
|
# add definition for this release type
|
||||||
|
@ -192,12 +192,12 @@ macro(SET_PACKAGING_PARAMETERS)
|
||||||
|
|
||||||
# shortcut names
|
# shortcut names
|
||||||
if (PRODUCTION_BUILD)
|
if (PRODUCTION_BUILD)
|
||||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface")
|
set(INTERFACE_SHORTCUT_NAME "High Fidelity")
|
||||||
set(CONSOLE_SHORTCUT_NAME "Console")
|
set(CONSOLE_SHORTCUT_NAME "Console")
|
||||||
set(SANDBOX_SHORTCUT_NAME "Sandbox")
|
set(SANDBOX_SHORTCUT_NAME "Sandbox")
|
||||||
set(APP_USER_MODEL_ID "com.highfidelity.console")
|
set(APP_USER_MODEL_ID "com.highfidelity.console")
|
||||||
else ()
|
else ()
|
||||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}")
|
set(INTERFACE_SHORTCUT_NAME "High Fidelity - ${BUILD_VERSION_NO_SHA}")
|
||||||
set(CONSOLE_SHORTCUT_NAME "Console - ${BUILD_VERSION_NO_SHA}")
|
set(CONSOLE_SHORTCUT_NAME "Console - ${BUILD_VERSION_NO_SHA}")
|
||||||
set(SANDBOX_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}")
|
set(SANDBOX_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
#
|
#
|
||||||
macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
|
macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
|
||||||
set(${TARGET_NAME}_SHARED 1)
|
set(${TARGET_NAME}_SHARED 1)
|
||||||
setup_hifi_library(${ARGV})
|
set(PLUGIN_SUBFOLDER ${ARGN})
|
||||||
|
setup_hifi_library()
|
||||||
|
|
||||||
if (BUILD_CLIENT)
|
if (BUILD_CLIENT)
|
||||||
add_dependencies(interface ${TARGET_NAME})
|
add_dependencies(interface ${TARGET_NAME})
|
||||||
|
@ -27,6 +28,11 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
|
||||||
set(SERVER_PLUGIN_PATH "plugins")
|
set(SERVER_PLUGIN_PATH "plugins")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (PLUGIN_SUBFOLDER)
|
||||||
|
set(CLIENT_PLUGIN_PATH "${CLIENT_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
|
||||||
|
set(SERVER_PLUGIN_PATH "${SERVER_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||||
set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/")
|
set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/")
|
||||||
set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/")
|
set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/")
|
||||||
|
|
|
@ -20,7 +20,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
foreach(SRC ${AVX_SRCS})
|
foreach(SRC ${AVX_SRCS})
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX)
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX)
|
||||||
elseif (APPLE OR UNIX)
|
elseif (APPLE OR (UNIX AND NOT ANDROID))
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx)
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -30,7 +30,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
foreach(SRC ${AVX2_SRCS})
|
foreach(SRC ${AVX2_SRCS})
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX2)
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX2)
|
||||||
elseif (APPLE OR UNIX)
|
elseif (APPLE OR (UNIX AND NOT ANDROID))
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -44,7 +44,7 @@ macro(SETUP_HIFI_LIBRARY)
|
||||||
if (COMPILER_SUPPORTS_AVX512)
|
if (COMPILER_SUPPORTS_AVX512)
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512)
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512)
|
||||||
endif()
|
endif()
|
||||||
elseif (APPLE OR UNIX)
|
elseif (APPLE OR (UNIX AND NOT ANDROID))
|
||||||
check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512)
|
check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512)
|
||||||
if (COMPILER_SUPPORTS_AVX512)
|
if (COMPILER_SUPPORTS_AVX512)
|
||||||
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f)
|
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f)
|
||||||
|
|
|
@ -15,9 +15,11 @@ macro(TARGET_WEBRTC)
|
||||||
# select_library_configurations(WEBRTC)
|
# select_library_configurations(WEBRTC)
|
||||||
else()
|
else()
|
||||||
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
|
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
|
||||||
find_library(WEBRTC_LIBRARY NAMES webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib/ NO_DEFAULT_PATH)
|
|
||||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
|
||||||
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARY})
|
find_library(WEBRTC_LIBRARY_RELEASE webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib NO_DEFAULT_PATH)
|
||||||
|
find_library(WEBRTC_LIBRARY_DEBUG webrtc PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH)
|
||||||
|
select_library_configurations(WEBRTC)
|
||||||
|
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#
|
|
||||||
# FindiViewHMD.cmake
|
|
||||||
#
|
|
||||||
# Try to find the SMI iViewHMD eye tracker library
|
|
||||||
#
|
|
||||||
# You must provide a IVIEWHMD_ROOT_DIR which contains 3rdParty, include, and libs directories
|
|
||||||
#
|
|
||||||
# Once done this will define
|
|
||||||
#
|
|
||||||
# IVIEWHMD_FOUND - system found iViewHMD
|
|
||||||
# IVIEWHMD_INCLUDE_DIRS - the iViewHMD include directory
|
|
||||||
# IVIEWHMD_LIBRARIES - link this to use iViewHMD
|
|
||||||
#
|
|
||||||
# Created on 27 Jul 2015 by David Rowe
|
|
||||||
# Copyright 2015 High Fidelity, Inc.
|
|
||||||
#
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
|
|
||||||
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
|
||||||
hifi_library_search_hints("iViewHMD")
|
|
||||||
|
|
||||||
find_path(IVIEWHMD_INCLUDE_DIRS iViewHMDAPI.h PATH_SUFFIXES include HINTS ${IVIEWHMD_SEARCH_DIRS})
|
|
||||||
find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
|
|
||||||
find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
|
|
||||||
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_API_DLL_PATH)
|
|
||||||
|
|
||||||
find_path(IVIEWHMD_DLL_PATH_3RD_PARTY libiViewNG.dll PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
|
|
||||||
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH_3RD_PARTY)
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(IVIEWHMD DEFAULT_MSG ${IVIEWHMD_REQUIREMENTS})
|
|
||||||
|
|
||||||
add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATH_3RD_PARTY})
|
|
||||||
|
|
||||||
mark_as_advanced(IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_SEARCH_DIRS)
|
|
||||||
|
|
||||||
endif()
|
|
36
cmake/ports/bullet3/bullet-git-fix-build-clang-8.patch
Normal file
36
cmake/ports/bullet3/bullet-git-fix-build-clang-8.patch
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
From 7638b7c5a659dceb4e580ae87d4d60b00847ef94 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Emil=20Nord=C3=A9n?= <emilnorden@yahoo.se>
|
||||||
|
Date: Sat, 4 May 2019 08:38:53 +0200
|
||||||
|
Subject: [PATCH] fixed build on latest version of clang
|
||||||
|
|
||||||
|
---
|
||||||
|
src/Bullet3Common/b3Vector3.h | 2 +-
|
||||||
|
src/LinearMath/btVector3.h | 2 +-
|
||||||
|
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/Bullet3Common/b3Vector3.h b/src/Bullet3Common/b3Vector3.h
|
||||||
|
index 56e6c13311..a70d68d6e1 100644
|
||||||
|
--- a/src/Bullet3Common/b3Vector3.h
|
||||||
|
+++ b/src/Bullet3Common/b3Vector3.h
|
||||||
|
@@ -36,7 +36,7 @@ subject to the following restrictions:
|
||||||
|
#pragma warning(disable : 4556) // value of intrinsic immediate argument '4294967239' is out of range '0 - 255'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#define B3_SHUFFLE(x, y, z, w) ((w) << 6 | (z) << 4 | (y) << 2 | (x))
|
||||||
|
+#define B3_SHUFFLE(x, y, z, w) (((w) << 6 | (z) << 4 | (y) << 2 | (x)) & 0xff)
|
||||||
|
//#define b3_pshufd_ps( _a, _mask ) (__m128) _mm_shuffle_epi32((__m128i)(_a), (_mask) )
|
||||||
|
#define b3_pshufd_ps(_a, _mask) _mm_shuffle_ps((_a), (_a), (_mask))
|
||||||
|
#define b3_splat3_ps(_a, _i) b3_pshufd_ps((_a), B3_SHUFFLE(_i, _i, _i, 3))
|
||||||
|
diff --git a/src/LinearMath/btVector3.h b/src/LinearMath/btVector3.h
|
||||||
|
index 61fd8d1e46..d65ed9808d 100644
|
||||||
|
--- a/src/LinearMath/btVector3.h
|
||||||
|
+++ b/src/LinearMath/btVector3.h
|
||||||
|
@@ -36,7 +36,7 @@ subject to the following restrictions:
|
||||||
|
#pragma warning(disable : 4556) // value of intrinsic immediate argument '4294967239' is out of range '0 - 255'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#define BT_SHUFFLE(x, y, z, w) ((w) << 6 | (z) << 4 | (y) << 2 | (x))
|
||||||
|
+#define BT_SHUFFLE(x, y, z, w) (((w) << 6 | (z) << 4 | (y) << 2 | (x)) & 0xff)
|
||||||
|
//#define bt_pshufd_ps( _a, _mask ) (__m128) _mm_shuffle_epi32((__m128i)(_a), (_mask) )
|
||||||
|
#define bt_pshufd_ps(_a, _mask) _mm_shuffle_ps((_a), (_a), (_mask))
|
||||||
|
#define bt_splat3_ps(_a, _i) bt_pshufd_ps((_a), BT_SHUFFLE(_i, _i, _i, 3))
|
|
@ -27,6 +27,7 @@ vcpkg_from_github(
|
||||||
REF ab8f16961e19a86ee20c6a1d61f662392524cc77
|
REF ab8f16961e19a86ee20c6a1d61f662392524cc77
|
||||||
SHA512 927742db29867517283d45e475f0c534a9a57e165cae221f26e08e88057253a1682ac9919b2dc547b9cf388ba0b931b175623461d44f28c9184796ba90b1ed55
|
SHA512 927742db29867517283d45e475f0c534a9a57e165cae221f26e08e88057253a1682ac9919b2dc547b9cf388ba0b931b175623461d44f28c9184796ba90b1ed55
|
||||||
HEAD_REF master
|
HEAD_REF master
|
||||||
|
PATCHES "bullet-git-fix-build-clang-8.patch"
|
||||||
)
|
)
|
||||||
|
|
||||||
vcpkg_configure_cmake(
|
vcpkg_configure_cmake(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Source: hifi-deps
|
Source: hifi-deps
|
||||||
Version: 0.1
|
Version: 0.3
|
||||||
Description: Collected dependencies for High Fidelity applications
|
Description: Collected dependencies for High Fidelity applications
|
||||||
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
|
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
|
||||||
|
|
|
@ -14,9 +14,9 @@ elseif (WIN32)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
vcpkg_download_distfile(
|
vcpkg_download_distfile(
|
||||||
WEBRTC_SOURCE_ARCHIVE
|
WEBRTC_SOURCE_ARCHIVE
|
||||||
URLS https://hifi-public.s3.amazonaws.com/seth/webrtc-20190626-osx.tar.gz
|
URLS https://hifi-public.s3.amazonaws.com/seth/webrtc-m78-osx.tar.gz
|
||||||
SHA512 fc70cec1b5ee87395137b7090f424e2fc2300fc17d744d5ffa1cf7aa0e0f1a069a9d72ba1ad2fb4a640ebeb6c218bda24351ba0083e1ff96c4a4b5032648a9d2
|
SHA512 8b547da921cc96f5c22b4253a1c9e707971bb627898fbdb6b238ef1318c7d2512e878344885c936d4bd6a66005cc5b63dfc3fa5ddd14f17f378dcaa17b5e25df
|
||||||
FILENAME webrtc-20190626-osx.tar.gz
|
FILENAME webrtc-m78-osx.tar.gz
|
||||||
)
|
)
|
||||||
else ()
|
else ()
|
||||||
# else Linux desktop
|
# else Linux desktop
|
||||||
|
|
|
@ -1156,7 +1156,17 @@ FunctionEnd
|
||||||
|
|
||||||
Section "-Core installation"
|
Section "-Core installation"
|
||||||
|
|
||||||
;The following delete blocks are temporary and can be removed once users who had the initial installer have updated
|
; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated
|
||||||
|
; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are.
|
||||||
|
|
||||||
|
; MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@"
|
||||||
|
|
||||||
|
;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer
|
||||||
|
${If} "@INSTALLER_TYPE@" == "client_only"
|
||||||
|
; MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries"
|
||||||
|
Delete "$INSTDIR\assignment-client.exe"
|
||||||
|
Delete "$INSTDIR\domain-server.exe"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
;Delete any server-console files installed before it was placed in sub-folder
|
;Delete any server-console files installed before it was placed in sub-folder
|
||||||
Delete "$INSTDIR\server-console.exe"
|
Delete "$INSTDIR\server-console.exe"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 2.3,
|
"version": 2.4,
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"name": "metaverse",
|
"name": "metaverse",
|
||||||
|
@ -1705,6 +1705,114 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "oauth",
|
||||||
|
"label": "OAuth",
|
||||||
|
"show_on_enable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"name": "enable",
|
||||||
|
"type": "checkbox",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin-users",
|
||||||
|
"label": "Admin Users",
|
||||||
|
"type": "table",
|
||||||
|
"can_add_new_rows": true,
|
||||||
|
"help": "Any of these users can administer the domain.",
|
||||||
|
"numbered": false,
|
||||||
|
"backup": false,
|
||||||
|
"advanced": false,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "username",
|
||||||
|
"label": "Username",
|
||||||
|
"can_set": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin-roles",
|
||||||
|
"label": "Admin Roles",
|
||||||
|
"type": "table",
|
||||||
|
"can_add_new_rows": true,
|
||||||
|
"help": "Any user with any of these metaverse roles can administer the domain.",
|
||||||
|
"numbered": false,
|
||||||
|
"backup": false,
|
||||||
|
"advanced": true,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "role",
|
||||||
|
"label": "Role",
|
||||||
|
"can_set": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "client-id",
|
||||||
|
"label": "Client ID",
|
||||||
|
"help": "OAuth client ID.",
|
||||||
|
"default": "",
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "client-secret",
|
||||||
|
"label": "Client Secret",
|
||||||
|
"help": "OAuth client secret.",
|
||||||
|
"type": "password",
|
||||||
|
"password_placeholder": "******",
|
||||||
|
"value-hidden": true,
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "provider",
|
||||||
|
"label": "Provider",
|
||||||
|
"help": "OAuth provider URL.",
|
||||||
|
"default": "https://metaverse.highfidelity.com",
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hostname",
|
||||||
|
"label": "Hostname",
|
||||||
|
"help": "OAuth hostname.",
|
||||||
|
"default": "",
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key-passphrase",
|
||||||
|
"label": "SSL Private Key Passphrase",
|
||||||
|
"help": "SSL Private Key Passphrase",
|
||||||
|
"type": "password",
|
||||||
|
"password_placeholder": "******",
|
||||||
|
"value-hidden": true,
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cert-fingerprint",
|
||||||
|
"type": "hidden",
|
||||||
|
"readonly": true,
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cert",
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"advanced": true,
|
||||||
|
"backup": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "automatic_content_archives",
|
"name": "automatic_content_archives",
|
||||||
"label": "Automatic Content Archives",
|
"label": "Automatic Content Archives",
|
||||||
|
|
|
@ -2,6 +2,9 @@ var DomainInfo = null;
|
||||||
|
|
||||||
var viewHelpers = {
|
var viewHelpers = {
|
||||||
getFormGroup: function(keypath, setting, values, isAdvanced) {
|
getFormGroup: function(keypath, setting, values, isAdvanced) {
|
||||||
|
if (setting.hidden) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
form_group = "<div class='form-group " +
|
form_group = "<div class='form-group " +
|
||||||
(isAdvanced ? Settings.ADVANCED_CLASS : "") + " " +
|
(isAdvanced ? Settings.ADVANCED_CLASS : "") + " " +
|
||||||
(setting.deprecated ? Settings.DEPRECATED_CLASS : "" ) + "' " +
|
(setting.deprecated ? Settings.DEPRECATED_CLASS : "" ) + "' " +
|
||||||
|
@ -82,8 +85,9 @@ var viewHelpers = {
|
||||||
"placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
|
"placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
|
||||||
"' value='" + (_.has(setting, 'password_placeholder') ? setting.password_placeholder : setting_value) + "'/>"
|
"' value='" + (_.has(setting, 'password_placeholder') ? setting.password_placeholder : setting_value) + "'/>"
|
||||||
}
|
}
|
||||||
|
if (setting.help) {
|
||||||
form_group += "<span class='help-block'>" + setting.help + "</span>"
|
form_group += "<span class='help-block'>" + setting.help + "</span>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,12 +118,17 @@ function reloadSettings(callback) {
|
||||||
data.descriptions.push(Settings.extraGroupsAtEnd[endGroupIndex]);
|
data.descriptions.push(Settings.extraGroupsAtEnd[endGroupIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.descriptions = data.descriptions.map(function(x) {
|
||||||
|
x.hidden = x.hidden || (x.show_on_enable && data.values[x.name] && !data.values[x.name].enable);
|
||||||
|
return x;
|
||||||
|
});
|
||||||
|
|
||||||
$('#panels').html(Settings.panelsTemplate(data));
|
$('#panels').html(Settings.panelsTemplate(data));
|
||||||
|
|
||||||
Settings.data = data;
|
Settings.data = data;
|
||||||
Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true);
|
Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true);
|
||||||
|
|
||||||
Settings.afterReloadActions();
|
Settings.afterReloadActions(data);
|
||||||
|
|
||||||
// setup any bootstrap switches
|
// setup any bootstrap switches
|
||||||
$('.toggle-checkbox').bootstrapSwitch();
|
$('.toggle-checkbox').bootstrapSwitch();
|
||||||
|
@ -129,10 +138,14 @@ function reloadSettings(callback) {
|
||||||
Settings.pendingChanges = 0;
|
Settings.pendingChanges = 0;
|
||||||
|
|
||||||
// call the callback now that settings are loaded
|
// call the callback now that settings are loaded
|
||||||
callback(true);
|
if (callback) {
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
}).fail(function() {
|
}).fail(function() {
|
||||||
// call the failure object since settings load faild
|
// call the failure object since settings load faild
|
||||||
callback(false)
|
if (callback) {
|
||||||
|
callback(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,14 +250,14 @@ $(document).ready(function(){
|
||||||
|
|
||||||
// set focus to the first input in the new row
|
// set focus to the first input in the new row
|
||||||
$target.closest('table').find('tr.inputs input:first').focus();
|
$target.closest('table').find('tr.inputs input:first').focus();
|
||||||
}
|
} else {
|
||||||
|
var tableRows = sibling.parent();
|
||||||
|
var tableBody = tableRows.parent();
|
||||||
|
|
||||||
var tableRows = sibling.parent();
|
// if theres no more siblings, we should jump to a new row
|
||||||
var tableBody = tableRows.parent();
|
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
|
||||||
|
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
|
||||||
// if theres no more siblings, we should jump to a new row
|
}
|
||||||
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
|
|
||||||
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,23 @@ function getCurrentDomainIDType() {
|
||||||
return DOMAIN_ID_TYPE_UNKNOWN;
|
return DOMAIN_ID_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isCloudDomain() {
|
||||||
|
|
||||||
|
if (!domainIDIsSet()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (typeof DomainInfo === 'undefined') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (DomainInfo === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (typeof DomainInfo.cloud_domain !== "boolean") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DomainInfo.cloud_domain;
|
||||||
|
}
|
||||||
|
|
||||||
function showLoadingDialog(msg) {
|
function showLoadingDialog(msg) {
|
||||||
var message = '<div class="text-center">';
|
var message = '<div class="text-center">';
|
||||||
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> ' + msg;
|
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> ' + msg;
|
||||||
|
|
|
@ -18,7 +18,19 @@ $(document).ready(function(){
|
||||||
Settings.extraGroupsAtIndex = Settings.extraDomainGroupsAtIndex;
|
Settings.extraGroupsAtIndex = Settings.extraDomainGroupsAtIndex;
|
||||||
var METAVERSE_URL = URLs.METAVERSE_URL;
|
var METAVERSE_URL = URLs.METAVERSE_URL;
|
||||||
|
|
||||||
Settings.afterReloadActions = function() {
|
var SSL_PRIVATE_KEY_FILE_ID = 'ssl-private-key-file';
|
||||||
|
var SSL_PRIVATE_KEY_CONTENTS_ID = 'key-contents';
|
||||||
|
var SSL_PRIVATE_KEY_CONTENTS_NAME = 'oauth.key-contents';
|
||||||
|
var SSL_CERT_UPLOAD_ID = 'ssl-cert-button';
|
||||||
|
var SSL_CERT_FILE_ID = 'ssl-cert-file';
|
||||||
|
var SSL_CERT_FINGERPRINT_ID = 'cert-fingerprint';
|
||||||
|
var SSL_CERT_FINGERPRINT_SPAN_ID = 'cert-fingerprint-span-id';
|
||||||
|
var SSL_CERT_CONTENTS_ID = 'cert-contents';
|
||||||
|
var SSL_CERT_CONTENTS_NAME = 'oauth.cert-contents';
|
||||||
|
var SSL_PRIVATE_KEY_PATH = 'oauth.key';
|
||||||
|
var SSL_CERT_PATH = 'oauth.cert';
|
||||||
|
|
||||||
|
Settings.afterReloadActions = function(data) {
|
||||||
|
|
||||||
getMetaverseUrl(function(metaverse_url) {
|
getMetaverseUrl(function(metaverse_url) {
|
||||||
METAVERSE_URL = metaverse_url;
|
METAVERSE_URL = metaverse_url;
|
||||||
|
@ -32,6 +44,8 @@ $(document).ready(function(){
|
||||||
setupDomainNetworkingSettings();
|
setupDomainNetworkingSettings();
|
||||||
// setupDomainLabelSetting();
|
// setupDomainLabelSetting();
|
||||||
|
|
||||||
|
setupSettingsOAuth(data);
|
||||||
|
|
||||||
setupSettingsBackup();
|
setupSettingsBackup();
|
||||||
|
|
||||||
if (domainIDIsSet()) {
|
if (domainIDIsSet()) {
|
||||||
|
@ -124,6 +138,48 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (formJSON["oauth"]) {
|
||||||
|
var private_key = formJSON["oauth"]["key-contents"];
|
||||||
|
var cert = formJSON["oauth"]["cert-contents"];
|
||||||
|
var oauthErrors = "";
|
||||||
|
if (private_key != undefined) {
|
||||||
|
var pattern = /-+BEGIN PRIVATE KEY-+[A-Za-z0-9+/\n=]*-+END PRIVATE KEY-+/m;
|
||||||
|
if (!pattern.test(private_key)) {
|
||||||
|
oauthErrors += "Private key must be in PEM format<BR/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cert != undefined) {
|
||||||
|
var pattern = /-+BEGIN CERTIFICATE-+[A-Za-z0-9+/\n=]*-+END CERTIFICATE-+/m;
|
||||||
|
if (!pattern.test(cert)) {
|
||||||
|
oauthErrors += "Certificate must be in PEM format<BR/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($('#oauth.panel').length) {
|
||||||
|
if (!$('input[name="oauth.client-id"]').val()) {
|
||||||
|
oauthErrors += "OAuth requires a client Id.<BR/>";
|
||||||
|
}
|
||||||
|
if (!$('input[name="oauth.provider"]').val()) {
|
||||||
|
oauthErrors += "OAuth requires a provider.<BR/>";
|
||||||
|
}
|
||||||
|
if (!$('input[name="oauth.hostname"]').val()) {
|
||||||
|
oauthErrors += "OAuth requires a hostname.<BR/>";
|
||||||
|
}
|
||||||
|
if (!$('input[name="' + SSL_PRIVATE_KEY_PATH + '"]').val() && !$('input[name="' + SSL_PRIVATE_KEY_CONTENTS_NAME + '"]').val()) {
|
||||||
|
oauthErrors += "OAuth requires an SSL Private Key.<BR/>";
|
||||||
|
}
|
||||||
|
if (!$('input[name="' + SSL_CERT_PATH + '"]').val() && !$('input[name="' + SSL_CERT_CONTENTS_NAME + '"]').val()) {
|
||||||
|
oauthErrors += "OAuth requires an SSL Certificate.<BR/>";
|
||||||
|
}
|
||||||
|
if (!$("table[name='oauth.admin-users'] tr.value-row").length &&
|
||||||
|
!$("table[name='oauth.admin-roles'] tr.value-row").length) {
|
||||||
|
oauthErrors += "OAuth must have at least one admin user or admin role.<BR/>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oauthErrors) {
|
||||||
|
bootbox.alert({ "message": oauthErrors, "title": "OAuth Configuration Error" });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
postSettings(formJSON);
|
postSettings(formJSON);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -550,6 +606,9 @@ $(document).ready(function(){
|
||||||
var address = DomainInfo.network_address === null ? '' : DomainInfo.network_address;
|
var address = DomainInfo.network_address === null ? '' : DomainInfo.network_address;
|
||||||
var port = DomainInfo.network_port === null ? '' : DomainInfo.network_port;
|
var port = DomainInfo.network_port === null ? '' : DomainInfo.network_port;
|
||||||
var modal_body = "<div class='form-group'>";
|
var modal_body = "<div class='form-group'>";
|
||||||
|
if (isCloudDomain()) {
|
||||||
|
modal_body += '<div style="color:red;font-weight: bold">Changing the network settings may actually break your domain.</div>';
|
||||||
|
}
|
||||||
if (includeAddress) {
|
if (includeAddress) {
|
||||||
modal_body += "<label class='control-label'>Address</label>";
|
modal_body += "<label class='control-label'>Address</label>";
|
||||||
modal_body += "<input type='text' id='network-address-input' class='form-control' value='" + address + "'>";
|
modal_body += "<input type='text' id='network-address-input' class='form-control' value='" + address + "'>";
|
||||||
|
@ -811,6 +870,10 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getCurrentDomainIDType() === DOMAIN_ID_TYPE_TEMP) {
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).siblings('span').append(" <b>This is a temporary domain and will not be visible in your domain list.</b>");
|
||||||
|
}
|
||||||
|
|
||||||
if (accessTokenIsSet()) {
|
if (accessTokenIsSet()) {
|
||||||
appendAddButtonToPlacesTable();
|
appendAddButtonToPlacesTable();
|
||||||
}
|
}
|
||||||
|
@ -1035,6 +1098,67 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupSettingsOAuth(data) {
|
||||||
|
// construct the HTML needed for the settings backup panel
|
||||||
|
var html = "<div class='form-group undefined'>";
|
||||||
|
html += "<label class='control-label'>SSL Private Key</label><BR/>";
|
||||||
|
html += "<label id='key-path-label'class='control-label'>Path</label>";
|
||||||
|
html += "<input id='" + SSL_PRIVATE_KEY_FILE_ID + "' type='file' accept='.key'/>";
|
||||||
|
html += "<input id='" + SSL_PRIVATE_KEY_CONTENTS_ID + "' name='" + SSL_PRIVATE_KEY_CONTENTS_NAME + "' type='hidden'/>";
|
||||||
|
html += "</div>";
|
||||||
|
html += "<div class='form-group undefined'>";
|
||||||
|
html += "<label class='control-label'>SSL Cert</label>";
|
||||||
|
html += "<div id='cert-fingerprint'><b>Fingerprint:</b><span id='" + SSL_CERT_FINGERPRINT_SPAN_ID + "'>" + data.values.oauth["cert-fingerprint"] + "</span></div>";
|
||||||
|
html += "<label id='cert-path-label' class='control-label'>Path</label>";
|
||||||
|
html += "<input id='" + SSL_CERT_FILE_ID + "' type='file' accept='.cer,.crt'/>";
|
||||||
|
html += "<input id='" + SSL_CERT_CONTENTS_ID + "' name='" + SSL_CERT_CONTENTS_NAME + "' type='hidden'/>";
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
$('#oauth-advanced').append(html);
|
||||||
|
|
||||||
|
$('#key-path-label').after($('[data-keypath="' + SSL_PRIVATE_KEY_PATH + '"]'));
|
||||||
|
$('#cert-path-label').after($('[data-keypath="' + SSL_CERT_PATH + '"]'));
|
||||||
|
$('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val(data.values.oauth.key);
|
||||||
|
$('[name="' + SSL_CERT_PATH + '"]').val(data.values.oauth.cert);
|
||||||
|
|
||||||
|
$('body').on('change input propertychange', '#' + SSL_PRIVATE_KEY_FILE_ID, function(e){
|
||||||
|
var f = e.target.files[0];
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val(reader.result);
|
||||||
|
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).attr('data-changed', true);
|
||||||
|
$('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val('');
|
||||||
|
badgeForDifferences($('#' + SSL_PRIVATE_KEY_CONTENTS_ID));
|
||||||
|
}
|
||||||
|
reader.readAsText(f);
|
||||||
|
});
|
||||||
|
$('body').on('change input propertychange', '#' + SSL_CERT_FILE_ID, function(e){
|
||||||
|
var f = e.target.files[0];
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
$('#' + SSL_CERT_CONTENTS_ID).val(reader.result);
|
||||||
|
$('#' + SSL_CERT_CONTENTS_ID).attr('data-changed', true);
|
||||||
|
$('[name="' + SSL_CERT_PATH + '"]').val('');
|
||||||
|
$('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text('');
|
||||||
|
badgeForDifferences($('#' + SSL_CERT_CONTENTS_ID));
|
||||||
|
}
|
||||||
|
reader.readAsText(f);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('change input propertychange', '[name="' + SSL_PRIVATE_KEY_PATH + '"]', function(e){
|
||||||
|
$('#' + SSL_PRIVATE_KEY_FILE_ID).val('');
|
||||||
|
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val('');
|
||||||
|
badgeForDifferences($('[name="' + SSL_PRIVATE_KEY_PATH + '"]').attr('data-changed', true));
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('change input propertychange', '[name="' + SSL_CERT_PATH + '"]', function(e){
|
||||||
|
$('#' + SSL_CERT_FILE_ID).val('');
|
||||||
|
$('#' + SSL_CERT_CONTENTS_ID).val('');
|
||||||
|
$('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text('');
|
||||||
|
badgeForDifferences($('[name="' + SSL_CERT_PATH + '"]').attr('data-changed', true));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var RESTORE_SETTINGS_UPLOAD_ID = 'restore-settings-button';
|
var RESTORE_SETTINGS_UPLOAD_ID = 'restore-settings-button';
|
||||||
var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file';
|
var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file';
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <AssetClient.h>
|
#include <AssetClient.h>
|
||||||
#include <BuildInfo.h>
|
#include <BuildInfo.h>
|
||||||
|
#include <CrashAnnotations.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <HifiConfigVariantMap.h>
|
#include <HifiConfigVariantMap.h>
|
||||||
#include <HTTPConnection.h>
|
#include <HTTPConnection.h>
|
||||||
|
@ -174,6 +175,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
|
||||||
|
LogHandler::getInstance().moveToThread(thread());
|
||||||
|
LogHandler::getInstance().setupRepeatedMessageFlusher();
|
||||||
|
|
||||||
qDebug() << "Setting up domain-server";
|
qDebug() << "Setting up domain-server";
|
||||||
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||||
qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
|
qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
|
||||||
|
@ -182,6 +186,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
|
qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
|
||||||
qDebug() << "[VERSION] We will be using this name to find ICE servers:" << _iceServerAddr;
|
qDebug() << "[VERSION] We will be using this name to find ICE servers:" << _iceServerAddr;
|
||||||
|
|
||||||
|
connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit);
|
||||||
|
|
||||||
// make sure we have a fresh AccountManager instance
|
// make sure we have a fresh AccountManager instance
|
||||||
// (need this since domain-server can restart itself and maintain static variables)
|
// (need this since domain-server can restart itself and maintain static variables)
|
||||||
|
@ -226,9 +231,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
|
||||||
setupGroupCacheRefresh();
|
setupGroupCacheRefresh();
|
||||||
|
|
||||||
// if we were given a certificate/private key or oauth credentials they must succeed
|
optionallySetupOAuth();
|
||||||
if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) {
|
|
||||||
return;
|
if (_oauthEnable) {
|
||||||
|
_oauthEnable = optionallyReadX509KeyAndCertificate();
|
||||||
}
|
}
|
||||||
|
|
||||||
_settingsManager.apiRefreshGroupInformation();
|
_settingsManager.apiRefreshGroupInformation();
|
||||||
|
@ -319,7 +325,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
|
||||||
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
|
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
|
||||||
|
|
||||||
static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND;
|
static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND;
|
||||||
_nodePingMonitorTimer = new QTimer{ this };
|
_nodePingMonitorTimer = new QTimer{ this };
|
||||||
connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor);
|
connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor);
|
||||||
_nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS);
|
_nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS);
|
||||||
|
@ -379,7 +385,7 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_iceServerAddr.isEmpty()) {
|
if (_iceServerAddr.isEmpty()) {
|
||||||
qCWarning(domain_server_ice) << "Could not parse an IP address and port combination from" << hostnamePortString;
|
qCWarning(domain_server_ice) << "ALERT: Could not parse an IP address and port combination from" << hostnamePortString;
|
||||||
::exit(0);
|
::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,6 +434,10 @@ DomainServer::~DomainServer() {
|
||||||
DependencyManager::destroy<LimitedNodeList>();
|
DependencyManager::destroy<LimitedNodeList>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainServer::aboutToQuit() {
|
||||||
|
crash::annotations::setShutdownState(true);
|
||||||
|
}
|
||||||
|
|
||||||
void DomainServer::queuedQuit(QString quitMessage, int exitCode) {
|
void DomainServer::queuedQuit(QString quitMessage, int exitCode) {
|
||||||
if (!quitMessage.isEmpty()) {
|
if (!quitMessage.isEmpty()) {
|
||||||
qWarning() << qPrintable(quitMessage);
|
qWarning() << qPrintable(quitMessage);
|
||||||
|
@ -447,8 +457,9 @@ QUuid DomainServer::getID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
||||||
const QString X509_CERTIFICATE_OPTION = "cert";
|
const QString X509_CERTIFICATE_OPTION = "oauth.cert";
|
||||||
const QString X509_PRIVATE_KEY_OPTION = "key";
|
const QString X509_PRIVATE_KEY_OPTION = "oauth.key";
|
||||||
|
const QString X509_PRIVATE_KEY_PASSPHRASE_OPTION = "oauth.key-passphrase";
|
||||||
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
|
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
|
||||||
|
|
||||||
QString certPath = _settingsManager.valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
|
QString certPath = _settingsManager.valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
|
||||||
|
@ -459,7 +470,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
||||||
// this is used for Oauth callbacks when authorizing users against a data server
|
// this is used for Oauth callbacks when authorizing users against a data server
|
||||||
// let's make sure we can load the key and certificate
|
// let's make sure we can load the key and certificate
|
||||||
|
|
||||||
QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
|
QString keyPassphraseEnv = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
|
||||||
|
QString keyPassphraseString = _settingsManager.valueForKeyPath(X509_PRIVATE_KEY_PASSPHRASE_OPTION).toString();
|
||||||
|
|
||||||
|
if (!keyPassphraseEnv.isEmpty()) {
|
||||||
|
keyPassphraseString = keyPassphraseEnv;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
|
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
|
||||||
qDebug() << "Reading key file at" << keyPath << "for HTTPS.";
|
qDebug() << "Reading key file at" << keyPath << "for HTTPS.";
|
||||||
|
@ -473,16 +489,15 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
||||||
QSslCertificate sslCertificate(&certFile);
|
QSslCertificate sslCertificate(&certFile);
|
||||||
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
||||||
|
|
||||||
|
if (privateKey.isNull()) {
|
||||||
|
qCritical() << "SSL Private Key Not Loading. Bad password or key format?";
|
||||||
|
}
|
||||||
|
|
||||||
_httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this));
|
_httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this));
|
||||||
|
|
||||||
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
|
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
|
||||||
|
|
||||||
} else if (!certPath.isEmpty() || !keyPath.isEmpty()) {
|
} else if (!certPath.isEmpty() || !keyPath.isEmpty()) {
|
||||||
static const QString MISSING_CERT_ERROR_MSG = "Missing certificate or private key. domain-server will now quit.";
|
|
||||||
static const int MISSING_CERT_ERROR_CODE = 3;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection,
|
|
||||||
Q_ARG(QString, MISSING_CERT_ERROR_MSG), Q_ARG(int, MISSING_CERT_ERROR_CODE));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,10 +505,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServer::optionallySetupOAuth() {
|
bool DomainServer::optionallySetupOAuth() {
|
||||||
const QString OAUTH_PROVIDER_URL_OPTION = "oauth-provider";
|
const QString OAUTH_ENABLE_OPTION = "oauth.enable";
|
||||||
const QString OAUTH_CLIENT_ID_OPTION = "oauth-client-id";
|
const QString OAUTH_PROVIDER_URL_OPTION = "oauth.provider";
|
||||||
|
const QString OAUTH_CLIENT_ID_OPTION = "oauth.client-id";
|
||||||
const QString OAUTH_CLIENT_SECRET_ENV = "DOMAIN_SERVER_CLIENT_SECRET";
|
const QString OAUTH_CLIENT_SECRET_ENV = "DOMAIN_SERVER_CLIENT_SECRET";
|
||||||
const QString REDIRECT_HOSTNAME_OPTION = "hostname";
|
const QString OAUTH_CLIENT_SECRET_OPTION = "oauth.client-secret";
|
||||||
|
const QString REDIRECT_HOSTNAME_OPTION = "oauth.hostname";
|
||||||
|
|
||||||
_oauthProviderURL = QUrl(_settingsManager.valueForKeyPath(OAUTH_PROVIDER_URL_OPTION).toString());
|
_oauthProviderURL = QUrl(_settingsManager.valueForKeyPath(OAUTH_PROVIDER_URL_OPTION).toString());
|
||||||
|
|
||||||
|
@ -502,22 +519,24 @@ bool DomainServer::optionallySetupOAuth() {
|
||||||
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
|
||||||
|
if (_oauthClientSecret.isEmpty()) {
|
||||||
|
_oauthClientSecret = _settingsManager.valueForKeyPath(OAUTH_CLIENT_SECRET_OPTION).toString();
|
||||||
|
}
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
accountManager->setAuthURL(_oauthProviderURL);
|
accountManager->setAuthURL(_oauthProviderURL);
|
||||||
|
|
||||||
_oauthClientID = _settingsManager.valueForKeyPath(OAUTH_CLIENT_ID_OPTION).toString();
|
_oauthClientID = _settingsManager.valueForKeyPath(OAUTH_CLIENT_ID_OPTION).toString();
|
||||||
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
|
|
||||||
_hostname = _settingsManager.valueForKeyPath(REDIRECT_HOSTNAME_OPTION).toString();
|
_hostname = _settingsManager.valueForKeyPath(REDIRECT_HOSTNAME_OPTION).toString();
|
||||||
|
|
||||||
if (!_oauthClientID.isEmpty()) {
|
_oauthEnable = _settingsManager.valueForKeyPath(OAUTH_ENABLE_OPTION).toBool();
|
||||||
|
|
||||||
|
if (_oauthEnable) {
|
||||||
if (_oauthProviderURL.isEmpty()
|
if (_oauthProviderURL.isEmpty()
|
||||||
|| _hostname.isEmpty()
|
|| _hostname.isEmpty()
|
||||||
|| _oauthClientID.isEmpty()
|
|| _oauthClientID.isEmpty()
|
||||||
|| _oauthClientSecret.isEmpty()) {
|
|| _oauthClientSecret.isEmpty()) {
|
||||||
static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit.";
|
_oauthEnable = false;
|
||||||
static const int MISSING_OAUTH_INFO_ERROR_CODE = 4;
|
|
||||||
QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection,
|
|
||||||
Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE));
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString();
|
qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString();
|
||||||
|
@ -857,7 +876,7 @@ void DomainServer::setupAutomaticNetworking() {
|
||||||
nodeList->startSTUNPublicSocketUpdate();
|
nodeList->startSTUNPublicSocketUpdate();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
|
qCCritical(domain_server) << "PAGE: Cannot enable domain-server automatic networking without a domain ID."
|
||||||
<< "Please add an ID to your config file or via the web interface.";
|
<< "Please add an ID to your config file or via the web interface.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1616,8 +1635,9 @@ void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply* requestRepl
|
||||||
} else {
|
} else {
|
||||||
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
|
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
|
||||||
|
|
||||||
qCWarning(domain_server_ice) << "Failed to update ice-server address (" << _iceServerSocket << ") with High Fidelity Metaverse - error was"
|
qCWarning(domain_server_ice) << "PAGE: Failed to update ice-server address (" << _iceServerSocket <<
|
||||||
<< requestReply->errorString();
|
") with Metaverse (" << requestReply->url() << ") (critical error for auto-networking) error:" <<
|
||||||
|
requestReply->errorString();
|
||||||
qCWarning(domain_server_ice) << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
|
qCWarning(domain_server_ice) << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
|
||||||
|
|
||||||
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
|
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
|
||||||
|
@ -1746,8 +1766,8 @@ void DomainServer::nodePingMonitor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessage> message) {
|
void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessage> message) {
|
||||||
qDebug() << "Received octree data persist message";
|
|
||||||
auto data = message->readAll();
|
auto data = message->readAll();
|
||||||
|
qDebug() << "Received octree data persist message" << (data.size() / 1000) << "kbytes.";
|
||||||
auto filePath = getEntitiesFilePath();
|
auto filePath = getEntitiesFilePath();
|
||||||
|
|
||||||
QDir dir(getEntitiesDirPath());
|
QDir dir(getEntitiesDirPath());
|
||||||
|
@ -1759,12 +1779,16 @@ void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessag
|
||||||
QFile f(filePath);
|
QFile f(filePath);
|
||||||
if (f.open(QIODevice::WriteOnly)) {
|
if (f.open(QIODevice::WriteOnly)) {
|
||||||
f.write(data);
|
f.write(data);
|
||||||
|
#ifdef EXPENSIVE_NETWORK_DIAGNOSTICS
|
||||||
|
// These diagnostics take take more than 200ms (depending on content size),
|
||||||
|
// causing Socket::readPendingDatagrams to overrun its timebox.
|
||||||
OctreeUtils::RawEntityData entityData;
|
OctreeUtils::RawEntityData entityData;
|
||||||
if (entityData.readOctreeDataInfoFromData(data)) {
|
if (entityData.readOctreeDataInfoFromData(data)) {
|
||||||
qCDebug(domain_server) << "Wrote new entities file" << entityData.id << entityData.dataVersion;
|
qCDebug(domain_server) << "Wrote new entities file" << entityData.id << entityData.dataVersion;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(domain_server) << "Failed to read new octree data info";
|
qCDebug(domain_server) << "Failed to read new octree data info";
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
qCDebug(domain_server) << "Failed to write new entities file:" << filePath;
|
qCDebug(domain_server) << "Failed to write new entities file:" << filePath;
|
||||||
}
|
}
|
||||||
|
@ -2689,8 +2713,8 @@ void DomainServer::profileRequestFinished() {
|
||||||
std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* connection) {
|
std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* connection) {
|
||||||
|
|
||||||
static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie";
|
static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie";
|
||||||
static const QString ADMIN_USERS_CONFIG_KEY = "admin-users";
|
static const QString ADMIN_USERS_CONFIG_KEY = "oauth.admin-users";
|
||||||
static const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles";
|
static const QString ADMIN_ROLES_CONFIG_KEY = "oauth.admin-roles";
|
||||||
static const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username";
|
static const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username";
|
||||||
static const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password";
|
static const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password";
|
||||||
const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)";
|
const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)";
|
||||||
|
@ -2700,8 +2724,7 @@ std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* c
|
||||||
QVariant adminUsersVariant = _settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY);
|
QVariant adminUsersVariant = _settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY);
|
||||||
QVariant adminRolesVariant = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY);
|
QVariant adminRolesVariant = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY);
|
||||||
|
|
||||||
if (!_oauthProviderURL.isEmpty()
|
if (_oauthEnable) {
|
||||||
&& (adminUsersVariant.isValid() || adminRolesVariant.isValid())) {
|
|
||||||
QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY);
|
QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY);
|
||||||
|
|
||||||
QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING);
|
QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING);
|
||||||
|
@ -3428,8 +3451,9 @@ void DomainServer::randomizeICEServerAddress(bool shouldTriggerHostLookup) {
|
||||||
// we ended up with an empty list since everything we've tried has failed
|
// we ended up with an empty list since everything we've tried has failed
|
||||||
// so clear the set of failed addresses and start going through them again
|
// so clear the set of failed addresses and start going through them again
|
||||||
|
|
||||||
qCWarning(domain_server_ice) << "All current ice-server addresses have failed - re-attempting all current addresses for"
|
qCWarning(domain_server_ice) <<
|
||||||
<< _iceServerAddr;
|
"PAGE: All current ice-server addresses have failed - re-attempting all current addresses for"
|
||||||
|
<< _iceServerAddr;
|
||||||
|
|
||||||
_failedIceServerAddresses.clear();
|
_failedIceServerAddresses.clear();
|
||||||
candidateICEAddresses = _iceServerAddresses;
|
candidateICEAddresses = _iceServerAddresses;
|
||||||
|
|
|
@ -136,6 +136,8 @@ private slots:
|
||||||
void tokenGrantFinished();
|
void tokenGrantFinished();
|
||||||
void profileRequestFinished();
|
void profileRequestFinished();
|
||||||
|
|
||||||
|
void aboutToQuit();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void iceServerChanged();
|
void iceServerChanged();
|
||||||
void userConnected();
|
void userConnected();
|
||||||
|
@ -236,6 +238,7 @@ private:
|
||||||
|
|
||||||
bool _isUsingDTLS { false };
|
bool _isUsingDTLS { false };
|
||||||
|
|
||||||
|
bool _oauthEnable { false };
|
||||||
QUrl _oauthProviderURL;
|
QUrl _oauthProviderURL;
|
||||||
QString _oauthClientID;
|
QString _oauthClientID;
|
||||||
QString _oauthClientSecret;
|
QString _oauthClientSecret;
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
#include <QtCore/QUrlQuery>
|
#include <QtCore/QUrlQuery>
|
||||||
|
#include <QtNetwork/QSslKey>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
|
@ -46,10 +48,14 @@ 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 DESCRIPTION_GROUP_LABEL_KEY = "label";
|
const QString DESCRIPTION_GROUP_LABEL_KEY = "label";
|
||||||
|
const QString DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY = "show_on_enable";
|
||||||
|
const QString DESCRIPTION_ENABLE_KEY = "enable";
|
||||||
const QString DESCRIPTION_BACKUP_FLAG_KEY = "backup";
|
const QString DESCRIPTION_BACKUP_FLAG_KEY = "backup";
|
||||||
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
|
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
|
||||||
const QString DESCRIPTION_COLUMNS_KEY = "columns";
|
const QString DESCRIPTION_COLUMNS_KEY = "columns";
|
||||||
const QString CONTENT_SETTING_FLAG_KEY = "content_setting";
|
const QString CONTENT_SETTING_FLAG_KEY = "content_setting";
|
||||||
|
static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings";
|
||||||
|
static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings";
|
||||||
|
|
||||||
const QString SETTINGS_VIEWPOINT_KEY = "viewpoint";
|
const QString SETTINGS_VIEWPOINT_KEY = "viewpoint";
|
||||||
|
|
||||||
|
@ -136,6 +142,10 @@ void DomainServerSettingsManager::splitSettingsDescription() {
|
||||||
|
|
||||||
settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY];
|
settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY];
|
||||||
|
|
||||||
|
if (groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY)) {
|
||||||
|
settingsDropdownGroup[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY] = groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY];
|
||||||
|
}
|
||||||
|
|
||||||
static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id";
|
static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id";
|
||||||
if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) {
|
if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) {
|
||||||
settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY];
|
settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY];
|
||||||
|
@ -170,9 +180,6 @@ void DomainServerSettingsManager::splitSettingsDescription() {
|
||||||
|
|
||||||
// populate the settings menu groups with what we've collected
|
// populate the settings menu groups with what we've collected
|
||||||
|
|
||||||
static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings";
|
|
||||||
static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings";
|
|
||||||
|
|
||||||
_settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups;
|
_settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups;
|
||||||
_settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups;
|
_settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups;
|
||||||
}
|
}
|
||||||
|
@ -448,6 +455,77 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena
|
||||||
packPermissions();
|
packPermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 2.4) {
|
||||||
|
// migrate oauth settings to their own group
|
||||||
|
const QString ADMIN_USERS = "admin-users";
|
||||||
|
const QString OAUTH_ADMIN_USERS = "oauth.admin-users";
|
||||||
|
const QString OAUTH_CLIENT_ID = "oauth.client-id";
|
||||||
|
const QString ALT_ADMIN_USERS = "admin.users";
|
||||||
|
const QString ADMIN_ROLES = "admin-roles";
|
||||||
|
const QString OAUTH_ADMIN_ROLES = "oauth.admin-roles";
|
||||||
|
const QString OAUTH_ENABLE = "oauth.enable";
|
||||||
|
|
||||||
|
QVector<QPair<const char*, const char*> > conversionMap = {
|
||||||
|
{"key", "oauth.key"},
|
||||||
|
{"cert", "oauth.cert"},
|
||||||
|
{"hostname", "oauth.hostname"},
|
||||||
|
{"oauth-client-id", "oauth.client-id"},
|
||||||
|
{"oauth-provider", "oauth.provider"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto & conversion : conversionMap) {
|
||||||
|
QVariant* prevValue = _configMap.valueForKeyPath(conversion.first);
|
||||||
|
if (prevValue) {
|
||||||
|
auto newValue = _configMap.valueForKeyPath(conversion.second, true);
|
||||||
|
*newValue = *prevValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant* client_id = _configMap.valueForKeyPath(OAUTH_CLIENT_ID);
|
||||||
|
if (client_id) {
|
||||||
|
QVariant* oauthEnable = _configMap.valueForKeyPath(OAUTH_ENABLE, true);
|
||||||
|
|
||||||
|
*oauthEnable = QVariant(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant* oldAdminUsers = _configMap.valueForKeyPath(ADMIN_USERS);
|
||||||
|
QVariant* newAdminUsers = _configMap.valueForKeyPath(OAUTH_ADMIN_USERS, true);
|
||||||
|
QVariantList adminUsers(newAdminUsers->toList());
|
||||||
|
if (oldAdminUsers) {
|
||||||
|
QStringList adminUsersList = oldAdminUsers->toStringList();
|
||||||
|
for (auto & user : adminUsersList) {
|
||||||
|
if (!adminUsers.contains(user)) {
|
||||||
|
adminUsers.append(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QVariant* altAdminUsers = _configMap.valueForKeyPath(ALT_ADMIN_USERS);
|
||||||
|
if (altAdminUsers) {
|
||||||
|
QStringList adminUsersList = altAdminUsers->toStringList();
|
||||||
|
for (auto & user : adminUsersList) {
|
||||||
|
if (!adminUsers.contains(user)) {
|
||||||
|
adminUsers.append(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*newAdminUsers = adminUsers;
|
||||||
|
|
||||||
|
QVariant* oldAdminRoles = _configMap.valueForKeyPath(ADMIN_ROLES);
|
||||||
|
QVariant* newAdminRoles = _configMap.valueForKeyPath(OAUTH_ADMIN_ROLES, true);
|
||||||
|
QVariantList adminRoles(newAdminRoles->toList());
|
||||||
|
if (oldAdminRoles) {
|
||||||
|
QStringList adminRoleList = oldAdminRoles->toStringList();
|
||||||
|
for (auto & role : adminRoleList) {
|
||||||
|
if (!adminRoles.contains(role)) {
|
||||||
|
adminRoles.append(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*newAdminRoles = adminRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// write the current description version to our settings
|
// write the current description version to our settings
|
||||||
*versionVariant = _descriptionVersion;
|
*versionVariant = _descriptionVersion;
|
||||||
|
@ -1185,7 +1263,24 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (url.path() == SETTINGS_MENU_GROUPS_PATH) {
|
} else if (url.path() == SETTINGS_MENU_GROUPS_PATH) {
|
||||||
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(_settingsMenuGroups).toJson(), "application/json");
|
|
||||||
|
QJsonObject settings;
|
||||||
|
for (auto & key : _settingsMenuGroups.keys()) {
|
||||||
|
const QJsonArray& settingGroups = _settingsMenuGroups[key].toArray();
|
||||||
|
QJsonArray groups;
|
||||||
|
foreach (const QJsonValue& group, settingGroups) {
|
||||||
|
QJsonObject groupObject = group.toObject();
|
||||||
|
QVariant* enableKey = _configMap.valueForKeyPath(groupObject[DESCRIPTION_NAME_KEY].toString() + "." + DESCRIPTION_ENABLE_KEY);
|
||||||
|
|
||||||
|
if (!groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY)
|
||||||
|
|| (groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY].toBool() && enableKey && enableKey->toBool() )) {
|
||||||
|
groups.append(groupObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings[key] = groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(settings).toJson(), "application/json");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (url.path() == SETTINGS_BACKUP_PATH) {
|
} else if (url.path() == SETTINGS_BACKUP_PATH) {
|
||||||
|
@ -1446,6 +1541,28 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add 'derived' values used primarily for UI
|
||||||
|
|
||||||
|
const QString X509_CERTIFICATE_OPTION = "oauth.cert";
|
||||||
|
|
||||||
|
QString certPath = valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
|
||||||
|
if (!certPath.isEmpty()) {
|
||||||
|
// the user wants to use the following cert and key for HTTPS
|
||||||
|
// this is used for Oauth callbacks when authorizing users against a data server
|
||||||
|
// let's make sure we can load the key and certificate
|
||||||
|
|
||||||
|
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
|
||||||
|
|
||||||
|
QFile certFile(certPath);
|
||||||
|
certFile.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
QSslCertificate sslCertificate(&certFile);
|
||||||
|
QString digest = sslCertificate.digest().toHex(':');
|
||||||
|
auto groupObject = responseObject["oauth"].toObject();
|
||||||
|
groupObject["cert-fingerprint"] = digest;
|
||||||
|
responseObject["oauth"] = groupObject;
|
||||||
|
}
|
||||||
|
|
||||||
return responseObject;
|
return responseObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,23 +1668,65 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
|
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedSettingsObject,
|
||||||
SettingsType settingsType) {
|
SettingsType settingsType) {
|
||||||
|
|
||||||
// take a write lock since we're about to overwrite settings in the config map
|
// take a write lock since we're about to overwrite settings in the config map
|
||||||
QWriteLocker locker(&_settingsLock);
|
QWriteLocker locker(&_settingsLock);
|
||||||
|
|
||||||
|
QJsonObject postedObject(postedSettingsObject);
|
||||||
|
|
||||||
static const QString SECURITY_ROOT_KEY = "security";
|
static const QString SECURITY_ROOT_KEY = "security";
|
||||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||||
static const QString BROADCASTING_KEY = "broadcasting";
|
static const QString BROADCASTING_KEY = "broadcasting";
|
||||||
static const QString WIZARD_KEY = "wizard";
|
static const QString WIZARD_KEY = "wizard";
|
||||||
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
||||||
|
static const QString OAUTH_ROOT_KEY = "oauth";
|
||||||
|
static const QString OAUTH_KEY_CONTENTS = "key-contents";
|
||||||
|
static const QString OAUTH_CERT_CONTENTS = "cert-contents";
|
||||||
|
static const QString OAUTH_CERT_PATH = "cert";
|
||||||
|
static const QString OAUTH_KEY_PASSPHRASE = "key-passphrase";
|
||||||
|
static const QString OAUTH_KEY_PATH = "key";
|
||||||
|
|
||||||
auto& settingsVariant = _configMap.getConfig();
|
auto& settingsVariant = _configMap.getConfig();
|
||||||
bool needRestart = false;
|
bool needRestart = false;
|
||||||
|
|
||||||
auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription;
|
auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription;
|
||||||
|
|
||||||
|
auto oauthObject = postedObject[OAUTH_ROOT_KEY].toObject();
|
||||||
|
if (oauthObject.contains(OAUTH_CERT_CONTENTS)) {
|
||||||
|
QSslCertificate cert(oauthObject[OAUTH_CERT_CONTENTS].toString().toUtf8());
|
||||||
|
if (!cert.isNull()) {
|
||||||
|
static const QString CERT_FILE_NAME = "certificate.crt";
|
||||||
|
auto certPath = PathUtils::getAppDataFilePath(CERT_FILE_NAME);
|
||||||
|
QFile file(certPath);
|
||||||
|
if (file.open(QFile::WriteOnly)) {
|
||||||
|
file.write(cert.toPem());
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
oauthObject[OAUTH_CERT_PATH] = certPath;
|
||||||
|
}
|
||||||
|
oauthObject.remove(OAUTH_CERT_CONTENTS);
|
||||||
|
}
|
||||||
|
if (oauthObject.contains(OAUTH_KEY_CONTENTS)) {
|
||||||
|
QString keyPassphraseString = oauthObject[OAUTH_KEY_PASSPHRASE].toString();
|
||||||
|
QSslKey key(oauthObject[OAUTH_KEY_CONTENTS].toString().toUtf8(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
|
||||||
|
if (!key.isNull()) {
|
||||||
|
static const QString KEY_FILE_NAME = "certificate.key";
|
||||||
|
auto keyPath = PathUtils::getAppDataFilePath(KEY_FILE_NAME);
|
||||||
|
QFile file(keyPath);
|
||||||
|
if (file.open(QFile::WriteOnly)) {
|
||||||
|
file.write(key.toPem());
|
||||||
|
file.close();
|
||||||
|
file.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
|
||||||
|
}
|
||||||
|
oauthObject[OAUTH_KEY_PATH] = keyPath;
|
||||||
|
}
|
||||||
|
oauthObject.remove(OAUTH_KEY_CONTENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
postedObject[OAUTH_ROOT_KEY] = oauthObject;
|
||||||
|
|
||||||
// Iterate on the setting groups
|
// Iterate on the setting groups
|
||||||
foreach(const QString& rootKey, postedObject.keys()) {
|
foreach(const QString& rootKey, postedObject.keys()) {
|
||||||
const QJsonValue& rootValue = postedObject[rootKey];
|
const QJsonValue& rootValue = postedObject[rootKey];
|
||||||
|
@ -1752,6 +1911,8 @@ void DomainServerSettingsManager::persistToFile() {
|
||||||
_configMap.loadConfig();
|
_configMap.loadConfig();
|
||||||
return; // defend against future code
|
return; // defend against future code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFile(settingsFilename).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DomainServerSettingsManager::getAllKnownGroupNames() {
|
QStringList DomainServerSettingsManager::getAllKnownGroupNames() {
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <BuildInfo.h>
|
||||||
|
#include <CrashAnnotations.h>
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <BuildInfo.h>
|
|
||||||
|
|
||||||
#include "DomainServer.h"
|
#include "DomainServer.h"
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
// use a do-while to handle domain-server restart
|
// use a do-while to handle domain-server restart
|
||||||
do {
|
do {
|
||||||
|
crash::annotations::setShutdownState(false);
|
||||||
DomainServer domainServer(argc, argv);
|
DomainServer domainServer(argc, argv);
|
||||||
currentExitCode = domainServer.exec();
|
currentExitCode = domainServer.exec();
|
||||||
} while (currentExitCode == DomainServer::EXIT_CODE_REBOOT);
|
} while (currentExitCode == DomainServer::EXIT_CODE_REBOOT);
|
||||||
|
@ -39,4 +41,3 @@ int main(int argc, char* argv[]) {
|
||||||
qInfo() << "Quitting.";
|
qInfo() << "Quitting.";
|
||||||
return currentExitCode;
|
return currentExitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ endif()
|
||||||
downloadVcpkg = True
|
downloadVcpkg = True
|
||||||
|
|
||||||
if not downloadVcpkg and not os.path.isfile(self.exe):
|
if not downloadVcpkg and not os.path.isfile(self.exe):
|
||||||
print("Missing executable, boostrapping")
|
print("Missing executable, boot-strapping")
|
||||||
downloadVcpkg = True
|
downloadVcpkg = True
|
||||||
|
|
||||||
# Make sure we have a vcpkg executable
|
# Make sure we have a vcpkg executable
|
||||||
|
@ -265,7 +265,7 @@ endif()
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows3.tar.gz'
|
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-windows3.tar.gz'
|
||||||
elif platform.system() == 'Darwin':
|
elif platform.system() == 'Darwin':
|
||||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos3.tar.gz'
|
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-macos.tar.gz?versionId=bLAgnoJ8IMKpqv8NFDcAu8hsyQy3Rwwz'
|
||||||
elif platform.system() == 'Linux':
|
elif platform.system() == 'Linux':
|
||||||
if platform.linux_distribution()[1][:3] == '16.':
|
if platform.linux_distribution()[1][:3] == '16.':
|
||||||
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04-with-symbols.tar.gz'
|
url = 'https://hifi-public.s3.amazonaws.com/dependencies/vcpkg/qt5-install-5.12.3-ubuntu-16.04-with-symbols.tar.gz'
|
||||||
|
|
|
@ -70,12 +70,16 @@ file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
|
||||||
GroupSources("src")
|
GroupSources("src")
|
||||||
list(APPEND INTERFACE_SRCS ${RESOURCES_RCC})
|
list(APPEND INTERFACE_SRCS ${RESOURCES_RCC})
|
||||||
|
|
||||||
|
# grab the Objective-C sources on OS X
|
||||||
|
if (APPLE)
|
||||||
|
file(GLOB_RECURSE INTERFACE_OBJCPP_SRCS "src/*.m" "src/*.mm")
|
||||||
|
list(APPEND INTERFACE_SRCS ${INTERFACE_OBJCPP_SRCS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
|
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# Use .cpp and .h files as is.
|
# Use .cpp and .h files as is.
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
file(GLOB INTERFACE_OBJCPP_SRCS "src/SpeechRecognizer.mm")
|
|
||||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_OBJCPP_SRCS})
|
|
||||||
get_filename_component(SPEECHRECOGNIZER_CPP "src/SpeechRecognizer.cpp" ABSOLUTE)
|
get_filename_component(SPEECHRECOGNIZER_CPP "src/SpeechRecognizer.cpp" ABSOLUTE)
|
||||||
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
||||||
else ()
|
else ()
|
||||||
|
@ -117,6 +121,7 @@ if (APPLE)
|
||||||
# configure CMake to use a custom Info.plist
|
# configure CMake to use a custom Info.plist
|
||||||
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
||||||
|
|
||||||
|
set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity")
|
||||||
if (PRODUCTION_BUILD)
|
if (PRODUCTION_BUILD)
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
|
||||||
else ()
|
else ()
|
||||||
|
@ -151,7 +156,7 @@ elseif (WIN32)
|
||||||
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
|
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
|
||||||
|
|
||||||
set(APP_FULL_NAME "High Fidelity Interface")
|
set(APP_FULL_NAME "High Fidelity")
|
||||||
set(CONFIGURE_VERSION_INFO_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.rc")
|
set(CONFIGURE_VERSION_INFO_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.rc")
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||||
|
|
||||||
|
|
14
interface/external/iViewHMD/readme.txt
vendored
14
interface/external/iViewHMD/readme.txt
vendored
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
Instructions for adding SMI HMD Eye Tracking to Interface on Windows
|
|
||||||
David Rowe, 27 Jul 2015.
|
|
||||||
|
|
||||||
1. Download and install the SMI HMD Eye Tracking software from http://update.smivision.com/iViewNG-HMD.exe.
|
|
||||||
|
|
||||||
2. Copy the SDK folders (3rdParty, include, libs) from the SDK installation folder C:\Program Files (x86)\SMI\iViewNG-HMD\SDK
|
|
||||||
into the interface/externals/iViewHMD folder. This readme.txt should be there as well.
|
|
||||||
|
|
||||||
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different
|
|
||||||
checkouts and different projects). If so, set the ENV variable "HIFI_LIB_DIR" to a directory containing a subfolder
|
|
||||||
"iViewHMD" that contains the folders mentioned above.
|
|
||||||
|
|
||||||
3. Clear your build directory, run cmake and build, and you should be all set.
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 26 KiB |
20
interface/interface.entitlements
Normal file
20
interface/interface.entitlements
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>high-fidelity.hifi</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.device.audio-input</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
interface/resources/avatar/animations/idle_aimoffsets.fbx
Normal file
BIN
interface/resources/avatar/animations/idle_aimoffsets.fbx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue