mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-04-08 05:48:05 +02:00
* Preload files
This commit is contained in:
parent
b84e5c60bf
commit
7c9edfcac7
packages/wasi/src
@ -41,6 +41,23 @@ Const
|
||||
type
|
||||
TMemBufferArray = Array of TJSUint8Array;
|
||||
|
||||
TPreLoadFile = record
|
||||
url : String;
|
||||
localname : string;
|
||||
end;
|
||||
TPreLoadFileDynArray = Array of TPreLoadFile;
|
||||
|
||||
TLoadFileFailure = record
|
||||
url : String;
|
||||
error : string;
|
||||
end;
|
||||
TLoadFileFailureDynArray = Array of TLoadFileFailure;
|
||||
|
||||
TPreLoadFilesResult = record
|
||||
failedurls : TLoadFileFailureDynArray;
|
||||
loadcount : integer;
|
||||
end;
|
||||
|
||||
EWasiError = Class(Exception);
|
||||
|
||||
EWasiFSError = class(Exception)
|
||||
@ -76,6 +93,8 @@ type
|
||||
|
||||
TPas2JSWASIEnvironment = class (TObject,IWASI)
|
||||
Private
|
||||
FArguments: TStrings;
|
||||
FEnvironment: TStrings;
|
||||
FExitCode: Nativeint;
|
||||
FImportObject : TJSObject;
|
||||
Finstance: TJSWebAssemblyInstance;
|
||||
@ -98,6 +117,8 @@ type
|
||||
function GetTotalIOVsLen(iovs: TMemBufferArray): Integer;
|
||||
function GetIOVsAsBytes(iovs, iovsLen: NativeInt): TJSUInt8array;
|
||||
function GetMemory: TJSWebassemblyMemory;
|
||||
procedure SetArguments(AValue: TStrings);
|
||||
procedure SetEnvironment(AValue: TStrings);
|
||||
procedure SetInstance(AValue: TJSWebAssemblyInstance);
|
||||
procedure SetLogAPI(AValue: Boolean);
|
||||
procedure WriteFileStatToMem(BufPtr: TWasmMemoryLocation;
|
||||
@ -122,12 +143,12 @@ type
|
||||
// IWASI calls
|
||||
// !! Please keep these sorted !!
|
||||
|
||||
function args_get(argv, argvBuf : NativeInt) : NativeInt; virtual;
|
||||
function args_sizes_get(argc, argvBufSize : NativeInt) : NativeInt; virtual;
|
||||
function args_get(argv, argvBuf : TWasmMemoryLocation) : NativeInt; virtual;
|
||||
function args_sizes_get(argc, argvBufSize : TWasmMemoryLocation) : NativeInt; virtual;
|
||||
function clock_res_get(clockId, resolution: NativeInt): NativeInt; virtual;
|
||||
function clock_time_get(clockId, precision : NativeInt; time: TWasmMemoryLocation): NativeInt; virtual;
|
||||
function environ_get(environ, environBuf : NativeInt) : NativeInt; virtual;
|
||||
function environ_sizes_get(environCount, environBufSize : NativeInt) : NativeInt; virtual;
|
||||
function environ_get(environ, environBuf : TWasmMemoryLocation) : NativeInt; virtual;
|
||||
function environ_sizes_get(environCount, environBufSize : TWasmMemoryLocation) : NativeInt; virtual;
|
||||
function fd_advise (fd, offset, len, advice : NativeInt) : NativeInt; virtual;
|
||||
function fd_allocate (fd, offset, len : NativeInt) : NativeInt; virtual;
|
||||
function fd_close(fd : NativeInt) : NativeInt; virtual;
|
||||
@ -189,6 +210,11 @@ type
|
||||
Procedure AddImports(aObject: TJSObject);
|
||||
Property ImportObject : TJSObject Read GetImportObject;
|
||||
Property IsLittleEndian : Boolean Read FIsLittleEndian Write FIsLittleEndian;
|
||||
// Filesystem
|
||||
function PreLoadFiles(aFiles: array of string): TPreLoadFilesResult; async;
|
||||
function PreLoadFiles(aFiles: TPreLoadFileDynArray): TPreLoadFilesResult; async;
|
||||
function PreLoadFilesIntoDirectory(aDirectory : String; aFiles: array of string): TPreLoadFilesResult; async;
|
||||
|
||||
Property OnStdOutputWrite : TWASIWriteEvent Read FOnStdOutputWrite Write FOnStdOutputWrite;
|
||||
Property OnStdErrorWrite : TWASIWriteEvent Read FOnStdErrorWrite Write FOnStdErrorWrite;
|
||||
Property OnGetConsoleInputBuffer : TGetConsoleInputBufferEvent Read FOnGetConsoleInputBuffer Write FOnGetConsoleInputBuffer;
|
||||
@ -200,6 +226,8 @@ type
|
||||
Property WASIImportName : String Read FWASIImportName Write FWASIImportName;
|
||||
Property LogAPI : Boolean REad FLogAPI Write SetLogAPI;
|
||||
Property FS : IWASIFS Read FWasiFS Write FWasiFS;
|
||||
Property Arguments : TStrings Read FArguments Write SetArguments;
|
||||
Property Environment : TStrings Read FEnvironment Write SetEnvironment;
|
||||
end;
|
||||
|
||||
{ TImportExtension }
|
||||
@ -747,6 +775,7 @@ begin
|
||||
FImportExtensions.Remove(aExtension);
|
||||
end;
|
||||
|
||||
|
||||
function TPas2JSWASIEnvironment.getModuleMemoryDataView: TJSDataView;
|
||||
begin
|
||||
Result:=TJSDataView.New(Memory.buffer);
|
||||
@ -827,55 +856,78 @@ begin
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.environ_sizes_get(environCount,
|
||||
environBufSize: NativeInt): NativeInt;
|
||||
environBufSize: TWasmMemoryLocation): NativeInt;
|
||||
|
||||
Var
|
||||
View : TJSDataView;
|
||||
Size : integer;
|
||||
|
||||
begin
|
||||
{$IFNDEF NO_WASI_DEBUG}
|
||||
if LogAPI then
|
||||
DoLog('TPas2JSWASIEnvironment.environ_sizes_get(%d,%d)',[environCount,environBufSize]);
|
||||
DoLog('TPas2JSWASIEnvironment.environ_sizes_get([%x],[%x])',[environCount,environBufSize]);
|
||||
{$ENDIF}
|
||||
view:=getModuleMemoryDataView();
|
||||
view.setUint32(environCount, 0, IsLittleEndian);
|
||||
view.setUint32(environBufSize, 0, IsLittleEndian);
|
||||
view.setUint32(environCount, Environment.Count, IsLittleEndian);
|
||||
Size:=0;
|
||||
// the LF will be counted for null terminators
|
||||
if Environment.Count>0 then
|
||||
Size:=Length(Environment.Text)+1;
|
||||
view.setUint32(environBufSize, Size, IsLittleEndian);
|
||||
Result:= WASI_ESUCCESS;
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.environ_get(environ, environBuf: NativeInt
|
||||
): NativeInt;
|
||||
function TPas2JSWASIEnvironment.environ_get(environ, environBuf: TWasmMemoryLocation): NativeInt;
|
||||
begin
|
||||
{$IFNDEF NO_WASI_DEBUG}
|
||||
if LogAPI then
|
||||
DoLog('TPas2JSWASIEnvironment.environ_get(%d,%d)',[environ,environBuf]);
|
||||
DoLog('TPas2JSWASIEnvironment.environ_get([%x],[%x])',[environ,environBuf]);
|
||||
{$ENDIF}
|
||||
Result:= WASI_ESUCCESS;
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.args_sizes_get(argc, argvBufSize: NativeInt
|
||||
): NativeInt;
|
||||
function TPas2JSWASIEnvironment.args_sizes_get(argc, argvBufSize: TWasmMemoryLocation): NativeInt;
|
||||
|
||||
Var
|
||||
View : TJSDataView;
|
||||
|
||||
Size : Integer;
|
||||
begin
|
||||
{$IFNDEF NO_WASI_DEBUG}
|
||||
if LogAPI then
|
||||
DoLog('TPas2JSWASIEnvironment.args_sizes_get(%d,%d)',[argc,argvbufsize]);
|
||||
DoLog('TPas2JSWASIEnvironment.args_sizes_get([%x],[%x])',[argc,argvbufsize]);
|
||||
{$ENDIF}
|
||||
view:=getModuleMemoryDataView();
|
||||
view.setUint32(argc, 0, IsLittleEndian);
|
||||
view.setUint32(argvBufSize, 0, IsLittleEndian);
|
||||
view.setUint32(argc, Arguments.Count, IsLittleEndian);
|
||||
// the LF will be counted for null terminators
|
||||
Size:=0;
|
||||
if Arguments.Count>0 then
|
||||
Size:=Length(Arguments.Text)+1;
|
||||
view.setUint32(argvBufSize, Size , IsLittleEndian);
|
||||
Result:=WASI_ESUCCESS;
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.args_get(argv, argvBuf: NativeInt): NativeInt;
|
||||
function TPas2JSWASIEnvironment.args_get(argv, argvBuf: TWasmMemoryLocation): NativeInt;
|
||||
|
||||
var
|
||||
Ptr : TWasmMemoryLocation;
|
||||
PtrV : TWasmMemoryLocation;
|
||||
S : String;
|
||||
i : Integer;
|
||||
|
||||
begin
|
||||
{$IFNDEF NO_WASI_DEBUG}
|
||||
if LogAPI then
|
||||
DoLog('TPas2JSWASIEnvironment.args_get(%d,%d)',[argv, argvBuf]);
|
||||
DoLog('TPas2JSWASIEnvironment.args_get([%x],[%x])',[argv, argvBuf]);
|
||||
{$ENDIF}
|
||||
Ptr:=ArgvBuf;
|
||||
PtrV:=ArgV;
|
||||
for I:=0 to Arguments.Count-1 do
|
||||
begin
|
||||
S:=Arguments[I];
|
||||
PtrV:=SetMemInfoUInt32(PtrV,Ptr);
|
||||
Ptr:=Ptr+SetUTF8StringInMem(Ptr,Length(S),S);
|
||||
Ptr:=SetMemInfoUInt8(Ptr,0);
|
||||
end;
|
||||
Result:=WASI_ESUCCESS;
|
||||
end;
|
||||
|
||||
@ -1078,6 +1130,18 @@ begin
|
||||
Result:= FModuleInstanceExports.Memory;
|
||||
end;
|
||||
|
||||
procedure TPas2JSWASIEnvironment.SetArguments(AValue: TStrings);
|
||||
begin
|
||||
if FArguments=AValue then Exit;
|
||||
FArguments.Assign(AValue);
|
||||
end;
|
||||
|
||||
procedure TPas2JSWASIEnvironment.SetEnvironment(AValue: TStrings);
|
||||
begin
|
||||
if FEnvironment=AValue then Exit;
|
||||
FEnvironment.Assign(AValue);
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.GetIOVsAsBytes(iovs, iovsLen : NativeInt) : TJSUInt8array;
|
||||
|
||||
var
|
||||
@ -2062,10 +2126,14 @@ begin
|
||||
FIsLittleEndian:=True;
|
||||
// Default expected by FPC runtime
|
||||
WASIImportName:='wasi_snapshot_preview1';
|
||||
FArguments:=TStringList.Create;
|
||||
FEnvironment:=TStringList.Create;
|
||||
end;
|
||||
|
||||
destructor TPas2JSWASIEnvironment.Destroy;
|
||||
begin
|
||||
FreeAndNil(FEnvironment);
|
||||
FreeAndNil(FArguments);
|
||||
FreeAndNil(FImportExtensions);
|
||||
inherited Destroy;
|
||||
end;
|
||||
@ -2185,6 +2253,115 @@ begin
|
||||
Result:=aLoc+SizeUint64;
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.PreLoadFiles(aFiles: array of string): TPreLoadFilesResult;
|
||||
|
||||
var
|
||||
I,Idx,Len : Integer;
|
||||
FileArray : TPreLoadFileDynArray;
|
||||
|
||||
begin
|
||||
if not assigned(FS) then
|
||||
Raise EWasiError.Create('No filesystem available');
|
||||
Len:=Length(aFiles);
|
||||
if (Len mod 2)=1 then
|
||||
Raise EWasiError.Create('Number of arguments must be even: pairs of url, local');
|
||||
SetLength(FileArray,Len div 2);
|
||||
I:=0;
|
||||
Idx:=0;
|
||||
while I<Len do
|
||||
begin
|
||||
FileArray[Idx].Url:=aFiles[i];
|
||||
FileArray[Idx].localname:=aFiles[i+1];
|
||||
Inc(I,2);
|
||||
Inc(Idx);
|
||||
end;
|
||||
Result:=Await(PreloadFiles(FileArray));
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.PreLoadFiles(aFiles: TPreLoadFileDynArray): TPreLoadFilesResult;
|
||||
|
||||
var
|
||||
I,res,failcount : Integer;
|
||||
Resp: TJSResponse;
|
||||
blob : TJSBlob;
|
||||
buf : TJSarrayBuffer;
|
||||
Data : TJSUint8Array;
|
||||
Fails : TLoadFileFailureDynArray;
|
||||
|
||||
procedure AddFailure(aUrl,aError: String);
|
||||
|
||||
begin
|
||||
fails[FailCount].url:=aUrl;
|
||||
fails[FailCount].error:=aError;
|
||||
inc(Failcount);
|
||||
end;
|
||||
|
||||
begin
|
||||
if not assigned(FS) then
|
||||
Raise EWasiError.Create('No filesystem available');
|
||||
Res:=0;
|
||||
failcount:=0;
|
||||
SetLength(Fails,Length(aFiles));
|
||||
For I:=0 to Length(afiles)-1 do
|
||||
try
|
||||
resp:=await(fetch(aFiles[I].url));
|
||||
blob:=await(resp.blob);
|
||||
buf:=await(TJSArrayBuffer,blob.arrayBuffer);
|
||||
FS.PreloadFile(aFiles[i].localname,TJSDataView.new(Buf));
|
||||
inc(Res);
|
||||
except
|
||||
on E : Exception do
|
||||
AddFailure(aFiles[i].Url,E.Message);
|
||||
on JE : TJSError do
|
||||
AddFailure(aFiles[i].Url,JE.Message);
|
||||
on OE : TJSObject do
|
||||
AddFailure(aFiles[i].Url,TJSJSON.Stringify(OE));
|
||||
end;
|
||||
SetLength(Fails,FailCount);
|
||||
Result.failedurls:=Fails;
|
||||
Result.LoadCount:=Res;
|
||||
end;
|
||||
|
||||
function TPas2JSWASIEnvironment.PreLoadFilesIntoDirectory(aDirectory: String; aFiles: array of string): TPreLoadFilesResult;
|
||||
|
||||
function ExtractFileFromURL(aURL : String) : string;
|
||||
|
||||
var
|
||||
S : String;
|
||||
URLObj : TJSURL;
|
||||
|
||||
begin
|
||||
if aUrl.StartsWith('http://',true) or aUrl.StartsWith('https://',true) then
|
||||
begin
|
||||
UrlObj:=TJSURL.new(aURL);
|
||||
S:=UrlObj.PathName
|
||||
end
|
||||
else
|
||||
S:=aURL;
|
||||
Result:=ExtractFileName(S);
|
||||
end;
|
||||
|
||||
var
|
||||
I,Len : Integer;
|
||||
FileArray : TPreLoadFileDynArray;
|
||||
|
||||
begin
|
||||
if not assigned(FS) then
|
||||
Raise EWasiError.Create('No filesystem available');
|
||||
Len:=Length(aFiles);
|
||||
SetLength(FileArray,Len);
|
||||
aDirectory:=IncludeTrailingPathDelimiter(aDirectory);
|
||||
I:=0;
|
||||
while I<Len do
|
||||
begin
|
||||
FileArray[I].Url:=aFiles[i];
|
||||
FileArray[I].localname:=aDirectory+ExtractFileFromURL(aFiles[i]);
|
||||
Inc(I);
|
||||
end;
|
||||
Result:=Await(PreloadFiles(FileArray));
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
|
||||
end.
|
||||
|
@ -8,9 +8,9 @@ interface
|
||||
|
||||
uses
|
||||
{$IFDEF FPC_DOTTEDUNITS}
|
||||
System.Classes, System.SysUtils, Fcl.App.Browser, JSApi.JS, BrowserApi.WebAssembly, Wasi.Env;
|
||||
System.Classes, System.SysUtils, Fcl.App.Browser, JSApi.JS, BrowserApi.WebAssembly, Wasi.Env, BrowserApi.Web, System.Types;
|
||||
{$ELSE}
|
||||
Classes, SysUtils, browserapp, js, webassembly, wasienv;
|
||||
Classes, SysUtils, browserapp, js, webassembly, wasienv, web, types;
|
||||
{$ENDIF}
|
||||
|
||||
Type
|
||||
@ -44,6 +44,9 @@ Type
|
||||
public
|
||||
Constructor Create(aOwner : TComponent); override;
|
||||
Destructor Destroy; override;
|
||||
function PreLoadFiles(aFiles : Array of string) : TPreLoadFilesResult; async;
|
||||
function PreLoadFiles(aFiles : TPreLoadFileDynArray) : TPreLoadFilesResult; async;
|
||||
function PreLoadFilesIntoDirectory(aDirectory: String; aFiles: array of string): TPreLoadFilesResult; async;
|
||||
// Load and start webassembly. If DoRun is true, then Webassembly entry point is called.
|
||||
// If aBeforeStart is specified, then it is called prior to calling run, and can disable running.
|
||||
// If aAfterStart is specified, then it is called after calling run. It is not called is running was disabled.
|
||||
@ -185,6 +188,24 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TBrowserWASIHostApplication.PreLoadFiles(aFiles: array of string): TPreLoadFilesResult;
|
||||
|
||||
begin
|
||||
Result:=Await(WasiEnvironment.PreloadFiles(aFiles));
|
||||
end;
|
||||
|
||||
function TBrowserWASIHostApplication.PreLoadFiles(aFiles : TPreLoadFileDynArray) : TPreLoadFilesResult;
|
||||
|
||||
begin
|
||||
Result:=Await(WasiEnvironment.PreloadFiles(aFiles));
|
||||
end;
|
||||
|
||||
function TBrowserWASIHostApplication.PreLoadFilesIntoDirectory(aDirectory : String; aFiles: array of string): TPreLoadFilesResult;
|
||||
|
||||
begin
|
||||
Result:=Await(WasiEnvironment.PreloadFilesIntoDirectory(aDirectory,aFiles));
|
||||
end;
|
||||
|
||||
function TBrowserWASIHostApplication.StartWebAssembly(aPath: string; DoRun: Boolean;
|
||||
aBeforeStart: TBeforeStartCallback = nil; aAfterStart: TAfterStartCallback = nil) : TJSPromise;
|
||||
|
||||
|
@ -45,6 +45,7 @@ Type
|
||||
Function Read(FD : Integer; Data : TJSUint8Array; AtPos : Integer; Out BytesRead : Integer) : NativeInt;
|
||||
function ReadDir(FD: Integer; Cookie: NativeInt; out DirEnt: TWasiFSDirent): NativeInt;
|
||||
Function GetPrestat(FD: Integer) : String;
|
||||
Procedure PreLoadFile(aPath : String; aData : TJSDataView);
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -430,6 +431,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWASIZenFS.PreLoadFile(aPath: String; aData: TJSDataView);
|
||||
begin
|
||||
ZenFS.WriteFileSync(aPath,aData);
|
||||
end;
|
||||
|
||||
function TWASIZenFS.UnLinkAt(FD: Integer; const aPath: String): NativeInt;
|
||||
|
||||
var
|
||||
|
Loading…
Reference in New Issue
Block a user