Skip to content

Commit 0907cb9

Browse files
authored
Merge pull request #115 from extism/update-pdk
feat: update the PDK to use the latest features
2 parents 1a8c9e7 + 422b6da commit 0907cb9

File tree

15 files changed

+229
-96
lines changed

15 files changed

+229
-96
lines changed

samples/KitchenSink/KitchenSink.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
<TrimmerSingleWarn>false</TrimmerSingleWarn>
1010
</PropertyGroup>
1111

12+
<ItemGroup>
13+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
14+
</ItemGroup>
15+
1216
<ItemGroup>
1317
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
1418
<ProjectReference Include="..\SampleLib\SampleLib.csproj" />

samples/KitchenSink/Program.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Extism;
44
using SampleLib;
55
using System.Text.Json.Serialization;
6+
using System.Collections.Generic;
67

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

8384
var response = Pdk.SendRequest(request);
85+
86+
if (!response.Headers.TryGetValue("content-type", out var contentType) || !contentType.Contains("application/json"))
87+
{
88+
Pdk.SetError($"Invalid content-type header. Expected 'application/json', got '{contentType}'");
89+
}
90+
8491
Pdk.SetOutput(response.Body);
8592
return 0;
8693
}
8794

8895
[UnmanagedCallersOnly(EntryPoint = "throw")]
8996
public static int Throw()
9097
{
91-
// Exceptions are also handled, but Pdk.SetError is recommeded to use.
98+
// Extism PDK also tries to handle Exceptions, but Pdk.SetError is recommeded to use.
9299
throw new InvalidOperationException("Something bad happened.");
93100
}
94101
}
95102

96103
[JsonSerializable(typeof(ConcatInput))]
97104
[JsonSerializable(typeof(ConcatOutput))]
105+
[JsonSerializable(typeof(Dictionary<string, string>))]
98106
public partial class JsonContext : JsonSerializerContext {}
99107

100108
public class ConcatInput

samples/SampleCSharpPlugin/SampleCSharpPlugin.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
88
</PropertyGroup>
99

10+
<ItemGroup>
11+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
12+
</ItemGroup>
13+
1014
<ItemGroup>
1115
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
1216
</ItemGroup>

samples/SampleFSharpPlugin/SampleFSharpPlugin.fsproj

+8
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@
1212
<Compile Include="Program.fs" />
1313
</ItemGroup>
1414

15+
<ItemGroup>
16+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
17+
</ItemGroup>
18+
1519
<ItemGroup>
1620
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
1721
</ItemGroup>
22+
23+
<ItemGroup>
24+
<PackageReference Update="FSharp.Core" Version="9.0.100" />
25+
</ItemGroup>
1826

1927
<!--This is only necessary for ProjectReference, when using the nuget package this will not be necessary-->
2028
<Import Project="..\..\src\Extism.Pdk\build\Extism.Pdk.targets" />

samples/SampleHost/SampleHost.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.0" />
12-
<PackageReference Include="Extism.Sdk" Version="1.2.1" />
11+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
12+
<PackageReference Include="Extism.Sdk" Version="1.9.0" />
1313
</ItemGroup>
1414

1515
</Project>

samples/SampleLib/SampleLib.csproj

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<PackageReference Include="Extism.runtime.all" Version="1.9.1" />
11+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
12+
</ItemGroup>
13+
914
<ItemGroup>
1015
<ProjectReference Include="..\..\src\Extism.Pdk\Extism.Pdk.csproj" />
1116
</ItemGroup>

src/Extism.Pdk.MSBuild/Extism.Pdk.MSBuild.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
<ItemGroup>
1919

20+
<PackageReference Include="Extism.runtime.all" Version="1.9.1" />
21+
22+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
23+
2024
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.12.6" ExcludeAssets="Runtime" />
2125

2226
<PackageReference Include="Mono.Cecil" Version="0.11.6">

src/Extism.Pdk.MSBuild/FFIGenerator.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,4 @@ public class FileEntry
315315
/// </summary>
316316
public string Content { get; set; } = default!;
317317
}
318-
}
318+
}

src/Extism.Pdk/Extism.Pdk.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
</PropertyGroup>
2323

2424
<ItemGroup>
25+
<PackageReference Include="Extism.runtime.all" Version="1.9.1" />
26+
<PackageReference Include="Extism.runtime.win-x64" Version="1.9.1" />
2527
<PackageReference Include="MinVer" Version="6.0.0">
2628
<PrivateAssets>all</PrivateAssets>
2729
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

src/Extism.Pdk/Interop.cs

+90-30
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System.Buffers.Binary;
22
using System.Diagnostics.CodeAnalysis;
3+
using System.Reflection.PortableExecutable;
34
using System.Text;
45
using System.Text.Json;
6+
using System.Text.Json.Serialization;
57
using System.Text.Json.Serialization.Metadata;
68

79
namespace Extism;
@@ -42,6 +44,7 @@ public static byte[] GetInput()
4244
return buffer;
4345
}
4446

47+
4548
/// <summary>
4649
/// Read the input data sent by the host as a UTF-8 encoded string.
4750
/// </summary>
@@ -79,7 +82,7 @@ public static void SetOutput(MemoryBlock block)
7982
/// Set the output data to be sent back to the host as a byte buffer.
8083
/// </summary>
8184
/// <param name="data">The byte buffer to set as output data.</param>
82-
public unsafe static void SetOutput(ReadOnlySpan<byte> data)
85+
public static unsafe void SetOutput(ReadOnlySpan<byte> data)
8386
{
8487
fixed (byte* ptr = data)
8588
{
@@ -133,6 +136,10 @@ public static void SetError(string errorMessage)
133136
public static MemoryBlock Allocate(ulong length)
134137
{
135138
var offset = Native.extism_alloc(length);
139+
if (offset == 0 && length > 0)
140+
{
141+
throw new InvalidOperationException("Failed to allocate memory block.");
142+
}
136143

137144
return new MemoryBlock(offset, length);
138145
}
@@ -203,8 +210,17 @@ public static bool TryGetConfig(string key, [NotNullWhen(true)] out string value
203210
/// <param name="block">The memory block containing the log message.</param>
204211
public static void Log(LogLevel level, MemoryBlock block)
205212
{
213+
if (level < (LogLevel)Native.extism_get_log_level())
214+
{
215+
return;
216+
}
217+
206218
switch (level)
207219
{
220+
case LogLevel.Trace:
221+
Native.extism_log_trace(block.Offset);
222+
break;
223+
208224
case LogLevel.Info:
209225
Native.extism_log_info(block.Offset);
210226
break;
@@ -230,6 +246,11 @@ public static void Log(LogLevel level, MemoryBlock block)
230246
/// <param name="message"></param>
231247
public static void Log(LogLevel level, string message)
232248
{
249+
if (level < (LogLevel)Native.extism_get_log_level())
250+
{
251+
return;
252+
}
253+
233254
var block = Allocate(message);
234255
Log(level, block);
235256
}
@@ -306,36 +327,31 @@ public static void RemoveVar(string key)
306327
/// <returns>The HTTP response received from the host. The plugin takes ownership of the memory block and is expected to free it.</returns>
307328
public static HttpResponse SendRequest(HttpRequest request)
308329
{
309-
using var stream = new MemoryStream();
310-
using (var writer = new Utf8JsonWriter(stream))
311-
{
312-
writer.WriteStartObject();
313-
writer.WriteString("url", request.Url.AbsoluteUri);
314-
writer.WriteString("method", Enum.GetName(typeof(HttpMethod), request.Method));
330+
var requestJson = JsonSerializer.Serialize(request, JsonContext.Default.HttpRequest);
315331

316-
if (request.Headers.Count > 0)
317-
{
318-
writer.WriteStartObject("headers");
319-
foreach (var kvp in request.Headers)
320-
{
321-
writer.WriteString(kvp.Key, kvp.Value);
322-
}
323-
writer.WriteEndObject();
324-
}
332+
using var requestBlock = Allocate(requestJson);
333+
using var bodyBlock = Allocate(request.Body);
325334

326-
writer.WriteEndObject();
335+
var responseOffset = Native.extism_http_request(requestBlock.Offset, bodyBlock.Offset);
336+
if (responseOffset == 0)
337+
{
338+
throw new InvalidOperationException("Failed to send HTTP request.");
327339
}
328340

329-
var bytes = stream.ToArray();
341+
var responseBody = MemoryBlock.Find(responseOffset);
342+
var status = Native.extism_http_status_code();
343+
var httpResponse = new HttpResponse(responseBody, status);
330344

331-
var requestBlock = Allocate(bytes);
332-
var bodyBlock = Allocate(request.Body);
345+
var headersOffset = Native.extism_http_headers();
346+
if (headersOffset > 0)
347+
{
348+
using var headersBlock = MemoryBlock.Find(headersOffset);
349+
var headersJson = headersBlock.ReadString();
333350

334-
var offset = Native.extism_http_request(requestBlock.Offset, bodyBlock.Offset);
335-
var block = MemoryBlock.Find(offset);
336-
var status = Native.extism_http_status_code();
351+
httpResponse.Headers = JsonSerializer.Deserialize(headersJson, JsonContext.Default.DictionaryStringString) ?? [];
352+
}
337353

338-
return new HttpResponse(block, status);
354+
return httpResponse;
339355
}
340356
}
341357

@@ -345,24 +361,29 @@ public static HttpResponse SendRequest(HttpRequest request)
345361
public enum LogLevel
346362
{
347363
/// <summary>
348-
/// Information
364+
/// Trace
349365
/// </summary>
350-
Info,
366+
Trace = 0,
351367

352368
/// <summary>
353369
/// Debug
354370
/// </summary>
355-
Debug,
371+
Debug = 1,
372+
373+
/// <summary>
374+
/// Information
375+
/// </summary>
376+
Info = 2,
356377

357378
/// <summary>
358379
/// Warning
359380
/// </summary>
360-
Warn,
381+
Warn = 3,
361382

362383
/// <summary>
363384
/// Error
364385
/// </summary>
365-
Error
386+
Error = 4,
366387
}
367388

368389
/// <summary>
@@ -391,21 +412,26 @@ public HttpRequest(string url)
391412
/// <summary>
392413
/// HTTP URL
393414
/// </summary>
415+
[JsonPropertyName("url")]
394416
public Uri Url { get; set; }
395417

396418
/// <summary>
397419
/// HTTP Headers
398420
/// </summary>
421+
[JsonPropertyName("headers")]
399422
public Dictionary<string, string> Headers { get; } = new();
400423

401424
/// <summary>
402425
/// HTTP method
403426
/// </summary>
427+
[JsonPropertyName("method")]
428+
[JsonConverter(typeof(JsonStringEnumConverter<HttpMethod>))]
404429
public HttpMethod Method { get; set; } = HttpMethod.GET;
405430

406431
/// <summary>
407432
/// An optional body.
408433
/// </summary>
434+
[JsonIgnore]
409435
public byte[] Body { get; set; } = Array.Empty<byte>();
410436
}
411437

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

500+
/// <summary>
501+
/// HTTP Headers. Make sure HTTP response headers are enabled in the host.
502+
/// </summary>
503+
public Dictionary<string, string> Headers { get; set; } = new();
504+
474505
/// <summary>
475506
/// Frees the current memory block.
476507
/// </summary>
@@ -534,6 +565,8 @@ public MemoryBlock(ulong offset, ulong length)
534565
/// <exception cref="InvalidOperationException"></exception>
535566
public unsafe void CopyTo(Span<byte> buffer)
536567
{
568+
CheckDisposed();
569+
537570
if ((ulong)buffer.Length < Length)
538571
{
539572
throw new InvalidOperationException($"Buffer must be at least ${Length} bytes.");
@@ -562,7 +595,9 @@ public void WriteString(string text)
562595
/// <exception cref="IndexOutOfRangeException"></exception>
563596
public unsafe void WriteBytes(ReadOnlySpan<byte> bytes)
564597
{
565-
if ((ulong)bytes.Length > Length)
598+
CheckDisposed();
599+
600+
if((ulong)bytes.Length > Length)
566601
{
567602
throw new IndexOutOfRangeException("Memory block is not big enough.");
568603
}
@@ -579,6 +614,8 @@ public unsafe void WriteBytes(ReadOnlySpan<byte> bytes)
579614
/// <returns></returns>
580615
public byte[] ReadBytes()
581616
{
617+
CheckDisposed();
618+
582619
var buffer = new byte[Length];
583620
CopyTo(buffer);
584621

@@ -606,6 +643,15 @@ public static MemoryBlock Find(ulong offset)
606643
return new MemoryBlock(offset, length);
607644
}
608645

646+
private void CheckDisposed()
647+
{
648+
if (_disposed)
649+
{
650+
throw new ObjectDisposedException(nameof(MemoryBlock));
651+
}
652+
}
653+
654+
private bool _disposed;
609655
/// <summary>
610656
/// Frees the current memory block.
611657
/// </summary>
@@ -617,6 +663,13 @@ public void Dispose()
617663

618664
private void Dispose(bool disposing)
619665
{
666+
if (_disposed)
667+
{
668+
return;
669+
}
670+
671+
_disposed = true;
672+
620673
if (disposing)
621674
{
622675
// free managed resources
@@ -628,3 +681,10 @@ private void Dispose(bool disposing)
628681
}
629682
}
630683
}
684+
685+
[JsonSerializable(typeof(HttpRequest))]
686+
[JsonSerializable(typeof(Dictionary<string, string>))]
687+
internal partial class JsonContext : JsonSerializerContext
688+
{
689+
690+
}

0 commit comments

Comments
 (0)