// Uses GDI+ to fill the LOGFONT structure. This is computationally expensive // but easy to get right. However it doesn't handle some fonts like Terminal. // font_size is in units of tenths of point size. i.e. 100 is a 10 point font bool get_logfont(const tstring & font_name, int font_size, LOGFONT * lf) { Bitmap b(1, 1); Graphics g(&b); FontFamily font_family(WideBuffer(font_name.c_str())); const FontFamily * ff = &font_family; if (!font_family.IsAvailable()) return false; Gdiplus::Font font(ff, static_cast<REAL>(font_size) / POINT_SIZE_SCALE); if (!font.IsAvailable()) return false; #ifdef UNICODE font.GetLogFontW(&g, lf); #else font.GetLogFontA(&g, lf); #endif return true; }
bool FPerfCounters::Tick(float DeltaTime) { // if we didn't get a socket, don't tick if (Socket == nullptr) { return false; } // accept any connections static const FString PerfCounterRequest = TEXT("FPerfCounters Request"); FSocket* IncomingConnection = Socket->Accept(PerfCounterRequest); if (IncomingConnection) { // make sure this is non-blocking bool bSuccess = false; IncomingConnection->SetNonBlocking(true); // read any data that's ready // NOTE: this is not a full HTTP implementation, just enough to be usable by curl uint8 Buffer[2*1024] = { 0 }; int32 DataLen = 0; if (IncomingConnection->Recv(Buffer, sizeof(Buffer)-1, DataLen, ESocketReceiveFlags::None)) { // scan the buffer for a line FUTF8ToTCHAR WideBuffer(reinterpret_cast<const ANSICHAR*>(Buffer)); const TCHAR* BufferEnd = FCString::Strstr(WideBuffer.Get(), TEXT("\r\n")); if (BufferEnd != nullptr) { // crack into pieces FString MainLine(BufferEnd - WideBuffer.Get(), WideBuffer.Get()); TArray<FString> Tokens; MainLine.ParseIntoArrayWS(Tokens); if (Tokens.Num() >= 2) { FString Body; int ResponseCode = 200; // handle the request if (Tokens[0] != TEXT("GET")) { Body = FString::Printf(TEXT("{ \"error\": \"Method %s not allowed\" }"), *Tokens[0]); ResponseCode = 405; } else if (Tokens[1] == TEXT("/stats")) { Body = ToJson(); } else { Body = FString::Printf(TEXT("{ \"error\": \"%s not found\" }"), *Tokens[1]); ResponseCode = 404; } // send the response headers FString Header = FString::Printf(TEXT("HTTP/1.0 %d\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n"), ResponseCode, Body.Len()); if (SendAsUtf8(IncomingConnection, Header) && SendAsUtf8(IncomingConnection, Body)) { bSuccess = true; } } } } // log if we didn't succeed if (!bSuccess) { UE_LOG(LogPerfCounters, Warning, TEXT("FPerfCounters was unable to send a JSON response (or sent partial response)")); } // close the socket (whether we processed or not IncomingConnection->Close(); ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(IncomingConnection); } // keep ticking return true; }
bool FPerfCounters::ProcessRequest(uint8* Buffer, int32 BufferLen, FResponse& Response) { bool bSuccess = false; // scan the buffer for a line FUTF8ToTCHAR WideBuffer(reinterpret_cast<const ANSICHAR*>(Buffer)); const TCHAR* BufferEnd = FCString::Strstr(WideBuffer.Get(), TEXT("\r\n")); if (BufferEnd != nullptr) { // crack into pieces FString MainLine(BufferEnd - WideBuffer.Get(), WideBuffer.Get()); TArray<FString> Tokens; MainLine.ParseIntoArrayWS(Tokens); if (Tokens.Num() >= 2) { FString ContentType(TEXT("application/json")); Response.Code = 200; // handle the request if (Tokens[0] != TEXT("GET")) { Response.Body = FString::Printf(TEXT("{ \"error\": \"Method %s not allowed\" }"), *Tokens[0]); Response.Code = 405; } else if (Tokens[1].StartsWith(TEXT("/stats"))) { Response.Body = GetAllCountersAsJson(); } else if (Tokens[1].StartsWith(TEXT("/exec?c="))) { FString ExecCmd = Tokens[1].Mid(8); FString ExecCmdDecoded = FPlatformHttp::UrlDecode(ExecCmd); FStringOutputDevice StringOutDevice; StringOutDevice.SetAutoEmitLineTerminator(true); bool bResult = false; if (ExecCmdCallback.IsBound()) { bResult = ExecCmdCallback.Execute(ExecCmdDecoded, StringOutDevice); Response.Body = StringOutDevice; ContentType = TEXT("text/text"); } else { Response.Body = FString::Printf(TEXT("{ \"error\": \"exec handler not found\" }")); } Response.Code = bResult ? 200 : 404; } else { Response.Body = FString::Printf(TEXT("{ \"error\": \"%s not found\" }"), *Tokens[1]); Response.Code = 404; } // send the response headers Response.Header = FString::Printf(TEXT("HTTP/1.0 %d\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n"), Response.Code, Response.Body.Len(), *ContentType); bSuccess = true; } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to parse HTTP request header: %s"), *MainLine); } } else { UE_LOG(LogPerfCounters, Warning, TEXT("Unable to immediately receive full request header")); } return bSuccess; }