├── .gitignore ├── AWSCustomRuntime.lpi ├── AWSCustomRuntime.pas ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /lib 3 | /backup 4 | /AWSCustomRuntime 5 | 6 | *.exe 7 | *.dll 8 | *.bpl 9 | *.bpi 10 | *.dcp 11 | *.so 12 | *.apk 13 | *.drc 14 | *.map 15 | *.mab 16 | *.dres 17 | *.rsm 18 | *.tds 19 | *.dcu 20 | *.lib 21 | *.a 22 | *.o 23 | *.ocx 24 | *.lps 25 | *.com 26 | *.ppu 27 | *.compiled 28 | *.rsj 29 | *.or 30 | 31 | -------------------------------------------------------------------------------- /AWSCustomRuntime.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <UseAppBundle Value="False"/> 15 | <ResourceType Value="res"/> 16 | </General> 17 | <BuildModes Count="2"> 18 | <Item1 Name="Debug" Default="True"/> 19 | <Item2 Name="Release"> 20 | <CompilerOptions> 21 | <Version Value="11"/> 22 | <Target> 23 | <Filename Value="bin/$(TargetCPU)-$(TargetOS)/bootstrap"/> 24 | </Target> 25 | <SearchPaths> 26 | <IncludeFiles Value="$(ProjOutDir)"/> 27 | <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> 28 | </SearchPaths> 29 | <CodeGeneration> 30 | <TargetCPU Value="x86_64"/> 31 | <TargetOS Value="linux"/> 32 | <Optimizations> 33 | <OptimizationLevel Value="2"/> 34 | </Optimizations> 35 | </CodeGeneration> 36 | <Linking> 37 | <Debugging> 38 | <GenerateDebugInfo Value="False"/> 39 | </Debugging> 40 | </Linking> 41 | </CompilerOptions> 42 | </Item2> 43 | </BuildModes> 44 | <PublishOptions> 45 | <Version Value="2"/> 46 | <UseFileFilters Value="True"/> 47 | </PublishOptions> 48 | <RunParams> 49 | <FormatVersion Value="2"/> 50 | <Modes Count="0"/> 51 | </RunParams> 52 | <Units Count="1"> 53 | <Unit0> 54 | <Filename Value="AWSCustomRuntime.pas"/> 55 | <IsPartOfProject Value="True"/> 56 | </Unit0> 57 | </Units> 58 | </ProjectOptions> 59 | <CompilerOptions> 60 | <Version Value="11"/> 61 | <Target> 62 | <Filename Value="bin/$(TargetCPU)-$(TargetOS)/AWSCustomRuntime"/> 63 | </Target> 64 | <SearchPaths> 65 | <IncludeFiles Value="$(ProjOutDir)"/> 66 | <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> 67 | </SearchPaths> 68 | <CodeGeneration> 69 | <Optimizations> 70 | <OptimizationLevel Value="0"/> 71 | </Optimizations> 72 | </CodeGeneration> 73 | </CompilerOptions> 74 | <Debugging> 75 | <Exceptions Count="3"> 76 | <Item1> 77 | <Name Value="EAbort"/> 78 | </Item1> 79 | <Item2> 80 | <Name Value="ECodetoolError"/> 81 | </Item2> 82 | <Item3> 83 | <Name Value="EFOpenError"/> 84 | </Item3> 85 | </Exceptions> 86 | </Debugging> 87 | </CONFIG> 88 | -------------------------------------------------------------------------------- /AWSCustomRuntime.pas: -------------------------------------------------------------------------------- 1 | program AWSCustomRuntime; 2 | 3 | {$mode objfpc}{$H+} 4 | 5 | uses 6 | sysutils, classes, fphttpclient, fpjson, jsonparser; 7 | 8 | var 9 | awsHost, awsBaseUrl, awsResponseUrl, awsErrorUrl, awsRequestId, awsEventBody: String; 10 | httpClient: TFPHTTPClient; 11 | awsEvent, awsError: TJSONObject; 12 | 13 | const 14 | // Current AWS runtime API version 15 | APIVERSION = '2018-06-01'; 16 | 17 | begin 18 | awsEvent := TJSONObject.Create; 19 | awsError := TJSONObject.Create; 20 | httpClient := TFPHttpClient.Create(Nil); 21 | try 22 | // Get the runtime api awsHost 23 | awsHost := GetEnvironmentVariable('AWS_LAMBDA_RUNTIME_API'); 24 | 25 | // Create the base url 26 | awsBaseUrl := 'http://' + awsHost + '/' + APIVERSION + '/runtime/invocation/'; 27 | 28 | while true do begin 29 | try 30 | // Get the event 31 | awsEventBody := httpClient.get(awsBaseUrl + 'next'); 32 | 33 | // Get the JSON data and set the TJSONObject 34 | awsEvent := TJSONObject(GetJSON(awsEventBody)); 35 | 36 | // Pretty-print the event (Should be visible in logwatch) 37 | WriteLn(awsEvent.FormatJSON); 38 | 39 | // Get the request id, used when responding 40 | awsRequestId := trim(httpClient.ResponseHeaders.Values['Lambda-Runtime-AWS-Request-Id']); 41 | 42 | // Create the response url 43 | awsResponseUrl := awsBaseUrl + awsRequestId + '/response'; 44 | 45 | // Create error url 46 | awsErrorUrl := awsBaseUrl + awsRequestId + '/error'; 47 | 48 | // Send successful event response 49 | TFPHttpClient.SimpleFormPost(awsResponseUrl, awsEventBody); 50 | 51 | { 52 | Error responses should follow the JSON format below, see here for details 53 | https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html#runtimes-api-invokeerror 54 | 55 | Example 56 | ------- 57 | 58 | awsError.Strings['errorMessage'] := 'Something went horribly wrong'; 59 | awsError.Strings['errorType'] := 'InvalidEventDataException'; 60 | 61 | TFPHttpClient.SimpleFormPost(awsErrorUrl, awsError.AsJSON); 62 | } 63 | except 64 | end; 65 | end; 66 | 67 | finally 68 | httpClient.Free; 69 | awsEvent.Free; 70 | awsError.Free; 71 | end; 72 | end. 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Marcus Fernstrom - Rights extended to PascalAWS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS FreePascal Custom Runtime 2 | 3 | A bare bones FreePascal Custom Runtime for AWS Lambda 4 | 5 | The custom runtime allows you to use FreePascal natively on AWS Lambda without any side-loading or hacky tricks. 6 | 7 | This is the core skeleton and contains no functionality other than the basic setup and event polling. 8 | 9 | Use it as-is for max performance, or wait for the webserver one (Coming soon) which lets you easily use fpHttpServer (Equivalent to using Express.js with the Node.js runtime) 10 | 11 | ### Useful links 12 | 13 | https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html 14 | 15 | https://docs.aws.amazon.com/lambda/latest/dg/runtimes-walkthrough.html 16 | --------------------------------------------------------------------------------