initial commit
This commit is contained in:
commit
9d20827c46
2469 changed files with 470994 additions and 0 deletions
351
third-party/JsonQt/lib/JsonRpcAdaptorPrivate.cpp
vendored
Normal file
351
third-party/JsonQt/lib/JsonRpcAdaptorPrivate.cpp
vendored
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
#include "JsonRpcAdaptorPrivate.h"
|
||||
|
||||
#include "VariantToJson.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QGenericArgument>
|
||||
#include <QMetaClassInfo>
|
||||
#include <QMetaObject>
|
||||
|
||||
namespace JsonQt
|
||||
{
|
||||
JsonRpcAdaptorPrivate::JsonRpcAdaptorPrivate(QObject* adapt, QObject* parent) : QObject(parent)
|
||||
{
|
||||
m_adapted = adapt;
|
||||
connect(
|
||||
&m_jsonRpc,
|
||||
SIGNAL(sendJson(const QString&)),
|
||||
this,
|
||||
SIGNAL(sendJson(const QString&))
|
||||
);
|
||||
connect(
|
||||
&m_jsonRpc,
|
||||
SIGNAL(requestReceived(const QVariant&, const QString&, const QVariant&)),
|
||||
this,
|
||||
SLOT(requestReceived(const QVariant&, const QString&, const QVariant&))
|
||||
);
|
||||
populateServiceDescription();
|
||||
}
|
||||
|
||||
void JsonRpcAdaptorPrivate::populateServiceDescription()
|
||||
{
|
||||
m_serviceDescription.clear();
|
||||
const QMetaObject* metaObject = m_adapted->metaObject();
|
||||
|
||||
QString id = getClassInfo("JsonQt-RPC-id");
|
||||
Q_ASSERT(!id.isEmpty());
|
||||
m_serviceDescription["id"] = id;
|
||||
m_serviceDescription["sdversion"] = "1.0";
|
||||
QString name = getClassInfo("JsonQt-RPC-name");
|
||||
if(name.isEmpty()) name = metaObject->className();
|
||||
m_serviceDescription["name"] = name;
|
||||
|
||||
QString version = getClassInfo("JsonQt-RPC-version");
|
||||
if(!version.isNull()) m_serviceDescription["version"] = version;
|
||||
|
||||
QString summary = getClassInfo("JsonQt-RPC-summary");
|
||||
if(!summary.isNull()) m_serviceDescription["summary"] = summary;
|
||||
|
||||
QString help = getClassInfo("JsonQt-RPC-help");
|
||||
if(!help.isNull()) m_serviceDescription["help"] = help;
|
||||
|
||||
QMap<QString, QString> typeMap;
|
||||
typeMap[""] = "nil"; // void
|
||||
typeMap["bool"] = "bit";
|
||||
typeMap["int"] = "num";
|
||||
typeMap["QString"] = "str";
|
||||
// typeMap["QVariant"] = "any"; // not supported
|
||||
typeMap["QVariantList"] = "arr";
|
||||
typeMap["QVariantMap"] = "obj";
|
||||
|
||||
QVariantList procs;
|
||||
|
||||
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
|
||||
{
|
||||
QMetaMethod method = metaObject->method(i);
|
||||
|
||||
// Check we should export it
|
||||
if(method.access() != QMetaMethod::Public || method.methodType() != QMetaMethod::Slot) continue;
|
||||
|
||||
QVariantMap proc;
|
||||
QString signature = method.signature();
|
||||
|
||||
// Name
|
||||
QString methodName = signature.left(signature.indexOf('('));
|
||||
proc["name"] = methodName;
|
||||
|
||||
// Return type
|
||||
if(!typeMap.contains(method.typeName()))
|
||||
{
|
||||
qDebug() << "Public slot" << signature << "has unknown return type" << method.typeName();
|
||||
continue;
|
||||
}
|
||||
proc["return"] = typeMap.value(method.typeName());
|
||||
|
||||
// Parameters
|
||||
QVariantList parameters;
|
||||
bool badParameter = false;
|
||||
for(int i = 0; i < method.parameterNames().count(); ++i)
|
||||
{
|
||||
QVariantMap parameter;
|
||||
QString parameterName(method.parameterNames().at(i));
|
||||
parameter["name"] = parameterName;
|
||||
|
||||
QString parameterType = method.parameterTypes().at(i);
|
||||
if(!typeMap.contains(method.parameterTypes().at(i)))
|
||||
{
|
||||
qDebug() << "Public slot" << signature << "has parameter" << parameterName << "with unknown type" << parameterType;
|
||||
badParameter = true;
|
||||
continue;
|
||||
}
|
||||
parameter["type"] = typeMap.value(parameterType);
|
||||
parameters.append(parameter);
|
||||
m_parameterIndices[methodName].insert(parameterName, i);
|
||||
}
|
||||
if(badParameter) continue;
|
||||
|
||||
m_methods.insert(methodName, method);
|
||||
proc["params"] = parameters;
|
||||
|
||||
// Done
|
||||
procs.append(proc);
|
||||
}
|
||||
m_serviceDescription["procs"] = procs;
|
||||
}
|
||||
|
||||
QString JsonRpcAdaptorPrivate::getClassInfo(const char* name)
|
||||
{
|
||||
const QMetaObject* metaObject = m_adapted->metaObject();
|
||||
int index = metaObject->indexOfClassInfo(name);
|
||||
if(index == -1) return QString();
|
||||
return metaObject->classInfo(index).value();
|
||||
}
|
||||
|
||||
void JsonRpcAdaptorPrivate::requestReceived(const QVariant& id, const QString& method, const QVariant& parameters)
|
||||
{
|
||||
if(method == "system.describe")
|
||||
{
|
||||
m_jsonRpc.sendResponse(id, m_serviceDescription);
|
||||
return;
|
||||
}
|
||||
ReturnData result = invokeMethod(method, parameters);
|
||||
if(result.succeeded)
|
||||
{
|
||||
m_jsonRpc.sendResponse(id, result.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_jsonRpc.sendError(id, result.code, result.message, result.data);
|
||||
}
|
||||
}
|
||||
|
||||
JsonRpcAdaptorPrivate::ReturnData JsonRpcAdaptorPrivate::invokeMethod(const QString& methodName, const QVariant& parameters)
|
||||
{
|
||||
ReturnData ret;
|
||||
ret.succeeded = false;
|
||||
if(!m_methods.contains(methodName))
|
||||
{
|
||||
ret.code = JsonRpc::MethodNotFound;
|
||||
ret.message = QString("The method %1 does not exist.").arg(methodName);
|
||||
return ret;
|
||||
}
|
||||
QMetaMethod metaMethod(m_methods.value(methodName));
|
||||
|
||||
int parameterCount;
|
||||
QVariantList parameterList;
|
||||
switch(parameters.type())
|
||||
{
|
||||
case QVariant::List:
|
||||
parameterList = parameters.toList();
|
||||
parameterCount = parameterList.count();
|
||||
break;
|
||||
case QVariant::Map:
|
||||
parameterCount = parameters.toMap().count();
|
||||
for(int i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
parameterList.append(QVariant());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parameterCount = 0;
|
||||
}
|
||||
Q_ASSERT(parameterCount <= 9);
|
||||
|
||||
ret.code = JsonRpc::BadParameters;
|
||||
if(parameterCount != metaMethod.parameterNames().count())
|
||||
{
|
||||
ret.message = "Parameter count mismatch.";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if(parameters.type() == QVariant::Map)
|
||||
{
|
||||
QMap<QString, int> parameterIndices = m_parameterIndices.value(methodName);
|
||||
QVariantMap parameterMap = parameters.toMap();
|
||||
for(QVariantMap::ConstIterator it = parameterMap.constBegin(); it != parameterMap.constEnd(); ++it)
|
||||
{
|
||||
if(!parameterIndices.contains(it.key()))
|
||||
{
|
||||
ret.message = QString("'%1' is not a parameter of method '%2'.").arg(it.key()).arg(methodName);
|
||||
return ret;
|
||||
}
|
||||
int index = parameterIndices.value(it.key());
|
||||
Q_ASSERT(index < parameterCount);
|
||||
parameterList[index] = it.value();
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QVariant::Type> typeMap;
|
||||
typeMap[""] = QVariant::Invalid;
|
||||
typeMap["bool"] = QVariant::Bool;
|
||||
typeMap["int"] = QVariant::Int;
|
||||
typeMap["QString"] = QVariant::String;
|
||||
typeMap["QVariantList"] = QVariant::List;
|
||||
typeMap["QVariantMap"] = QVariant::Map;
|
||||
///@todo more types
|
||||
|
||||
QVariant::Type returnType = typeMap.value(metaMethod.typeName());
|
||||
|
||||
// QMetaObject::invokeMethod takes 9 generic arguments
|
||||
QGenericArgument arguments[9];
|
||||
for(int i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
const QVariant& value = parameterList.value(i);
|
||||
if(typeMap.value(metaMethod.parameterTypes().at(i)) != value.type())
|
||||
{
|
||||
ret.message = QString("Value for parameter %1 was not of the correct type.").arg(QString(metaMethod.parameterNames().at(i)));
|
||||
return ret;
|
||||
}
|
||||
void* data = 0;
|
||||
switch(value.type())
|
||||
{
|
||||
case QVariant::Bool:
|
||||
data = new bool(value.toBool());
|
||||
arguments[i] = Q_ARG(bool, *static_cast<bool*>(data));
|
||||
break;
|
||||
case QVariant::Int:
|
||||
data = new int(value.toInt());
|
||||
arguments[i] = Q_ARG(int, *static_cast<int*>(data));
|
||||
break;
|
||||
case QVariant::String:
|
||||
data = new QString(value.toString());
|
||||
arguments[i] = Q_ARG(QString, *static_cast<QString*>(data));
|
||||
break;
|
||||
case QVariant::List:
|
||||
data = new QVariantList(value.toList());
|
||||
arguments[i] = Q_ARG(QVariantList, *static_cast<QVariantList*>(data));
|
||||
break;
|
||||
case QVariant::Map:
|
||||
data = new QVariantMap(value.toMap());
|
||||
arguments[i] = Q_ARG(QVariantMap, *static_cast<QVariantMap*>(data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QGenericReturnArgument returnValue;
|
||||
|
||||
switch(returnType)
|
||||
{
|
||||
case QVariant::Bool:
|
||||
returnValue = Q_RETURN_ARG(bool, *(new bool));
|
||||
break;
|
||||
case QVariant::Int:
|
||||
returnValue = Q_RETURN_ARG(int, *(new int));
|
||||
break;
|
||||
case QVariant::String:
|
||||
returnValue = Q_RETURN_ARG(QString, *(new QString));
|
||||
break;
|
||||
case QVariant::List:
|
||||
returnValue = Q_RETURN_ARG(QVariantList, *(new QVariantList));
|
||||
break;
|
||||
case QVariant::Map:
|
||||
returnValue = Q_RETURN_ARG(QVariantMap, *(new QVariantMap));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bool success = m_adapted->metaObject()->invokeMethod(
|
||||
m_adapted,
|
||||
methodName.toLatin1().constData(),
|
||||
Qt::DirectConnection,
|
||||
returnValue,
|
||||
arguments[0],
|
||||
arguments[1],
|
||||
arguments[2],
|
||||
arguments[3],
|
||||
arguments[4],
|
||||
arguments[5],
|
||||
arguments[6],
|
||||
arguments[7],
|
||||
arguments[8],
|
||||
arguments[9]
|
||||
);
|
||||
|
||||
// clean up memory allocation
|
||||
for(int i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
QVariant::Type parameterType = parameterList.value(i).type();
|
||||
switch(parameterType)
|
||||
{
|
||||
case QVariant::Bool:
|
||||
delete static_cast<bool*>(arguments[i].data());
|
||||
break;
|
||||
case QVariant::Int:
|
||||
delete static_cast<int*>(arguments[i].data());
|
||||
break;
|
||||
case QVariant::String:
|
||||
delete static_cast<QString*>(arguments[i].data());
|
||||
break;
|
||||
case QVariant::List:
|
||||
delete static_cast<QVariantList*>(arguments[i].data());
|
||||
break;
|
||||
case QVariant::Map:
|
||||
delete static_cast<QVariantMap*>(arguments[i].data());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(success == false)
|
||||
{
|
||||
ret.code = JsonRpc::InternalError;
|
||||
ret.message = "Could not execute method.";
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.succeeded = true;
|
||||
|
||||
switch(returnType)
|
||||
{
|
||||
case QVariant::Bool:
|
||||
ret.data = *static_cast<bool*>(returnValue.data());
|
||||
break;
|
||||
case QVariant::Int:
|
||||
ret.data = *static_cast<int*>(returnValue.data());
|
||||
break;
|
||||
case QVariant::String:
|
||||
ret.data = *static_cast<QString*>(returnValue.data());
|
||||
break;
|
||||
case QVariant::List:
|
||||
ret.data = *static_cast<QVariantList*>(returnValue.data());
|
||||
break;
|
||||
case QVariant::Map:
|
||||
ret.data = *static_cast<QVariantMap*>(returnValue.data());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void JsonRpcAdaptorPrivate::processJson(const QString& json)
|
||||
{
|
||||
m_jsonRpc.processJson(json);
|
||||
}
|
||||
}
|
||||
Reference in a new issue