bool FStreamingNetworkPlatformFile::DeleteDirectoryRecursively(const TCHAR* Directory) { FScopeLock ScopeLock(&SynchronizationObject); FStreamingNetworkFileArchive Payload(NFS_Messages::DeleteDirectoryRecursively); FString RelativeDirectory = Directory; MakeStandardNetworkFilename(RelativeDirectory); Payload << RelativeDirectory; // perform a local operation FArrayReader Response; if (SendPayloadAndReceiveResponse(Payload, Response) == false) { return false; } bool bSuccess = 0; Response << bSuccess; return bSuccess; }
void FStreamingNetworkPlatformFile::GetFileInfo(const TCHAR* Filename, FFileInfo& Info) { FScopeLock ScopeLock(&SynchronizationObject); FString RelativeFilename = Filename; MakeStandardNetworkFilename(RelativeFilename); if (!CachedFileInfo.Contains(RelativeFilename)) { FStreamingNetworkFileArchive Payload(NFS_Messages::GetFileInfo); Payload << const_cast<FString&>(RelativeFilename); // if (RelativeFilename == TEXT("../../../UDKGame/Content/Maps/GDC12_Ice/GDC_2012_Throne_Cave.uasset")) // { // Info.ReadOnly = true; // } // Send the filename over FArrayReader Response; if (SendPayloadAndReceiveResponse(Payload, Response) == false) { return; } // Get info from the response Response << Info.FileExists; Response << Info.ReadOnly; Response << Info.Size; Response << Info.TimeStamp; Response << Info.AccessTimeStamp; CachedFileInfo.Add(RelativeFilename, Info); } else { Info = *(CachedFileInfo.Find(RelativeFilename)); } }
bool FNetworkPlatformFile::InitializeInternal(IPlatformFile* Inner, const TCHAR* HostIP) { // This platform file requires an inner. check(Inner != NULL); InnerPlatformFile = Inner; if (HostIP == NULL) { UE_LOG(LogNetworkPlatformFile, Error, TEXT("No Host IP specified in the commandline.")); bIsUsable = false; return false; } // Save and Intermediate directories are always local LocalDirectories.Add(FPaths::EngineDir() / TEXT("Binaries")); LocalDirectories.Add(FPaths::EngineIntermediateDir()); LocalDirectories.Add(FPaths::GameDir() / TEXT("Binaries")); LocalDirectories.Add(FPaths::GameIntermediateDir()); LocalDirectories.Add(FPaths::GameSavedDir() / TEXT("Backup")); LocalDirectories.Add(FPaths::GameSavedDir() / TEXT("Config")); LocalDirectories.Add(FPaths::GameSavedDir() / TEXT("Logs")); LocalDirectories.Add(FPaths::GameSavedDir() / TEXT("Sandboxes")); InnerPlatformFile->GetLowerLevel()->AddLocalDirectories(LocalDirectories); FNetworkFileArchive Payload(NFS_Messages::Heartbeat); FArrayReader Out; if (!SendPayloadAndReceiveResponse(Payload,Out)) bIsUsable = true; // lets see we can test whether the server is up. if (Out.Num()) { FCommandLine::AddToSubprocessCommandline( *FString::Printf( TEXT("-FileHostIP=%s"), HostIP ) ); bIsUsable = true; } return bIsUsable; }
bool FStreamingNetworkPlatformFile::CopyFile(const TCHAR* To, const TCHAR* From, EPlatformFileRead ReadFlags, EPlatformFileWrite WriteFlags) { FScopeLock ScopeLock(&SynchronizationObject); FStreamingNetworkFileArchive Payload(NFS_Messages::CopyFile); FString RelativeTo = To; MakeStandardNetworkFilename(RelativeTo); FString RelativeFrom = From; MakeStandardNetworkFilename(RelativeFrom); Payload << RelativeTo; Payload << RelativeFrom; // perform a local operation FArrayReader Response; if (SendPayloadAndReceiveResponse(Payload, Response) == false) { return false; } bool bSuccess = 0; Response << bSuccess; return bSuccess; }
bool FStreamingNetworkPlatformFile::SendWriteMessage(uint64 HandleId, const uint8* Source, int64 BytesToWrite) { FScopeLock ScopeLock(&SynchronizationObject); // Send the filename over. FStreamingNetworkFileArchive Payload(NFS_Messages::Write); Payload << HandleId; // Send the data over Payload << BytesToWrite; Payload.Serialize(const_cast<uint8*>(Source), BytesToWrite); FArrayReader Response; if (SendPayloadAndReceiveResponse(Payload, Response) == false) { return false; } // Get the number of bytes the server wrote. int64 ServerBytesWritten = 0; Response << ServerBytesWritten; return (ServerBytesWritten == BytesToWrite); }
bool FStreamingNetworkPlatformFile::SetReadOnly(const TCHAR* Filename, bool bNewReadOnlyValue) { FScopeLock ScopeLock(&SynchronizationObject); FStreamingNetworkFileArchive Payload(NFS_Messages::SetReadOnly); FString RelativeFilename = Filename; MakeStandardNetworkFilename(RelativeFilename); Payload << RelativeFilename; Payload << bNewReadOnlyValue; // perform a local operation FArrayReader Response; if (SendPayloadAndReceiveResponse(Payload, Response) == false) { return false; } bool bSuccess = 0; Response << bSuccess; return bSuccess; }
bool FHTTPTransport::Initialize(const TCHAR* InHostIp) { // parse out the format FString HostIp = InHostIp; // make sure that we have the correct protcol ensure( HostIp.RemoveFromStart("http://") ); // check if we have specified the port also if ( HostIp.Contains(":") == false) { // no port put the default one on HostIp = FString::Printf(TEXT("%s:%d"), *HostIp, (int)(DEFAULT_HTTP_FILE_SERVING_PORT) ); } // make sure that our string is again correctly formated HostIp = FString::Printf(TEXT("http://%s"),*HostIp); FCString::Sprintf(Url, *HostIp); #if !PLATFORM_HTML5 HttpRequest = FHttpModule::Get().CreateRequest(); HttpRequest->SetURL(Url); #endif #if PLATFORM_HTML5_WIN32 HTML5Win32::NFSHttp::Init(TCHAR_TO_ANSI(Url)); #endif #if PLATFORM_HTML5_BROWSER emscripten_log(EM_LOG_CONSOLE , "Unreal File Server URL : %s ", TCHAR_TO_ANSI(Url)); #endif TArray<uint8> In,Out; bool RetResult = SendPayloadAndReceiveResponse(In,Out); return RetResult; }
void FNetworkPlatformFile::EnsureFileIsLocal(const FString& Filename) { double StartTime; float ThisTime; StartTime = FPlatformTime::Seconds(); { FScopeLock ScopeLock(&SynchronizationObject); // have we already cached this file? if (CachedLocalFiles.Find(Filename) != NULL) { return; } } if ( FinishedAsyncNetworkReadUnsolicitedFiles ) { delete FinishedAsyncNetworkReadUnsolicitedFiles; // wait here for any async unsolicited files to finish reading being read from the network FinishedAsyncNetworkReadUnsolicitedFiles = NULL; } if( FinishedAsyncWriteUnsolicitedFiles) { delete FinishedAsyncWriteUnsolicitedFiles; // wait here for any async unsolicited files to finish writing to disk FinishedAsyncWriteUnsolicitedFiles = NULL; } FScopeLock ScopeLock(&SynchronizationObject); ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Lock and wait for old async writes %6.2fms"), ThisTime); // have we already cached this file? (test again, since some other thread might have done this between waits) if (CachedLocalFiles.Find(Filename) != NULL) { return; } // even if an error occurs later, we still want to remember not to try again CachedLocalFiles.Add(Filename); StartTime = FPlatformTime::Seconds(); // no need to read it if it already exists // @todo: Handshake with server to delete files that are out of date if (InnerPlatformFile->FileExists(*Filename)) { return; } ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Check for local file %6.2fms - %s"), ThisTime, *Filename); // this is a bit of a waste if we aren't doing cook on the fly, but we assume missing asset files are relatively rare bool bIsCookable = GConfig && GConfig->IsReadyForUse() && FPackageName::IsPackageExtension(*FPaths::GetExtension(Filename, true)); // we only copy files that actually exist on the server, can greatly reduce network traffic for, say, // the INT file each package tries to load if (!bIsCookable && ServerFiles.FindFile(Filename) == NULL) { // Uncomment this to have the server file list dumped // the first time a file requested is not found. #if 0 static bool sb_DumpedServer = false; if (sb_DumpedServer == false) { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Dumping server files... %s not found\n"), *Filename); for (TMap<FString, FServerTOC::FDirectory*>::TIterator ServerDumpIt(ServerFiles.Directories); ServerDumpIt; ++ServerDumpIt) { FServerTOC::FDirectory& Directory = *ServerDumpIt.Value(); for (FServerTOC::FDirectory::TIterator DirDumpIt(Directory); DirDumpIt; ++DirDumpIt) { FPlatformMisc::LowLevelOutputDebugStringf(TEXT("%10s - %s\n"), *(DirDumpIt.Value().ToString()), *(DirDumpIt.Key())); } } sb_DumpedServer = true; } #endif return; } // send the filename over (cast away const here because we know this << will not modify the string) FNetworkFileArchive Payload(NFS_Messages::SyncFile); Payload << (FString&)Filename; StartTime = FPlatformTime::Seconds(); // allocate array reader on the heap, because the SyncWriteFile function will delete it FArrayReader Response; if (!SendPayloadAndReceiveResponse(Payload, Response)) { UE_LOG(LogNetworkPlatformFile, Fatal, TEXT("Receive failure!")); return; } ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Send and receive %6.2fms"), ThisTime); StartTime = FPlatformTime::Seconds(); FString ReplyFile; Response << ReplyFile; ConvertServerFilenameToClientFilename(ReplyFile); check(ReplyFile == Filename); // get the server file timestamp FDateTime ServerTimeStamp; Response << ServerTimeStamp; // write the file in chunks, synchronously SyncWriteFile(&Response, ReplyFile, ServerTimeStamp, *InnerPlatformFile); int32 NumUnsolictedFiles; Response << NumUnsolictedFiles; if (NumUnsolictedFiles) { check( FinishedAsyncNetworkReadUnsolicitedFiles == NULL ); check( FinishedAsyncWriteUnsolicitedFiles == NULL ); FinishedAsyncNetworkReadUnsolicitedFiles = new FScopedEvent; FinishedAsyncWriteUnsolicitedFiles = new FScopedEvent; AsyncReadUnsolicitedFiles(NumUnsolictedFiles, *this, *InnerPlatformFile, ServerEngineDir, ServerGameDir, FinishedAsyncNetworkReadUnsolicitedFiles, FinishedAsyncWriteUnsolicitedFiles); } ThisTime = 1000.0f * float(FPlatformTime::Seconds() - StartTime); //UE_LOG(LogNetworkPlatformFile, Display, TEXT("Write file to local %6.2fms"), ThisTime); }
void FNetworkPlatformFile::InitializeAfterSetActive() { double NetworkFileStartupTime = 0.0; { SCOPE_SECONDS_COUNTER(NetworkFileStartupTime); // send the filenames and timestamps to the server FNetworkFileArchive Payload(NFS_Messages::GetFileList); FillGetFileList(Payload, false); // send the directories over, and wait for a response FArrayReader Response; if (!SendPayloadAndReceiveResponse(Payload, Response)) { delete Transport; return; } else { // receive the cooked version information int32 ServerPackageVersion = 0; int32 ServerPackageLicenseeVersion = 0; ProcessServerInitialResponse(Response, ServerPackageVersion, ServerPackageLicenseeVersion); // receive a list of the cache files and their timestamps TMap<FString, FDateTime> ServerCachedFiles; Response << ServerCachedFiles; bool bDeleteAllFiles = true; // Check the stored cooked version FString CookedVersionFile = FPaths::GeneratedConfigDir() / TEXT("CookedVersion.txt"); if (InnerPlatformFile->FileExists(*CookedVersionFile) == true) { IFileHandle* FileHandle = InnerPlatformFile->OpenRead(*CookedVersionFile); if (FileHandle != NULL) { int32 StoredPackageCookedVersion; int32 StoredPackageCookedLicenseeVersion; if (FileHandle->Read((uint8*)&StoredPackageCookedVersion, sizeof(int32)) == true) { if (FileHandle->Read((uint8*)&StoredPackageCookedLicenseeVersion, sizeof(int32)) == true) { if ((ServerPackageVersion == StoredPackageCookedVersion) && (ServerPackageLicenseeVersion == StoredPackageCookedLicenseeVersion)) { bDeleteAllFiles = false; } else { UE_LOG(LogNetworkPlatformFile, Display, TEXT("Engine version mismatch: Server %d.%d, Stored %d.%d\n"), ServerPackageVersion, ServerPackageLicenseeVersion, StoredPackageCookedVersion, StoredPackageCookedLicenseeVersion); } } } delete FileHandle; } } else { UE_LOG(LogNetworkPlatformFile, Display, TEXT("Cooked version file missing: %s\n"), *CookedVersionFile); } if (bDeleteAllFiles == true) { // Make sure the config file exists... InnerPlatformFile->CreateDirectoryTree(*(FPaths::GeneratedConfigDir())); // Update the cooked version file IFileHandle* FileHandle = InnerPlatformFile->OpenWrite(*CookedVersionFile); if (FileHandle != NULL) { FileHandle->Write((const uint8*)&ServerPackageVersion, sizeof(int32)); FileHandle->Write((const uint8*)&ServerPackageLicenseeVersion, sizeof(int32)); delete FileHandle; } } // list of directories to skip TArray<FString> DirectoriesToSkip; TArray<FString> DirectoriesToNotRecurse; // use the timestamp grabbing visitor to get all the content times FLocalTimestampDirectoryVisitor Visitor(*InnerPlatformFile, DirectoriesToSkip, DirectoriesToNotRecurse, false); TArray<FString> RootContentPaths; FPackageName::QueryRootContentPaths( RootContentPaths ); for( TArray<FString>::TConstIterator RootPathIt( RootContentPaths ); RootPathIt; ++RootPathIt ) { const FString& RootPath = *RootPathIt; const FString& ContentFolder = FPackageName::LongPackageNameToFilename(RootPath); InnerPlatformFile->IterateDirectory( *ContentFolder, Visitor); } // delete out of date files using the server cached files for (TMap<FString, FDateTime>::TIterator It(ServerCachedFiles); It; ++It) { bool bDeleteFile = bDeleteAllFiles; FString ServerFile = It.Key(); // Convert the filename to the client version ConvertServerFilenameToClientFilename(ServerFile); // Set it in the visitor file times list Visitor.FileTimes.Add(ServerFile, FDateTime::MinValue()); if (bDeleteFile == false) { // Check the time stamps... // get local time FDateTime LocalTime = InnerPlatformFile->GetTimeStamp(*ServerFile); // If local time == MinValue than the file does not exist in the cache. if (LocalTime != FDateTime::MinValue()) { FDateTime ServerTime = It.Value(); // delete if out of date // We will use 1.0 second as the tolerance to cover any platform differences in resolution FTimespan TimeDiff = LocalTime - ServerTime; double TimeDiffInSeconds = TimeDiff.GetTotalSeconds(); bDeleteFile = (TimeDiffInSeconds > 1.0) || (TimeDiffInSeconds < -1.0); if (bDeleteFile == true) { if (InnerPlatformFile->FileExists(*ServerFile) == true) { UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: TimeDiff %5.3f, %s"), TimeDiffInSeconds, *It.Key()); } else { // It's a directory bDeleteFile = false; } } } } if (bDeleteFile == true) { InnerPlatformFile->DeleteFile(*ServerFile); } } // Any content files we have locally that were not cached, delete them for (TMap<FString, FDateTime>::TIterator It(Visitor.FileTimes); It; ++It) { if (It.Value() != FDateTime::MinValue()) { // This was *not* found in the server file list... delete it UE_LOG(LogNetworkPlatformFile, Display, TEXT("Deleting cached file: %s"), *It.Key()); InnerPlatformFile->DeleteFile(*It.Key()); } } // make sure we can sync a file FString TestSyncFile = FPaths::Combine(*(FPaths::EngineDir()), TEXT("Config/BaseEngine.ini")); InnerPlatformFile->SetReadOnly(*TestSyncFile, false); InnerPlatformFile->DeleteFile(*TestSyncFile); if (InnerPlatformFile->FileExists(*TestSyncFile)) { UE_LOG(LogNetworkPlatformFile, Fatal, TEXT("Could not delete file sync test file %s."), *TestSyncFile); } EnsureFileIsLocal(TestSyncFile); if (!InnerPlatformFile->FileExists(*TestSyncFile) || InnerPlatformFile->FileSize(*TestSyncFile) < 1) { UE_LOG(LogNetworkPlatformFile, Fatal, TEXT("Could not sync test file %s."), *TestSyncFile); } } } FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Network file startup time: %5.3f seconds\n"), NetworkFileStartupTime); }