Skip to content

Commit

Permalink
Merge pull request #115 from extism/update-pdk
Browse files Browse the repository at this point in the history
feat: update the PDK to use the latest features
  • Loading branch information
mhmd-azeez authored Dec 5, 2024
2 parents 1a8c9e7 + 422b6da commit 0907cb9
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 96 deletions.
4 changes: 4 additions & 0 deletions samples/KitchenSink/KitchenSink.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
<ProjectReference Include="..\SampleLib\SampleLib.csproj" />
Expand Down
10 changes: 9 additions & 1 deletion samples/KitchenSink/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Extism;
using SampleLib;
using System.Text.Json.Serialization;
using System.Collections.Generic;

Class1.noop(); // Import Class1 from SampleLib so that it's included during compilation
Console.WriteLine("Hello world!");
Expand Down Expand Up @@ -81,20 +82,27 @@ public static int GetTodo()
request.Headers.Add("Authorization", $"Basic {token}");

var response = Pdk.SendRequest(request);

if (!response.Headers.TryGetValue("content-type", out var contentType) || !contentType.Contains("application/json"))
{
Pdk.SetError($"Invalid content-type header. Expected 'application/json', got '{contentType}'");
}

Pdk.SetOutput(response.Body);
return 0;
}

[UnmanagedCallersOnly(EntryPoint = "throw")]
public static int Throw()
{
// Exceptions are also handled, but Pdk.SetError is recommeded to use.
// Extism PDK also tries to handle Exceptions, but Pdk.SetError is recommeded to use.
throw new InvalidOperationException("Something bad happened.");
}
}

[JsonSerializable(typeof(ConcatInput))]
[JsonSerializable(typeof(ConcatOutput))]
[JsonSerializable(typeof(Dictionary<string, string>))]
public partial class JsonContext : JsonSerializerContext {}

public class ConcatInput
Expand Down
4 changes: 4 additions & 0 deletions samples/SampleCSharpPlugin/SampleCSharpPlugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
</ItemGroup>
Expand Down
8 changes: 8 additions & 0 deletions samples/SampleFSharpPlugin/SampleFSharpPlugin.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@
<Compile Include="Program.fs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="9.0.100" />
</ItemGroup>

<!--This is only necessary for ProjectReference, when using the nuget package this will not be necessary-->
<Import Project="..\..\src\Extism.Pdk\build\Extism.Pdk.targets" />
Expand Down
4 changes: 2 additions & 2 deletions samples/SampleHost/SampleHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.0" />
<PackageReference Include="Extism.Sdk" Version="1.2.1" />
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
<PackageReference Include="Extism.Sdk" Version="1.9.0" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions samples/SampleLib/SampleLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.all" Version="1.9.1" />
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
</ItemGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/Extism.Pdk.MSBuild/Extism.Pdk.MSBuild.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

<ItemGroup>

<PackageReference Include="Extism.runtime.all" Version="1.9.1" />

<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />

<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.12.6" ExcludeAssets="Runtime" />

<PackageReference Include="Mono.Cecil" Version="0.11.6">
Expand Down
2 changes: 1 addition & 1 deletion src/Extism.Pdk.MSBuild/FFIGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,4 @@ public class FileEntry
/// </summary>
public string Content { get; set; } = default!;
}
}
}
2 changes: 2 additions & 0 deletions src/Extism.Pdk/Extism.Pdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Extism.runtime.all" Version="1.9.1" />
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
<PackageReference Include="MinVer" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
120 changes: 90 additions & 30 deletions src/Extism.Pdk/Interop.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;

namespace Extism;
Expand Down Expand Up @@ -42,6 +44,7 @@ public static byte[] GetInput()
return buffer;
}


/// <summary>
/// Read the input data sent by the host as a UTF-8 encoded string.
/// </summary>
Expand Down Expand Up @@ -79,7 +82,7 @@ public static void SetOutput(MemoryBlock block)
/// Set the output data to be sent back to the host as a byte buffer.
/// </summary>
/// <param name="data">The byte buffer to set as output data.</param>
public unsafe static void SetOutput(ReadOnlySpan<byte> data)
public static unsafe void SetOutput(ReadOnlySpan<byte> data)
{
fixed (byte* ptr = data)
{
Expand Down Expand Up @@ -133,6 +136,10 @@ public static void SetError(string errorMessage)
public static MemoryBlock Allocate(ulong length)
{
var offset = Native.extism_alloc(length);
if (offset == 0 && length > 0)
{
throw new InvalidOperationException("Failed to allocate memory block.");
}

return new MemoryBlock(offset, length);
}
Expand Down Expand Up @@ -203,8 +210,17 @@ public static bool TryGetConfig(string key, [NotNullWhen(true)] out string value
/// <param name="block">The memory block containing the log message.</param>
public static void Log(LogLevel level, MemoryBlock block)
{
if (level < (LogLevel)Native.extism_get_log_level())
{
return;
}

switch (level)
{
case LogLevel.Trace:
Native.extism_log_trace(block.Offset);
break;

case LogLevel.Info:
Native.extism_log_info(block.Offset);
break;
Expand All @@ -230,6 +246,11 @@ public static void Log(LogLevel level, MemoryBlock block)
/// <param name="message"></param>
public static void Log(LogLevel level, string message)
{
if (level < (LogLevel)Native.extism_get_log_level())
{
return;
}

var block = Allocate(message);
Log(level, block);
}
Expand Down Expand Up @@ -306,36 +327,31 @@ public static void RemoveVar(string key)
/// <returns>The HTTP response received from the host. The plugin takes ownership of the memory block and is expected to free it.</returns>
public static HttpResponse SendRequest(HttpRequest request)
{
using var stream = new MemoryStream();
using (var writer = new Utf8JsonWriter(stream))
{
writer.WriteStartObject();
writer.WriteString("url", request.Url.AbsoluteUri);
writer.WriteString("method", Enum.GetName(typeof(HttpMethod), request.Method));
var requestJson = JsonSerializer.Serialize(request, JsonContext.Default.HttpRequest);

if (request.Headers.Count > 0)
{
writer.WriteStartObject("headers");
foreach (var kvp in request.Headers)
{
writer.WriteString(kvp.Key, kvp.Value);
}
writer.WriteEndObject();
}
using var requestBlock = Allocate(requestJson);
using var bodyBlock = Allocate(request.Body);

writer.WriteEndObject();
var responseOffset = Native.extism_http_request(requestBlock.Offset, bodyBlock.Offset);
if (responseOffset == 0)
{
throw new InvalidOperationException("Failed to send HTTP request.");
}

var bytes = stream.ToArray();
var responseBody = MemoryBlock.Find(responseOffset);
var status = Native.extism_http_status_code();
var httpResponse = new HttpResponse(responseBody, status);

var requestBlock = Allocate(bytes);
var bodyBlock = Allocate(request.Body);
var headersOffset = Native.extism_http_headers();
if (headersOffset > 0)
{
using var headersBlock = MemoryBlock.Find(headersOffset);
var headersJson = headersBlock.ReadString();

var offset = Native.extism_http_request(requestBlock.Offset, bodyBlock.Offset);
var block = MemoryBlock.Find(offset);
var status = Native.extism_http_status_code();
httpResponse.Headers = JsonSerializer.Deserialize(headersJson, JsonContext.Default.DictionaryStringString) ?? [];
}

return new HttpResponse(block, status);
return httpResponse;
}
}

Expand All @@ -345,24 +361,29 @@ public static HttpResponse SendRequest(HttpRequest request)
public enum LogLevel
{
/// <summary>
/// Information
/// Trace
/// </summary>
Info,
Trace = 0,

/// <summary>
/// Debug
/// </summary>
Debug,
Debug = 1,

/// <summary>
/// Information
/// </summary>
Info = 2,

/// <summary>
/// Warning
/// </summary>
Warn,
Warn = 3,

/// <summary>
/// Error
/// </summary>
Error
Error = 4,
}

/// <summary>
Expand Down Expand Up @@ -391,21 +412,26 @@ public HttpRequest(string url)
/// <summary>
/// HTTP URL
/// </summary>
[JsonPropertyName("url")]
public Uri Url { get; set; }

/// <summary>
/// HTTP Headers
/// </summary>
[JsonPropertyName("headers")]
public Dictionary<string, string> Headers { get; } = new();

/// <summary>
/// HTTP method
/// </summary>
[JsonPropertyName("method")]
[JsonConverter(typeof(JsonStringEnumConverter<HttpMethod>))]
public HttpMethod Method { get; set; } = HttpMethod.GET;

/// <summary>
/// An optional body.
/// </summary>
[JsonIgnore]
public byte[] Body { get; set; } = Array.Empty<byte>();
}

Expand Down Expand Up @@ -471,6 +497,11 @@ public HttpResponse(MemoryBlock memory, ushort status)
/// </summary>
public ushort Status { get; set; }

/// <summary>
/// HTTP Headers. Make sure HTTP response headers are enabled in the host.
/// </summary>
public Dictionary<string, string> Headers { get; set; } = new();

/// <summary>
/// Frees the current memory block.
/// </summary>
Expand Down Expand Up @@ -534,6 +565,8 @@ public MemoryBlock(ulong offset, ulong length)
/// <exception cref="InvalidOperationException"></exception>
public unsafe void CopyTo(Span<byte> buffer)
{
CheckDisposed();

if ((ulong)buffer.Length < Length)
{
throw new InvalidOperationException($"Buffer must be at least ${Length} bytes.");
Expand Down Expand Up @@ -562,7 +595,9 @@ public void WriteString(string text)
/// <exception cref="IndexOutOfRangeException"></exception>
public unsafe void WriteBytes(ReadOnlySpan<byte> bytes)
{
if ((ulong)bytes.Length > Length)
CheckDisposed();

if((ulong)bytes.Length > Length)
{
throw new IndexOutOfRangeException("Memory block is not big enough.");
}
Expand All @@ -579,6 +614,8 @@ public unsafe void WriteBytes(ReadOnlySpan<byte> bytes)
/// <returns></returns>
public byte[] ReadBytes()
{
CheckDisposed();

var buffer = new byte[Length];
CopyTo(buffer);

Expand Down Expand Up @@ -606,6 +643,15 @@ public static MemoryBlock Find(ulong offset)
return new MemoryBlock(offset, length);
}

private void CheckDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(MemoryBlock));
}
}

private bool _disposed;
/// <summary>
/// Frees the current memory block.
/// </summary>
Expand All @@ -617,6 +663,13 @@ public void Dispose()

private void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

_disposed = true;

if (disposing)
{
// free managed resources
Expand All @@ -628,3 +681,10 @@ private void Dispose(bool disposing)
}
}
}

[JsonSerializable(typeof(HttpRequest))]
[JsonSerializable(typeof(Dictionary<string, string>))]
internal partial class JsonContext : JsonSerializerContext
{

}
Loading

0 comments on commit 0907cb9

Please sign in to comment.