33 #include "private/ArnClient_p.hpp" 39 #include <QStringList> 42 #include <QMutexLocker> 53 int remove(
const QString& id);
61 QMap<QString, ArnClient*> _clientTab;
68 if (
id.isEmpty())
return false;
70 QMutexLocker locker( &_mutex);
72 if (_clientTab.contains(
id))
return false;
74 _clientTab.insert(
id, client);
81 QMutexLocker locker( &_mutex);
83 return _clientTab.value(
id, arnNullptr);
89 QMutexLocker locker( &_mutex);
91 return _clientTab.remove(
id);
97 QMutexLocker locker( &_mutex);
101 QMap<QString, ArnClient*>::iterator i = _clientTab.begin();
102 while (i != _clientTab.end()) {
103 if (i.value() == client) {
104 i = _clientTab.erase(i);
123 ArnClientPrivate::ArnClientPrivate()
125 _arnMountPoint = arnNullptr;
126 _isAutoConnect =
false;
127 _isValidCredent =
false;
129 _receiveTimeout = 10;
130 _recTimeoutCount = 0;
136 resetConnectionFlags();
138 _socket =
new QTcpSocket;
139 _arnNetSync =
new ArnSync( _socket,
true, arnNullptr);
140 _arnNetSync->setClientSyncMode( _syncMode);
141 _arnNetSync->start();
142 _connectTimer =
new QTimer;
143 _recTimer =
new QTimer;
147 ArnClientPrivate::~ArnClientPrivate()
151 delete _connectTimer;
156 void ArnClientPrivate::resetConnectionFlags()
158 _isReContact =
false;
159 _isReConnect =
false;
165 void ArnClientPrivate::clearArnList(
int prioFilter)
170 if ((prioFilter < 0) || _hostTab.isEmpty()) {
172 _hostPrioTab.clear();
178 index = _hostPrioTab.indexOf( prioFilter, index + 1);
179 if (index < 0)
break;
180 _hostTab.removeAt( index);
181 _hostPrioTab.removeAt( index);
188 if ((prioFilter < 0) || _hostTab.isEmpty())
194 index = _hostPrioTab.indexOf( prioFilter, index + 1);
195 if (index < 0)
break;
196 retVal += _hostTab.at( index);
202 void ArnClientPrivate::addToArnList(
const QString& arnHost, quint16 port,
int prio)
204 if (arnHost.isEmpty())
return;
211 for (index = 0; index < _hostPrioTab.size(); ++index) {
212 if (prio < _hostPrioTab.at( index))
break;
214 _hostTab.insert( index, slot);
215 _hostPrioTab.insert( index, prio);
219 void ArnClient::init()
223 QString stdId =
"std";
227 ArnSync* arnSync = d->_arnNetSync;
228 QTcpSocket* socket = d->_socket;
229 arnSync->setSessionHandler(
this);
230 arnSync->setToRemotePathCB( &toRemotePathCB);
231 connect( socket, SIGNAL(connected()),
this, SLOT(doTcpConnected()));
232 connect( socket, SIGNAL(disconnected()),
this, SLOT(doTcpDisconnected()));
233 connect( arnSync, SIGNAL(
loginRequired(
int)),
this, SLOT(doLoginRequired(
int)));
234 connect( arnSync, SIGNAL(stateChanged(
int)),
this, SLOT(doSyncStateChanged(
int)));
237 connect( arnSync, SIGNAL(xcomDelete(QString)),
this, SLOT(onCommandDelete(QString)));
238 connect( arnSync, SIGNAL(messageReceived(
int,QByteArray)),
239 this, SLOT(onMessageReceived(
int,QByteArray)));
240 connect( d->_recTimer, SIGNAL(timeout()),
this, SLOT(doRecTimeout()));
241 connect( socket, SIGNAL(readyRead()),
this, SLOT(doRecNotified()));
242 #if (QT_VERSION >= QT_VERSION_CHECK( 5, 15, 0)) 243 connect( socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
244 this, SLOT(doTcpError(QAbstractSocket::SocketError)));
246 connect( socket, SIGNAL(error(QAbstractSocket::SocketError)),
247 this, SLOT(doTcpError(QAbstractSocket::SocketError)));
249 connect( d->_connectTimer, SIGNAL(timeout()),
this, SLOT(onConnectWaitDone()));
255 , d_ptr( new ArnClientPrivate)
281 d->clearArnList( prioFilter);
289 return d->arnList( prioFilter);
297 d->addToArnList( arnHost, port, prio);
305 if (d->_hostTab.isEmpty())
return;
307 d->_isValidCredent =
false;
309 d->resetConnectionFlags();
318 d->_isValidCredent =
false;
320 d->_arnHost = arnHost;
322 d->resetConnectionFlags();
331 d->_arnNetSync->sendExit();
333 d->_socket->disconnectFromHost();
349 d->_isValidCredent = !userName.isEmpty();
350 d->_arnNetSync->loginToArn( userName, passwordHashed, allow);
359 d->_arnNetSync->close();
368 return d->_connectStat;
376 QMutexLocker locker( &d->_mutex);
378 if (d->_mountPoints.size() == 1)
379 removeMountPointNL( d->_mountPoints.at(0).localPath);
381 return addMountPointNL( path, QString());
390 bool retVal = addMountPointNL( localPath, remotePath);
397 bool ArnClient::addMountPointNL(
const QString& localPath,
const QString& remotePath)
402 <<
" remotePath=" << remotePath;
403 if (localPath.isEmpty()) {
409 foreach (
const MountPointSlot& mpSlot, d->_mountPoints) {
410 QString mplPath = mpSlot.localPath;
411 if (localPath_.startsWith( mplPath) || mplPath.startsWith( localPath_)) {
413 localPath +
" existing=" + mplPath,
419 MountPointSlot mpSlot;
420 mpSlot.arnMountPoint =
new ArnItemNetEar(
this);
421 bool isOk = mpSlot.arnMountPoint->openFolder( localPath_);
423 mpSlot.localPath = localPath_;
424 mpSlot.remotePath = remotePath.isEmpty() ? localPath_ :
Arn::fullPath( remotePath);
425 connect( mpSlot.arnMountPoint, SIGNAL(arnItemCreated(QString)),
this, SLOT(createNewItem(QString)));
426 connect( mpSlot.arnMountPoint, SIGNAL(arnTreeCreated(QString)),
427 this, SLOT(doCreateArnTree(QString)));
428 connect( mpSlot.arnMountPoint, SIGNAL(arnTreeDestroyed(QString,
bool)),
429 this, SLOT(doDestroyArnTree(QString,
bool)));
430 d->_mountPoints += mpSlot;
431 mpSlot.arnMountPoint->setReference( &d->_mountPoints.last());
434 delete mpSlot.arnMountPoint;
445 bool retVal = removeMountPointNL( localPath);
452 bool ArnClient::removeMountPointNL(
const QString& localPath)
458 int mpSize = d->_mountPoints.size();
459 for (
int i = 0; i < mpSize; ++ i) {
460 const MountPointSlot& mountPoint = d->_mountPoints.at(i);
461 if (mountPoint.localPath == localPath_) {
462 if (mountPoint.arnMountPoint)
463 delete mountPoint.arnMountPoint;
464 d->_mountPoints.removeAt(i);
476 d->_isAutoConnect = isAuto;
477 d->_retryTime = retryTime > 1 ? retryTime : 1;
510 return d->_receiveTimeout;
526 return d->_arnNetSync->isDemandLogin();
552 d->_arnNetSync->setClientSyncMode(
syncMode);
559 return ArnSyncLogin::passwordHash( password);
567 return d->_arnNetSync->freePaths();
575 d->_arnNetSync->setWhoIAm( whoIAmXsm.
toXString());
583 return XStringMap( d->_arnNetSync->remoteWhoIAm());
591 return d->_isReContact;
599 return d->_isReConnect;
603 int ArnClient::curPrio()
const 615 d->_arnNetSync->sendMessage( prioType == 1 ? ArnSync::MessageType::ChatPrio
616 : ArnSync::MessageType::ChatNormal,
625 d->_arnNetSync->sendMessage( ArnSync::MessageType::AbortKillRequest);
633 d->_arnNetSync->getTraffic( in, out);
638 void ArnClient::commandGet(
const QString& path)
642 d->_commandMap.clear();
643 d->_commandMap.add(
ARNRECNAME,
"get").add(
"path", path);
645 d->_arnNetSync->sendXSMap( d->_commandMap);
649 void ArnClient::commandSet(
const QString& path,
const QString& data)
653 d->_commandMap.clear();
654 d->_commandMap.add(
ARNRECNAME,
"set").add(
"path", path).add(
"data", data);
656 d->_arnNetSync->sendXSMap( d->_commandMap);
660 void ArnClient::commandLs(
const QString& path)
664 d->_commandMap.clear();
665 d->_commandMap.add(
ARNRECNAME,
"ls").add(
"path", path);
668 d->_arnNetSync->sendXSMap( d->_commandMap);
672 void ArnClient::commandInfo(
int type,
const QByteArray& data)
677 d->_arnNetSync->sendInfo( type, data);
681 void ArnClient::commandVersion()
685 d->_commandMap.clear();
688 d->_arnNetSync->sendXSMap( d->_commandMap);
692 void ArnClient::newNetItemProxy( ArnThreadCom *threadCom,
693 const QString &path,
int syncMode,
void* isNewPtr)
695 ArnThreadComProxyLock proxyLock( threadCom);
698 threadCom->_retObj = newNetItem( path, Arn::ObjectSyncMode::fromInt(
syncMode), (
bool*) isNewPtr);
703 bool ArnClient::getLocalRemotePath(
const QString& path,
704 QString& localMountPath, QString& remoteMountPath)
708 QMutexLocker locker( &d->_mutex);
712 MountPointSlot mpSlot;
713 foreach (
const MountPointSlot& mountPoint, d->_mountPoints) {
714 if (path_.startsWith( mountPoint.localPath)) {
720 localMountPath = mpSlot.localPath;
721 remoteMountPath = mpSlot.remotePath;
727 QString ArnClient::toRemotePathCB(
void* context,
const QString& path)
732 QString localMountPath;
733 QString remoteMountPath;
734 that->getLocalRemotePath( path, localMountPath, remoteMountPath);
740 ArnItemNet* ArnClient::newNetItem(
const QString& path,
Arn::ObjectSyncMode syncMode,
bool* isNewPtr)
746 return d->_arnNetSync->newNetItem( path_,
syncMode, isNewPtr);
749 ArnThreadComCaller threadCom;
751 threadCom.p()->_retObj = arnNullptr;
753 QMetaObject::invokeMethod(
this,
755 Qt::QueuedConnection,
756 Q_ARG( ArnThreadCom*, threadCom.p()),
757 Q_ARG( QString, path),
759 Q_ARG(
void*, isNewPtr));
760 threadCom.waitCommandEnd();
761 ArnItemNet* retItemNet =
static_cast<ArnItemNet*
>( threadCom.p()->_retObj);
762 if (retItemNet)
if (
Arn::debugThreading) qDebug() <<
"newNetItem-thread: end path=" << retItemNet->path();
769 void ArnClient::createNewItem(
const QString& path)
775 d->_arnNetSync->newNetItem( path);
779 void ArnClient::doCreateArnTree(
const QString& path)
784 ArnItemNetEar* item = qobject_cast<ArnItemNetEar*>( sender());
786 MountPointSlot* mpSlot =
static_cast<MountPointSlot*
>( item->reference());
790 d->_arnNetSync->sendSetTree( remotePath);
794 void ArnClient::doDestroyArnTree(
const QString& path,
bool isGlobal)
799 ArnItemNetEar* item = qobject_cast<ArnItemNetEar*>( sender());
801 MountPointSlot* mpSlot =
static_cast<MountPointSlot*
>( item->reference());
806 d->_arnNetSync->sendDelete( remotePath);
808 d->_arnNetSync->sendNoSync( remotePath);
812 void ArnClient::doTcpError( QAbstractSocket::SocketError socketError)
816 d->_recTimer->stop();
818 QMetaObject::invokeMethod(
this,
820 Qt::QueuedConnection,
821 Q_ARG(
int, socketError));
825 void ArnClient::doTcpError(
int socketError)
830 QString errTextSum = QString(tr(
"TCP Client Msg:")) + d->_socket->errorString();
842 emit
tcpError( d->_socket->errorString(), QAbstractSocket::SocketError( socketError));
851 void ArnClient::doTcpDisconnected()
856 d->_recTimer->stop();
871 void ArnClient::startConnectArn()
875 d->_isClosed =
false;
880 void ArnClient::reConnectArn()
885 bool wantDelayConnect =
true;
886 if (d->_nextHost >= 0) {
888 wantDelayConnect = d->_nextHost == 0;
891 if (wantDelayConnect && d->_isAutoConnect) {
892 d->_connectTimer->start( d->_retryTime * 1000);
897 void ArnClient::onConnectWaitDone()
901 d->_connectTimer->stop();
906 void ArnClient::doTcpConnected()
915 d->_isReContact = d->_wasContact;
916 d->_wasContact =
true;
919 d->_recTimer->start( d->_receiveTimeout * 1000 / 2);
920 d->_recTimeoutCount = 0;
922 d->_arnNetSync->connected();
924 emit
tcpConnected( d->_curConnectAP.addr, d->_curConnectAP.port);
930 void ArnClient::doSyncStateChanged(
int state)
935 ArnSync::State syncState = ArnSync::State::fromInt( state);
936 if (syncState == syncState.Normal) {
939 d->_isReConnect = d->_wasConnect;
940 d->_wasConnect =
true;
947 void ArnClient::doRecNotified()
951 if (d->_recTimer->isActive())
952 d->_recTimer->start();
953 d->_recTimeoutCount = 0;
962 void ArnClient::doRecTimeout()
966 ++d->_recTimeoutCount;
968 if (d->_recTimeoutCount == 1) {
971 else if (d->_recTimeoutCount == 6) {
975 if (d->_recTimeoutCount > 1) {
984 void ArnClient::onCommandDelete(
const QString& remotePath)
988 QMutexLocker locker( &d->_mutex);
992 foreach (
const MountPointSlot& mountPoint, d->_mountPoints) {
993 if (remotePath.startsWith( mountPoint.remotePath)) {
998 if (!localPath.isEmpty())
1003 void ArnClient::onMessageReceived(
int type,
const QByteArray& data)
1009 case ArnSync::MessageType::KillRequest:
1013 case ArnSync::MessageType::AbortKillRequest:
1016 case ArnSync::MessageType::ChatPrio:
1017 emit
chatReceived( QString::fromUtf8( data.constData(), data.size()), 1);
1019 case ArnSync::MessageType::ChatNormal:
1020 emit
chatReceived( QString::fromUtf8( data.constData(), data.size()), 2);
1028 void ArnClient::doConnectArnLogic()
1035 d->_curPrio = curPrio;
1037 if (d->_nextHost < 0) {
1038 arnHost = d->_arnHost;
1041 else if (!d->_hostTab.isEmpty()) {
1042 if (d->_nextHost >= d->_hostTab.size()) {
1048 const HostAddrPort& slot = d->_hostTab.at( d->_nextHost);
1049 arnHost = slot.
addr;
1051 curPrio = d->_hostPrioTab.at( d->_nextHost);
1057 if (arnHost.isEmpty())
return;
1062 d->_socket->abort();
1064 d->_curConnectAP.addr = arnHost;
1065 d->_curConnectAP.port = port;
1066 d->_curPrio = curPrio;
1069 d->_arnNetSync->connectStarted();
1074 void ArnClient::doReplyRecord(
XStringMap& replyMap)
1076 QByteArray reply = replyMap.
value(0);
1078 if (reply ==
"Rget") {
1081 else if (reply ==
"Rls") {
1082 emit replyLs( makeItemList( replyMap), replyMap.
valueString(
"path"));
1084 else if (reply ==
"Rinfo") {
1085 int type = replyMap.
value(
"type",
"-1").toInt();
1086 QByteArray data = replyMap.
value(
"data");
1087 emit replyInfo( type, data);
1089 else if (reply ==
"Rver") {
1091 QString type = replyMap.
valueString(
"type",
"ArnNetSync");
1092 emit replyVer( type +
" ver " + ver);
1097 void ArnClient::doLoginRequired(
int contextCode)
1101 if (d->_isValidCredent && (contextCode == 0))
1102 d->_arnNetSync->loginToArn();
1104 d->_isValidCredent =
false;
1110 QStringList ArnClient::makeItemList(
XStringMap& xsMap)
1115 for (
int i = 1; i <= n; ++i) {
int maxEnumOf(const char *keyPrefix) const
QString hostFromHostWithInfo(const QString &hostWithInfo)
Get the host from the HostWithInfo string.
HostList arnList(int prioFilter=-1) const
Return the Arn connection list.
bool getTraffic(quint64 &in, quint64 &out) const
Get traffic metrics.
static bool isMainThread()
void tcpDisConnected()
Signal emitted when the tcp connection is broken (has been successfull).
void loginToArn(const QString &userName, const QString &password, Arn::Allow allow=Arn::Allow::All)
Login to an Arn Server
void killRequested()
Signal emitted when the server request this client to kill its connection.
No data flow within set timeout (still connected)
Unsuccessfull when trying to connect to an Arn host.
void tcpConnected(const QString &arnHost, quint16 port)
Signal emitted when the tcp connection is successfull.
int remove(const QString &id)
Successfully connected to an Arn host.
bool isDemandLogin() const
Get clients demand for login.
void connectionStatusChanged(int status, int curPrio)
Signal emitted when the connection status is changed.
Arn::XStringMap remoteWhoIAm() const
Returns remote side (server) readable identification information.
void close()
Close sharing with an Arn Server
ConnectStat connectStatus() const
Return the Arn connection status.
QList< HostAddrPort > HostList
Unsuccessfully tried to connect to all hosts in the Arn connection List.
QStringList freePaths() const
Returns current list of freePaths.
Container class with string representation for serialized data.
void setReceiveTimeout(int receiveTimeout)
Set receive data timeout (base time)
void setDemandLogin(bool isDemandLogin)
Set clients demand for login.
bool addMountPoint(const QString &localPath, const QString &remotePath=QString())
Add a sharing tree path.
QString fullPath(const QString &path)
Convert a path to a full absolute path.
TCP connection is broken (has been successfull)
bool isReConnect() const
Is last Arn Connection a reConnect.
bool isReContact() const
Is last TCP connection a reContact.
Value for Server, can not be set in Client.
void setAutoConnect(bool isAuto, int retryTime=2)
Set automatic reconnect.
The Client session Sync mode at connect & reconnect.
const quint16 defaultTcpPort
Negotiating terms and compatibility with an Arn host.
static ArnClientReg & instance()
void connectToArn(const QString &arnHost, quint16 port=0)
Connect to an Arn Server
void clearArnList(int prioFilter=-1)
Clear the Arn connection list.
void chatReceived(const QString &text, int prioType)
Signal emitted when a chat message is received from the server.
QByteArray value(int i, const char *def=arnNullptr) const
void connectToArnList()
Connect to an Arn Server in the Arn connection list.
void addToArnList(const QString &arnHost, quint16 port=0, int prio=0)
Add an Arn Server to the Arn connection list.
bool store(ArnClient *client, const QString &id)
QString changeBasePath(const QString &oldBasePath, const QString &newBasePath, const QString &path)
Change the base (start) of a path.
Class for connecting to an Arn Server.
QByteArray toXString() const
Trying to connect to an Arn host.
void disconnectFromArn()
Disconnect from an Arn Server
bool removeMountPoint(const QString &localPath)
Remove a sharing tree path.
static QString passwordHash(const QString &password)
Generate a hashed password from clear text password.
void loginToArnHashed(const QString &userName, const QString &passwordHashed, Arn::Allow allow=Arn::Allow::All)
Login to an Arn Server using hashed password.
QString id() const
Get the id of this client.
QString valueString(int i, const QString &def=QString()) const
ArnClient * get(const QString &id)
void setWhoIAm(const Arn::XStringMap &whoIAmXsm)
Set clients human readable identification information.
void tcpError(const QString &errorText, QAbstractSocket::SocketError socketError)
Signal emitted when a connection tcp error occur.
SyncMode syncMode() const
Get ClientSyncMode.
void chatSend(const QString &text, int prioType)
Send chat message to server.
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
void abortKillRequest()
Send abort kill requst to server.
static void destroyLink(const QString &path, bool isGlobal=true)
Destroy the Arn Data Object at path
int receiveTimeout() const
Get receive data timeout (base time)
bool setMountPoint(const QString &path)
Set the sharing tree path.
Default dynamic auto master mode, general purpose, prohibit Null value sync.
void loginRequired(int contextCode)
Signal emitted when the remote ArnServer demands a login.
void setSyncMode(SyncMode syncMode)
Set ClientSyncMode.
ArnClient(QObject *parent=arnNullptr)
static ArnClient * getClient(const QString &id)
Get a client by its id.
void registerClient(const QString &id)
Register this client to be avaiable with id.