Prechádzať zdrojové kódy

* More examples, add examples to install

Michaël Van Canneyt 11 mesiacov pred
rodič
commit
05d527bd9c

+ 92 - 0
demo/regexp/demoregex.lpi

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="demoregex"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="4">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="Pas2JSProject" Value="1"/>
+      <Item2 Name="PasJSLocation" Value="$NameOnly($(ProjFile))"/>
+      <Item3 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="demoregex.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target FileExt=".js">
+      <Filename Value="demoregex"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <UseAnsiStrings Value="False"/>
+        <CPPInline Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <ConfigFile>
+        <WriteConfigFilePath Value=""/>
+      </ConfigFile>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 124 - 0
demo/regexp/demoregex.lpr

@@ -0,0 +1,124 @@
+program demoregex;
+
+{$mode objfpc}
+
+uses
+  browserconsole, JS, Classes, SysUtils, Web, fpexprpars, db,jsondataset;
+
+Procedure AssertTrue(Msg : String; B : Boolean);
+
+begin
+  if not B then
+    Writeln('Failed: '+Msg)
+  else
+    Writeln('OK: '+Msg);
+end;
+
+Procedure TestEx;
+
+var
+  Ex : TFPExpressionParser;
+
+begin
+  Ex:=TFPExpressionParser.Create(Nil);
+  Ex.AllowLike:=True;
+  Ex.Identifiers.AddStringVariable('aField','Michael');
+  Ex.Expression:='aField like ''M%''';
+  AssertTrue('M% on match',Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Aimee';
+  AssertTrue('M% on no match (not beginning)',not Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Liesbet';
+  AssertTrue('M% on not match',Not Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Liam';
+  Ex.Expression:='aField like ''%M''';
+  AssertTrue('%M on match',Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Aimee';
+  AssertTrue('%M on no match (not end)',not Ex.AsBoolean);
+end;
+
+Procedure TestEx2;
+
+var
+  Ex : TFPExpressionParser;
+
+begin
+  Ex:=TFPExpressionParser.Create(Nil);
+  Ex.AllowLike:=True;
+  Ex.Identifiers.AddStringVariable('aField','Michael');
+  Ex.Expression:='aField like ''%e%''';
+  AssertTrue('%e% on match',Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Sara';
+  AssertTrue('%e% on not match',Not Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Liesbet';
+  AssertTrue('%e% on match 2',Ex.AsBoolean);
+end;
+
+
+Procedure TestDotted;
+
+var
+  Ex : TFPExpressionParser;
+
+begin
+  Ex:=TFPExpressionParser.Create(Nil);
+  Ex.AllowLike:=True;
+  Ex.Identifiers.AddStringVariable('aField','12.14.2023');
+  Ex.Expression:='aField like ''%.%.%''';
+  AssertTrue('%.%.% on match',Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='Liesbet';
+  AssertTrue('%.%.% on not match',Not Ex.AsBoolean);
+end;
+
+Procedure TestUnderscore;
+
+var
+  Ex : TFPExpressionParser;
+
+begin
+  Ex:=TFPExpressionParser.Create(Nil);
+  Ex.AllowLike:=True;
+  Ex.Identifiers.AddStringVariable('aField','man');
+  Ex.Expression:='aField like ''M_n''';
+  AssertTrue('M_n on match',Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='moon';
+  AssertTrue('M_n on not match',Not Ex.AsBoolean);
+  Ex.IdentifierByName('aField').AsString:='mon';
+  AssertTrue('M_n on match 2',Ex.AsBoolean);
+end;
+
+Procedure TestDatasetFilter;
+
+var
+  DS : TJSONDataset;
+
+begin
+  DS:=TJSONDataset.Create(Nil);
+  DS.FieldDefs.Add('name',ftString,50);
+  DS.Open;
+  DS.AppendRecord(['Michael']);
+  DS.AppendRecord(['mattias']);
+  DS.AppendRecord(['Bruno']);
+  DS.AppendRecord(['Detlef']);
+  DS.AppendRecord(['Aimee']);
+  AssertTrue('RecordCount',5=DS.RecordCount);
+  DS.First;
+  DS.Filter:='(name like ''M%'')';
+  DS.Filtered:=True;
+  AssertTrue('First',DS.Fields[0].AsString='Michael');
+  DS.Next;
+  AssertTrue('Second',DS.Fields[0].AsString='mattias');
+  DS.Next;
+  AssertTrue('EOf',DS.EOF);
+  DS.Free;
+end;
+
+
+
+
+begin
+  testex;
+  testex2;
+  TestDotted;
+  TestUnderscore;
+  TestDatasetFilter;
+end.

+ 14 - 0
demo/regexp/index.html

@@ -0,0 +1,14 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <title>Project1</title>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <script src="demoregex.js"></script>
+</head>
+<body>
+  <script>
+    rtl.run();
+  </script>
+</body>
+</html>

+ 10 - 0
demo/wasienv/wasm-http/Readme.md

@@ -0,0 +1,10 @@
+# Webassembly HTTP api demo.
+
+This demo shows how to do HTTP requests from Webassembly. 
+Because HTTP requests in the browser are asynchronous, the API is also
+asynchronous.
+
+To make this demo work, you need to compile the wasmhttpdemo.pp example
+project that comes with fpc (in `packages/wasm-utils/demos/http`), and put
+it in this demo directory.
+

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
demo/wasienv/wasm-http/bulma.min.css


+ 99 - 0
demo/wasienv/wasm-http/httphost.lpi

@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <SaveOnlyProjectUnits Value="True"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="httphost"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <CustomData Count="3">
+      <Item0 Name="MaintainHTML" Value="1"/>
+      <Item1 Name="Pas2JSProject" Value="1"/>
+      <Item2 Name="PasJSWebBrowserProject" Value="1"/>
+    </CustomData>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="httphost.lpr"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="FMXHost"/>
+      </Unit>
+      <Unit>
+        <Filename Value="index.html"/>
+        <IsPartOfProject Value="True"/>
+        <CustomData Count="1">
+          <Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
+        </CustomData>
+      </Unit>
+      <Unit>
+        <Filename Value="hostconfig.js"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="../../Src/HTTP/pas2js/wasm.pas2js.httpapi.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="httphost"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../../Src/HTTP;../../Src/HTTP/pas2js"/>
+      <UnitOutputDirectory Value="js"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <AllowLabel Value="False"/>
+        <UseAnsiStrings Value="False"/>
+        <CPPInline Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <CodeGeneration>
+      <TargetOS Value="browser"/>
+    </CodeGeneration>
+    <Linking>
+      <Debugging>
+        <GenerateDebugInfo Value="False"/>
+        <UseLineInfoUnit Value="False"/>
+      </Debugging>
+    </Linking>
+    <Other>
+      <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
+      <CompilerPath Value="$(pas2js)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 84 - 0
demo/wasienv/wasm-http/httphost.lpr

@@ -0,0 +1,84 @@
+{
+    This file is part of the Free Component Library
+
+    Webassembly HTTP API - demo host program 
+    Copyright (c) 2024 by Michael Van Canneyt [email protected]
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+program httphost;
+
+{$mode objfpc}
+{$modeswitch externalclass}
+
+uses
+  BrowserConsole, JS, Classes, SysUtils, Web, WasiEnv, WasiHostApp,
+  wasm.pas2js.httpapi;
+
+Type
+  THostConfig = class external name 'Object' (TJSObject)
+    wasmFilename : String;
+    logHTTPAPI : Boolean;
+    logWasiAPI : Boolean;
+  end;
+
+var
+  HostConfig : THostConfig; external name 'hostConfig';
+
+Type
+
+
+   { THTTPHostApplication }
+
+  THTTPHostApplication = class(TBrowserWASIHostApplication)
+  Private
+    FHTTPAPI : TWasmHTTPAPI;
+  Public
+    constructor Create(aOwner : TComponent); override;
+    procedure DoRun; override;
+  end;
+
+
+constructor THTTPHostApplication.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  FHTTPAPI:=TWasmHTTPAPI.Create(WasiEnvironment);
+  RunEntryFunction:='_initialize';
+  if isDefined(hostConfig) and Assigned(hostConfig) then
+    begin
+    WasiEnvironment.LogAPI:=HostConfig.logWasiAPi;
+    FHTTPAPI.LogAPICalls:=HostConfig.logHTTPAPI;
+    end;
+end;
+
+procedure THTTPHostApplication.DoRun;
+
+var
+  wasm : String;
+
+begin
+  Terminate;
+  if Assigned(HostConfig) and isString(HostConfig.wasmFilename) then
+    Wasm:=HostConfig.wasmFilename
+  else
+    begin
+    Wasm:=ParamStr(1);
+    if Wasm='' then
+      Wasm:='wasmhttpdemo.wasm';
+    end;
+  StartWebAssembly(Wasm, true);
+end;
+
+var
+  Application : THTTPHostApplication;
+begin
+  Application:=THTTPHostApplication.Create(nil);
+  Application.Initialize;
+  Application.Run;
+end.

+ 34 - 0
demo/wasienv/wasm-http/index.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <title>FMX Host</title>
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> <!-- Prevents caching -->
+    <meta http-equiv="Pragma" content="no-cache"> <!-- Legacy HTTP 1.0 backward compatibility -->
+    <meta http-equiv="Expires" content="0"> <!-- Proxies -->
+    <link href="bulma.min.css" rel="stylesheet">
+    <script src="hostconfig.js"></script>
+    <script src="httphost.js"></script>
+    <style>
+      #pasjsconsole {
+        border-style: solid;
+        border-width: 1px;
+        margin-left: 64px;
+        margin-right: 64px;
+      }
+    </style>
+  </head>
+<body>
+  <div class="container">
+  <h3 class="title is-3">Webassembly program output</h3>
+  <hr>
+  <div class="box">
+    <div id="pasjsconsole" >
+    </div>
+  </div>  
+  <script>
+    rtl.showUncaughtExceptions=true;
+    rtl.run();
+  </script>
+</body>
+</html>

+ 18 - 8
fpmake.pp

@@ -170,15 +170,27 @@ end;
 Procedure AddDemoFiles(Files : TConditionalDestStrings; ADir,APrefix : String);
 
 Const
-  DemoExt = '.pp.pas.inc.lpr.lpi.html.md';
+  DemoExt = '.pp.pas.inc.lpr.lpi.html.md.css';
 
 begin
   AddInstallFiles(Files,'demo'+PathDelim+ADir,demoExt,APrefix);
 end;
 
+const 
+  demos : Array of string = (
+    'apiclient','asyncawait','atom','bootstrap','chartjs','css','dataabstract',
+    'datamodule','datatables','debugcapture','design','dynload','electron',
+    'errorhandler','extend_jsclass','fcldb','fpcunit','fpreport','fullcalendar',
+    'hotreload','jitsimeet','jquery','jspdf','kurento','library','modules',
+    'nodehttpserver','opentok','pacman','player','promise','pushjs','pwa',
+    'regexp','resources','restbridge','router','rtl','scratch','templates',
+    'testinsight','tetris','tinyeditor','translate','ts2pas','uselibpas2js',
+    'vscode','wasienv','webcompiler','webgl','websockets','webwidget/designdemo',
+    'webwidget/nativedesign', 'webwidget/widgets','xterm','zenfs' );
+
 Var
   P : TPackage;
-  UnitDir,DemoDir,BD, TmpCfg, TmpCfg2: String;
+  aDemo, UnitDir,DemoDir,BD, TmpCfg, TmpCfg2: String;
   {$IF FPC_FULLVERSION>=30301}
   T: TTarget;
   {$ENDIF}
@@ -336,14 +348,12 @@ begin
       AddPackageFiles(P.InstallFiles,'vscode',UnitDir);   
       AddPackageFiles(P.InstallFiles,'webwidget',UnitDir);   
       AddPackageFiles(P.InstallFiles,'zenfs',UnitDir);   
+      AddPackageFiles(P.InstallFiles,'wasm-utils',UnitDir);   
+      AddPackageFiles(P.InstallFiles,'wasm-oi',UnitDir);   
       // Demo files
       DemoDir:=IncludeTrailingPathDelimiter(Defaults.ExamplesInstallDir);
-      AddDemoFiles(P.InstallFiles,'fcldb',DemoDir);
-      AddDemoFiles(P.InstallFiles,'fpcunit',DemoDir);
-      AddDemoFiles(P.InstallFiles,'fpreport',DemoDir);
-      AddDemoFiles(P.InstallFiles,'hotreload',DemoDir);
-      AddDemoFiles(P.InstallFiles,'jquery',DemoDir);
-      AddDemoFiles(P.InstallFiles,'rtl',DemoDir);
+      For aDemo in Demos do
+        AddDemoFiles(P.InstallFiles,aDemo,DemoDir);
       end;
     rmClean:
       begin

+ 697 - 0
packages/wasm-utils/src/wasm.pas2js.httpapi.pas

@@ -0,0 +1,697 @@
+{
+    This file is part of the Pas2JS run time library.
+    
+    Provides a Webassembly module with HTTP protocol capabilities
+    Copyright (c) 2024 by Michael Van Canneyt
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+unit wasm.pas2js.httpapi;
+
+{$mode ObjFPC}
+
+{ $DEFINE NOLOGAPICALLS}
+
+interface
+
+uses
+  {$IFDEF FPC_DOTTEDUNITS}
+  System.Classes, System.SysUtils, JSApi.JS, BrowserApi.Web, Wasi.Env, wasm.http.shared;
+  {$ELSE}
+  Classes, SysUtils, JS, Web, WasiEnv, types, wasm.http.shared;
+  {$ENDIF}
+
+Type
+  TWasmHTTPAPI = Class;
+  TWasmHTTPFetch = Class;
+
+  TWasmHTTPRequest = Record
+    Url : String;
+    Method : String;
+    Headers : TStringDynArray;
+    Body : TJSArrayBuffer;
+    Integrity : String;
+    Redirect: string;
+    Cache : String;
+    KeepAlive : Boolean;
+    Mode : String;
+    Priority : String;
+    Referrer : String;
+    ReferrerPolicy : String;
+    AbortSignal : Boolean;
+    Credentials: String;
+  end;
+
+  PWasmHTTPRequest = TWasmPointer;
+  PLongint = TWasmPointer;
+  PByte = TWasmPointer;
+
+  { TWasmHTTPFetch }
+
+  TWasmHTTPFetch = Class(TObject)
+  Private
+    FAPI : TWasmHTTPAPI;
+    FID : TWasmHTTPRequestID;
+    FUserData : TWasmPointer;
+    FRequestData : TWasmHTTPRequest;
+    FResponse : TJSResponse;
+    FheaderNames : TStringDynArray;
+    FAbortController : TJSAbortController;
+    FResultBody : TJSArrayBuffer;
+    FRequestError : String;
+    FInProgress : Boolean;
+    function GetHeaderName(aIndex : Longint): String;
+    function GetHeaderCount: Integer;
+  Public
+    Constructor Create(aAPI: TWasmHTTPAPI; aID : TWasmHTTPRequestID; aUserData : TWasmPointer; const aRequestData : TWasmHTTPRequest);
+    Procedure Execute; async;
+    Property ID : TWasmHTTPRequestID Read FID;
+    Property UserData : TWasmPointer Read FUserData;
+    Property RequestData : TWasmHTTPRequest Read FRequestData;
+    Property Response : TJSResponse Read FResponse;
+    Property HeaderNames[aIndex : Longint] : String Read GetHeaderName;
+    Property HeaderCount : Integer Read GetHeaderCount;
+    Property InProgress : Boolean Read FInProgress;
+    Property RequestError : String Read FRequestError;
+  end;
+
+  { TWasmHTTPAPI }
+
+  TWasmHTTPAPI = class(TImportExtension)
+  private
+    FNextRequestID : TWasmHTTPRequestID;
+    FLogApiCalls: Boolean;
+    FRequests : TJSOBject;
+    function ReadRequest(aRequest :PWasmHTTPRequest) : TWasmHTTPRequest;
+    function RequestExecute(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
+  Protected
+    Procedure LogCall(const Msg : String);
+    Procedure LogCall(Const Fmt : String; const Args : Array of const);
+    Procedure DoneRequest(aFetch : TWasmHTTPFetch);
+    Function CreateRequestID : TWasmHTTPRequestID;
+    Function FetchByID(aID : TWasmHTTPRequestID) : TWasmHTTPFetch;
+    function RequestAllocate(aRequest : PWasmHTTPRequest; aUserData : TWasmPointer; aRequestID : PWasmHTTPRequestID) : TWasmHTTPResult;
+    function RequestDeallocate(aRequestID : TWasmHTTPRequestID) : TWasmHTTPResult;
+    function RequestAbort(aRequestID : TWasmHTTPRequestID) : TWasmHTTPResult;
+    function ResponseGetStatus(aRequestID : TWasmHTTPRequestID; aStatus : PLongint) : TWasmHTTPResult;
+    function ResponseGetStatusText(aRequestID: TWasmHTTPRequestID; aStatusText: PByte; aMaxTextLen: PLongint): TWasmHTTPResult;
+    function ResponseGetHeaderCount(aRequestID : TWasmHTTPRequestID; aHeaderCount : PLongint) : TWasmHTTPResult;
+    function ResponseGetHeaderName(aRequestID : TWasmHTTPRequestID; aHeaderIdx: Longint; aHeader : PByte; aMaxHeaderLen : PLongint) : TWasmHTTPResult;
+    function ResponseGetHeader(aRequestID : TWasmHTTPRequestID; aHeaderName: PByte; aHeaderLen : PLongint; aHeader : PByte; aMaxHeaderLen : Longint) : TWasmHTTPResult;
+    function ResponseGetBody(aRequestID : TWasmHTTPRequestID; aBody : PByte; aMaxBodyLen : PLongint) : TWasmHTTPResult;
+  Public
+    Constructor Create(aEnv: TPas2JSWASIEnvironment); override;
+    Procedure FillImportObject(aObject: TJSObject); override;
+    Function ImportName : String; override;
+    property LogApiCalls : Boolean Read FLogApiCalls Write FLogApiCalls;
+  end;
+
+Function CacheToString(aCache : Integer) : String;
+
+implementation
+
+Const
+  CacheNames : Array[0..5] of string = ('default','no-store','reload','no-cache','force-cache','only-if-cached');
+  ModeNames : Array[0..4] of string = ('cors','same-origin','no-cors','navigate','websocket');
+  PriorityNames : Array[0..2] of string = ('auto','low','high');
+  RedirectNames : Array[0..2] of string = ('follow','error','manual');
+  CredentialNames : Array[0..2] of string = ('same-origin','omit','include');
+
+Function CacheToString(aCache : Integer) : String;
+
+begin
+  Result:='';
+  if (aCache>=0) and (aCache<=5) then
+    Result:=CacheNames[aCache];
+end;
+
+Function RedirectToString(aRedirect : Integer) : String;
+
+begin
+  Result:='';
+  if (aRedirect>=0) and (aRedirect<=2) then
+    Result:=RedirectNames[aRedirect];
+end;
+
+
+function KeepAliveToBool(const aKeepAlive : Integer) : boolean;
+
+begin
+  Result:=aKeepAlive<>0;
+end;
+
+function AbortSignalToBool(const aKeepAlive : Integer) : boolean;
+
+begin
+  Result:=aKeepAlive<>0;
+end;
+
+function ModeToString(const aMode : Integer) : string;
+
+
+begin
+  Result:='';
+  if (aMode>=0) and (aMode<=4) then
+    Result:=ModeNames[aMode];
+end;
+
+function PriorityToString(const aPriority : Integer) : string;
+
+begin
+  Result:='';
+  if (aPriority>=0) and (aPriority<=2) then
+    Result:=PriorityNames[aPriority];
+end;
+
+function CredentialsToString(const aCredentials : Integer) : string;
+
+begin
+  Result:='';
+  if (aCredentials>=0) and (aCredentials<=2) then
+    Result:=CredentialNames[aCredentials];
+end;
+
+{ TWasmHTTPFetch }
+
+function TWasmHTTPFetch.GetHeaderCount: Integer;
+
+var
+  It : TJSIterator;
+  Itm : TJSIteratorValue;
+
+begin
+  if (Length(FheaderNames)=0) and Assigned(FResponse) then
+    begin
+    It:=FResponse.headers.Keys;
+    Itm:=It.next;
+    While not Itm.done do
+      begin
+      TJSArray(FheaderNames).Push(Itm.value);
+      Itm:=It.Next;
+      end;
+    end;
+  Result:=Length(FHeaderNames);
+end;
+
+function TWasmHTTPFetch.GetHeaderName(aIndex : Longint): String;
+begin
+  if (aIndex>=0) and (aIndex<Length(FHeaderNames)) then
+    Result:=FHeaderNames[aIndex]
+  else
+    Result:='';
+end;
+
+constructor TWasmHTTPFetch.Create(aAPI: TWasmHTTPAPI; aID: TWasmHTTPRequestID; aUserData: TWasmPointer;
+  const aRequestData: TWasmHTTPRequest);
+begin
+  FAPI:=aAPI;
+  FID:=aID;
+  FUserData:=aUserData;
+  FRequestData:=aRequestData;
+  FheaderNames:=[];
+  FInProgress:=True;
+end;
+
+procedure TWasmHTTPFetch.Execute; async;
+
+var
+  lResponse : TJSResponse;
+  lBuf : TJSarrayBuffer;
+  lRequest : TJSRequest;
+  lHeaders,lRequestInit : TJSObject;
+
+  HNV : TStringDynArray;
+  H,N,V : String;
+
+  Procedure MaybeInit(const aName,aValue : String);
+
+  begin
+    if aValue<>'' then
+      lRequestInit[aName]:=aValue;
+  end;
+
+begin
+  lRequestInit:=TJSObject.New;
+  if Length(FRequestData.Headers)>0 then
+    begin
+    lHeaders:=TJSObject.new;
+    lRequestInit['headers']:=lHeaders;
+    for H in FRequestData.Headers do
+      begin
+      HNV:=TJSString(H).split(':');
+      V:='';
+      N:=Trim(HNV[0]);
+      if Length(HNV)>1 then
+        V:=Trim(HNV[1]);
+      lHeaders[N]:=V;
+      end;
+    end;
+  With FRequestData do
+    begin
+    MaybeInit('mode',Mode);
+    MaybeInit('method',Method);
+    MaybeInit('cache',Cache);
+    MaybeInit('integrity',Integrity);
+    if Assigned(Body) then
+      lRequestInit['body']:=Body;
+    if KeepAlive then
+    lRequestInit['keepalive']:=KeepAlive;
+    MaybeInit('redirect',Redirect);
+    MaybeInit('priority',Priority);
+    MaybeInit('referrer',Referrer);
+    MaybeInit('referrerPolicy',ReferrerPolicy);
+    if AbortSignal then
+      begin
+      FAbortController:=TJSAbortController.New;
+      lRequestInit['signal']:=FAbortController.Signal;
+      end;
+    end;
+  lRequest:=TJSRequest.New(FRequestData.Url,lRequestInit);
+  lBuf:=Nil;
+  try
+    lResponse:=aWait(Window.Asyncfetch(lRequest));
+    lBuf:=aWait(TJSArrayBuffer,lResponse.arrayBuffer);
+    fResultBody:=lBuf;
+    FResponse:=lResponse;
+  except
+    on E : TJSError do
+      FRequestError:=e.Message;
+    on O : TJSObject do
+      if  O.hasOwnProperty('message') and IsString(O.Properties['message']) then
+       FRequestError:=String(O.Properties['message']);
+  end;
+  FInProgress:=False;
+  // Notify the API
+  if assigned(FAPI) then
+    FAPI.DoneRequest(Self);
+end;
+
+{ TWasmHTTPAPI }
+
+function TWasmHTTPAPI.ReadRequest(aRequest: PWasmHTTPRequest): TWasmHTTPRequest;
+
+Var
+  P : TWasmPointer;
+  V : TJSDataView;
+  HeaderCount : Integer;
+
+  Function GetInt32 : longint;
+  begin
+    Result:=v.getInt32(P,Env.IsLittleEndian);
+    Inc(P,SizeInt32);
+  end;
+
+  Function GetString : string;
+
+  var
+    Ptr,Len : Longint;
+
+  begin
+    Ptr:=v.getInt32(P,Env.IsLittleEndian);
+    Inc(P,SizeInt32);
+    Len:=v.getInt32(P,Env.IsLittleEndian);
+    Inc(P,SizeInt32);
+    Result:=Env.GetUTF8StringFromMem(Ptr,Len);
+  end;
+
+  Function GetBuffer : TJSArrayBuffer;
+
+  var
+    Ptr,Len : Longint;
+
+  begin
+    Result:=Nil;
+    Ptr:=v.getInt32(P,Env.IsLittleEndian);
+    Inc(P,SizeInt32);
+    Len:=v.getInt32(P,Env.IsLittleEndian);
+    Inc(P,SizeInt32);
+    if Len>0 then
+      Result:=Env.Memory.buffer.slice(Ptr,Ptr+Len);
+  end;
+
+var
+  i : Integer;
+
+begin
+  v:=getModuleMemoryDataView;
+  P:=aRequest;
+  // Order is important !
+  Result.Url:=GetString;
+  Result.Method:=GetString;
+  HeaderCount:=v.getInt32(P,Env.IsLittleEndian);
+  inc(P,SizeInt32);
+  SetLength(Result.Headers,HeaderCount);
+  for I:=0 to HeaderCount-1 do
+    Result.Headers[i]:=Getstring;
+  Result.Body:=GetBuffer;
+  Result.Integrity:=GetString;
+  Result.Redirect:=RedirectToString(GetInt32);
+  Result.Cache:=CacheToString(GetInt32);
+  Result.KeepAlive:=KeepAliveToBool(GetInt32);
+  Result.Mode:=ModeToString(GetInt32);
+  Result.Priority:=PriorityToString(GetInt32);
+  Result.Referrer:=GetString;
+  Result.ReferrerPolicy:=GetString;
+  Result.AbortSignal:=AbortSignalToBool(GetInt32);
+  Result.Credentials:=CredentialsToString(GetInt32);
+end;
+
+procedure TWasmHTTPAPI.LogCall(const Msg: String);
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If not LogAPICalls then exit;
+  Writeln(Msg);
+  {$ENDIF}
+end;
+
+procedure TWasmHTTPAPI.LogCall(const Fmt: String; const Args: array of const);
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If not LogAPICalls then exit;
+  Writeln(Format(Fmt,Args));
+  {$ENDIF}
+end;
+
+type
+  TDoneCallback = Function(aRequestID : TWasmHTTPRequestID; aUserData : TWasmPointer; aStatus : TWasmHTTPResponseStatus) : TWasmHTTPResponseResult;
+
+procedure TWasmHTTPAPI.DoneRequest(aFetch: TWasmHTTPFetch);
+
+var
+  Exp : JSValue;
+  Callback : TDoneCallback absolute exp;
+  Res,Stat : Longint;
+  doDispose : Boolean;
+
+begin
+  doDispose:=True;
+  Exp:=InstanceExports[httpFN_ResponseCallback];
+  if aFetch.FRequestError<>'' then
+    Stat:=-1
+  else
+    Stat:=aFetch.Response.status;
+  if isFunction(Exp) then
+    begin
+    Res:=Callback(aFetch.ID,aFetch.UserData,Stat);
+    DoDispose:=(Res=WASMHTTP_RESPONSE_DEALLOCATE);
+    end
+  else
+    console.error('No request callback available!');
+  if DoDispose then
+    begin
+    FRequests[IntToStr(aFetch.ID)]:=undefined;
+    FreeAndNil(aFetch);
+    end;
+end;
+
+function TWasmHTTPAPI.CreateRequestID: TWasmHTTPRequestID;
+begin
+  Inc(FNextRequestID);
+  Result:=FNextRequestID;
+end;
+
+function TWasmHTTPAPI.FetchByID(aID: TWasmHTTPRequestID): TWasmHTTPFetch;
+
+var
+  Value : JSValue;
+
+begin
+  Value:=FRequests[IntToStr(aID)];
+  if isObject(Value) then
+    Result:=TWasmHTTPFetch(Value)
+  else
+    Result:=Nil;
+end;
+
+function TWasmHTTPAPI.RequestAllocate(aRequest: PWasmHTTPRequest; aUserData: TWasmPointer; aRequestID: PWasmHTTPRequestID
+  ): TWasmHTTPResult;
+
+var
+  lReq : TWasmHTTPRequest;
+  lID : TWasmHTTPRequestID;
+  lfetch : TWasmHTTPFetch;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestAllocate([%x],[%x],[%x])',[aRequest,aUserData,aRequestID]);
+  {$ENDIF}
+  lReq:=ReadRequest(aRequest);
+  if (lReq.Url='') then
+    Exit(WASMHTTP_RESULT_NO_URL);
+  lID:=CreateRequestID;
+  lFetch:=TWasmHTTPFetch.Create(Self,lID,aUserData,lReq);
+  FRequests[IntToStr(lID)]:=lFetch;
+  env.SetMemInfoInt32(aRequestID,lID);
+  Result:=WASMHTTP_RESULT_SUCCESS;
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestAllocate([%x],[%x]) => %d',[aRequest,aUserData,lID]);
+  {$ENDIF}
+end;
+
+function TWasmHTTPAPI.RequestExecute(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
+
+var
+  lReq : TWasmHTTPRequest;
+  lID : TWasmHTTPRequestID;
+  lfetch : TWasmHTTPFetch;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestExecute(%d)',[aRequestID]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  lFetch.Execute;
+  Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.RequestDeallocate(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
+
+var
+  lFetch : TWasmHTTPFetch;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestDeAllocate(%d)',[aRequestID]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+end;
+
+function TWasmHTTPAPI.RequestAbort(aRequestID: TWasmHTTPRequestID): TWasmHTTPResult;
+
+var
+  lFetch : TWasmHTTPFetch;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestAbort(%d)',[aRequestID]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+end;
+
+function TWasmHTTPAPI.ResponseGetStatus(aRequestID: TWasmHTTPRequestID; aStatus: PLongint): TWasmHTTPResult;
+var
+  lFetch : TWasmHTTPFetch;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.ResponseGetStatus(%d,[%x])',[aRequestID,aStatus]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  Env.SetMemInfoInt32(aStatus,lFetch.Response.status);
+  Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.ResponseGetStatusText(aRequestID: TWasmHTTPRequestID; aStatusText: PByte; aMaxTextLen: PLongint
+  ): TWasmHTTPResult;
+var
+  lFetch : TWasmHTTPFetch;
+  v : TJSDataView;
+  Written,MaxLen : Longint;
+  S : String;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.ResponseGetStatusText(%d,[%x],[%x])',[aRequestID,aStatusText,aMaxTextlen]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  v:=getModuleMemoryDataView;
+  MaxLen:=v.getInt32(aMaxTextLen,Env.IsLittleEndian);
+  S:=lFetch.Response.statusText;
+  Written:=Env.SetUTF8StringInMem(aStatusText,MaxLen,S);
+  Env.SetMemInfoInt32(aMaxTextLen,Abs(Written));
+  if Written<0 then
+    Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
+  else
+    Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.ResponseGetHeaderCount(aRequestID: TWasmHTTPRequestID; aHeaderCount: PLongint): TWasmHTTPResult;
+
+var
+  lFetch : TWasmHTTPFetch;
+  lCount : Longint;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.ResponseGetHeaderCount(%d,[%x])',[aRequestID,aHeaderCount]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  lCount:=lFetch.HeaderCount;
+  Env.SetMemInfoInt32(aHeaderCount,lCount);
+  Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.ResponseGetHeaderName(aRequestID: TWasmHTTPRequestID; aHeaderIdx: Longint; aHeader: PByte;
+  aMaxHeaderLen: PLongint): TWasmHTTPResult;
+
+var
+  lFetch : TWasmHTTPFetch;
+  S : String;
+  MaxLen,Written : Longint;
+  v : TJSDataView;
+
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.RequestGetHeaderName(%d,%d,[%x],[%x])',[aRequestID,aHeaderIdx,aHeader,aMaxHeaderLen]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  V:=getModuleMemoryDataView;
+  MaxLen:=v.getInt32(aMaxheaderLen,Env.IsLittleEndian);
+  S:=lFetch.HeaderNames[aHeaderIdx];
+  Written:=Env.SetUTF8StringInMem(aHeader,MaxLen,S);
+  Env.SetMemInfoInt32(aMaxheaderLen,Abs(Written));
+  if Written<0 then
+    Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
+  else
+    Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.ResponseGetHeader(aRequestID: TWasmHTTPRequestID; aHeaderName: PByte; aHeaderLen: PLongint; aHeader: PByte;
+  aMaxHeaderLen: Longint): TWasmHTTPResult;
+var
+  lFetch : TWasmHTTPFetch;
+  lHeader, lName : String;
+  Written,Maxlen : Longint;
+  v : TJSDataView;
+begin
+  v:=getModuleMemoryDataView;
+  lName:=Env.GetUTF8StringFromMem(aHeaderName,aHeaderLen);
+  MaxLen:=v.getInt32(aMaxHeaderLen,Env.IsLittleEndian);
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.ResponseGetHeader(%d,"%s",[%x])',[aRequestID,lName,aHeader,aMaxHeaderLen]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  lHeader:=lfetch.Response.headers[lName];
+  Written:=Env.SetUTF8StringInMem(aHeader,MaxLen,lheader);
+  Env.SetMemInfoInt32(aMaxheaderLen,Abs(Written));
+  if Written<0 then
+    Result:=WASMHTTP_RESULT_INSUFFICIENTMEM
+  else
+    Result:=WASMHTTP_RESULT_SUCCESS;
+end;
+
+function TWasmHTTPAPI.ResponseGetBody(aRequestID: TWasmHTTPRequestID; aBody: PByte; aMaxBodyLen: PLongint): TWasmHTTPResult;
+var
+  lFetch : TWasmHTTPFetch;
+  lwasmMem,lUint8Array : TJSUint8Array;
+  v : TJSDataView;
+  bodyLen,maxLen : longint;
+begin
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    LogCall('HTTP.ResponseGetBody([%x],[%x],[%x])',[aRequestID,aBody,aMaxBodyLen]);
+  {$ENDIF}
+  lfetch:=FetchByID(aRequestID);
+  if not Assigned(lFetch) then
+    Exit(WASMHTTP_RESULT_INVALIDID);
+  if lFetch.InProgress then
+    Exit(WASMHTTP_RESULT_INPROGRESS);
+  if Not Assigned(lFetch.FResultBody) then
+    begin
+    Env.SetMemInfoInt32(aMaxBodyLen,0);
+    exit;
+    end;
+  v:=getModuleMemoryDataView;
+  MaxLen:=v.getInt32(aMaxBodyLen,Env.IsLittleEndian);
+  bodyLen:=lFetch.FResultBody.byteLength;
+  Env.SetMemInfoInt32(aMaxBodyLen,bodyLen);
+  if (MaxLen<bodyLen) then
+    Exit(WASMHTTP_RESULT_INSUFFICIENTMEM);
+  lUint8Array:=TJSUint8Array.new(lFetch.FResultBody);
+  lwasmMem:=TJSUint8Array.New(v.buffer);
+  lWasmMem._set(lUint8Array,aBody);
+  Exit(WASMHTTP_RESULT_SUCCESS);
+end;
+
+constructor TWasmHTTPAPI.Create(aEnv: TPas2JSWASIEnvironment);
+begin
+  inherited Create(aEnv);
+  FRequests:=TJSOBject.new;
+
+end;
+
+procedure TWasmHTTPAPI.FillImportObject(aObject: TJSObject);
+begin
+  AObject[httpFN_RequestAllocate]:=@RequestAllocate;
+  AObject[httpFN_RequestExecute]:=@RequestExecute;
+  AObject[httpFN_RequestDeAllocate]:=@RequestDeallocate;
+  AObject[httpFN_RequestAbort]:=@RequestAbort;
+  AObject[httpFN_ResponseGetStatus]:=@ResponseGetStatus;
+  AObject[httpFN_ResponseGetStatusText]:=@ResponseGetStatusText;
+  AObject[httpFN_ResponseGetHeaderName]:=@ResponseGetHeaderName;
+  AObject[httpFN_ResponseGetHeaderCount]:=@ResponseGetHeaderCount;
+  AObject[httpFN_ResponseGetHeader]:=@ResponseGetHeader;
+  AObject[httpFN_ResponseGetBody]:=@ResponseGetBody;
+
+end;
+
+function TWasmHTTPAPI.ImportName: String;
+begin
+  Result:=httpExportName
+end;
+
+end.
+

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov