33 #include "private/ArnRpc_p.hpp" 39 #include <QMetaMethod> 41 #include <QDataStream> 47 #define RPC_STORAGE_NAME "_ArnRpcStorage" 49 ArnRpc::RpcTypeInfo ArnRpc::_rpcTypeInfoTab[] = {
51 {
"int",
"int", QMetaType::Int},
52 {
"uint",
"uint", QMetaType::UInt},
53 {
"int64",
"qint64", QMetaType::LongLong},
54 {
"uint64",
"quint64", QMetaType::ULongLong},
55 {
"bool",
"bool", QMetaType::Bool},
56 {
"float",
"float", QMetaType::Float},
57 {
"double",
"double", QMetaType::Double},
58 {
"bytes",
"QByteArray", QMetaType::QByteArray},
59 {
"date",
"QDate", QMetaType::QDate},
60 {
"time",
"QTime", QMetaType::QTime},
61 {
"datetime",
"QDateTime", QMetaType::QDateTime},
62 {
"list",
"QStringList", QMetaType::QStringList},
63 {
"string",
"QString", QMetaType::QString},
69 class ArnRpcReceiverStorage :
public QObject
74 explicit ArnRpcReceiverStorage( QObject* parent) :
82 class ArnDynamicSignals :
public QObject
85 explicit ArnDynamicSignals(
ArnRpc* rpc);
86 int qt_metacall( QMetaObject::Call call,
int id,
void **arguments);
87 bool addSignal( QObject *sender,
int signalId,
const QByteArray& funcName);
92 QList<QByteArray> typeNames;
93 QList<QByteArray> parNames;
103 ArnDynamicSignals::ArnDynamicSignals(
ArnRpc* rpc) :
106 _slotIdCount = QObject::staticMetaObject.methodCount();
111 int ArnDynamicSignals::qt_metacall( QMetaObject::Call call,
int id,
void **arguments)
113 if (
Arn::debugRPC) qDebug() <<
"Rpc metaCall-1: call=" << call <<
" id=" << id;
115 id = QObject::qt_metacall( call,
id, arguments);
116 if ((
id < 0) || (call != QMetaObject::InvokeMetaMethod))
119 Q_ASSERT(
id < _slotTab.size());
122 const Slot& slot = _slotTab.at(
id);
123 int argNum = slot.typeNames.size();
125 for (
int i = 0; i < argNum; ++i) {
127 slot.parNames.at(i).constData(),
131 if (
Arn::debugRPC) qDebug() <<
"Rpc metaCall-2: call=" << call <<
" id=" <<
id 132 <<
" func=" << slot.funcName <<
" flags=" << slot.invokeFlags;
134 _rpc->invoke( QString::fromLatin1( slot.funcName),
149 bool ArnDynamicSignals::addSignal( QObject *sender,
int signalId,
const QByteArray& funcName)
151 const QMetaObject* metaObject = sender->metaObject();
152 QMetaMethod method = metaObject->method( signalId);
155 slot.funcName = funcName;
156 slot.typeNames = method.parameterTypes();
157 slot.parNames = method.parameterNames();
159 ivf.set( ivf.
NoQueue, QByteArray( method.tag()).contains(
"no_queue"));
160 slot.invokeFlags = ivf;
163 bool status = QMetaObject::connect( sender, signalId,
this, _slotIdCount);
171 ArnRpcPrivate::ArnRpcPrivate()
174 _receiver = arnNullptr;
175 _receiverStorage = arnNullptr;
176 _receiverMethodsParam = arnNullptr;
177 _convVariantPar =
false;
178 _isIncludeSender =
false;
179 _dynamicSignals = arnNullptr;
180 _isHeartBeatOk =
true;
181 _timerHeartBeatSend =
new QTimer;
182 _timerHeartBeatCheck =
new QTimer;
186 ArnRpcPrivate::~ArnRpcPrivate()
188 delete _timerHeartBeatSend;
189 delete _timerHeartBeatCheck;
197 d->_dynamicSignals =
new ArnDynamicSignals(
this);
199 connect( d->_timerHeartBeatSend, SIGNAL(timeout()),
this, SLOT(timeoutHeartBeatSend()));
200 connect( d->_timerHeartBeatCheck, SIGNAL(timeout()),
this, SLOT(timeoutHeartBeatCheck()));
206 , d_ptr( new ArnRpcPrivate)
230 if (!d->_pipe)
return QString();
232 return d->_pipe->path();
278 if (
Arn::debugRPC) qDebug() <<
"Rpc delete pipe: path=" << d->_pipe->path();
279 d->_pipe->deleteLater();
283 d->_pipe->setParent(
this);
284 connect( d->_pipe, SIGNAL(changed(QByteArray)),
this, SLOT(pipeInput(QByteArray)),
285 Qt::QueuedConnection);
286 connect( d->_pipe, SIGNAL(arnLinkDestroyed()),
this, SLOT(destroyPipe()));
307 deleteReceiverMethodsParam();
308 d->_receiverStorage = arnNullptr;
311 bool isSameThread =
receiver->thread() == this->thread();
312 if (useTrackRpcSender && isSameThread) {
313 d->_receiverStorage = d->_receiver->findChild<ArnRpcReceiverStorage*>(
RPC_STORAGE_NAME);
314 if (!d->_receiverStorage) {
315 d->_receiverStorage =
new ArnRpcReceiverStorage( d->_receiver);
319 else if (useTrackRpcSender) {
320 errorLog( QString(tr(
"Can't track rpcSender to receiver in other thread")),
341 d->_methodPrefix = prefix.toLatin1();
342 deleteReceiverMethodsParam();
350 return d->_methodPrefix;
354 bool ArnRpc::isConvVariantPar()
const 358 return d->_convVariantPar;
362 void ArnRpc::setConvVariantPar(
bool convVariantPar)
366 d->_convVariantPar = convVariantPar;
374 d->_isIncludeSender = v;
399 d->_timerHeartBeatSend->stop();
401 d->_timerHeartBeatSend->start( time * 1000);
409 return d->_timerHeartBeatSend->interval() / 1000;
418 d->_timerHeartBeatCheck->stop();
420 d->_timerHeartBeatCheck->start( time * 1000);
428 return d->_timerHeartBeatCheck->interval() / 1000;
436 return d->_isHeartBeatOk;
444 const QMetaObject* metaObject = sender->metaObject();
445 int methodCount = metaObject->methodCount();
446 QByteArray methodSignCompHead;
447 int methodIdCompHead = -1;
448 for (
int methodId = 0; methodId < methodCount; ++methodId) {
449 QMetaMethod method = metaObject->method( methodId);
450 if (method.methodType() != QMetaMethod::Signal)
continue;
452 QByteArray methodSign = methodSignature( method);
453 if (!methodSign.startsWith( prefix.toLatin1()))
continue;
455 QByteArray methodName = methodSign.left( methodSign.indexOf(
'('));
456 QByteArray funcName = methodName.mid( prefix.size());
458 QByteArray methodSignComp = methodSign;
459 methodSignComp.chop(1);
462 && methodSignCompHead.startsWith( methodSignComp)
463 && hasSameParamNames( method, metaObject->method( methodIdCompHead)))
466 methodSignCompHead = methodSignComp;
467 methodIdCompHead = methodId;
468 d->_dynamicSignals->addSignal( sender, methodId, funcName);
477 if (!d->_receiverStorage)
return arnNullptr;
479 return d->_receiverStorage->_rpcSender;
488 if (!recStore)
return arnNullptr;
490 return recStore->_rpcSender;
506 if (!d->_pipe || !d->_pipe->isOpen()) {
507 errorLog( QString(tr(
"Pipe not open")),
513 xsmCall.
add(
"", funcName.toLatin1());
517 stat &= xsmAddArg( xsmCall, arg1, 1, nArg);
518 stat &= xsmAddArg( xsmCall, arg2, 2, nArg);
519 stat &= xsmAddArg( xsmCall, arg3, 3, nArg);
520 stat &= xsmAddArg( xsmCall, arg4, 4, nArg);
521 stat &= xsmAddArg( xsmCall, arg5, 5, nArg);
522 stat &= xsmAddArg( xsmCall, arg6, 6, nArg);
523 stat &= xsmAddArg( xsmCall, arg7, 7, nArg);
524 stat &= xsmAddArg( xsmCall, arg8, 8, nArg);
546 if (!d->_pipe || !d->_pipe->isOpen()) {
547 errorLog( QString(tr(
"Pipe not open")),
553 xsmCall.
add(
"", funcName.toLatin1());
557 stat &= xsmAddArg( xsmCall, arg1, 1, nArg);
558 stat &= xsmAddArg( xsmCall, arg2, 2, nArg);
559 stat &= xsmAddArg( xsmCall, arg3, 3, nArg);
560 stat &= xsmAddArg( xsmCall, arg4, 4, nArg);
561 stat &= xsmAddArg( xsmCall, arg5, 5, nArg);
562 stat &= xsmAddArg( xsmCall, arg6, 6, nArg);
563 stat &= xsmAddArg( xsmCall, arg7, 7, nArg);
564 stat &= xsmAddArg( xsmCall, arg8, 8, nArg);
569 d->_pipe->setValueOverwrite( xsmCall.
toXString(), rx);
582 if (!arg.name() || !arg.
label() || !arg.data())
return true;
583 if (nArg + 1 !=
int( index))
return true;
586 QByteArray typeName = arg.name();
588 #if QT_VERSION >= 0x060000 589 QMetaType mType = QMetaType::fromName( typeName);
590 int type = mType.id();
592 int type = QMetaType::type( typeName.constData());
596 errorLog( QString(tr(
"Unknown type:") + typeName.constData()),
600 const RpcTypeInfo& rpcTypeInfo = typeInfoFromId( type);
603 QByteArray argLabel = arg.
label();
606 QByteArray argDataDump;
607 QStringList argDataList;
608 bool isBinaryType =
false;
609 #if QT_VERSION >= 0x060000 610 QVariant varArg( mType, arg.data());
612 QVariant varArg( type, arg.data());
614 if (type == QMetaType::QStringList) {
615 argDataList = varArg.toStringList();
617 else if (type == QMetaType::QByteArray) {
618 argDataDump = varArg.toByteArray();
620 else if (varArg.canConvert( QVariant::String)) {
621 argDataDump = varArg.toString().toUtf8();
624 QDataStream stream( &argDataDump, QIODevice::WriteOnly);
628 if (!QMetaType::save( stream, type, arg.data())) {
629 errorLog( QString(tr(
"Can't export type:") + typeName.constData()),
638 if (!rpcTypeInfo.typeId)
639 argKey = (isBinaryType ?
"tb<" :
"t<") + typeName +
">";
641 argKey = rpcTypeInfo.rpcTypeName;
642 if (!argLabel.isEmpty()) {
646 argKey = argLabel +
":" + argKey;
648 argKey +=
"." + argLabel;
652 if (type == QMetaType::QStringList) {
655 if (!argDataList.isEmpty() && !argDataList.at(0).isEmpty()) {
656 argData = argDataList.at(0);
659 xsm.
add( argKey, argData);
661 for(; i < argDataList.size(); ++i) {
662 argData = argDataList.at(i);
663 if (argData.isEmpty() || argData.contains( QChar(
'=')))
664 xsm.
add(
"+", argData);
666 xsm.
add(
"", argData);
670 xsm.
add( argKey, argDataDump);
678 void ArnRpc::pipeInput(
const QByteArray& data)
682 if (
Arn::debugRPC) qDebug() <<
"Rpc pipeInput: path=" << d->_pipe->path()
683 <<
" itemId=" << d->_pipe->itemId() <<
" data=" << data;
691 if (data.startsWith(
'"')) {
692 int endSize = data.endsWith(
'"') ? (data.size() - 1) : data.size();
695 emit
textReceived( QString::fromUtf8( data.mid( 1, endSize - 1), endSize - 1));
702 QByteArray rpcFunc = xsmCall.value(0);
703 if (rpcFunc ==
"$heartbeat")
704 return funcHeartBeat( xsmCall);
705 if (rpcFunc ==
"$arg")
706 return funcArg( xsmCall);
707 if (rpcFunc ==
"$help")
708 return funcHelp( xsmCall);
712 QByteArray methodName = d->_methodPrefix + rpcFunc;
714 setupReceiverMethodsParam();
716 int pslotIndex = d->_receiverMethodsParam->methodNames.indexOf( methodName);
717 if (pslotIndex < 0) {
727 if (d->_isIncludeSender) {
728 argInfo[ argc].arg = Q_ARG(
ArnRpc*,
this);
735 if (index >= xsmCall.size())
738 errorLog( QString(tr(
"To many args:") + QString::number( argc))
739 + tr(
" method=") + methodName.constData(),
744 stat = xsmLoadArg( xsmCall, argInfo[ argc], index, methodName);
751 for (
int i = 0; i < 10; ++i) {
752 argOrder[i] = char(i);
754 stat = argLogic( argInfo, argOrder, argc, methodName);
755 for (
int i = argc; i < 10; ++i) {
756 argOrder[i] = char(20);
761 bool useVarPar = checkConvVarPar( methodName, argc);
762 for (
int i = d->_isIncludeSender; i < argc; ++i) {
763 stat = importArgData( argInfo[
int(argOrder[i])], methodName, useVarPar);
769 if (d->_receiverStorage)
770 d->_receiverStorage->_rpcSender =
this;
771 stat = QMetaObject::invokeMethod( d->_receiver,
772 methodName.constData(),
774 argInfo[ int(argOrder[0])].arg,
775 argInfo[ int(argOrder[1])].arg,
776 argInfo[ int(argOrder[2])].arg,
777 argInfo[ int(argOrder[3])].arg,
778 argInfo[ int(argOrder[4])].arg,
779 argInfo[ int(argOrder[5])].arg,
780 argInfo[ int(argOrder[6])].arg,
781 argInfo[ int(argOrder[7])].arg,
782 argInfo[ int(argOrder[8])].arg,
783 argInfo[ int(argOrder[9])].arg);
784 if (d->_receiverStorage)
785 d->_receiverStorage->_rpcSender = arnNullptr;
787 errorLog( QString(tr(
"Can't invoke method:")) + methodName.constData(),
789 sendText(
"Can't invoke method, use $help");
794 for (
int i = d->_isIncludeSender; i < 20; ++i) {
795 ArgInfo& aiSlot = argInfo[i];
796 if (aiSlot.isArgAlloc && aiSlot.arg.data()) {
797 int type = QMetaType::type( aiSlot.arg.name());
798 QMetaType::destroy( type, aiSlot.arg.data());
800 if (aiSlot.isDataAlloc) {
801 void* data =
const_cast<void*
>( aiSlot.data);
802 QMetaType::destroy( aiSlot.typeId, data);
808 bool ArnRpc::xsmLoadArg(
const XStringMap& xsm, ArgInfo& argInfo,
int &index,
809 const QByteArray& methodName)
814 const QByteArray& typeKey = xsm.
keyRef( index);
816 argInfo.isPositional =
true;
817 int sepPos = typeKey.indexOf(
':');
819 argInfo.isPositional =
false;
821 sepPos = typeKey.indexOf(
'.');
823 QByteArray t1 = typeKey.left( sepPos);
824 QByteArray t2 = typeKey.mid( sepPos + 1);
825 rpcType = argInfo.isPositional ? t1 : t2;
826 argInfo.name = argInfo.isPositional ? t2 : t1;
827 argInfo.hasType = !rpcType.isEmpty();
828 argInfo.hasName = !argInfo.name.isEmpty();
835 bool isTypeGen =
false;
836 if (rpcType.startsWith(
"t<"))
838 else if (rpcType.startsWith(
"tb<")) {
840 argInfo.isBinary =
true;
844 const RpcTypeInfo& rpcTypeInfo = (isTypeGen || (!argInfo.hasType && d->_mode.is(
Mode::NamedArg)))
845 ? typeInfoNull() : typeInfoFromRpc( rpcType);
846 bool isListFormat = rpcTypeInfo.typeId == QMetaType::QStringList;
848 int posStart = rpcType.indexOf(
'<') + 1;
849 int posEnd = rpcType.lastIndexOf(
'>');
850 argInfo.qtType = rpcType.mid( posStart, (posEnd < 0 ? -1 : posEnd - posStart));
851 argInfo.typeId = QMetaType::type( argInfo.qtType.constData());
852 argInfo.hasType =
true;
854 else if (rpcTypeInfo.typeId) {
855 argInfo.qtType = rpcTypeInfo.qtTypeName;
856 argInfo.typeId = rpcTypeInfo.typeId;
858 else if (rpcType.isEmpty() && argInfo.name.isEmpty()) {
859 argInfo.qtType =
"QString";
860 argInfo.typeId = QMetaType::QString;
863 if (!argInfo.hasType)
865 if (!argInfo.hasName) {
866 argInfo.name = typeKey;
867 argInfo.isPositional =
false;
874 if ((!argInfo.typeId)
875 && (argInfo.hasType || argInfo.isPositional || !possibleNameArg)) {
876 errorLog( QString(tr(
"Unknown type:"))
877 + (argInfo.qtType.isEmpty() ? rpcType.constData() : argInfo.qtType.constData())
878 + (argInfo.hasName ? (tr(
" name=") + argInfo.name.constData()) : QString())
879 + tr(
" method=") + methodName.constData(),
885 const QByteArray& argDataDump = xsm.
valueRef( index);
887 QStringList* argDataList =
new QStringList;
888 if (!argDataDump.isEmpty())
889 *argDataList += QString::fromUtf8( argDataDump.constData(), argDataDump.size());
891 while (index < xsm.
size()) {
892 const QByteArray& key = xsm.
keyRef( index);
893 if ((key !=
"") && (key !=
"+"))
895 const QByteArray& arg = xsm.
valueRef( index);
896 *argDataList += QString::fromUtf8( arg.constData(), arg.size());
899 argInfo.data = argDataList;
900 argInfo.dataAsArg =
true;
901 argInfo.isDataAlloc =
true;
905 argInfo.data = &argDataDump;
912 bool ArnRpc::argLogic( ArgInfo* argInfo,
char* argOrder,
int& argc,
const QByteArray& methodName)
917 if (d->_isIncludeSender)
return true;
919 bool isOnlyPositional =
true;
920 bool isOnlyNamed =
true;
921 for (
int i = 0; i < argc; ++i) {
922 if ( argInfo[i].isPositional)
925 isOnlyPositional =
false;
927 if (isOnlyPositional && (argc > 0))
931 errorLog( QString(tr(
"Mixed positional & named arg call not supported, method="))
932 + methodName.constData(),
937 int methodIndex = argLogicFindMethod( argInfo, argc, methodName);
938 if (methodIndex < 0)
return false;
940 const QMetaObject* metaObject = d->_receiver->metaObject();
941 QMetaMethod method = metaObject->method( methodIndex);
942 QList<QByteArray> parNames = method.parameterNames();
943 QList<QByteArray> parTypes = method.parameterTypes();
944 int parCount = parNames.size();
945 int defArgIndex = 10;
946 for (
int parIndex = 0; parIndex < parCount; ++parIndex) {
948 for (
int argIndex = 0; argIndex < argc; ++argIndex) {
949 ArgInfo& aiSlot = argInfo[ argIndex];
950 if (aiSlot.name == parNames.at( parIndex)) {
951 QByteArray parType = parTypes.at( parIndex);
952 if (!aiSlot.qtType.isEmpty()) {
953 if ((parType != aiSlot.qtType)
954 && ((parType !=
"QVariant") || !d->_convVariantPar)) {
955 errorLog( QString(tr(
"Type mismatch, arg=")) + parNames.at( parIndex)
956 + tr(
" in method=") + methodName.constData(),
962 aiSlot.qtType = parType;
963 aiSlot.typeId = QMetaType::type( aiSlot.qtType.constData());
965 const RpcTypeInfo& typeInfo = typeInfoFromId( aiSlot.typeId);
966 if ((aiSlot.typeId == QMetaType::QVariant) && d->_convVariantPar) {
967 aiSlot.qtType =
"QString";
968 aiSlot.typeId = QMetaType::QString;
970 else if ((!typeInfo.typeId)
971 || typeInfo.typeId == QMetaType::QStringList) {
972 errorLog( QString(tr(
"Type mandatory, arg=")) + parNames.at( parIndex)
973 + tr(
" type=") + aiSlot.qtType.constData()
974 + tr(
" in method=") + methodName.constData(),
979 argOrder[ parIndex] = char( argIndex);
985 ArgInfo& aiSlot = argInfo[ defArgIndex];
986 aiSlot.name = parNames.at( parIndex);
987 aiSlot.qtType = parTypes.at( parIndex);
988 aiSlot.typeId = QMetaType::type( aiSlot.qtType.constData());
989 #if QT_VERSION >= 0x050000 990 aiSlot.data = QMetaType::create( aiSlot.typeId);
992 aiSlot.data = QMetaType::construct( aiSlot.typeId);
994 aiSlot.isDataAlloc =
true;
995 aiSlot.dataAsArg =
true;
997 argOrder[ parIndex] = char( defArgIndex);
1007 int ArnRpc::argLogicFindMethod(
const ArnRpc::ArgInfo* argInfo,
int argc,
const QByteArray& methodName)
1011 setupReceiverMethodsParam();
1013 int pslotIndex = d->_receiverMethodsParam->methodNames.indexOf( methodName);
1014 if (pslotIndex < 0) {
1015 errorLog( QString(tr(
"Not found, method=")) + methodName.constData(),
1020 const MethodsParam::Params& pslot = d->_receiverMethodsParam->paramTab.at( pslotIndex);
1023 if ((pslot.paramNames.size() == 1) && pslot.paramNames.at(0).isEmpty())
1024 return pslot.methodIdsTab.at(0).at(0);
1026 int foundArgCount = 0;
1027 QList<int> methodCand = pslot.allMethodIds;
1028 for (
int argIndex = 0; argIndex < argc; ++argIndex) {
1029 int parIndex = pslot.paramNames.indexOf( argInfo[ argIndex].name);
1037 const QList<int>& methodIds = pslot.methodIdsTab.at( parIndex);
1038 for (
int i = 0; i < methodCand.size();) {
1039 if (methodIds.contains( methodCand.at(i))) {
1043 methodCand.removeAt(i);
1047 if (methodCand.isEmpty()) {
1048 errorLog( QString(tr(
"Not found method with matching parameters, method=")) + methodName.constData(),
1053 if (methodCand.size() == 1)
1054 return methodCand.at(0);
1057 const QMetaObject* metaObject = d->_receiver->metaObject();
1058 for (
int i = 0; i < methodCand.size();) {
1059 QMetaMethod method = metaObject->method( methodCand.at(i));
1060 if (method.parameterNames().size() == foundArgCount) {
1064 methodCand.removeAt(i);
1067 if (methodCand.size() == 1)
1068 return methodCand.at(0);
1070 errorLog( QString(tr(
"Many methods with matching parameters, method=")) + methodName.constData(),
1076 void ArnRpc::setupReceiverMethodsParam()
1080 if (d->_receiverMethodsParam)
return;
1082 MethodsParam* mpar =
new MethodsParam;
1083 d->_receiverMethodsParam = mpar;
1085 const QMetaObject* metaObject = d->_receiver->metaObject();
1086 int methodCount = metaObject->methodCount();
1087 QByteArray lastMethodName;
1088 for (
int methodIndex = 0; methodIndex < methodCount; ++methodIndex) {
1089 QMetaMethod method = metaObject->method( methodIndex);
1090 QByteArray methodSign = methodSignature( method);
1091 if (!methodSign.startsWith( d->_methodPrefix))
continue;
1094 QByteArray methodName = methodSign.left( methodSign.indexOf(
'('));
1095 if (methodName != lastMethodName) {
1096 mpar->methodNames += methodName;
1097 mpar->paramTab += MethodsParam::Params();
1098 lastMethodName = methodName;
1100 MethodsParam::Params& pslot = mpar->paramTab[ mpar->paramTab.size() - 1];
1102 pslot.allMethodIds += methodIndex;
1104 QList<QByteArray> parNames = method.parameterNames();
1105 int parCount = parNames.size();
1106 int parIndexStart = parCount == 0 ? -1 : 0;
1107 for (
int parIndex = parIndexStart; parIndex < parCount; ++parIndex) {
1109 const char* parName = parIndex < 0 ?
"" : parNames.at( parIndex).constData();
1110 int parI = pslot.paramNames.indexOf( parName);
1112 pslot.paramNames += parName;
1113 pslot.methodIdsTab += QList<int>();
1114 parI = pslot.paramNames.size() - 1;
1116 pslot.methodIdsTab[ parI] += methodIndex;
1122 void ArnRpc::deleteReceiverMethodsParam()
1126 if (!d->_receiverMethodsParam)
return;
1128 delete d->_receiverMethodsParam;
1129 d->_receiverMethodsParam = arnNullptr;
1133 bool ArnRpc::hasSameParamNames(
const QMetaMethod& method1,
const QMetaMethod& method2)
1135 QList<QByteArray> parNames1 = method1.parameterNames();
1136 QList<QByteArray> parNames2 = method2.parameterNames();
1137 int parCount = qMin( parNames1.size(), parNames2.size());
1138 for (
int i = 0; i < parCount; ++i) {
1139 if (parNames2.at(i) != parNames1.at(i))
1146 bool ArnRpc::checkConvVarPar(
const QByteArray& methodName,
int argc)
1150 if (!d->_convVariantPar)
return false;
1152 bool useVarPar =
false;
1153 setupReceiverMethodsParam();
1155 int pslotIndex = d->_receiverMethodsParam->methodNames.indexOf( methodName);
1156 if (pslotIndex < 0)
return false;
1159 const MethodsParam::Params& pslot = d->_receiverMethodsParam->paramTab.at( pslotIndex);
1160 const QMetaObject* metaObject = d->_receiver->metaObject();
1161 foreach (
int methodIndex, pslot.allMethodIds) {
1162 QMetaMethod method = metaObject->method( methodIndex);
1163 QList<QByteArray> typesNames = method.parameterTypes();
1164 if (typesNames.size() != argc)
continue;
1166 foreach (
const QByteArray& typeName, typesNames) {
1167 useVarPar &= typeName ==
"QVariant";
1175 bool ArnRpc::importArgData( ArnRpc::ArgInfo& argInfo,
const QByteArray& methodName,
bool useVarPar)
1177 if (argInfo.typeId == QMetaType::QByteArray)
1178 argInfo.dataAsArg =
true;
1180 if (argInfo.dataAsArg) {
1181 argInfo.arg = QGenericArgument( argInfo.qtType.constData(), argInfo.data);
1185 const QByteArray& argDataDump = *
static_cast<const QByteArray*
>( argInfo.data);
1186 if (argInfo.isBinary) {
1187 if ((argDataDump.size() < 2) || (argDataDump.at(1) !=
DATASTREAM_VER)) {
1188 errorLog( QString(tr(
"Not same DataStream version, method=")) + methodName.constData(),
1192 #if QT_VERSION >= 0x050000 1193 void* argData = QMetaType::create( argInfo.typeId);
1195 void* argData = QMetaType::construct( argInfo.typeId);
1198 argInfo.arg = QGenericArgument( argInfo.qtType.constData(), argData);
1199 argInfo.isArgAlloc =
true;
1200 QDataStream stream( argDataDump);
1202 stream.skipRawData(2);
1203 if (!QMetaType::load( stream, argInfo.typeId, argData)) {
1204 errorLog( QString(tr(
"Can't' import bin type:") + argInfo.qtType.constData())
1205 + tr(
" method=") + methodName.constData(),
1211 QVariant varArg( QString::fromUtf8( argDataDump.constData(), argDataDump.size()));
1212 if (!varArg.convert( QVariant::Type( argInfo.typeId))) {
1213 errorLog( QString(tr(
"Can't' import str type:") + argInfo.qtType.constData())
1214 + tr(
" method=") + methodName.constData(),
1219 void* argData = arnNullptr;
1221 argData =
new QVariant( varArg);
1222 argInfo.typeId = QMetaType::QVariant;
1223 argInfo.qtType =
"QVariant";
1226 #if QT_VERSION >= 0x050000 1227 argData = QMetaType::create( argInfo.typeId, varArg.constData());
1229 argData = QMetaType::construct( argInfo.typeId, varArg.constData());
1233 argInfo.arg = QGenericArgument( argInfo.qtType.constData(), argData);
1234 argInfo.isArgAlloc =
true;
1241 void ArnRpc::funcHeartBeat(
const XStringMap& xsm)
1245 QByteArray time = xsm.
value(1);
1246 if (time ==
"off") {
1247 d->_timerHeartBeatSend->stop();
1250 if (time ==
"off1") {
1251 d->_timerHeartBeatSend->stop();
1254 else if (time ==
"0") {
1255 d->_timerHeartBeatCheck->stop();
1256 d->_isHeartBeatOk =
true;
1260 if (!d->_isHeartBeatOk) {
1261 d->_isHeartBeatOk =
true;
1266 if (d->_timerHeartBeatCheck->isActive())
1267 d->_timerHeartBeatCheck->start();
1271 void ArnRpc::funcHelp(
const XStringMap& xsm)
1275 if (!d->_receiver) {
1276 sendText(
"$help: rpc-receiver = 0");
1280 QByteArray modePar = xsm.
value(1);
1283 if (modePar.isEmpty()) {
1287 else if (modePar.startsWith(
"p")) {
1290 else if (modePar.startsWith(
"n")) {
1299 sendText(
"* Only positional args allowed.");
1300 if (d->_convVariantPar)
1301 sendText(
"* Type VAR can be any, e.g. string or int.");
1303 const QMetaObject* metaObject = d->_receiver->metaObject();
1304 int methodIdHead = -1;
1305 int parCountMin = 10;
1306 QByteArray methodNameHead;
1307 QByteArray methodSignHead;
1308 int methodCount = metaObject->methodCount();
1309 for (
int methodId = 0; methodId < methodCount; ++methodId) {
1310 QMetaMethod method = metaObject->method(methodId);
1311 QByteArray methodSign = methodSignature( method);
1312 if (!methodSign.startsWith( d->_methodPrefix))
continue;
1315 QList<QByteArray> parNames = method.parameterNames();
1316 int parCount = parNames.size();
1319 && methodSignHead.startsWith( methodSign)
1320 && hasSameParamNames( method, metaObject->method( methodIdHead)))
1321 parCountMin = parCount;
1323 if (methodIdHead >= 0)
1324 funcHelpMethod( metaObject->method( methodIdHead),
1325 methodNameHead, parCountMin, flags);
1326 methodIdHead = methodId;
1327 methodSignHead = methodSign;
1328 methodNameHead = methodSign.left( methodSign.indexOf(
'('));
1329 parCountMin = parCount;
1332 if (methodIdHead >= 0)
1333 funcHelpMethod( metaObject->method( methodIdHead), methodNameHead, parCountMin, flags);
1337 sendText(
"$heartbeat [`time`|off|off1]");
1342 void ArnRpc::funcHelpMethod(
const QMetaMethod &method,
const QByteArray& name,
int parNumMin,
int flags)
1346 QString line = QString::fromLatin1( name.mid( d->_methodPrefix.size()));
1348 QList<QByteArray> typesNames = method.parameterTypes();
1349 QList<QByteArray> parNames = method.parameterNames();
1351 bool wasListType =
false;
1352 int parCount = parNames.size();
1353 for (
int i = d->_isIncludeSender; i < parCount; ++i) {
1355 QByteArray parName = parNames.at(i);
1356 QByteArray typeName = typesNames.at(i);
1358 int type = QMetaType::type( typeName.constData());
1359 QVariant varPar( type);
1360 bool isBinaryType = (type == 0) || !varPar.canConvert( QVariant::String);
1362 const RpcTypeInfo& rpcTypeInfo = typeInfoFromQt( typeName);
1363 bool isList = rpcTypeInfo.typeId == QMetaType::QStringList;
1364 bool isTypeGen =
false;
1365 bool isTypeVar =
false;
1366 if (rpcTypeInfo.typeId == QMetaType::QString) {
1367 rpcType = wasListType ? rpcTypeInfo.rpcTypeName :
"";
1369 else if (rpcTypeInfo.typeId) {
1370 rpcType = rpcTypeInfo.rpcTypeName;
1372 else if ((type == QMetaType::QVariant) && d->_convVariantPar) {
1377 rpcType = (isBinaryType ?
"tb<" :
"t<") + typeName +
">";
1383 if (isTypeGen | isTypeVar)
1384 param +=
":" + rpcType +
"=`data`";
1386 QByteArray rpcTypeVal = rpcType.isEmpty() ? QByteArray(
"string") : rpcType;
1387 param +=
"=`" + rpcTypeVal +
"`";
1391 if (!rpcType.isEmpty()) {
1397 param +=
"`" + parName +
"`";
1401 param =
"[" + param +
"]";
1402 line +=
" " + QString::fromLatin1( param);
1404 wasListType = isList;
1414 QByteArray modePar = xsm.
value(1);
1416 if (modePar.startsWith(
"p")) {
1420 else if (modePar.startsWith(
"n")) {
1424 else if (modePar.startsWith(
"t")) {
1429 sendText(
"$arg: Unknown mode, use $help");
1434 void ArnRpc::destroyPipe()
1438 if (
Arn::debugRPC) qDebug() <<
"Rpc Destroy pipe: path=" << d->_pipe->path();
1444 void ArnRpc::timeoutHeartBeatSend()
1448 if (!d->_pipe || !d->_pipe->isOpen())
return;
1451 MQ_ARG( QString, time, QByteArray::number( d->_timerHeartBeatSend->interval() / 1000)));
1455 void ArnRpc::timeoutHeartBeatCheck()
1459 if (d->_isHeartBeatOk) {
1460 d->_isHeartBeatOk =
false;
1471 *d->_pipe =
"\"" + txt.toUtf8() +
"\"";
1475 void ArnRpc::errorLog(
const QString& errText,
ArnError err,
void* reference)
1481 idText +=
" pipe:" + d->_pipe->path();
1488 const QObject* receiver,
const QString& replace,
1491 QList<QByteArray> signalSignTab;
1492 QList<QByteArray> methodSignLowTab;
1494 qDebug() <<
"batchConnect: regExp=" << rgx.pattern() <<
" replace=" << replace;
1497 const QMetaObject* metaObject = sender->metaObject();
1498 QList<QByteArray> doneMethodSignTab;
1499 int methodCount = metaObject->methodCount();
1500 for (
int i = 0; i < methodCount; ++i) {
1501 QMetaMethod method = metaObject->method(i);
1502 if (method.methodType() != QMetaMethod::Signal)
continue;
1504 QByteArray signalSign = methodSignature( method);
1505 if (doneMethodSignTab.contains( signalSign))
continue;
1506 doneMethodSignTab += signalSign;
1508 QString signalName = QString::fromLatin1( signalSign.left( signalSign.indexOf(
'(')).constData());
1509 QByteArray paramSign = signalSign.mid( signalName.size());
1510 if (rgx.indexIn( signalName) >= 0) {
1511 QString methodName = replace;
1512 for (
int j = 1; j <= rgx.captureCount(); ++j) {
1513 methodName.replace(
"\\" + QString::number(j), rgx.cap(j));
1515 signalSignTab += signalSign;
1516 QByteArray methodSignLow = (methodName.toLatin1() + paramSign).toLower();
1517 methodSignLowTab += methodSignLow;
1519 qDebug() <<
"batchConnect: try match signal=" << signalSign <<
1520 " method(low)=" << methodSignLow;
1523 qDebug() <<
"batchConnect: No regExp match on signal=" << signalSign;
1527 metaObject =
receiver->metaObject();
1528 methodCount = metaObject->methodCount();
1529 doneMethodSignTab.clear();
1530 QByteArray methodSignCompHead;
1531 int methodIdCompHead = -1;
1532 for (
int methodId = 0; methodId < methodCount; ++methodId) {
1533 QMetaMethod method = metaObject->method(methodId);
1534 QByteArray methodSign = methodSignature( method);
1535 if (doneMethodSignTab.contains( methodSign))
continue;
1536 doneMethodSignTab += methodSign;
1538 QByteArray methodSignComp = methodSign;
1539 methodSignComp.chop(1);
1542 && methodSignCompHead.startsWith( methodSignComp)
1543 && hasSameParamNames( method, metaObject->method( methodIdCompHead)))
1546 methodSignCompHead = methodSignComp;
1547 methodIdCompHead = methodId;
1549 QByteArray methodSignLow = methodSign.toLower();
1550 int index = methodSignLowTab.indexOf( methodSignLow);
1552 const char*
methodPrefix = (method.methodType() == QMetaMethod::Signal) ?
"2" :
"1";
1553 connect( sender,
"2" + signalSignTab[ index],
1556 qDebug() <<
"batchConnect: connect signal=" << signalSignTab[ index] <<
1557 " method=" << methodSign;
1560 qDebug() <<
"batchConnect: No match on method=" << methodSignLow;
1565 QByteArray ArnRpc::methodSignature(
const QMetaMethod &method)
1567 #if QT_VERSION >= 0x050000 1568 return method.methodSignature();
1570 return QByteArray( method.signature());
1575 const ArnRpc::RpcTypeInfo& ArnRpc::typeInfoFromRpc(
const QByteArray& rpcTypeName)
1577 RpcTypeInfo* typeInfo = _rpcTypeInfoTab;
1578 while (typeInfo->typeId) {
1579 if (rpcTypeName == typeInfo->rpcTypeName)
1588 const ArnRpc::RpcTypeInfo& ArnRpc::typeInfoFromQt(
const QByteArray& qtTypeName)
1590 RpcTypeInfo* typeInfo = _rpcTypeInfoTab;
1591 while (typeInfo->typeId) {
1592 if (qtTypeName == typeInfo->qtTypeName)
1601 const ArnRpc::RpcTypeInfo& ArnRpc::typeInfoFromId(
int typeId)
1603 RpcTypeInfo* typeInfo = _rpcTypeInfoTab;
1604 while (typeInfo->typeId) {
1605 if (typeId == typeInfo->typeId)
1614 const ArnRpc::RpcTypeInfo& ArnRpc::typeInfoNull()
1616 return _rpcTypeInfoTab[
sizeof(_rpcTypeInfoTab) /
sizeof(RpcTypeInfo) - 1];
void setMethodPrefix(const QString &prefix)
Mode mode() const
Get the mode.
bool setReceiver(QObject *receiver, bool useTrackRpcSender=true)
bool isHeartBeatOk() const
Get the state of heart beat.
When calling out, uses named argument e.g "myFunc count=123".
void addSenderSignals(QObject *sender, const QString &prefix)
static void batchConnect(const QObject *sender, const ARN_RegExp &rgx, const QObject *receiver, const QString &replace, Mode mode=Mode())
Make batch connection from one senders signals to another receivers slots/signals.
void setIncludeSender(bool v)
Add sender as argument when calling a rpc method.
This invoke is not queued, multiple calls to same method might overwrite.
void setSendSeq(bool useSendSeq)
Change usage of sending sequence numbers.
Container class with string representation for serialized data.
ArnRpc(QObject *parent=arnNullptr)
Only allow calling in with positional argument (typed)
bool openUuid(const QString &path)
Open a handle to an Arn Pipe Object with a unique uuid name.
const QByteArray & keyRef(int i) const
When receiver method missing, send defaultCall() signal instead of error.
void defaultCall(const QByteArray &data)
Signal emitted when receiver method missing.
QByteArray value(int i, const char *def=arnNullptr) const
Check sequence order information from pipe. Can generate signal outOfSequence().
const QByteArray & valueRef(int i) const
#define MQ_ARG(type, label, data)
Similar to Q_ARG but with added argument label (parameter name)
bool open(const QString &path)
Open a handle to an Arn Data Object
QObject * receiver() const
QByteArray toXString() const
void heartBeatReceived()
Signal emitted when Heart beat message is received.
ArnPipe * pipe() const
Get the used pipe
void setHeartBeatCheck(int time)
Set max time period for receiving heart beat message.
Provider side (opposed to requester)
ArnPipe & setMaster()
Set client session sync mode as Master for this ArnItem.
QString twinPath(const QString &path)
Get the bidirectional twin to a given path
bool invoke(const QString &funcName, MQGenericArgument val0=MQGenericArgument(0), MQGenericArgument val1=MQGenericArgument(), MQGenericArgument val2=MQGenericArgument(), MQGenericArgument val3=MQGenericArgument(), MQGenericArgument val4=MQGenericArgument(), MQGenericArgument val5=MQGenericArgument(), MQGenericArgument val6=MQGenericArgument(), MQGenericArgument val7=MQGenericArgument())
Calls a named remote procedure.
QString pipePath() const
Get the path for the used pipe
QString methodPrefix() const
void setHeartBeatSend(int time)
Set period time for sending heart beat message.
When calling out, uses named argument with type e.g "myFunc count:int=123".
const char * label() const
Send sequence order information to pipe.
Use AutoDestroy for the pipe, i.e. it is closed when tcp/ip is broken.
int getHeartBeatCheck() const
Get max time period for receiving heart beat message.
Use an unique uuid in the pipe name.
ArnItem specialized as a pipe.
void textReceived(const QString &text)
Signal emitted when a general text message is received.
void pipeClosed()
Signal emitted when the used pipe is closed.
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
If guarantied no default arguments, full member name overload is ok.
XStringMap & add(const char *key, const QByteArray &val)
Similar to QGenericArgument but with added argument label (parameter name)
Convenience, combined NamedArg and NamedTypedArg
void setPipe(ArnPipe *pipe)
Set pipe for this Rpc.
ArnPipe & setAutoDestroy()
Set client session sync mode as AutoDestroy for this ArnItem.
bool open(const QString &pipePath)
Debug mode, dumping info for the batch connections.
void outOfSequence()
Signal emitted when checked sequence order is wrong.
void setCheckSeq(bool useCheckSeq)
Change usage of checking received sequence numbers.
void sendText(const QString &txt)
Send a general text message to the other end of the used pipe
int getHeartBeatSend() const
Get period time for sending heart beat message.
void heartBeatChanged(bool isOk)
Signal emitted when Heart beat changes state.
bool isProviderPath(const QString &path)
Test if path is a provider path