Initial import

This commit is contained in:
admin_d committed 2026-09-11 18:19:50 +05:00
commit dfcc43c72d
34 files changed
+3057

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
unit ProbeDecision;
{$mode objfpc}{$H+}{$codepage utf8}
{$ifndef ANDROID}{$fatal Decision probes are Android-only}{$endif}
interface
uses ProbeReport;
procedure RunDecisionChecks(Report:TProbeReport;const WorkDir:string);
implementation
uses Classes,SysUtils,fpjson,jsonparser,CastleDownload,CastleFilesUtils;
procedure WriteAscii(const Name,Value:string);
var F:TFileStream; A:AnsiString;
begin
A:=AnsiString(Value);F:=TFileStream.Create(Name,fmCreate);
try if Length(A)>0 then F.WriteBuffer(A[1],Length(A));finally F.Free;end;
end;
function ReadAscii(const Name:string):string;
var F:TFileStream; A:AnsiString;
begin
Result:='';F:=TFileStream.Create(Name,fmOpenRead or fmShareDenyWrite);
try SetLength(A,F.Size);if Length(A)>0 then F.ReadBuffer(A[1],Length(A));Result:=string(A);finally F.Free;end;
end;
procedure ProbeRenameReplace(Report:TProbeReport;const WorkDir:string);
var Target,Temp,Detail:string; Ok:Boolean;
begin
Target:=WorkDir+'decision-rename-target.txt';Temp:=Target+'.tmp';
try
WriteAscii(Target,'old');WriteAscii(Temp,'new');
Ok:=RenameFile(Temp,Target);
if Ok then Ok:=(ReadAscii(Target)='new') and not FileExists(Temp);
Detail:='replace_existing=' + LowerCase(BoolToStr(Ok,True));
if (not Ok) and FileExists(Temp) then DeleteFile(Temp);
Report.Add('decision.persistence.rename_replace','OBSERVED',Detail);
except on E:Exception do
Report.Add('decision.persistence.rename_replace','OBSERVED','replace_existing=false; error='+E.ClassName+': '+E.Message);
end;
end;
procedure ProbeAppend(Report:TProbeReport;const WorkDir:string);
var Name:string;F:TFileStream;A:AnsiString;Ok:Boolean;
procedure Append(const S:AnsiString);
begin
F:=TFileStream.Create(Name,fmOpenReadWrite or fmShareDenyNone);
try F.Position:=F.Size;if Length(S)>0 then F.WriteBuffer(S[1],Length(S));finally F.Free;end;
end;
begin
Name:=WorkDir+'decision-append.log';
try
WriteAscii(Name,'A'+LineEnding);Append('B'+LineEnding);Append('C'+LineEnding);
A:=AnsiString(ReadAscii(Name));
Ok:=A=AnsiString('A'+LineEnding+'B'+LineEnding+'C'+LineEnding);
Report.Add('decision.persistence.append_reopen','OBSERVED',
'append_reopen_ordered='+LowerCase(BoolToStr(Ok,True))+'; bytes='+IntToStr(Length(A)));
except on E:Exception do
Report.Add('decision.persistence.append_reopen','OBSERVED','append_reopen_ordered=false; error='+E.ClassName+': '+E.Message);
end;
end;
function FirstAsset(out Rel,Url:string;out Expected:Int64):Boolean;
var Manifest:TJSONData;Files:TJSONArray;
begin
Result:=False;Rel:='';Url:='';Expected:=-1;
Manifest:=GetJSON(FileToString('castle-data:/assets-manifest.json'));
try
Files:=TJSONObject(Manifest).Arrays['files'];
if Files.Count=0 then Exit;
Rel:=Files.Objects[0].Strings['path'];
Url:=Files.Objects[0].Strings['url'];
Expected:=Files.Objects[0].Int64s['size'];
Result:=True;
finally Manifest.Free;end;
end;
procedure ProbeCastleStream(Report:TProbeReport);
var S:TStream;Rel,Url:string;Expected,SizeValue:Int64;N:Integer;B:array[0..31] of Byte;SizeOk,SeekOk:Boolean;
begin
if not FirstAsset(Rel,Url,Expected) then begin
Report.Add('decision.fixture.castle_stream','NOT_RUN','No server fixture selected; pass --assets and --asset-path');Exit;
end;
SizeOk:=False;SeekOk:=False;SizeValue:=-1;
try
S:=Download(Url);
try
try SizeValue:=S.Size;SizeOk:=SizeValue=Expected;except SizeOk:=False;end;
try
if Expected>SizeOf(B) then S.Position:=Expected div 2 else S.Position:=0;
N:=S.Read(B,SizeOf(B));SeekOk:=N>0;
except SeekOk:=False;end;
finally S.Free;end;
Report.Add('decision.fixture.castle_stream','OBSERVED',
Format('path=%s; expected_size=%d; size=%d; size_matches=%s; seek_read=%s',
[Rel,Expected,SizeValue,LowerCase(BoolToStr(SizeOk,True)),LowerCase(BoolToStr(SeekOk,True))]));
except on E:Exception do
Report.Add('decision.fixture.castle_stream','OBSERVED','path='+Rel+'; open=false; error='+E.ClassName+': '+E.Message);
end;
end;
procedure ProbeMaterialize(Report:TProbeReport;const WorkDir:string);
var S:TStream;F:TFileStream;Rel,Url,Name:string;Expected:Int64;Ok:Boolean;
begin
if not FirstAsset(Rel,Url,Expected) then begin
Report.Add('decision.fixture.materialized_native_path','NOT_RUN','No server fixture selected; pass --assets and --asset-path');Exit;
end;
Name:=WorkDir+'decision-materialized.dat';Ok:=False;
try
S:=Download(Url);
try
F:=TFileStream.Create(Name,fmCreate);
try F.CopyFrom(S,0);finally F.Free;end;
finally S.Free;end;
F:=TFileStream.Create(Name,fmOpenRead or fmShareDenyWrite);
try Ok:=F.Size=Expected;finally F.Free;end;
Report.Add('decision.fixture.materialized_native_path','OBSERVED',
'source='+Rel+'; supported='+LowerCase(BoolToStr(Ok,True))+'; native_path='+Name+'; bytes='+IntToStr(Expected));
except on E:Exception do
Report.Add('decision.fixture.materialized_native_path','OBSERVED','source='+Rel+'; supported=false; error='+E.ClassName+': '+E.Message);
end;
end;
procedure RunDecisionChecks(Report:TProbeReport;const WorkDir:string);
begin
ProbeRenameReplace(Report,WorkDir);
ProbeAppend(Report,WorkDir);
ProbeCastleStream(Report);
ProbeMaterialize(Report,WorkDir);
end;
end.