Remoto - VFS: VFS_remotoserver.cpp Source File
Remoto - VFS
VFS_remotoserver.cpp
Go to the documentation of this file.
1 #include <QDateTime>
2 #include <QProcessEnvironment>
3 #include <QHostInfo>
4 #include <QCoreApplication>
5 #include <QFile>
6 #include <QFileInfo>
7 
8 #include "VFS_remotoserver.h"
9 
10 #include "defines.h"
11 #include "utilities/rutils.h"
12 
13 #include "VFS.h"
14 #include "VFS_creator.h"
15 
17 
45 VFS_remotoserver::VFS_remotoserver(quint16 port, QString authPaths, QString sessions, QHostAddress addr, QWebSocketServer::SslMode ssl, QString sslCertPath, QString sslKeyPath)
46 : VFS_websocket_server(port,authPaths,sessions,addr,ssl,sslCertPath,sslKeyPath)
47 {
48  count++;
49 }
50 
52 {
53 }
54 
67 {
68  VFS_remotoserver_client *s = dynamic_cast< VFS_remotoserver_client * >(sender());
69 
70  //VFS::WARN("Binary message received on websocket...\n");
71  //printf("MESSAGE:\n%s\n",qUtf8Printable(message));
72 
73  if (s)
74  {
75  s->receive(message);
76  }
77  else
78  VFS::ERROR( QString("%1 clientBinaryMessage() called without client!").arg(className()) );
79 }
80 
93 {
94  VFS_remotoserver_client *s = dynamic_cast< VFS_remotoserver_client * >(sender());
95 
96  //printf("MESSAGE:\n%s\n",qUtf8Printable(message));
97 
98  if (s)
99  {
100  s->receive(message.toUtf8());
101  }
102  else
103  VFS::ERROR( QString("%1 clientTextMessage() called without client!").arg(className()) );
104 }
105 
113 {
114  return new VFS_remotoserver_client(s,this);
115 }
116 
123 {
124  QString s = QString("port: %1\nsessions: %2").arg(_port).arg(_sessionsPath);
125 
126  return s;
127 }
128 
129 
151 : VFS_websocket_client(socket,server)
152 , _session(nullptr)
153 , _user("unknownuser")
154 {
155 }
156 
158 {
159  //printf("DELETE RMO CLIENT\n");
160 }
161 
173 VFS_request *VFS_remotoserver_client::createRequest(VFS_request::requestType type, QString path, QString user, QJsonDocument data, QJsonObject metadata, bool dontDelete)
174 {
175  Q_UNUSED(dontDelete)
176 
177  VFS_remotoserver_request *r = new VFS_remotoserver_request(type,this,path,user,data,metadata,false);
178 
179  r->_session = _session;
180 
181  return r;
182 }
183 
197 {
198  QMutexLocker l(&_lock);
199 
200  VFS_node *source = t->_origin;
201 
202  //printf("INITIAL: %s\n",qUtf8Printable(t->_initialPath));
203  //if ( ! t->_notifyExceptions.contains( notifyException(source,t->_initialPath) ) )
204  //{
205  if (_sourcePathMap.contains(source))
206  {
207  QString path = rutils::cleanPath( _sourcePathMap.value(source)+"/"+t->_path );
208 
209  writeUIDiff(path,t->_data,t->_user);
210  }
211  else
212  { VFS::ERROR( QString("Could not find _sourcePathMap reference for 0x%1 (%2). Not applying diff for '%3'").arg((quintptr)source, QT_POINTER_SIZE * 2, 16, QChar('0')).arg(source->className()).arg(t->_initialPath), 0, t->_user );
213  //printf("NO SOURCEPATHMAP:%s\n",qUtf8Printable(t->toJson(0,true,true)));
214  t->_success = false;
215  return;
216  }
217  //}
218  //else
219  // printf("Skipped due to exception!\n");
220 
221  t->_success = true;
222 
224 }
225 
289 QJsonDocument VFS_remotoserver_client::receive(QByteArray data)
290 {
291  //printf("%s\n", qUtf8Printable( QString("Received Remotoserver Message:\n%1").arg(data.data()) ) );
292 
293  QJsonDocument d = VFS_websocket_client::receive(data);
294  if (d.isNull())
295  return d;
296 
297  //QMutexLocker l(&_lock);
298 
299  QJsonObject dob = d.object();
300  QJsonObject attrs = dob["attributes"].toObject();
301  QString tag = dob["command"].toString();
302 
303  if (!_authenticated || !_authorized)
304  { authenticate(d);
305  return d;
306  }
307 
308  if (tag == "ping")
309  {
310  VFS::LOG( QString("ping"), 9, _user );
311 
312  writeText( "{ \"command\":\"pong\" }" );
313  return d;
314  }
315 
316  if (tag == "create")
317  {
318  QJsonObject::iterator i = attrs.begin();
319 
320  while (i != attrs.end() )
321  {
322  QString path = rutils::cleanPath( i.key() );
323  VFS_request *r=nullptr;
324 
325  QJsonValue v = i.value();
326  if (v.isBool())
327  {
328  if (v.toBool()==true)
329  {
330  QJsonObject m;
331  m["container"] = true;
332  r = createRequest(VFS_request::create, path, _user, QJsonDocument(), m );
333  }
334  else
335  {
336  VFS::ERROR( QString("Useless create request on '%1'. Value was false." ).arg(path), 5, _user );
337  }
338  }
339  else
340  {
341  r = createRequest(VFS_request::create, path, _user, QJsonDocument(i.value().toObject()) );
342  }
343 
344  //add _notifyExceptions entries for the new file and its containing folder.
345  //FIXME: Disabled notifyException for create... does it need to be enabled?
346  // QStringList dirs = path.split("/",Qt::SkipEmptyParts);
347  // QString newFile = dirs.takeLast();
348  // QString dirPath = "/"+dirs.join("/");
349 
350  // _notifyExceptions.append(path);
351  // _notifyExceptions.append(dirPath);
352  // r->_notifyExceptions.append( this );
353 
354  if (r)
355  VFS::LOG( QString("Creating on '%1'").arg(path), 8, _user );
356 
357  issueRequest(r);
358 
359  ++i;
360  }
361 
362  return d;
363  }
364 
365  if (tag == "rm")
366  {
367  QJsonObject::iterator i = attrs.begin();
368 
369  while (i != attrs.end() )
370  {
371  QString path = rutils::cleanPath( i.key() );
372  bool s = i.value().toBool();
373 
374  if (s)
375  {
377 
378  //add _notifyExceptions entries for the new file and its containing folder.
379  //FIXME: Disabled notifyException for rm... does it need to be enabled?
380  // QStringList dirs = path.split("/",Qt::SkipEmptyParts);
381  // QString newFile = dirs.takeLast();
382  // QString dirPath = "/"+dirs.join("/");
383 
384  // _notifyExceptions.append(path);
385  // _notifyExceptions.append(dirPath);
386  // r->_notifyExceptions.append( this );
387 
388  VFS::LOG( QString("Deleting '%1'").arg(path), 8, _user );
389 
390  issueRequest(r);
391  }
392  else
393  VFS::ERROR( QString("Useless rm request on '%1'. Value was false." ).arg(path), 5, _user );
394 
395  ++i;
396  }
397 
398  return d;
399  }
400 
401  if (tag == "subscribe")
402  {
403  QJsonObject::iterator i = attrs.begin();
404 
406 
407  while (i != attrs.end() )
408  {
409  QString path = rutils::cleanPath( i.key() );
410  int c = i.value().toInt();
411 
412  if (c)
413  {
414  VFS_request *r = createRequest(reqtype,path,_user);
415 
416  r->_metadata["subscriptions"] = c;
417  VFS::LOG( QString("Subscribing +%1 to '%2'").arg(c).arg(path), 8, _user );
418 
419  issueRequest(r);
420  }
421  else
422  VFS::ERROR( QString("Useless subscribe request on '%1': count was %2." ).arg(path).arg(c), 5, _user );
423 
424  ++i;
425  }
426 
427  return d;
428  }
429 
430  if (tag == "read")
431  {
432  QJsonObject::iterator i = attrs.begin();
433 
434  while (i != attrs.end() )
435  {
437 
438  QString path = rutils::cleanPath( i.key() );
439 
440  if (i.value().isDouble()) //a normal request
441  {
442  int c = i.value().toInt();
443 
444  if (c)
445  {
446  VFS_request *r = createRequest(reqtype,path,_user);
447 
448  VFS::LOG( QString("Reading from '%1'").arg(path), 8, _user );
449 
450  issueRequest(r);
451  }
452  else
453  VFS::ERROR( QString("Useless read request on '%1': count was %2." ).arg(path).arg(c), 5, _user );
454  }
455  else if (i.value().isObject()) //a request with metadata
456  {
457  QJsonObject m = i.value().toObject();
458 
459  VFS_request *r = createRequest(reqtype,path,_user,QJsonDocument(),m);
460 
461  VFS::LOG( QString("Reading with metadata from '%1'").arg(path), 8, _user );
462 
463  issueRequest(r);
464  }
465  else
466  VFS::ERROR( QString("Malformed read request on '%1'." ).arg(path), 5, _user );
467 
468  ++i;
469  }
470 
471  return d;
472  }
473 
474  if (tag == "submit" || tag == "write")
475  {
476  QJsonObject::iterator i = attrs.begin();
477 
478  while (i != attrs.end() )
479  {
480  QString path = rutils::cleanPath( i.key() );
481  QJsonObject data = i.value().toObject();
482 
484 
485  VFS_request *r = createRequest(reqtype, path, _user, QJsonDocument(data) );
486 
487  //VFS::WARN( QString("DIFF: %1").arg(QString(d.toJson())) );
488 
489  //add to notifyExceptions because we don't want the submit data to come back to the sender
490  r->_notifyExceptions.append( notifyException(this,path) );
491  //printf("EXCEPT ADD: %p %s\n",this,qUtf8Printable(path));
492 
493  VFS::LOG( QString("%1 to '%2'").arg(tag[0].toUpper()+tag.mid(1)).arg(path), 8, _user );
494 
495  issueRequest(r);
496 
497  ++i;
498  }
499 
500  return d;
501  }
502 
503  if (tag == "diff")
504  {
505  QJsonObject::iterator i = attrs.begin();
506 
507  while (i != attrs.end() )
508  {
509  QString path = rutils::cleanPath( i.key() );
510  QJsonObject data = i.value().toObject();
511 
512  VFS_request *r = createRequest(VFS_request::diff, path, _user, QJsonDocument(data) );
513 
514  r->_notifyExceptions.append( notifyException(this,path) );
515 
516  VFS::LOG( QString("Diff on '%1'").arg(path), 8, _user );
517 
518  //issueRequest(r);
519  applyDiff(r);
520 
521  ++i;
522  }
523 
524  return d;
525  }
526 
527  if (tag == "unsubscribe")
528  {
529  QJsonObject::iterator i = attrs.begin();
530 
531  while (i != attrs.end() )
532  {
534 
535  QString path = rutils::cleanPath( i.key() );
536  int c = i.value().toInt();
537 
538  if (c)
539  {
540  // VFS_remotoserver_request *r = new VFS_remotoserver_request(reqtype,this,path,_user,false);
541  VFS_request *r = createRequest(reqtype,path,_user);
542 
543  r->_metadata["unsubscriptions"] = c;
544 
545  VFS::LOG( QString("Unsubscribing -%1 from '%2'").arg(c).arg(path), 8, _user );
546 
547  issueRequest(r);
548  }
549  else
550  VFS::ERROR( QString("Useless unsubscribe request on '%1': count was %2." ).arg(path).arg(c), 5, _user );
551 
552  ++i;
553  }
554 
555  return d;
556  }
557 
558  if (tag == "ls")
559  {
560  QJsonObject::iterator i = attrs.begin();
561 
562  while (i != attrs.end() )
563  {
564  QString id = i.key();
565  QJsonObject o = i.value().toObject();
566  QString path = o["path"].toString();
567  QJsonObject m = o["metadata"].toObject();
568  //QJsonDocument d = QJsonDoument(o["data"]); //should we include data here?
569 
570  // VFS_remotoserver_request *r = new VFS_remotoserver_request(VFS_request::ls,this,path,_user,false);
571  VFS_request *r = createRequest(VFS_request::ls,path,_user,QJsonDocument(),m);
572 
573  r->_metadata["id"] = id;
574 
575  VFS::LOG( QString("Listing '%1'").arg(path), 8, _user );
576 
577  issueRequest(r);
578 
579  ++i;
580  }
581 
582  return d;
583  }
584 
585  if (tag == "metadata")
586  {
587  QJsonObject::iterator i = attrs.begin();
588 
589  while (i != attrs.end() )
590  {
591  QString path = rutils::cleanPath( i.key() );
592  //int c = i.value().toInt();
593 
594  // VFS_remotoserver_request *r = new VFS_remotoserver_request(VFS_request::metadata,this,path,_user,false);
596 
597  VFS::LOG( QString("Metadata on '%1'").arg(path), 8, _user );
598 
599  issueRequest(r);
600 
601  ++i;
602  }
603 
604  return d;
605  }
606 
607  if (tag == "requestlock")
608  {
609  QJsonObject::iterator i = attrs.begin();
610 
611  while (i != attrs.end() )
612  {
613  QString path = rutils::cleanPath( i.key() );
614  QJsonObject data = i.value().toObject();
615 
616  VFS::LOG( QString("Request lock on '%1'").arg(path), 8, _user );
617 
618  VFS_request *r = createRequest(VFS_request::requestlock, path, _user, QJsonDocument(data) );
619 
620  issueRequest(r);
621 
622  ++i;
623  }
624 
625  return d;
626  }
627 
628  if (tag == "releaselock")
629  {
630  QJsonObject::iterator i = attrs.begin();
631 
632  while ( i != attrs.end() )
633  {
634  QString path = rutils::cleanPath( i.key() );
635  QJsonObject data = i.value().toObject();
636 
637  VFS::LOG( QString("Release lock on '%1'").arg(path), 8, _user );
638 
639  VFS_request *r = createRequest(VFS_request::releaselock, path, _user, QJsonDocument(data) );
640 
641  issueRequest(r);
642 
643  ++i;
644  }
645 
646  return d;
647  }
648 
649  if (tag == "code")
650  {
651  QJsonObject::iterator i = attrs.begin();
652 
653  while ( i != attrs.end() )
654  {
655  QString library = i.key();
656  //we ignore i.value() for now, which should always be true
657 
660 
661  if (c->hasCallback()) //it needs to be dispatched, probably because it is remote
662  {
663  //printf("ORIGIN: %s\n",qUtf8Printable(c->_origin->className()));
664 
665  //this is almost certainly on a different thread
666  QMetaObject::invokeMethod(c->_origin,"executeRequest",Qt::AutoConnection,Q_ARG(VFS_request*, c));
667  }
668  else
669  {
670  if (c->_success)
671  { QJsonObject o = c->_data.object();
672  writeUICode(o["name"].toString(),o["code"].toString(),r->_reason);
673  }
674  else
675  {
676  writeUICode(library,"",r->_reason);
677  }
678 
679  delete c;
680  }
681 
682  ++i;
683  }
684 
685  return d;
686  }
687 
688  /*
689  if (tag == "codeDirectory")
690  {
691  QString error;
692  QJsonObject o = VFS_creator::codeDirectory(error);
693 
694  VFS::LOG( QString("Requested code directory"), 9, _user );
695 
696  writeUICodeDirectory(o,error);
697 
698  return d;
699  }
700  */
701 
702  VFS::ERROR( QString("Received invalid %1 command: %2").arg(className()).arg(tag), 0, _user );
703  VFS::ERROR( QString("%1").arg(data.data()), 0, _user );
704 
705  return d;
706 }
707 
719 {
720  QString command = d.object()["command"].toString();
721 
722  if ( command!="identify")
723  {
724  VFS::ERROR( "Not authenticated!", 0, className() );
725  VFS::ERROR( QString("Received: %1").arg(qUtf8Printable(d.toJson())), 0, className() );
726  //printf("Not authenticated!\nReceived:\n%s\n",qUtf8Printable(d.toJson()));
727 
728  QJsonObject r,a;
729  r["command"] = "authorization";
730  a["accepted"] = false;
731  r["attributes"] = a;
732  QJsonDocument rd(r);
733  writeText(rd.toJson());
734  close();
735  return;
736  }
737  else
738  {
739  QJsonObject o = d.object()["attributes"].toObject();
740  o["address"] = _address.toString();
741  _server->authenticate(this, o);
742  }
743 }
744 
757 {
758  Q_UNUSED(r);
759 
760  return this;
761 }
762 
769 {
770  QString s = QString("user: %1\ntype: %2").arg(_user).arg(_type);
771 
772  return s;
773 }
774 
791 {
792  //printf("VFS_remotoserver_client WRITE!\n");
793  writeUIWrite(r->_path,r->_data,r->_metadata);
794 
795  //VFS_node::write(r);
796  r->_success = true;
797 }
798 
814 {
815  writeUIRM(r->_path);
816 
817  r->_success = true;
818 }
819 
836 {
837  //printf("RECEIVED: %s\n",qUtf8Printable(t->toJson(0,true)));
838 
839  if (!_authenticated)
840  {
842 
843  if (_authenticated)
844  {
845  QJsonObject o = t->_data.object();
846  _user = o["username"].toString();
847  _type = o["type"].toString();
848  _parameters = o["parameters"].toObject();
849 
850  if (_user == "")
851  printf("AUTH:\n%s\n",qUtf8Printable(t->toJson(0,true)));
852 
853  VFS::LOG( QString("'%1' authenticated by '%2' on %3").arg(_user).arg(t->_initialPath).arg(QDateTime::currentDateTime().toString(Qt::SystemLocaleLongDate)), 3 );
854 
855  //if (!_parameters.isEmpty())
856  // printf("PARAMETERS:\n%s\n",qUtf8Printable( QJsonDocument(_parameters).toJson() ));
857 
858  _server->authorize( this, o );
859  }
860  else
861  {
862  if (!t->_reason.isEmpty())
863  VFS::WARN( t->_reason );
864 
865  //keep looping through the auth paths until sent is false.
866  bool sent = _server->authenticate(this, t->_data.object());
867 
868  if (!sent)
869  {
870  QString m = "Authentication denied.";
871  QString user = t->_data.object()["username"].toString();
872 
873  //if (!t->_reason.isEmpty())
874  // m = t->_reason;
875 
876  //if (!t->_user.isEmpty())
877  if (!user.isEmpty())
878  { m = QString("Authentication denied for user '%1'").arg(user);
879  VFS::ERROR( m );
880  }
881 
882  QJsonObject r,a;
883  r["command"] = "authorization";
884  a["reason"] = m;
885  a["accepted"] = false;
886  r["attributes"] = a;
887 
888  writeText(QJsonDocument(r).toJson());
889  close();
890  }
891  }
892 
893  delete t;
894  return;
895  }
896  else if (!_authorized)
897  {
898  _authorized = t->_success;
899 
900  if (_authorized) //authentication and authorization are successful now
901  {
902  _session = t->_session; //store the session pointer
903 
904  QJsonObject r;
905  r["command"] = "authorization";
906  r["attributes"] = t->_data.object();
907 
908  writeText(QJsonDocument(r).toJson());
909  authorized(); //the node has been authorized... call this for subclasses that need it.
910  }
911  else
912  {
913  QString m = QString("Authorization denied for user '%1'").arg(t->_user);
914  VFS::ERROR( m );
915 
916  if (!t->_reason.isEmpty())
917  m = t->_reason;
918 
919  QJsonObject r,a;
920  r["command"] = "authorization";
921  a["reason"] = m;
922  a["accepted"] = false;
923  r["attributes"] = a;
924 
925  writeText(QJsonDocument(r).toJson());
926  close();
927  }
928 
929  delete t;
930  return;
931  }
932 
934  //VFS_node::receiveResponse(t);
935 }
936 
951 {
952  QMutexLocker l(&_lock);
953 
954  if (!source)
955  { VFS::ERROR("NO SOURCE, WON'T ADD!\n");
956  return;
957  }
958 
959  if (!_sourcePathMap.contains(source))
960  { _sourcePathMap.insert(source,path);
961  connect(source, SIGNAL(unmounted(VFS_node*)), this, SLOT(removeSourcePathMap(VFS_node*)));
962  }
963  //else
964  // VFS::WARN( QString("Not duplicating path %1 in pathMap. Attempted: %2, existing: %3").arg((quintptr)source).arg(path).arg(_sourcePathMap[source]) );
965 }
966 
975 {
976  QMutexLocker l(&_lock);
977 
978  if (s)
979  { if (_sourcePathMap.contains(s))
980  { //QString p = _sourcePathMap.value(s);
981  _sourcePathMap.remove(s);
982  }
983  //else
984  // VFS::WARN( QString("Could not remove non-existent entry %1 from sourcePathMap.").arg((quintptr)s) );
985  }
986  else
987  VFS::WARN( QString("Could not remove null sender %1 from sourcePathMap.").arg((quintptr)sender()) );
988 }
989 
1004 bool VFS_remotoserver_client::writeUIDiff(QString path, QJsonDocument diff, QString user, bool binary)
1005 {
1006  //printf("WRITE UI DIFF: %s\n",qUtf8Printable(path));
1007 
1008  //QMutexLocker l(&_lock);
1009 
1010  QJsonObject r;
1011  r["command"] = "diff";
1012  r["user"] = user;
1013 
1014  QJsonObject a;
1015  a["path"] = path;
1016 
1017  if (diff.isEmpty())
1018  a["diff"] = QJsonValue::Null;
1019  else
1020  a["diff"] = diff.object();
1021 
1022  r["attributes"] = a;
1023  QJsonDocument rd(r);
1024 
1025  if (binary)
1026  return writeBinary(rd.toJson());
1027  else
1028  return writeText(rd.toJson());
1029 }
1030 
1045 bool VFS_remotoserver_client::writeUIRead(QString path, QJsonDocument data, QJsonObject metadata, bool binary)
1046 {
1047  QJsonObject r;
1048  r["command"] = "read";
1049 
1050  QJsonObject a;
1051  a["path"] = path;
1052  a["type"] = metadata["type"].toString();
1053  a["metadata"] = metadata;
1054 
1055  if (data.isEmpty())
1056  a["data"] = QJsonValue::Null;
1057  else
1058  a["data"] = data.object();
1059 
1060  r["attributes"] = a;
1061  QJsonDocument rd(r);
1062 
1063  if (binary)
1064  return writeBinary(rd.toJson());
1065  else
1066  return writeText(rd.toJson());
1067 }
1068 
1084 bool VFS_remotoserver_client::writeUIWrite(QString path, QJsonDocument data, QJsonObject metadata, bool binary)
1085 {
1086  QJsonObject r;
1087  r["command"] = "write";
1088 
1089  QJsonObject a;
1090  a["path"] = path;
1091  a["type"] = metadata["type"].toString();
1092  a["metadata"] = metadata;
1093 
1094  if (data.isEmpty())
1095  a["data"] = QJsonValue::Null;
1096  else
1097  a["data"] = data.object();
1098 
1099  r["attributes"] = a;
1100  QJsonDocument rd(r);
1101 
1102  if (binary)
1103  return writeBinary(rd.toJson());
1104  else
1105  return writeText(rd.toJson());
1106 }
1107 
1121 bool VFS_remotoserver_client::writeUIRM(QString path, bool binary)
1122 {
1123  QJsonObject r;
1124  r["command"] = "rm";
1125 
1126  QJsonObject a;
1127  a["path"] = path;
1128 
1129  r["attributes"] = a;
1130  QJsonDocument rd(r);
1131 
1132  if (binary)
1133  return writeBinary(rd.toJson());
1134  else
1135  return writeText(rd.toJson());
1136 }
1137 
1152 bool VFS_remotoserver_client::writeUISubscribe(QString path, QJsonDocument data, QJsonObject metadata, bool binary)
1153 {
1154  //QMutexLocker l(&_lock);
1155 
1156  QJsonObject r;
1157  r["command"] = "subscribe";
1158 
1159  QJsonObject a;
1160  a["path"] = path;
1161  a["type"] = metadata["type"].toString();
1162  a["metadata"] = metadata;
1163 
1164  if (data.isEmpty())
1165  a["data"] = QJsonValue::Null;
1166  else
1167  a["data"] = data.object();
1168 
1169  r["attributes"] = a;
1170  QJsonDocument rd(r);
1171 
1172  if (binary)
1173  return writeBinary(rd.toJson());
1174  else
1175  return writeText(rd.toJson());
1176 }
1177 
1195 bool VFS_remotoserver_client::writeUILS(QString id, QString path, QJsonDocument data, QJsonObject metadata, bool binary)
1196 {
1197  QJsonObject r;
1198  r["command"] = "ls";
1199 
1200  QJsonObject a;
1201  a["id"] = id;
1202  a["path"] = path;
1203  a["metadata"] = metadata;
1204  a["data"] = data.object();
1205 
1206  r["attributes"] = a;
1207 
1208  QJsonDocument rd(r);
1209 
1210  if (binary)
1211  return writeBinary(rd.toJson());
1212  else
1213  return writeText(rd.toJson());
1214 }
1215 
1229 bool VFS_remotoserver_client::writeUIMetadata(QString path, QJsonObject metadata, bool binary)
1230 {
1231  QJsonObject r;
1232  r["command"] = "metadata";
1233 
1234  QJsonObject a;
1235  a["path"] = path;
1236  //a["type"] = metadata["type"].toString();
1237  a["metadata"] = metadata;
1238  //a["data"] = data.object();
1239 
1240  r["attributes"] = a;
1241  QJsonDocument rd(r);
1242 
1243  if (binary)
1244  return writeBinary(rd.toJson());
1245  else
1246  return writeText(rd.toJson());
1247 }
1248 
1265 bool VFS_remotoserver_client::writeUIRequestLock(QString path, QJsonDocument data, bool binary)
1266 {
1267  QJsonObject r;
1268  r["command"] = "requestlock";
1269 
1270  QJsonObject a;
1271  a["path"] = path;
1272  a["data"] = data.object();
1273 
1274  r["attributes"] = a;
1275  QJsonDocument rd(r);
1276 
1277  if (binary)
1278  return writeBinary(rd.toJson());
1279  else
1280  return writeText(rd.toJson());
1281 }
1282 
1299 bool VFS_remotoserver_client::writeUIReleaseLock(QString path, QJsonDocument data, bool binary)
1300 {
1301  QJsonObject r;
1302  r["command"] = "releaselock";
1303 
1304  QJsonObject a;
1305  a["path"] = path;
1306  a["data"] = data.object();
1307 
1308  r["attributes"] = a;
1309  QJsonDocument rd(r);
1310 
1311  if (binary)
1312  return writeBinary(rd.toJson());
1313  else
1314  return writeText(rd.toJson());
1315 }
1316 
1332 bool VFS_remotoserver_client::writeUICode(QString name, QString code, QString error, bool binary)
1333 {
1334  QJsonObject r;
1335  r["command"] = "code";
1336 
1337  QJsonObject a;
1338  a["name"] = name;
1339  a["code"] = code;
1340 
1341  if (!error.isEmpty())
1342  { a["error"] = error;
1343  VFS::ERROR( error );
1344  }
1345 
1346  r["attributes"] = a;
1347  QJsonDocument rd(r);
1348 
1349  if (binary)
1350  return writeBinary(rd.toJson());
1351  else
1352  return writeText(rd.toJson());
1353 }
1354 
1365 bool VFS_remotoserver_client::writeUICodeDirectory(QJsonObject o, QString error, bool binary)
1366 {
1367  QJsonObject r;
1368  r["command"] = "codeDirectory";
1369 
1370  QJsonObject a;
1371  a["directory"] = o;
1372 
1373  if (!error.isEmpty())
1374  { a["error"] = error;
1375  VFS::ERROR( error );
1376  }
1377 
1378  r["attributes"] = a;
1379  QJsonDocument rd(r);
1380 
1381  if (binary)
1382  return writeBinary(rd.toJson());
1383  else
1384  return writeText(rd.toJson());
1385 }
1386 
1397 {
1398  //QMutexLocker l(&_lock);
1399 
1400  QJsonObject r,a;
1401  r["command"] = "error";
1402  a["message"] = message;
1403  r["attributes"] = a;
1404  QJsonDocument rd(r);
1405 
1406  if (binary)
1407  return writeBinary(rd.toJson());
1408  else
1409  return writeText(rd.toJson());
1410 }
1411 
1424 bool VFS_remotoserver_client::writeRequestError(QString command, QString path, QString reason, bool binary)
1425 {
1426  QJsonObject r,a;
1427  r["command"] = "requesterror";
1428  a["command"] = command;
1429  a["path"] = path;
1430  a["reason"] = reason;
1431  r["attributes"] = a;
1432  QJsonDocument rd(r);
1433 
1434  if (binary)
1435  return writeBinary(rd.toJson());
1436  else
1437  return writeText(rd.toJson());
1438 }
1439 
1454 bool VFS_remotoserver_client::writeRequestSuccess(QString command, QString path, QJsonDocument data, QJsonObject metadata, bool binary)
1455 {
1456  QJsonObject r,a;
1457  r["command"] = "requestsuccess";
1458  a["command"] = command;
1459  a["path"] = path;
1460  if (!data.isEmpty())
1461  a["data"] = data.object();
1462  if (!metadata.isEmpty())
1463  a["metadata"] = metadata;
1464  r["attributes"] = a;
1465  QJsonDocument rd(r);
1466 
1467  if (binary)
1468  return writeBinary(rd.toJson());
1469  else
1470  return writeText(rd.toJson());
1471 }
1472 
1479 {
1480  return _parameters;
1481 }
1482 
1502 VFS_remotoserver_request::VFS_remotoserver_request(VFS_request::requestType type, VFS_remotoserver_client *origin, QString path, QString user, QJsonDocument data, QJsonObject metadata, bool binary)
1503 : VFS_request(type,origin,path,user,data,metadata)
1504 , _binary(binary)
1505 {
1506 }
1507 
1509 {
1510 }
1511 
1525 {
1527 
1528  if (c && VFS_node::__isNode(c))
1529  {
1530  switch(_requestType)
1531  {
1532  case VFS_request::read: if (!_success)
1533  {
1534  if (_reason.isEmpty())
1535  _reason = QString("remotoserver_request::read was not successful on '%1'.").arg(_initialPath);
1536 
1537  VFS::ERROR( _reason );
1538 
1539  //c->writeError(_reason);
1540  c->writeRequestError( "read", _initialPath, _reason );
1541  }
1542  else
1543  {
1544  //and upon successful read, send the contents of the file back.
1546  }
1547 
1548  break;
1549 
1550  case VFS_request::subscribe: if (!_success)
1551  {
1552  if (_reason.isEmpty())
1553  _reason = QString("remotoserver_request::subscribe was not successful on '%1'.").arg(_initialPath);
1554 
1555  VFS::ERROR( _reason );
1556 
1557  //c->writeError(_reason);
1558  c->writeRequestError( "subscribe", _initialPath, _reason );
1559  }
1560  else
1561  {
1562  //and upon subscription, send the contents of the file back.
1564 
1565  //add the (successfully subscribed) path to the paths map here for diffs on the client
1566  c->addSourcePathMap(_responder,_prefixPath.join('/'));
1567 
1568  //printf("XX INITIAL: %s\nXX PRFIXJN: %s\n",qUtf8Printable(_initialPath),qUtf8Printable(_prefixPath.join('\n')));
1569  }
1570 
1571  break;
1572 
1574  {
1575  //VFS::ERROR( "remotoserver_request::unsubscribe was not successful." );
1576  //c->writeError(_reason);
1577  c->writeRequestError( "unsubscribe", _initialPath, _reason );
1578  }
1579  else
1580  {
1581  //do nothing here... the path no longer exists for the client
1582  //c->writeRequestSuccess( "unsubscribe", _initialPath );
1583  }
1584 
1585  break;
1586 
1587  case VFS_request::write: if (!_success)
1588  {
1589  if (_reason.isEmpty())
1590  _reason = "remotoserver_request::write was not successful.";
1591 
1592  VFS::ERROR( _reason );
1593 
1594  //c->writeError(_reason);
1595  c->writeRequestError( "write", _initialPath, _reason );
1596  }
1597  else
1598  {
1599  //FIXME: this should be uncommented, but will require
1600  //re-working the paneManager to be a subscribed thing
1601  //instead of a special case in vfsClient...
1602  //the paneManager should be a plain old object in the objectRegistry
1603  //c->writeRequestSuccess( "write", _initialPath );
1604  }
1605 
1606  break;
1607 
1608  case VFS_request::submit: if (!_success)
1609  {
1610  if (_reason.isEmpty())
1611  _reason = "remotoserver_request::submit was not successful.";
1612 
1613  VFS::ERROR( _reason );
1614 
1615  c->writeError(_reason);
1616  //c->writeRequestError( "submit", _initialPath, _reason );
1617  }
1618  else
1619  {
1620  //c->writeRequestSuccess( "submit", _initialPath );
1621  }
1622 
1623  break;
1624 
1625  case VFS_request::create: if (!_success)
1626  {
1627  if (_reason.isEmpty())
1628  _reason = QString("remotoserver_request::create failed: '%1'.").arg(_initialPath);
1629 
1631 
1632  c->writeError(_reason);
1633  //c->writeRequestError( "create", _initialPath, _reason );
1634  }
1635  else
1636  {
1637  c->writeRequestSuccess( "create", _initialPath, _data, _metadata );
1638  }
1639 
1640  break;
1641 
1642  case VFS_request::rm: if (!_success)
1643  {
1644  if (_reason.isEmpty())
1645  _reason = QString("remotoserver_request::rm failed: '%1'.").arg(_initialPath);
1646 
1648 
1649  //c->writeError(_reason);
1651  }
1652  else
1653  {
1654  c->writeRequestSuccess( "rm", _initialPath );
1655  }
1656 
1657  break;
1658 
1659  case VFS_request::ls: if (!_success)
1660  {
1661  if (_reason.isEmpty())
1662  _reason = QString("remotoserver_request::ls failed: '%1'.").arg(_initialPath);
1663 
1664  VFS::ERROR( _reason );
1665 
1666  c->writeError(_reason);
1667  //c->writeRequestError( "ls", _initialPath, _reason );
1668  }
1669  else
1670  {
1671  //printf("ls was successful.\n");
1672 
1673  //FIXME: arguably, closest container should be set here
1674  //if (_metadata.value("closest",false).toBool())
1675  //{ printf("LS WITH CLOSEST:\n%s\n",qUtf8Printable(_prefixPath.join('/') + "/" + _path));
1676  // _metadata["closestContainer"] = ....
1677  //}
1678 
1679  _success = c->writeUILS(_metadata["id"].toString(),_initialPath,_data,_metadata);
1680  }
1681 
1682  break;
1683 
1684  case VFS_request::metadata: if (!_success)
1685  {
1686  if (_reason.isEmpty())
1687  _reason = QString("remotoserver_request::metadata was not successful on '%1'.").arg(_initialPath);
1688 
1689  VFS::ERROR( _reason );
1690 
1691  //c->writeError(_reason);
1692  c->writeRequestError( "metadata", _initialPath, _reason );
1693  }
1694  else
1695  {
1696  //and upon successful read, send the contents of the metadata back.
1698  }
1699 
1700  break;
1701 
1702  case VFS_request::diff: //printf("%s RECEIVED DIFF: %s\n",qUtf8Printable(_origin->className()),qUtf8Printable(toJson(0,true,true)));
1703 
1704  //DO NOT WRITE UIDIFF HERE
1705  //c->writeUIDiff( _initialPath, _data, _user, _binary );
1706 
1707  //instead execute as normal
1709  break;
1710 
1711  case VFS_request::requestlock: //if (!_success)
1712  //{
1713  //}
1715  break;
1716 
1717  case VFS_request::releaselock: //if (!_success)
1718  //{
1719  //}
1721  break;
1722 
1723  case VFS_request::code: if (_success)
1724  {
1725  //printf("RECEIVED CODE RESPONSE\n");
1726  QJsonObject o = _data.object();
1727  QString name = o["name"].toString();
1728  QString code = o["code"].toString();
1729  QString error = _reason;
1730 
1731  //upon successful code request, send the code back.
1732  _success = c->writeUICode(name,code,error);
1733  }
1734  else
1735  {
1736  if (_reason.isEmpty())
1737  _reason = QString("remotoserver_request::code was not successful on '%1'.").arg(_initialPath);
1738 
1739  VFS::ERROR( _reason );
1740 
1741  //c->writeError(_reason);
1742  c->writeUICode(_path,"",_reason);
1743  }
1744 
1745  break;
1746 
1747  default: VFS::ERROR( QString("unknown request type on remotoserver_request: %1").arg(_requestType), 0, _user );
1748  break;
1749  }
1750  }
1751  else
1752  {
1753  VFS::ERROR("COULD NOT CAST TO REMOTOSERVER_CLIENT... was it deleted?\n");
1754  //throw "Could not dynamic cast to remotoserver_client.";
1755  _success = false;
1756  }
1757 
1758  //provide error logging if unsuccessful
1759  //VFS_request::execute();
1760 }
QPair< VFS_node *, QString > notifyException
Definition: VFS_node.h:42
static VFS_request * code(VFS_request *r)
Resolve a request for code.
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual void metadata(VFS_request *r)
Fetch the metadata of this node.
Definition: VFS_node.cpp:797
virtual void issueRequest(VFS_request *t)
A convenience function.
Definition: VFS_node.cpp:1933
static bool __isNode(VFS_node *)
Check to see if a node is in the global registry.
Definition: VFS_node.cpp:588
static QString code(QString nodename, QString libname, QString &error)
Fetch code or any other resource from a node.
Definition: VFS_node.cpp:1038
void unmounted(VFS_node *self)
Emitted when a node is unmount()ed.
void diff(VFS_node *origin, VFS_request *t)
Emit a diff, which will trigger notifySubscribers() for a mounted node.
QString className()
Return the class name of a node.
Definition: VFS_node.cpp:2039
QMutex _lock
A recursive mutex that is local to this node.
Definition: VFS_node.h:178
virtual void applyDiff(VFS_request *r)
Apply a diff received via subscription.
Definition: VFS_node.cpp:1463
virtual void receiveResponse(VFS_request *t)
Once a VFS_request has been completed, a response will be issued back to its _origin.
Definition: VFS_node.cpp:1870
A subclass of VFS_websocket_client that implements the remoto websocket protocol and handles requests...
virtual QJsonDocument receive(QByteArray data)
Receive a message from a connected websocket client.
QString _type
The remote client type, which may be "browser" or "unity" or any other id string.
virtual void authenticate(QJsonDocument d)
Authenticate a user using VFS_websocket_server::authenticate().
bool writeUICode(QString libname, QString code, QString error, bool binary=false)
Write a VFS_request::code response to a connected client.
bool writeRequestError(QString command, QString path, QString reason, bool binary=false)
Write a requesterror command to a connected client.
QMap< VFS_node *, QString > _sourcePathMap
A map relating path requests from a client to path requests on the VFS.
bool writeUIRequestLock(QString path, QJsonDocument data, bool binary=false)
Write the results of a VFS_request::requestlock to a connected client.
bool writeError(QString message, bool binary=false)
Write an error state to a connected client.
void addSourcePathMap(VFS_node *source, QString path)
Add a VFS_remotoserver_client::_sourcePathMap entry for a path from a client's perspective to a VFS_n...
friend class VFS_remotoserver_request
bool writeUIWrite(QString path, QJsonDocument data, QJsonObject metadata, bool binary=false)
Write data to a connected client.
virtual void applyDiff(VFS_request *t)
Apply a diff to this node.
bool writeUIReleaseLock(QString path, QJsonDocument data, bool binary=false)
Write the results of a VFS_request::releaselock to a connected client.
bool writeUIMetadata(QString path, QJsonObject metadata, bool binary=false)
Write a VFS_request::metadata response to a connected client.
QJsonObject _parameters
Parameters provided during the auth process.
virtual void receiveResponse(VFS_request *t)
Receive a response from an issueRequest().
bool writeUIRead(QString path, QJsonDocument data, QJsonObject metadata, bool binary=false)
Send the results of a VFS_request::read command to a client.
QJsonObject parameters() const
Return the parameters provided to this client when authentication was granted.
VFS_session * _session
The session associated with this client connection.
virtual void write(VFS_request *r)
Write form or interface information back to a user.
QString _user
The authenticated client's username.
bool writeUICodeDirectory(QJsonObject o, QString error, bool binary=false)
Write a VFS_request::codeDirectory response to a connected client.
virtual void removeSourcePathMap(VFS_node *n)
Remove a VFS_remotoserver_client::_sourcePathMap entry for a VFS_node.
virtual VFS_node * find(VFS_request *r)
VFS_remotoserver_client cannot contain children, but instead points to a websocket client,...
virtual QString reportDetails()
Report the _user and _type of a connected client.
virtual VFS_request * createRequest(VFS_request::requestType type, QString path, QString user="unknown", QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool dontDelete=false)
Create a VFS_remotoserver_request to service a request received from a client.
bool writeRequestSuccess(QString command, QString path, QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool binary=false)
VFS_remotoserver_client::writeRequestSuccess.
bool writeUIDiff(QString path, QJsonDocument diff, QString user, bool binary=false)
Send a diff command to a client when something interesting happens on a subscribed VFS_node.
bool writeUIRM(QString path, bool binary=false)
Send an RM command to a connected client.
virtual void rm(VFS_request *r)
Send an RM command to a user.
bool writeUISubscribe(QString path, QJsonDocument data, QJsonObject metadata, bool binary=false)
Write a VFS_request::subscribe response to a connected client.
VFS_remotoserver_client(QWebSocket *socket, VFS_websocket_server *server)
bool writeUILS(QString id, QString path, QJsonDocument data, QJsonObject metadata, bool binary=false)
Write a VFS_request::ls response to a connected client.
A subclass of VFS_request used for websocket (VFS_remotoserver) communication.
bool _binary
Binary mode flag for websocket messages.
virtual void execute()
Dynamically cast the _origin node to a VFS_remotoserver_client and write the results of a request to ...
VFS_remotoserver_request(VFS_request::requestType type, VFS_remotoserver_client *origin, QString path="", QString user="unknown", QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool binary=false)
virtual void clientTextMessage(QString message)
The client has received as text websocket message.
Q_INVOKABLE VFS_remotoserver(quint16 port, QString auth, QString sessions, QHostAddress addr=QHostAddress::Any, QWebSocketServer::SslMode ssl=QWebSocketServer::NonSecureMode, QString sslCertPath="", QString sslKeyPath="")
virtual QString reportDetails()
Report the _port number.
virtual VFS_websocket_client * createWebsocketClient(QWebSocket *s)
Create a VFS_remotoserver_client to host a new connection.
static int count
The global count of VFS_remotoserver instances, used to create a config.json file if needed.
virtual void clientBinaryMessage(QByteArray message)
The client has received as binary websocket message.
virtual ~VFS_remotoserver()
The base class for all requests between nodes.
Definition: VFS_node.h:54
requestType
Requests perform one of these actions.
Definition: VFS_node.h:63
@ diff
send a diff (7)
Definition: VFS_node.h:71
@ read
read full contents (4)
Definition: VFS_node.h:68
@ requestlock
request a lock (13)
Definition: VFS_node.h:77
@ unsubscribe
unsubscribe from a path (10)
Definition: VFS_node.h:74
@ ls
list children of a node (1)
Definition: VFS_node.h:65
@ metadata
read metadata (6)
Definition: VFS_node.h:70
@ create
create a new file/path (2)
Definition: VFS_node.h:66
@ write
write full contents (5)
Definition: VFS_node.h:69
@ code
request code from a node (15)
Definition: VFS_node.h:79
@ releaselock
release a lock (14)
Definition: VFS_node.h:78
@ subscribe
subscribe to a path (9)
Definition: VFS_node.h:73
@ submit
apply a diff (8)
Definition: VFS_node.h:72
@ rm
delete an existing file/path (3)
Definition: VFS_node.h:67
VFS_node * _responder
the receiver of the request
Definition: VFS_node.h:92
VFS_node * _origin
the origin of the request
Definition: VFS_node.h:89
bool hasCallback()
Check if this request has a callback set.
Definition: VFS_node.cpp:336
requestType _requestType
the action this request is performing or requesting
Definition: VFS_node.h:87
QString _initialPath
the target path when the request was made (relative to the responder)
Definition: VFS_node.h:93
QStringList _prefixPath
the prefix elements found while searching for the target
Definition: VFS_node.h:94
QString _user
who initiated this request, mostly for logging
Definition: VFS_node.h:106
virtual void execute()
after a request has completed, a request may have a special execute function.
Definition: VFS_node.cpp:255
VFS_session * _session
The session associated with this request. This is an optional value, and care should be taken to chec...
Definition: VFS_node.h:105
QString _reason
if something (probably bad) happened, this is the reason
Definition: VFS_node.h:108
QString _path
the target path remnant... the remaining path element once the request has found its target
Definition: VFS_node.h:95
QList< notifyException > _notifyExceptions
a list of nodes not to send responses to for this transaction. For instance if a node submits to a no...
Definition: VFS_node.h:110
bool _success
if the request was successfully completed
Definition: VFS_node.h:107
QJsonDocument _data
the request payload
Definition: VFS_node.h:102
virtual QByteArray toJson(postID id=0, bool ignoreSuccess=false, bool includeInitialPath=false)
Serialize this request.
Definition: VFS_node.cpp:415
QJsonObject _metadata
the request payload
Definition: VFS_node.h:101
A VFS_node that manages a QWebSocket connection.
QHostAddress _address
The network address of the connected client.
virtual void authorized()
Notify the node that it has received authorization from some auth method.
bool _authorized
if this connection has a session
VFS_websocket_server * _server
owning server
bool _authenticated
if auth has taken place and succeeded
virtual void close()
Close the socket if it is connected.
virtual bool writeBinary(QByteArray data)
Write binary data over the websocket.
void error(QAbstractSocket::SocketError)
There has been a socket error.
virtual bool writeText(QString data)
Write text data over the websocket.
virtual QJsonDocument receive(QByteArray message)
VFS_websocket_VFSclient::receive.
A VFS_websocket server will listen for incoming websocket connections, optionally using ssl.
virtual bool authenticate(VFS_websocket_client *client, QJsonObject credentials)
Authenticate a client based on received credentials.
quint16 _port
Port to listen on.
QString _sessionsPath
The path to the sessionManager node.
virtual void authorize(VFS_websocket_client *client, QJsonObject authdata)
Authorize a client and create a session based on type and username.
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
Definition: VFS.cpp:307
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
message(m)
Change the message of an existing arrowMessage.
setter user
a setter DOCME
setter name
a setter DOCME
setter type
a setter DOCME
getter path
a getter DOCME
metadata(paths)
setter error
Set the error value of this widget.
QString cleanPath(QString path)
Clean and normalize a VFS path.
Definition: rutils.cpp:32