Skip to content
Snippets Groups Projects
Select Git revision
  • 18c1b762860a1678902a03b6efa61578cd943f52
  • master default protected
  • release
  • develop
4 results

streamlit_app.py

Blame
  • VAServerLauncher.cpp 10.18 KiB
    #include "VAServerLauncher.h"
    
    #include <string>
    
    #include "Misc/FileHelper.h"
    #include "SocketSubsystem.h"
    #include "GeneralProjectSettings.h"
    
    #include "Utility/VirtualRealityUtilities.h"
    
    #include "VAUtils.h"
    #include "VASettings.h"
    #include "VAPlugin.h"
    
    
    bool FVAServerLauncher::RemoteStartVAServer(const FString& Host, const int Port, const FString& VersionName)
    {
    	if (!UVirtualRealityUtilities::IsMaster())
    	{
    		return false;
    	}
    
    	if (VAServerLauncherSocket != nullptr)
    	{
    		return true;
    	}
    
    	FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Try to remotely start the VAServer at address " + 
    		Host + ":" + FString::FromInt(Port) + " for version: " + VersionName, false);
    
    
    	//Connect
    	const FString SocketName(TEXT("VAServerStarterConnection"));
    	VAServerLauncherSocket = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(
    		NAME_Stream, SocketName, false);
    
    	TSharedPtr<FInternetAddr> InternetAddress = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
    
    	bool bValidIP;
    	InternetAddress->SetIp(*Host, bValidIP);
    	InternetAddress->SetPort(Port);
    
    	if (!bValidIP)
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: The Ip cannot be parsed!", true);
    		return false;
    	}
    
    	if (VAServerLauncherSocket == nullptr || !VAServerLauncherSocket->Connect(*InternetAddress))
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Cannot connect to Launcher!", true);
    		return false;
    	}
    	FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Successfully connected to Launcher", false);
    
    	//Send requested version
    	TArray<uint8> RequestData = ConvertString(VersionName);	
    	int BytesSend = 0;
    	VAServerLauncherSocket->Send(RequestData.GetData(), RequestData.Num(), BytesSend);
    	FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Send " + FString::FromInt(BytesSend) + 
    		" bytes to the VAServer Launcher, with version name: " + VersionName + " Waiting for answer.", false);
    
    	//Receive response
    	const int32 BufferSize = 16;
    	int32 BytesRead = 0;
    	uint8 Response[16];
    	if (VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead) && BytesRead == 1)
    	{
    		switch (Response[0])
    		{
    		case 'g':
    			FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Received go from launcher, VAServer seems to be correctly started.", false);
    			break;
    		case 'n':
    			FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: VAServer cannot be launched, invalid VAServer binary file or cannot be found",
    			                        true);
    			VAServerLauncherSocket = nullptr;
    			return false;
    		case 'i':
    			FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: VAServer cannot be launched, invalid file entry in the config", true);
    			VAServerLauncherSocket = nullptr;
    			return false;
    		case 'a':
    			FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: VAServer was aborted", true);
    			VAServerLauncherSocket = nullptr;
    			return false;
    		case 'f':
    			FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: VAServer cannot be launched, requested version \"" + 
    				VersionName + "\" is not available/specified", true);
    			VAServerLauncherSocket = nullptr;
    			return false;
    		default:
    			FVAUtils::OpenMessageBox("[FVAServerLauncher::RemoteStartVAServer()]: Unexpected response from VAServer Launcher: " + 
    				FString(reinterpret_cast<char*>(&Response[0])), true);
    			VAServerLauncherSocket = nullptr;
    			return false;
    		}
    	}
    	else
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::RemoteStartVAServer()]: Error while receiving response from VAServer Launcher", true);
    		VAServerLauncherSocket = nullptr;
    		return false;
    	}
    	return true;
    }
    
    bool FVAServerLauncher::StartVAServerLauncher()
    {
      //check whether we can also start the VSServer Launcher python script.
    
    	if (!UVirtualRealityUtilities::IsMaster())
    	{
    		return false;
    	}
    
      const UVASettings* Settings = GetDefault<UVASettings>();
      FString LauncherScriptDir = Settings->VALauncherPath;
    
      if(FPaths::IsRelative(LauncherScriptDir))
      {
        FString ProjectDir = FPaths::ProjectDir();
        ProjectDir = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*ProjectDir);
        LauncherScriptDir = FPaths::ConvertRelativePathToFull(ProjectDir, LauncherScriptDir);
      }
    
      LauncherScriptDir = FPaths::Combine(LauncherScriptDir, TEXT("LaunchScript"));
      FString LauncherScript = TEXT("VirtualAcousticsStarterServer.py");
      if (FPaths::FileExists(FPaths::Combine(LauncherScriptDir, LauncherScript)))
      {
    		FString CMDCommand = "cd/d " + LauncherScriptDir + " & ";
    
    		//check whether py or python exist
    		auto DoesCommandExist = [&](FString Command)
    		{
    			//this checks whether a given command returns a result
    			FString TmpCmdResultFile = "tmpPyVersion.txt";
    			TmpCmdResultFile = FPaths::Combine(LauncherScriptDir, TmpCmdResultFile);
    			Command = Command + " >> " + TmpCmdResultFile;
    			system(TCHAR_TO_ANSI(*Command));
    			FString Result;
    			FFileHelper::LoadFileToString(Result, *TmpCmdResultFile);
    			IFileManager::Get().Delete(*TmpCmdResultFile);
    			return !Result.IsEmpty();
    		};
    
    		bool bPyExists = DoesCommandExist("py --version");
    		bool bPythonExists = DoesCommandExist("python --version");
    
    		if(bPythonExists || bPyExists)
    		{
    			FString Command = CMDCommand + "start " + (bPythonExists?"python":"py") + " " + LauncherScript;
    			system(TCHAR_TO_ANSI(*Command));
    			return true;
    		}
    		else
    		{
    			FVAUtils::OpenMessageBox("VA Launcher cannot be started since neither \"py\" nor \"python\" can be found. If it is installed add it to PATH (and restart Visual Studio)", true);
    			return false;
    		}
      }
      else
      {
        FVAUtils::LogStuff("[FVAServerLauncher::StartVAServerLauncher] Unable to automatically start the launcher script, looked for "+LauncherScript+" at "+LauncherScriptDir+". If you want to use this convenience function change the VALauncher Path in the Engine/Virtual Acoustics(VA) section of the project settings. However, nothing bad will happen without.");
      }
      return false;
    }
    
    bool FVAServerLauncher::SendFileToVAServer(const FString& RelativeFilename)
    {
    
    	if (!UVirtualRealityUtilities::IsMaster())
    	{
    		return false;
    	}
    	
    	if(VAServerLauncherSocket==nullptr)
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: No connection to VAServer Starter, so no files can be send to VAServer!", true);
    		return false;
    	}
    
    	if(!GetDefault<UVASettings>()->VALauncherCopyFiles)
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: Setting to not send files over the network to VAServer is set, so not sending anything!", false);
    		return false;
    	}
    
    	if(!FPaths::FileExists(FPaths::Combine(FPaths::ProjectContentDir(),RelativeFilename)))
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: File to send("+RelativeFilename+") could not be found and therefore not send!", true);
    		return false;
    	}
    
    	TArray<uint8> FileBinaryArray;
       FFileHelper::LoadFileToArray(FileBinaryArray, *FPaths::Combine(FPaths::ProjectContentDir(),RelativeFilename));
    
    	const FString ProjectName = GetDefault<UGeneralProjectSettings>()->ProjectName;
    	FString MetaInfo = "file:"+RelativeFilename+":"+FString::FromInt(FileBinaryArray.Num())+":"+ProjectName;
    	TArray<uint8> MetaInfoBinary = ConvertString(MetaInfo);
    
    	int32 BytesSend;
    	VAServerLauncherSocket->Send(MetaInfoBinary.GetData(), MetaInfoBinary.Num(), BytesSend);
    	//Receive response
    	const int32 BufferSize = 16;
    	int32 BytesRead = 0;
    	uint8 Response[16];
    	if (VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead))
    	{
    		FString ResponseString = ByteArrayToString(Response, BytesRead);
    		if(ResponseString=="ack"){
    			//VAServer waits for file
    			int32 BytesAlreadySend = 0;
    			while(BytesAlreadySend<FileBinaryArray.Num())
    			{
    				//send 1024 byte packages
    				int32 BytesToSend = (FileBinaryArray.Num()-BytesAlreadySend>1024?1024:FileBinaryArray.Num()-BytesAlreadySend);
    				VAServerLauncherSocket->Send(&FileBinaryArray[BytesAlreadySend],BytesToSend, BytesSend);
    				BytesAlreadySend += BytesSend;
    			}
    			FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: Entire file ("+RelativeFilename+") send!", false);
    			VAServerLauncherSocket->Recv(Response, BufferSize, BytesRead);
    			if(BytesRead==3 && Response[0]=='a' && Response[1]=='c' && Response[2]=='k')
    			{
    				FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: File was received by VAServerLauncher successfully!", false);
    				//the search path is added potenitally multiple times, but can only be added once the folder is created (which the above guarantees)
    				const std::string SearchPath = "../tmp/" + std::string(TCHAR_TO_UTF8(*GetDefault<UGeneralProjectSettings>()->ProjectName));
    				FVAPlugin::AddVAServerSearchPath(SearchPath);
    			}
    			else
    			{
    				FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: File was NOT received by VAServerLauncher!", true);
    				return false;
    			}
    		}
    		else if (ResponseString=="exists"){
    			FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: File already exists with same size, no need ro re-send!", false);
    		}
    		else
    		{
    			FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: Server Launcher does not want to receive a file, answer: "+ResponseString, true);
    			return false;	
    		}
    	}
    	else
    	{
    		FVAUtils::LogStuff("[FVAServerLauncher::SendFileToVAServer()]: Server Launcher does not want to receive a file, no answer!", true);
    		return false;	
    	}
    
    	//the search path is added in any case once after connecting to a new server
    
    	return true;
    }
    
    void FVAServerLauncher::ReleaseVAServerLauncherConnection()
    {
    	if (!UVirtualRealityUtilities::IsMaster())
    	{
    		return;
    	}
    
    	if(VAServerLauncherSocket!=nullptr){
    		VAServerLauncherSocket->Close();
    		VAServerLauncherSocket = nullptr;
    	}
    }
    
    bool FVAServerLauncher::IsVAServerLauncherConnected()
    {
    	return VAServerLauncherSocket!=nullptr;
    }
    
    TArray<uint8> FVAServerLauncher::ConvertString(const FString& String)
    {
    	TArray<uint8> RequestData;
    	for (TCHAR Character : String.GetCharArray())
    	{
    		const uint8 InByte = static_cast<uint8>(Character);
    		if (InByte != 0)
    		{
    			RequestData.Add(static_cast<uint8>(Character));
    		}
    	}
    	return RequestData;
    }
    
    FString FVAServerLauncher::ByteArrayToString(const uint8* In, int32 Count)
    {
    	FString Result;
    	Result.Empty(Count);
    
    	while (Count)
    	{
    		// Put the byte into an int16
    		int16 Value = *In;
    
    		Result += TCHAR(Value);
    
    		++In;
    		Count--;
    	}
    	return Result;
    }