fileServer.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/PlatformIncl.h>
  9. #include "fileServer.h"
  10. #include <native/connection/connection.h>
  11. #if !defined(APPLE) && !defined(LINUX)
  12. #include <io.h>
  13. #endif
  14. #include "native/utilities/assetUtils.h"
  15. #include <AzCore/IO/Path/Path.h>
  16. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  17. #include <AzFramework/IO/LocalFileIO.h>
  18. using namespace AZ::IO;
  19. using namespace AzFramework::AssetSystem;
  20. //#define VERBOSE_FILE_OPS
  21. //////////////////////////////////////////////////////////////////////////////////////////
  22. FileServer::FileServer(QObject* parent)
  23. : QObject(parent)
  24. {
  25. m_realtimeMetrics = true;
  26. setRealTimeMetrics(false);
  27. //metrics
  28. m_numOpenRequests = 0;
  29. m_numCloseRequests = 0;
  30. m_numOpened = 0;
  31. m_numClosed = 0;
  32. m_numReadRequests = 0;
  33. m_numWriteRequests = 0;
  34. m_numTellRequests = 0;
  35. m_numSeekRequests = 0;
  36. m_numIsReadOnlyRequests = 0;
  37. m_numIsDirectoryRequests = 0;
  38. m_numSizeRequests = 0;
  39. m_numModificationTimeRequests = 0;
  40. m_numExistsRequests = 0;
  41. m_numFlushRequests = 0;
  42. m_numCreatePathRequests = 0;
  43. m_numDestroyPathRequests = 0;
  44. m_numRemoveRequests = 0;
  45. m_numCopyRequests = 0;
  46. m_numRenameRequests = 0;
  47. m_numFindFileNamesRequests = 0;
  48. m_bytesRead = 0;
  49. m_bytesWritten = 0;
  50. m_bytesSent = 0;
  51. m_bytesReceived = 0;
  52. m_numOpenFiles = 0;
  53. }
  54. FileServer::~FileServer()
  55. {
  56. #ifdef REMOTEFILEIO_USE_PROFILING
  57. g_profiler.DumpTimerDataToOutput();
  58. g_profiler.DumpTimerDataToFile("../remotefileio_server_profile.txt");
  59. #endif
  60. }
  61. void FileServer::SetSystemRoot(const QDir& systemRoot)
  62. {
  63. m_systemRoot = systemRoot;
  64. m_displayRoot = m_systemRoot.absolutePath();
  65. Q_EMIT RootFolderChanged();
  66. }
  67. void FileServer::setRealTimeMetrics(bool enable)
  68. {
  69. if (enable)
  70. {
  71. m_realtimeMetrics = true;
  72. }
  73. else if (m_realtimeMetrics)
  74. {
  75. m_realtimeMetrics = false;
  76. UpdateMetrics();
  77. }
  78. }
  79. void FileServer::ConnectionAdded(unsigned int connId, Connection* connection)
  80. {
  81. Q_UNUSED(connection);
  82. // Connection has not completed negotiation yet, register to be notified
  83. // when we know what platform is connected and map the @products@ alias then
  84. connect(connection, &Connection::AssetPlatformChanged, this, [this, connection]()
  85. {
  86. auto fileIO = m_fileIOs[connection->ConnectionId()];
  87. if ((fileIO) && (!connection->AssetPlatforms().isEmpty())) // when someone disconnects, the asset platform may be cleared before disconnect is set.
  88. {
  89. QDir projectCacheRoot;
  90. // Because the platform based aliases below can only be one platform at a time we need to prefer a single platform in case multiple listening platforms
  91. // exist on the same connection
  92. QString assetPlatform = connection->AssetPlatforms().first();
  93. if (!AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot))
  94. {
  95. projectCacheRoot = m_systemRoot;
  96. }
  97. else
  98. {
  99. projectCacheRoot = QDir(projectCacheRoot.absoluteFilePath(assetPlatform));
  100. }
  101. fileIO->SetAlias("@products@", projectCacheRoot.absolutePath().toUtf8().data());
  102. if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
  103. {
  104. AZ::IO::Path projectUserPath;
  105. settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath);
  106. fileIO->SetAlias("@user@", projectUserPath.c_str());
  107. AZ::IO::Path logUserPath = projectUserPath / "log";
  108. fileIO->SetAlias("@log@", logUserPath.c_str());
  109. }
  110. // note that the cache folder is auto-created only upon first use of VFS.
  111. }
  112. });
  113. std::shared_ptr<AZ::IO::FileIOBase> fileIO = std::make_shared<AZ::IO::LocalFileIO>();
  114. m_fileIOs[connId] = fileIO;
  115. }
  116. void FileServer::EnsureCacheFolderExists(int connId)
  117. {
  118. std::shared_ptr<AZ::IO::FileIOBase> fileIO = m_fileIOs[connId];
  119. if (!fileIO)
  120. {
  121. return;
  122. }
  123. if (fileIO->GetAlias("@usercache@"))
  124. {
  125. // already created.
  126. return;
  127. }
  128. AZ::IO::FixedMaxPath cacheUserPath;
  129. auto settingsRegistry = AZ::SettingsRegistry::Get();
  130. if (settingsRegistry->Get(cacheUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath))
  131. {
  132. cacheUserPath /= "Cache";
  133. }
  134. auto cacheDir = QString::fromUtf8(cacheUserPath.c_str(), aznumeric_cast<int>(cacheUserPath.Native().size()));
  135. cacheDir = QDir::toNativeSeparators(cacheDir);
  136. // the Cache-dir is special in that we don't allow sharing of cache dirs for multiple running
  137. // apps of the same platform at the same time.
  138. // we do this through the use of lock-files. Do not use QLockFile as QLockFile can't be shared
  139. // with instances of lockfiles created through other means (such as the game itself running without VFS)
  140. #if defined(AZ_PLATFORM_WINDOWS)
  141. // todo: Future platforms such as MAC will need to use flock or NS to establish locks on folders
  142. // note that if we DO support file locking we must ALWAYS create and lock the lock file
  143. int attemptNumber = 0;
  144. const int maxAttempts = 16;
  145. QString originalPath = cacheDir;
  146. while (attemptNumber < maxAttempts)
  147. {
  148. cacheDir = originalPath;
  149. if (attemptNumber != 0)
  150. {
  151. cacheDir = QString("%1%2").arg(originalPath).arg(attemptNumber);
  152. }
  153. else
  154. {
  155. cacheDir = originalPath;
  156. }
  157. ++attemptNumber; // do this here so we don't forget
  158. QDir checkDir(cacheDir);
  159. checkDir.mkpath(".");
  160. // if the directory already exists, check for locked file
  161. QString finalPath = QDir(cacheDir).absoluteFilePath("lockfile.txt");
  162. // lock the file!
  163. // cannot use QLockFile, it depends on everyone else which might lock the file also using QLockFile
  164. // and actually cares about the files contents (your pid)
  165. // note, the zero here after GENERIC_READ|GENERIC_WRITE indicates no share access at all!
  166. std::wstring winFriendly = finalPath.toStdWString();
  167. HANDLE lockHandle = CreateFileW(winFriendly.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0);
  168. if (lockHandle != INVALID_HANDLE_VALUE)
  169. {
  170. m_locks[connId] = lockHandle;
  171. break;
  172. }
  173. }
  174. if (attemptNumber >= maxAttempts)
  175. {
  176. // do the best we can.
  177. AZ_Warning("File Server", false, "Unable to establish a cache folder after %i attempts, using %s", attemptNumber, cacheDir.toUtf8().data());
  178. cacheDir = originalPath;
  179. }
  180. #endif
  181. fileIO->SetAlias("@usercache@", cacheDir.toUtf8().data());
  182. }
  183. void FileServer::ConnectionRemoved(unsigned int connId)
  184. {
  185. #if defined(AZ_PLATFORM_WINDOWS)
  186. auto it = m_locks.find(connId);
  187. if (it != m_locks.end())
  188. {
  189. if (it.value() != INVALID_HANDLE_VALUE)
  190. {
  191. CloseHandle(it.value());
  192. }
  193. m_locks.erase(it);
  194. }
  195. #endif
  196. m_fileIOs.remove(connId);
  197. }
  198. void FileServer::UpdateMetrics()
  199. {
  200. if (!m_realtimeMetrics)
  201. {
  202. //update server metrics
  203. Q_EMIT NumOpenRequestsChanged();
  204. Q_EMIT NumCloseRequestsChanged();
  205. Q_EMIT NumOpenedChanged();
  206. Q_EMIT NumClosedChanged();
  207. Q_EMIT NumReadRequestsChanged();
  208. Q_EMIT NumWriteRequestsChanged();
  209. Q_EMIT NumSeekRequestsChanged();
  210. Q_EMIT NumTellRequestsChanged();
  211. Q_EMIT NumIsReadOnlyRequestsChanged();
  212. Q_EMIT NumIsDirectoryRequestsChanged();
  213. Q_EMIT NumSizeRequestsChanged();
  214. Q_EMIT NumModificationTimeRequestsChanged();
  215. Q_EMIT NumExistsRequestsChanged();
  216. Q_EMIT NumFlushRequestsChanged();
  217. Q_EMIT NumCreatePathRequestsChanged();
  218. Q_EMIT NumDestroyPathRequestsChanged();
  219. Q_EMIT NumRemoveRequestsChanged();
  220. Q_EMIT NumCopyRequestsChanged();
  221. Q_EMIT NumRenameRequestsChanged();
  222. Q_EMIT NumFindFileNamesRequestsChanged();
  223. Q_EMIT BytesReadChanged();
  224. Q_EMIT BytesWrittenChanged();
  225. Q_EMIT BytesSentChanged();
  226. Q_EMIT BytesReceivedChanged();
  227. Q_EMIT NumOpenFilesChanged();
  228. //update connections metrics
  229. Q_EMIT UpdateConnectionMetrics();
  230. //schedule another update one second from now
  231. QTimer::singleShot(1000, this, SLOT(UpdateMetrics()));
  232. }
  233. }
  234. template <class R>
  235. inline void FileServer::Send(unsigned int connId, unsigned int serial, const R& response)
  236. {
  237. size_t bytesSent;
  238. AssetProcessor::ConnectionBus::EventResult(bytesSent, connId, &AssetProcessor::ConnectionBus::Events::SendResponse, serial, response);
  239. m_bytesSent += bytesSent;
  240. AddBytesSent(connId, bytesSent, m_realtimeMetrics);
  241. }
  242. template <class R>
  243. inline bool FileServer::Recv(unsigned int connId, QByteArray payload, R& request)
  244. {
  245. bool readFromStream = AZ::Utils::LoadObjectFromBufferInPlace(payload.data(), payload.size(), request);
  246. AZ_Assert(readFromStream, "FileServer::Recv: Could not deserialize from stream");
  247. if (readFromStream)
  248. {
  249. m_bytesReceived += payload.size();
  250. AddBytesReceived(connId, payload.size(), m_realtimeMetrics);
  251. return true;
  252. }
  253. return false;
  254. }
  255. void FileServer::ProcessOpenRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  256. {
  257. EnsureCacheFolderExists(connId);
  258. m_numOpenRequests++;
  259. //get the request
  260. FileOpenRequest request;
  261. if (!Recv(connId, payload, request))
  262. {
  263. AZ_Warning("FileServer", false, "ProcessOpenRequest: unable to read request");
  264. // send a failure response
  265. FileOpenResponse response(AZ::IO::InvalidHandle, static_cast<uint32_t>(ResultCode::Error));
  266. Send(connId, serial, response);
  267. }
  268. const char* filePath = request.m_filePath.c_str();
  269. AZ::IO::OpenMode mode = static_cast<AZ::IO::OpenMode>(request.m_mode);
  270. AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
  271. auto fileIO = m_fileIOs[connId];
  272. RecordFileOp(fileIO.get(), "OPEN", filePath, (((mode& AZ::IO::OpenMode::ModeWrite) != AZ::IO::OpenMode::Invalid) ? "for write" : "for read"));
  273. AZ::IO::Result res = fileIO->Open(filePath, mode, fileHandle);
  274. if (res)
  275. {
  276. m_numOpenFiles++;
  277. m_numOpened++;
  278. }
  279. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  280. FileOpenResponse response(fileHandle, resultCode);
  281. Send(connId, serial, response);
  282. AddOpenRequest(connId, m_realtimeMetrics);
  283. if (res)
  284. {
  285. AddOpened(connId, m_realtimeMetrics);
  286. }
  287. if (m_realtimeMetrics)
  288. {
  289. Q_EMIT BytesSentChanged();
  290. Q_EMIT NumOpenRequestsChanged();
  291. Q_EMIT BytesReceivedChanged();
  292. Q_EMIT NumOpenFilesChanged();
  293. Q_EMIT NumOpenedChanged();
  294. }
  295. }
  296. void FileServer::ProcessCloseRequest(unsigned int connId, unsigned int, unsigned int, QByteArray payload)
  297. {
  298. m_numCloseRequests++;
  299. //get the request
  300. FileCloseRequest request;
  301. if (!Recv(connId, payload, request))
  302. {
  303. AZ_Error("FileServer", false, "Failed to deserialize FileCloseRequest for connection %u", connId);
  304. return;
  305. }
  306. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  307. auto fileIO = m_fileIOs[connId];
  308. RecordFileOp(fileIO.get(), "CLOSE", fileHandle, nullptr);
  309. AZ::IO::Result res = fileIO->Close(fileHandle);
  310. if (res)
  311. {
  312. m_numOpenFiles--;
  313. m_numClosed++;
  314. AddClosed(connId, m_realtimeMetrics);
  315. }
  316. AddCloseRequest(connId, m_realtimeMetrics);
  317. if (m_realtimeMetrics)
  318. {
  319. Q_EMIT NumCloseRequestsChanged();
  320. Q_EMIT BytesReceivedChanged();
  321. Q_EMIT NumOpenFilesChanged();
  322. Q_EMIT NumClosedChanged();
  323. }
  324. }
  325. void FileServer::ProcessReadRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  326. {
  327. m_numReadRequests++;
  328. //get the request
  329. FileReadRequest request;
  330. if (!Recv(connId, payload, request))
  331. {
  332. FileReadResponse response(static_cast<uint32_t>(ResultCode::Error), nullptr, 0);
  333. Send(connId, serial, response);
  334. return;
  335. }
  336. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  337. uint64_t size = request.m_bytesToRead;
  338. bool failOnFewerRead = request.m_failOnFewerRead;
  339. FileReadResponse response;
  340. response.m_data.resize_no_construct(request.m_bytesToRead);
  341. AZ::u64 bytesRead = 0;
  342. auto fileIO = m_fileIOs[connId];
  343. AZStd::string moreInfo = AZStd::string::format("%llu bytes", static_cast<AZ::u64>(size));
  344. RecordFileOp(fileIO.get(), "READ", fileHandle, moreInfo.c_str());
  345. AZ::IO::Result res = fileIO->Read(fileHandle, response.m_data.data(), response.m_data.size(), failOnFewerRead, &bytesRead);
  346. response.m_resultCode = static_cast<uint32_t>(res.GetResultCode());
  347. m_bytesRead += bytesRead;
  348. //if the read resulted in any size other than requested resize to the read size
  349. if (response.m_data.size() != bytesRead)
  350. {
  351. response.m_data.resize(bytesRead);
  352. AddBytesRead(connId, bytesRead, m_realtimeMetrics);
  353. }
  354. Send(connId, serial, response);
  355. AddReadRequest(connId, m_realtimeMetrics);
  356. if (m_realtimeMetrics)
  357. {
  358. Q_EMIT BytesSentChanged();
  359. Q_EMIT NumReadRequestsChanged();
  360. Q_EMIT BytesReceivedChanged();
  361. Q_EMIT BytesReadChanged();
  362. }
  363. }
  364. void FileServer::ProcessWriteRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  365. {
  366. m_numWriteRequests++;
  367. FileWriteRequest request;
  368. if (!Recv(connId, payload, request))
  369. {
  370. FileWriteResponse response(static_cast<uint32_t>(ResultCode::Error), 0);
  371. Send(connId, serial, response);
  372. return;
  373. }
  374. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  375. AZ::u64 bytesWritten = 0;
  376. auto fileIO = m_fileIOs[connId];
  377. AZStd::string moreInfo = AZStd::string::format("%zu bytes", request.m_data.size());
  378. RecordFileOp(fileIO.get(), "WRITE", fileHandle, moreInfo.c_str());
  379. AZ::IO::Result res = fileIO->Write(fileHandle, request.m_data.data(), static_cast<uint64_t>(request.m_data.size()), &bytesWritten);
  380. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  381. if (res)
  382. {
  383. m_bytesWritten += bytesWritten;
  384. AddBytesWritten(connId, bytesWritten, m_realtimeMetrics);
  385. }
  386. // 0 serial means the other side doesn't care about the result
  387. if (serial != 0)
  388. {
  389. FileWriteResponse response(resultCode, bytesWritten);
  390. Send(connId, serial, response);
  391. AddWriteRequest(connId, m_realtimeMetrics);
  392. }
  393. if (m_realtimeMetrics)
  394. {
  395. Q_EMIT BytesSentChanged();
  396. Q_EMIT NumWriteRequestsChanged();
  397. Q_EMIT BytesReceivedChanged();
  398. Q_EMIT BytesWrittenChanged();
  399. }
  400. }
  401. void FileServer::ProcessTellRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  402. {
  403. m_numTellRequests++;
  404. FileTellRequest request;
  405. if (!Recv(connId, payload, request))
  406. {
  407. FileTellResponse response(static_cast<AZ::u32>(ResultCode::Error), 0);
  408. Send(connId, serial, response);
  409. return;
  410. }
  411. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  412. AZ::u64 offset = 0;
  413. auto fileIO = m_fileIOs[connId];
  414. AZStd::string moreInfo = AZStd::string::format("offset: %llu", offset);
  415. RecordFileOp(fileIO.get(), "TELL", fileHandle, moreInfo.c_str());
  416. AZ::IO::Result res = fileIO->Tell(fileHandle, offset);
  417. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  418. FileTellResponse response(resultCode, offset);
  419. Send(connId, serial, response);
  420. AddTellRequest(connId, m_realtimeMetrics);
  421. if (m_realtimeMetrics)
  422. {
  423. Q_EMIT BytesSentChanged();
  424. Q_EMIT NumTellRequestsChanged();
  425. Q_EMIT BytesReceivedChanged();
  426. }
  427. }
  428. void FileServer::ProcessSeekRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  429. {
  430. m_numSeekRequests++;
  431. FileSeekRequest request;
  432. if (!Recv(connId, payload, request))
  433. {
  434. FileSeekResponse response(static_cast<AZ::u32>(ResultCode::Error));
  435. Send(connId, serial, response);
  436. return;
  437. }
  438. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  439. AZ::IO::SeekType seekType = static_cast<AZ::IO::SeekType>(request.m_seekMode);
  440. int64_t offset = request.m_offset;
  441. auto fileIO = m_fileIOs[connId];
  442. AZStd::string moreInfo = AZStd::string::format("offset: %lld, mode: %d", static_cast<AZ::s64>(offset), static_cast<AZ::u32>(seekType));
  443. RecordFileOp(fileIO.get(), "SEEK", fileHandle, moreInfo.c_str());
  444. AZ::IO::Result res = fileIO->Seek(fileHandle, offset, seekType);
  445. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  446. FileSeekResponse response(resultCode);
  447. Send(connId, serial, response);
  448. AddSeekRequest(connId, m_realtimeMetrics);
  449. if (m_realtimeMetrics)
  450. {
  451. Q_EMIT BytesSentChanged();
  452. Q_EMIT NumSeekRequestsChanged();
  453. Q_EMIT BytesReceivedChanged();
  454. }
  455. }
  456. void FileServer::ProcessIsReadOnlyRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  457. {
  458. EnsureCacheFolderExists(connId);
  459. m_numIsReadOnlyRequests++;
  460. FileIsReadOnlyRequest request;
  461. if (!Recv(connId, payload, request))
  462. {
  463. FileIsReadOnlyResponse response(false);
  464. Send(connId, serial, response);
  465. return;
  466. }
  467. const char* filePath = request.m_filePath.c_str();
  468. auto fileIO = m_fileIOs[connId];
  469. RecordFileOp(fileIO.get(), "ISREADONLY", filePath, nullptr);
  470. bool isReadOnly = fileIO->IsReadOnly(filePath);
  471. FileIsReadOnlyResponse response(isReadOnly);
  472. Send(connId, serial, response);
  473. AddIsReadOnlyRequest(connId, m_realtimeMetrics);
  474. if (m_realtimeMetrics)
  475. {
  476. Q_EMIT BytesSentChanged();
  477. Q_EMIT NumIsReadOnlyRequestsChanged();
  478. Q_EMIT BytesReceivedChanged();
  479. }
  480. }
  481. void FileServer::ProcessIsDirectoryRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  482. {
  483. EnsureCacheFolderExists(connId);
  484. m_numIsDirectoryRequests++;
  485. PathIsDirectoryRequest request;
  486. if (!Recv(connId, payload, request))
  487. {
  488. PathIsDirectoryResponse response(false);
  489. Send(connId, serial, response);
  490. return;
  491. }
  492. const char* filePath = request.m_path.c_str();
  493. auto fileIO = m_fileIOs[connId];
  494. RecordFileOp(fileIO.get(), "ISDIR", filePath, nullptr);
  495. bool isDirectory = fileIO->IsDirectory(filePath);
  496. PathIsDirectoryResponse response(isDirectory);
  497. Send(connId, serial, response);
  498. AddIsDirectoryRequest(connId, m_realtimeMetrics);
  499. if (m_realtimeMetrics)
  500. {
  501. Q_EMIT BytesSentChanged();
  502. Q_EMIT NumIsDirectoryRequestsChanged();
  503. Q_EMIT BytesReceivedChanged();
  504. }
  505. }
  506. void FileServer::ProcessSizeRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  507. {
  508. EnsureCacheFolderExists(connId);
  509. m_numSizeRequests++;
  510. FileSizeRequest request;
  511. if (!Recv(connId, payload, request))
  512. {
  513. FileSizeResponse response(static_cast<AZ::u32>(ResultCode::Error), 0);
  514. Send(connId, serial, response);
  515. return;
  516. }
  517. const char* filePath = request.m_filePath.c_str();
  518. AZ::u64 size = 0;
  519. auto fileIO = m_fileIOs[connId];
  520. RecordFileOp(fileIO.get(), "SIZE", filePath, nullptr);
  521. AZ::IO::Result res = fileIO->Size(filePath, size);
  522. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  523. FileSizeResponse response(resultCode, size);
  524. Send(connId, serial, response);
  525. AddSizeRequest(connId, m_realtimeMetrics);
  526. if (m_realtimeMetrics)
  527. {
  528. Q_EMIT BytesSentChanged();
  529. Q_EMIT NumSizeRequestsChanged();
  530. Q_EMIT BytesReceivedChanged();
  531. }
  532. }
  533. void FileServer::ProcessModificationTimeRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  534. {
  535. EnsureCacheFolderExists(connId);
  536. m_numModificationTimeRequests++;
  537. FileModTimeRequest request;
  538. if (!Recv(connId, payload, request))
  539. {
  540. FileModTimeResponse response(0);
  541. Send(connId, serial, response);
  542. return;
  543. }
  544. const char* filePath = request.m_filePath.c_str();
  545. auto fileIO = m_fileIOs[connId];
  546. RecordFileOp(fileIO.get(), "MODTIME", filePath, nullptr);
  547. uint64_t modTime = fileIO->ModificationTime(filePath);
  548. FileModTimeResponse response(modTime);
  549. Send(connId, serial, response);
  550. AddModificationTimeRequest(connId, m_realtimeMetrics);
  551. if (m_realtimeMetrics)
  552. {
  553. Q_EMIT BytesSentChanged();
  554. Q_EMIT NumModificationTimeRequestsChanged();
  555. Q_EMIT BytesReceivedChanged();
  556. }
  557. }
  558. void FileServer::ProcessExistsRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  559. {
  560. EnsureCacheFolderExists(connId);
  561. m_numExistsRequests++;
  562. FileExistsRequest request;
  563. if (!Recv(connId, payload, request))
  564. {
  565. FileExistsResponse response(false);
  566. Send(connId, serial, response);
  567. return;
  568. }
  569. const char* filePath = request.m_filePath.c_str();
  570. auto fileIO = m_fileIOs[connId];
  571. RecordFileOp(fileIO.get(), "EXISTS", filePath, nullptr);
  572. bool exists = fileIO->Exists(filePath);
  573. FileExistsResponse response(exists);
  574. Send(connId, serial, response);
  575. AddExistsRequest(connId, m_realtimeMetrics);
  576. if (m_realtimeMetrics)
  577. {
  578. Q_EMIT BytesSentChanged();
  579. Q_EMIT NumExistsRequestsChanged();
  580. Q_EMIT BytesReceivedChanged();
  581. }
  582. }
  583. void FileServer::ProcessFlushRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  584. {
  585. m_numFlushRequests++;
  586. FileFlushRequest request;
  587. if (!Recv(connId, payload, request))
  588. {
  589. if (serial != 0)
  590. {
  591. FileFlushResponse response(static_cast<AZ::u32>(ResultCode::Error));
  592. Send(connId, serial, response);
  593. }
  594. return;
  595. }
  596. AZ::IO::HandleType fileHandle = request.m_fileHandle;
  597. auto fileIO = m_fileIOs[connId];
  598. RecordFileOp(fileIO.get(), "FLUSH", fileHandle, nullptr);
  599. AZ::IO::Result res = fileIO->Flush(fileHandle);
  600. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  601. if (serial != 0)
  602. {
  603. FileFlushResponse response(resultCode);
  604. Send(connId, serial, response);
  605. }
  606. AddFlushRequest(connId, m_realtimeMetrics);
  607. if (m_realtimeMetrics)
  608. {
  609. Q_EMIT BytesSentChanged();
  610. Q_EMIT NumFlushRequestsChanged();
  611. Q_EMIT BytesReceivedChanged();
  612. }
  613. }
  614. void FileServer::ProcessCreatePathRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  615. {
  616. EnsureCacheFolderExists(connId);
  617. m_numCreatePathRequests++;
  618. PathCreateRequest request;
  619. if (!Recv(connId, payload, request))
  620. {
  621. PathCreateResponse response(static_cast<AZ::u32>(ResultCode::Error));
  622. Send(connId, serial, response);
  623. return;
  624. }
  625. const char* filePath = request.m_path.c_str();
  626. auto fileIO = m_fileIOs[connId];
  627. RecordFileOp(fileIO.get(), "CREATEPATH", filePath, nullptr);
  628. AZ::IO::Result res = fileIO->CreatePath(filePath);
  629. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  630. PathCreateResponse response(resultCode);
  631. Send(connId, serial, response);
  632. AddCreatePathRequest(connId, m_realtimeMetrics);
  633. if (m_realtimeMetrics)
  634. {
  635. Q_EMIT BytesSentChanged();
  636. Q_EMIT NumCreatePathRequestsChanged();
  637. Q_EMIT BytesReceivedChanged();
  638. }
  639. }
  640. void FileServer::ProcessDestroyPathRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  641. {
  642. EnsureCacheFolderExists(connId);
  643. m_numDestroyPathRequests++;
  644. PathDestroyRequest request;
  645. if (!Recv(connId, payload, request))
  646. {
  647. PathDestroyResponse response(static_cast<AZ::u32>(ResultCode::Error));
  648. Send(connId, serial, response);
  649. return;
  650. }
  651. const char* filePath = request.m_path.c_str();
  652. auto fileIO = m_fileIOs[connId];
  653. RecordFileOp(fileIO.get(), "DESTROYPATH", filePath, nullptr);
  654. AZ::IO::Result res = fileIO->DestroyPath(filePath);
  655. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  656. PathDestroyResponse response(resultCode);
  657. Send(connId, serial, response);
  658. AddDestroyPathRequest(connId, m_realtimeMetrics);
  659. if (m_realtimeMetrics)
  660. {
  661. Q_EMIT BytesSentChanged();
  662. Q_EMIT NumDestroyPathRequestsChanged();
  663. Q_EMIT BytesReceivedChanged();
  664. }
  665. }
  666. void FileServer::ProcessRemoveRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  667. {
  668. EnsureCacheFolderExists(connId);
  669. m_numRemoveRequests++;
  670. FileRemoveRequest request;
  671. if (!Recv(connId, payload, request))
  672. {
  673. FileRemoveResponse response(static_cast<AZ::u32>(ResultCode::Error));
  674. Send(connId, serial, response);
  675. return;
  676. }
  677. const char* filePath = request.m_filePath.c_str();
  678. auto fileIO = m_fileIOs[connId];
  679. RecordFileOp(fileIO.get(), "REMOVE", filePath, nullptr);
  680. AZ::IO::Result res = fileIO->Remove(filePath);
  681. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  682. FileRemoveResponse response(resultCode);
  683. Send(connId, serial, response);
  684. AddRemoveRequest(connId, m_realtimeMetrics);
  685. if (m_realtimeMetrics)
  686. {
  687. Q_EMIT BytesSentChanged();
  688. Q_EMIT NumRemoveRequestsChanged();
  689. Q_EMIT BytesReceivedChanged();
  690. }
  691. }
  692. void FileServer::ProcessCopyRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  693. {
  694. EnsureCacheFolderExists(connId);
  695. m_numCopyRequests++;
  696. FileCopyRequest request;
  697. if (!Recv(connId, payload, request))
  698. {
  699. FileCopyResponse response(static_cast<AZ::u32>(ResultCode::Error));
  700. Send(connId, serial, response);
  701. return;
  702. }
  703. const char* sourcePath = request.m_srcPath.c_str();
  704. const char* destinationPath = request.m_destPath.c_str();
  705. auto fileIO = m_fileIOs[connId];
  706. RecordFileOp(fileIO.get(), "COPY", sourcePath, destinationPath, nullptr);
  707. AZ::IO::Result res = fileIO->Copy(sourcePath, destinationPath);
  708. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  709. FileCopyResponse response(resultCode);
  710. Send(connId, serial, response);
  711. AddCopyRequest(connId, m_realtimeMetrics);
  712. if (m_realtimeMetrics)
  713. {
  714. Q_EMIT BytesSentChanged();
  715. Q_EMIT NumCopyRequestsChanged();
  716. Q_EMIT BytesReceivedChanged();
  717. }
  718. }
  719. void FileServer::ProcessRenameRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  720. {
  721. EnsureCacheFolderExists(connId);
  722. m_numRenameRequests++;
  723. FileRenameRequest request;
  724. if (!Recv(connId, payload, request))
  725. {
  726. FileRenameResponse response(static_cast<AZ::u32>(ResultCode::Error));
  727. Send(connId, serial, response);
  728. return;
  729. }
  730. const char* sourcePath = request.m_srcPath.c_str();
  731. const char* destinationPath = request.m_destPath.c_str();
  732. auto fileIO = m_fileIOs[connId];
  733. RecordFileOp(fileIO.get(), "RENAME", sourcePath, destinationPath, nullptr);
  734. AZ::IO::Result res = fileIO->Rename(sourcePath, destinationPath);
  735. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  736. FileRenameResponse response(resultCode);
  737. Send(connId, serial, response);
  738. AddRenameRequest(connId, m_realtimeMetrics);
  739. if (m_realtimeMetrics)
  740. {
  741. Q_EMIT BytesSentChanged();
  742. Q_EMIT NumRenameRequestsChanged();
  743. Q_EMIT BytesReceivedChanged();
  744. }
  745. }
  746. void FileServer::ProcessFindFileNamesRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  747. {
  748. EnsureCacheFolderExists(connId);
  749. m_numFindFileNamesRequests++;
  750. FindFilesRequest request;
  751. if (!Recv(connId, payload, request))
  752. {
  753. FindFilesResponse response(static_cast<AZ::u32>(ResultCode::Error));
  754. Send(connId, serial, response);
  755. return;
  756. }
  757. const char* filePath = request.m_path.c_str();
  758. const char* filter = request.m_filter.c_str();
  759. FindFilesResponse::FileList fileNames;
  760. auto fileIO = m_fileIOs[connId];
  761. AZStd::string moreInfo = AZStd::string::format("filter: %s", filter);
  762. RecordFileOp(fileIO.get(), "FINDFILES", filePath, moreInfo.c_str());
  763. AZ::IO::Result res = fileIO->FindFiles(filePath, filter,
  764. [&fileNames](const char* fileName)
  765. {
  766. fileNames.push_back(fileName);
  767. return true;
  768. });
  769. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  770. FindFilesResponse response(resultCode, fileNames);
  771. Send(connId, serial, response);
  772. AddFindFileNamesRequest(connId, m_realtimeMetrics);
  773. if (m_realtimeMetrics)
  774. {
  775. Q_EMIT BytesSentChanged();
  776. Q_EMIT NumFindFileNamesRequestsChanged();
  777. Q_EMIT BytesReceivedChanged();
  778. }
  779. }
  780. void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsigned int serial, QByteArray payload)
  781. {
  782. EnsureCacheFolderExists(connId);
  783. FileTreeRequest request;
  784. if (!Recv(connId, payload, request))
  785. {
  786. FileTreeResponse response(static_cast<AZ::u32>(ResultCode::Error));
  787. Send(connId, serial, response);
  788. return;
  789. }
  790. auto fileIO = m_fileIOs[connId];
  791. FileTreeResponse::FileList files;
  792. FileTreeResponse::FolderList folders;
  793. AZStd::vector<AZ::OSString> untestedFolders;
  794. if (fileIO->IsDirectory("@products@"))
  795. {
  796. folders.push_back("@products@");
  797. untestedFolders.push_back("@products@");
  798. }
  799. if (fileIO->IsDirectory("@usercache@"))
  800. {
  801. folders.push_back("@usercache@");
  802. untestedFolders.push_back("@usercache@");
  803. }
  804. if (fileIO->IsDirectory("@user@"))
  805. {
  806. folders.push_back("@user@");
  807. untestedFolders.push_back("@user@");
  808. }
  809. if (fileIO->IsDirectory("@log@"))
  810. {
  811. folders.push_back("@log@");
  812. untestedFolders.push_back("@log@");
  813. }
  814. AZ::IO::Result res = ResultCode::Success;
  815. while (untestedFolders.size() && res == ResultCode::Success)
  816. {
  817. AZ::OSString folderName = untestedFolders.back();
  818. untestedFolders.pop_back();
  819. res = fileIO->FindFiles(folderName.c_str(), "*",
  820. [&](const char* fileName)
  821. {
  822. if (fileIO->IsDirectory(fileName))
  823. {
  824. folders.push_back(fileName);
  825. untestedFolders.push_back(fileName);
  826. }
  827. else
  828. {
  829. files.push_back(fileName);
  830. }
  831. return true;
  832. }
  833. );
  834. }
  835. if (res == ResultCode::Error)
  836. {
  837. files.clear();
  838. folders.clear();
  839. }
  840. uint32_t resultCode = static_cast<uint32_t>(res.GetResultCode());
  841. FileTreeResponse response(resultCode, files, folders);
  842. Send(connId, serial, response);
  843. }
  844. void FileServer::RecordFileOp(AZ::IO::FileIOBase* fileIO, const char* op, const AZ::IO::HandleType& fileHandle, const char* moreInfo)
  845. {
  846. (void)fileIO;
  847. (void)op;
  848. (void)fileHandle;
  849. (void)moreInfo;
  850. #ifdef VERBOSE_FILE_OPS
  851. char filename[MAX_PATH];
  852. if (fileIO->GetFilename(fileHandle, filename, sizeof(filename)))
  853. {
  854. RecordFileOp(fileIO, op, filename, moreInfo);
  855. }
  856. #endif
  857. }
  858. void FileServer::RecordFileOp(AZ::IO::FileIOBase* fileIO, const char* op, const char* filePath, const char* moreInfo)
  859. {
  860. (void)fileIO;
  861. (void)op;
  862. (void)filePath;
  863. (void)moreInfo;
  864. #ifdef VERBOSE_FILE_OPS
  865. AZ_TracePrintf(AssetProcessor::DebugChannel, "FileServer Operation : %s, filePath : %s, moreInfo: %s.\n", op, filePath, moreInfo ? moreInfo : "");
  866. #endif
  867. }
  868. void FileServer::RecordFileOp(AZ::IO::FileIOBase* fileIO, const char* op, const char* sourceFile, const char* destFile, const char* moreInfo)
  869. {
  870. (void)fileIO;
  871. (void)op;
  872. (void)sourceFile;
  873. (void)destFile;
  874. (void)moreInfo;
  875. #ifdef VERBOSE_FILE_OPS
  876. AZ_TracePrintf(AssetProcessor::DebugChannel, "FileServer Operation : %s, sourceFile : %s, destFile : %s, moreInfo: %s.\n", op, sourceFile, destFile, moreInfo ? moreInfo : "");
  877. #endif
  878. }