Working on sessions.

This commit is contained in:
Andrzej Kapolka 2013-12-30 13:39:08 -08:00
parent 97e7340ba6
commit f70670d0a9
13 changed files with 298 additions and 81 deletions

View file

@ -11,6 +11,8 @@
#include <Logging.h>
#include <PacketHeaders.h>
#include <MetavoxelUtil.h>
#include "MetavoxelServer.h"
#include "Session.h"
@ -18,6 +20,10 @@ MetavoxelServer::MetavoxelServer(const unsigned char* dataBuffer, int numBytes)
ThreadedAssignment(dataBuffer, numBytes) {
}
void MetavoxelServer::removeSession(const QUuid& sessionId) {
delete _sessions.take(sessionId);
}
void MetavoxelServer::run() {
// change the logging target name while the metavoxel server is running
Logging::setTargetName("metavoxel-server");
@ -51,22 +57,17 @@ void MetavoxelServer::processDatagram(const QByteArray& dataByteArray, const Hif
}
void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& sender) {
// get the header size
int headerSize = numBytesForPacketHeader((unsigned char*)data.constData());
// read the session id
const int UUID_BYTES = 16;
if (data.size() < headerSize + UUID_BYTES) {
qWarning() << "Metavoxel data too short [size=" << data.size() << ", sender=" << sender << "]\n";
int headerPlusIDSize;
QUuid sessionID = readSessionID(data, sender, headerPlusIDSize);
if (sessionID.isNull()) {
return;
}
QUuid sessionId = QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES));
// forward to session, creating if necessary
Session*& session = _sessions[sessionId];
Session*& session = _sessions[sessionID];
if (!session) {
session = new Session(this);
session = new Session(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize));
}
session->receivedData(QByteArray::fromRawData(data.constData() + headerSize + UUID_BYTES,
data.size() - headerSize - UUID_BYTES), sender);
session->receivedData(data, sender);
}

View file

@ -25,7 +25,9 @@ class MetavoxelServer : public ThreadedAssignment {
public:
MetavoxelServer(const unsigned char* dataBuffer, int numBytes);
void removeSession(const QUuid& sessionId);
virtual void run();
virtual void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);

View file

@ -9,20 +9,39 @@
#include "MetavoxelServer.h"
#include "Session.h"
Session::Session(MetavoxelServer* server) :
Session::Session(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader) :
QObject(server),
_server(server) {
_server(server),
_sessionId(sessionId),
_sequencer(datagramHeader) {
const int TIMEOUT_INTERVAL = 30 * 1000;
_timeoutTimer.setInterval(TIMEOUT_INTERVAL);
_timeoutTimer.setSingleShot(true);
connect(&_timeoutTimer, SIGNAL(timeout()), SLOT(timedOut()));
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
}
void Session::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
// reset the timeout timer
_timeoutTimer.start();
// save the most recent sender
_sender = sender;
// process through sequencer
_sequencer.receivedDatagram(data);
}
void Session::timedOut() {
qDebug() << "Session timed out [sessionId=" << _sessionId << ", sender=" << _sender << "]\n";
_server->removeSession(_sessionId);
}
void Session::sendData(const QByteArray& data) {
NodeList::getInstance()->getNodeSocket().writeDatagram(data, _sender.getAddress(), _sender.getPort());
}
void Session::readPacket(Bitstream& in) {

View file

@ -9,9 +9,13 @@
#ifndef __hifi__Session__
#define __hifi__Session__
#include <QTimer>
#include <QUuid>
#include <HifiSockAddr.h>
#include <DatagramSequencer.h>
class HifiSockAddr;
class MetavoxelServer;
/// Contains the state of a single client session.
@ -20,12 +24,14 @@ class Session : public QObject {
public:
Session(MetavoxelServer* server);
Session(MetavoxelServer* server, const QUuid& sessionId, const QByteArray& datagramHeader);
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
private slots:
void timedOut();
void sendData(const QByteArray& data);
void readPacket(Bitstream& in);
@ -33,7 +39,12 @@ private slots:
private:
MetavoxelServer* _server;
QUuid _sessionId;
QTimer _timeoutTimer;
DatagramSequencer _sequencer;
HifiSockAddr _sender;
};
#endif /* defined(__hifi__Session__) */

View file

@ -4376,6 +4376,8 @@ void* Application::networkReceive(void* args) {
break;
}
case PACKET_TYPE_METAVOXEL_DATA:
app->_metavoxels.processData(QByteArray((const char*)app->_incomingPacket, bytesReceived),
senderSockAddr);
break;
case PACKET_TYPE_BULK_AVATAR_DATA:
NodeList::getInstance()->processBulkNodeData(senderSockAddr,

View file

@ -37,6 +37,7 @@
#include "Cloud.h"
#include "Environment.h"
#include "GLCanvas.h"
#include "MetavoxelSystem.h"
#include "PacketHeaders.h"
#include "PieMenu.h"
#include "Stars.h"
@ -59,7 +60,6 @@
#include "renderer/AmbientOcclusionEffect.h"
#include "renderer/GeometryCache.h"
#include "renderer/GlowEffect.h"
#include "renderer/MetavoxelSystem.h"
#include "renderer/PointShader.h"
#include "renderer/TextureCache.h"
#include "renderer/VoxelShader.h"

View file

@ -12,6 +12,8 @@
#include <SharedUtil.h>
#include <MetavoxelUtil.h>
#include "Application.h"
#include "MetavoxelSystem.h"
@ -23,6 +25,10 @@ MetavoxelSystem::MetavoxelSystem() :
_buffer(QOpenGLBuffer::VertexBuffer) {
}
MetavoxelSystem::~MetavoxelSystem() {
NodeList::getInstance()->removeHook(this);
}
void MetavoxelSystem::init() {
if (!_program.isLinked()) {
switchToResourcesParentIfRequired();
@ -32,6 +38,8 @@ void MetavoxelSystem::init() {
_pointScaleLocation = _program.uniformLocation("pointScale");
}
NodeList::getInstance()->addHook(this);
AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine);
QFile scriptFile("resources/scripts/sphere.js");
@ -44,6 +52,10 @@ void MetavoxelSystem::init() {
_buffer.create();
}
void MetavoxelSystem::processData(const QByteArray& data, const HifiSockAddr& sender) {
QMetaObject::invokeMethod(this, "receivedData", Q_ARG(const QByteArray&, data), Q_ARG(const HifiSockAddr&, sender));
}
void MetavoxelSystem::simulate(float deltaTime) {
_points.clear();
_data.guide(_pointVisitor);
@ -99,6 +111,43 @@ void MetavoxelSystem::render() {
_program.release();
}
void MetavoxelSystem::nodeAdded(Node* node) {
if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) {
QMetaObject::invokeMethod(this, "addClient", Q_ARG(const QUuid&, node->getUUID()),
Q_ARG(const HifiSockAddr&, node->getPublicSocket()));
}
}
void MetavoxelSystem::nodeKilled(Node* node) {
if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) {
QMetaObject::invokeMethod(this, "removeClient", Q_ARG(const QUuid&, node->getUUID()));
}
}
void MetavoxelSystem::addClient(const QUuid& uuid, const HifiSockAddr& address) {
MetavoxelClient* client = new MetavoxelClient(address);
_clients.insert(uuid, client);
_clientsBySessionID.insert(client->getSessionID(), client);
}
void MetavoxelSystem::removeClient(const QUuid& uuid) {
MetavoxelClient* client = _clients.take(uuid);
_clientsBySessionID.remove(client->getSessionID());
delete client;
}
void MetavoxelSystem::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
int headerPlusIDSize;
QUuid sessionID = readSessionID(data, sender, headerPlusIDSize);
if (sessionID.isNull()) {
return;
}
MetavoxelClient* client = _clientsBySessionID.value(sessionID);
if (client) {
client->receivedData(data, sender);
}
}
MetavoxelSystem::PointVisitor::PointVisitor(QVector<Point>& points) :
MetavoxelVisitor(QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getColorAttribute() <<
@ -120,3 +169,34 @@ bool MetavoxelSystem::PointVisitor::visit(const MetavoxelInfo& info) {
}
return false;
}
static QByteArray createDatagramHeader(const QUuid& sessionID) {
QByteArray header(MAX_PACKET_HEADER_BYTES, 0);
populateTypeAndVersion(reinterpret_cast<unsigned char*>(header.data()), PACKET_TYPE_METAVOXEL_DATA);
header += sessionID.toRfc4122();
return header;
}
MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
_address(address),
_sessionID(QUuid::createUuid()),
_sequencer(createDatagramHeader(_sessionID)) {
connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendData(const QByteArray&)));
connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readPacket(Bitstream&)));
}
void MetavoxelClient::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
// save the most recent sender
_address = sender;
// process through sequencer
_sequencer.receivedDatagram(data);
}
void MetavoxelClient::sendData(const QByteArray& data) {
NodeList::getInstance()->getNodeSocket().writeDatagram(data, _address.getAddress(), _address.getPort());
}
void MetavoxelClient::readPacket(Bitstream& in) {
}

View file

@ -0,0 +1,107 @@
//
// MetavoxelSystem.h
// interface
//
// Created by Andrzej Kapolka on 12/10/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__MetavoxelSystem__
#define __interface__MetavoxelSystem__
#include <QOpenGLBuffer>
#include <QScriptEngine>
#include <QVector>
#include <glm/glm.hpp>
#include <NodeList.h>
#include <DatagramSequencer.h>
#include <MetavoxelData.h>
#include "renderer/ProgramObject.h"
class MetavoxelClient;
/// Renders a metavoxel tree.
class MetavoxelSystem : public QObject, public NodeListHook {
Q_OBJECT
public:
MetavoxelSystem();
~MetavoxelSystem();
void init();
void processData(const QByteArray& data, const HifiSockAddr& sender);
void simulate(float deltaTime);
void render();
virtual void nodeAdded(Node* node);
virtual void nodeKilled(Node* node);
private:
Q_INVOKABLE void addClient(const QUuid& uuid, const HifiSockAddr& address);
Q_INVOKABLE void removeClient(const QUuid& uuid);
Q_INVOKABLE void receivedData(const QByteArray& data, const HifiSockAddr& sender);
class Point {
public:
glm::vec4 vertex;
quint8 color[4];
quint8 normal[3];
};
class PointVisitor : public MetavoxelVisitor {
public:
PointVisitor(QVector<Point>& points);
virtual bool visit(const MetavoxelInfo& info);
private:
QVector<Point>& _points;
};
static ProgramObject _program;
static int _pointScaleLocation;
QScriptEngine _scriptEngine;
MetavoxelData _data;
QVector<Point> _points;
PointVisitor _pointVisitor;
QOpenGLBuffer _buffer;
QHash<QUuid, MetavoxelClient*> _clients;
QHash<QUuid, MetavoxelClient*> _clientsBySessionID;
};
/// A client session associated with a single server.
class MetavoxelClient : public QObject {
Q_OBJECT
public:
MetavoxelClient(const HifiSockAddr& address);
const QUuid& getSessionID() const { return _sessionID; }
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
private slots:
void sendData(const QByteArray& data);
void readPacket(Bitstream& in);
private:
HifiSockAddr _address;
QUuid _sessionID;
DatagramSequencer _sequencer;
};
#endif /* defined(__interface__MetavoxelSystem__) */

View file

@ -1,61 +0,0 @@
//
// MetavoxelSystem.h
// interface
//
// Created by Andrzej Kapolka on 12/10/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__MetavoxelSystem__
#define __interface__MetavoxelSystem__
#include <QOpenGLBuffer>
#include <QScriptEngine>
#include <QVector>
#include <glm/glm.hpp>
#include <MetavoxelData.h>
#include "ProgramObject.h"
/// Renders a metavoxel tree.
class MetavoxelSystem {
public:
MetavoxelSystem();
void init();
void simulate(float deltaTime);
void render();
private:
class Point {
public:
glm::vec4 vertex;
quint8 color[4];
quint8 normal[3];
};
class PointVisitor : public MetavoxelVisitor {
public:
PointVisitor(QVector<Point>& points);
virtual bool visit(const MetavoxelInfo& info);
private:
QVector<Point>& _points;
};
static ProgramObject _program;
static int _pointScaleLocation;
QScriptEngine _scriptEngine;
MetavoxelData _data;
QVector<Point> _points;
PointVisitor _pointVisitor;
QOpenGLBuffer _buffer;
};
#endif /* defined(__interface__MetavoxelSystem__) */

View file

@ -12,10 +12,11 @@
const int MAX_DATAGRAM_SIZE = 1500;
DatagramSequencer::DatagramSequencer() :
DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader) :
_outgoingPacketStream(&_outgoingPacketData, QIODevice::WriteOnly),
_outputStream(_outgoingPacketStream),
_datagramStream(&_datagramBuffer),
_datagramHeaderSize(datagramHeader.size()),
_outgoingPacketNumber(0),
_outgoingDatagram(MAX_DATAGRAM_SIZE, 0),
_incomingPacketNumber(0),
@ -23,6 +24,7 @@ DatagramSequencer::DatagramSequencer() :
_inputStream(_incomingPacketStream) {
_datagramStream.setByteOrder(QDataStream::LittleEndian);
memcpy(_outgoingDatagram.data(), datagramHeader.constData(), _datagramHeaderSize);
}
/// Simple RAII-style object to keep a device open when in scope.
@ -53,7 +55,7 @@ void DatagramSequencer::endPacket() {
}
void DatagramSequencer::receivedDatagram(const QByteArray& datagram) {
_datagramBuffer.setBuffer(const_cast<QByteArray*>(&datagram));
_datagramBuffer.setData(datagram.constData() + _datagramHeaderSize, datagram.size() - _datagramHeaderSize);
QIODeviceOpener opener(&_datagramBuffer, QIODevice::ReadOnly);
// read the sequence number
@ -144,6 +146,7 @@ void DatagramSequencer::sendPacket(const QByteArray& packet) {
_sendRecords.append(record);
// write the sequence number and size, which are the same between all fragments
_datagramBuffer.seek(_datagramHeaderSize);
_datagramStream << (quint32)_outgoingPacketNumber;
_datagramStream << (quint32)packet.size();
int initialPosition = _datagramBuffer.pos();

View file

@ -23,7 +23,7 @@ class DatagramSequencer : public QObject {
public:
DatagramSequencer();
DatagramSequencer(const QByteArray& datagramHeader = QByteArray());
/// Starts a new packet for transmission.
/// \return a reference to the Bitstream to use for writing to the packet
@ -77,6 +77,7 @@ private:
QBuffer _datagramBuffer;
QDataStream _datagramStream;
int _datagramHeaderSize;
int _outgoingPacketNumber;
QByteArray _outgoingDatagram;

View file

@ -0,0 +1,29 @@
//
// MetavoxelUtil.cpp
// metavoxels
//
// Created by Andrzej Kapolka on 12/30/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <QByteArray>
#include <QtDebug>
#include <HifiSockAddr.h>
#include <PacketHeaders.h>
#include "MetavoxelUtil.h"
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize) {
// get the header size
int headerSize = numBytesForPacketHeader(reinterpret_cast<const unsigned char*>(data.constData()));
// read the session id
const int UUID_BYTES = 16;
headerPlusIDSize = headerSize + UUID_BYTES;
if (data.size() < headerPlusIDSize) {
qWarning() << "Metavoxel data too short [size=" << data.size() << ", sender=" << sender << "]\n";
return QUuid();
}
return QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES));
}

View file

@ -0,0 +1,23 @@
//
// MetavoxelUtil.h
// metavoxels
//
// Created by Andrzej Kapolka on 12/30/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__MetavoxelUtil__
#define __interface__MetavoxelUtil__
#include <QUuid>
class QByteArray;
class HifiSockAddr;
/// Reads and returns the session ID from a datagram.
/// \param[out] headerPlusIDSize the size of the header (including the session ID) within the data
/// \return the session ID, or a null ID if invalid (in which case a warning will be logged)
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize);
#endif /* defined(__interface__MetavoxelUtil__) */