From a29ce2d66451f45b5d7ae4beebd646165303cdd9 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Wed, 31 Dec 2025 16:06:51 -0800 Subject: [PATCH 1/2] Added HTTP support to C# module procedures. --- .../bindings-csharp/BSATN.Runtime/Builtins.cs | 2 +- .../BSATN.Runtime/HttpWireTypes.cs | 77 ++++++ crates/bindings-csharp/Runtime/Exceptions.cs | 5 + crates/bindings-csharp/Runtime/Http.cs | 261 ++++++++++++++++++ .../bindings-csharp/Runtime/Internal/FFI.cs | 18 ++ .../Runtime/Internal/Module.cs | 20 +- .../Runtime/ProcedureContext.cs | 5 +- crates/bindings-csharp/Runtime/bindings.c | 5 + .../regression-tests/client/Program.cs | 38 ++- .../examples~/regression-tests/server/Lib.cs | 37 +++ 10 files changed, 451 insertions(+), 17 deletions(-) create mode 100644 crates/bindings-csharp/BSATN.Runtime/HttpWireTypes.cs create mode 100644 crates/bindings-csharp/Runtime/Http.cs diff --git a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs index a3478d18023..8a8aa783a5c 100644 --- a/crates/bindings-csharp/BSATN.Runtime/Builtins.cs +++ b/crates/bindings-csharp/BSATN.Runtime/Builtins.cs @@ -365,7 +365,7 @@ public readonly TimeDuration TimeDurationSince(Timestamp earlier) => public static Timestamp operator -(Timestamp point, TimeDuration interval) => new Timestamp(checked(point.MicrosecondsSinceUnixEpoch - interval.Microseconds)); - public int CompareTo(Timestamp that) + public readonly int CompareTo(Timestamp that) { return this.MicrosecondsSinceUnixEpoch.CompareTo(that.MicrosecondsSinceUnixEpoch); } diff --git a/crates/bindings-csharp/BSATN.Runtime/HttpWireTypes.cs b/crates/bindings-csharp/BSATN.Runtime/HttpWireTypes.cs new file mode 100644 index 00000000000..b0efb0c3d4a --- /dev/null +++ b/crates/bindings-csharp/BSATN.Runtime/HttpWireTypes.cs @@ -0,0 +1,77 @@ +namespace SpacetimeDB; + +using System.ComponentModel; + +// NOTE: These types define the stable BSATN wire format for the procedure_http_request ABI. +// They must match `spacetimedb_lib::http::{Request, Response}` exactly (field order + types), +// because the host BSATN-decodes these bytes directly and may trap on mismatch. +// Do not reorder fields or extend these types; add a new versioned ABI instead. + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial record HttpMethodWire + : TaggedEnum<( + Unit Get, + Unit Head, + Unit Post, + Unit Put, + Unit Delete, + Unit Connect, + Unit Options, + Unit Trace, + Unit Patch, + string Extension + )>; + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public enum HttpVersionWire : byte +{ + Http09, + Http10, + Http11, + Http2, + Http3, +} + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial struct HttpHeaderPairWire +{ + public string Name; + public byte[] Value; +} + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial struct HttpHeadersWire +{ + public HttpHeaderPairWire[] Entries; +} + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial struct HttpTimeoutWire +{ + public TimeDuration Timeout; +} + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial struct HttpRequestWire +{ + public HttpMethodWire Method; + public HttpHeadersWire Headers; + public HttpTimeoutWire? Timeout; + public string Uri; + public HttpVersionWire Version; +} + +[Type] +[EditorBrowsable(EditorBrowsableState.Never)] +public partial struct HttpResponseWire +{ + public HttpHeadersWire Headers; + public HttpVersionWire Version; + public ushort Code; +} diff --git a/crates/bindings-csharp/Runtime/Exceptions.cs b/crates/bindings-csharp/Runtime/Exceptions.cs index a7a3cf8b09d..5255c8c64f7 100644 --- a/crates/bindings-csharp/Runtime/Exceptions.cs +++ b/crates/bindings-csharp/Runtime/Exceptions.cs @@ -98,6 +98,11 @@ public class TransactionIsMutableException : StdbException "ABI call can only be made while inside a read-only transaction"; } +public class HttpException : StdbException +{ + public override string Message => "HTTP request failed"; +} + public class UnknownException : StdbException { private readonly Errno code; diff --git a/crates/bindings-csharp/Runtime/Http.cs b/crates/bindings-csharp/Runtime/Http.cs new file mode 100644 index 00000000000..1d60d08974c --- /dev/null +++ b/crates/bindings-csharp/Runtime/Http.cs @@ -0,0 +1,261 @@ +namespace SpacetimeDB; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Internal; +using SpacetimeDB.BSATN; + +public enum HttpVersion : byte +{ + Http09, + Http10, + Http11, + Http2, + Http3, +} + +public readonly record struct HttpMethod(string Value) +{ + public static readonly HttpMethod Get = new("GET"); + public static readonly HttpMethod Head = new("HEAD"); + public static readonly HttpMethod Post = new("POST"); + public static readonly HttpMethod Put = new("PUT"); + public static readonly HttpMethod Delete = new("DELETE"); + public static readonly HttpMethod Connect = new("CONNECT"); + public static readonly HttpMethod Options = new("OPTIONS"); + public static readonly HttpMethod Trace = new("TRACE"); + public static readonly HttpMethod Patch = new("PATCH"); +} + +// `IsSensitive` is a local-only hint. The current stable HTTP wire format does not carry +// header sensitivity metadata (Rust wire type uses only (name: string, value: bytes)), +// so this flag is not transmitted to the host. +public readonly record struct HttpHeader(string Name, byte[] Value, bool IsSensitive = false) +{ + public HttpHeader(string name, string value) + : this(name, Encoding.ASCII.GetBytes(value), false) { } +} + +public readonly record struct HttpBody(byte[] Bytes) +{ + public static HttpBody Empty => new(Array.Empty()); + + public byte[] ToBytes() => Bytes; + + public string ToStringUtf8Lossy() => Encoding.UTF8.GetString(Bytes); + + public static HttpBody FromString(string s) => new(Encoding.UTF8.GetBytes(s)); +} + +public sealed class HttpRequest +{ + public required string Uri { get; init; } + public HttpMethod Method { get; init; } = HttpMethod.Get; + public List Headers { get; init; } = new(); + public HttpBody Body { get; init; } = HttpBody.Empty; + public HttpVersion Version { get; init; } = HttpVersion.Http11; + public TimeSpan? Timeout { get; init; } +} + +public readonly record struct HttpResponse( + ushort StatusCode, + HttpVersion Version, + List Headers, + HttpBody Body +); + +public sealed class HttpError(string message) : Exception(message) +{ + private readonly string message = message; + + public override string Message => message; +} + +public sealed class HttpClient +{ + private static readonly TimeSpan MaxTimeout = TimeSpan.FromMilliseconds(500); + + public Result Get(string uri, TimeSpan? timeout = null) => + Send( + new HttpRequest + { + Uri = uri, + Method = HttpMethod.Get, + Body = HttpBody.Empty, + Timeout = timeout, + } + ); + + public Result Send(HttpRequest request) + { + // The host syscall expects BSATN-encoded spacetimedb_lib::http::Request bytes. + // A mismatch in the wire layout can cause the host to trap during BSATN decode, + // so the C# `Http*Wire` types must remain in lockstep with the Rust definitions. + try + { + if (string.IsNullOrEmpty(request.Uri)) + { + return Result.Err( + new HttpError("URI must not be null or empty") + ); + } + + // The host clamps all HTTP timeouts to a maximum of 500ms. + // Clamp here as well to keep C# behavior aligned with the Rust docs and to reduce surprises. + var timeout = request.Timeout; + if (timeout is not null) + { + if (timeout.Value < TimeSpan.Zero) + { + return Result.Err( + new HttpError("Timeout must not be negative") + ); + } + + if (timeout.Value > MaxTimeout) + { + timeout = MaxTimeout; + } + } + + var requestWire = new HttpRequestWire + { + Method = ToWireMethod(request.Method), + Headers = new HttpHeadersWire + { + Entries = request.Headers.Select(ToWireHeader).ToArray(), + }, + Timeout = timeout is null + ? null + : new HttpTimeoutWire { Timeout = (TimeDuration)timeout.Value }, + Uri = request.Uri, + Version = ToWireVersion(request.Version), + }; + + var requestBytes = IStructuralReadWrite.ToBytes( + new HttpRequestWire.BSATN(), + requestWire + ); + var bodyBytes = request.Body.ToBytes(); + + var status = FFI.procedure_http_request( + requestBytes, + (uint)requestBytes.Length, + bodyBytes, + (uint)bodyBytes.Length, + out var out_ + ); + + switch (status) + { + case Errno.OK: + { + var responseWireBytes = out_.A.Consume(); + var responseWire = FromBytes(new HttpResponseWire.BSATN(), responseWireBytes); + + var body = new HttpBody(out_.B.Consume()); + var (statusCode, version, headers) = FromWireResponse(responseWire); + + return Result.Ok( + new HttpResponse(statusCode, version, headers, body) + ); + } + case Errno.HTTP_ERROR: + { + var errorWireBytes = out_.A.Consume(); + var err = FromBytes(new SpacetimeDB.BSATN.String(), errorWireBytes); + return Result.Err(new HttpError(err)); + } + case Errno.WOULD_BLOCK_TRANSACTION: + return Result.Err( + new HttpError( + "HTTP requests cannot be performed while a mutable transaction is open (WOULD_BLOCK_TRANSACTION)." + ) + ); + default: + return Result.Err( + new HttpError(FFI.ErrnoHelpers.ToException(status).ToString()) + ); + } + } + // Important: avoid throwing across the procedure boundary. + // Throwing here would trap the module (and fail the whole procedure invocation). + // Convert all unexpected failures (including decode errors / unexpected errno) into Result.Err instead. + catch (Exception ex) + { + return Result.Err(new HttpError(ex.ToString())); + } + } + + private static T FromBytes(IReadWrite rw, byte[] bytes) + { + using var ms = new MemoryStream(bytes); + using var reader = new BinaryReader(ms); + var value = rw.Read(reader); + if (ms.Position != ms.Length) + { + throw new InvalidOperationException( + "Unrecognized extra bytes while decoding BSATN value" + ); + } + return value; + } + + private static HttpMethodWire ToWireMethod(HttpMethod method) + { + var m = method.Value; + return m switch + { + "GET" => new HttpMethodWire.Get(default), + "HEAD" => new HttpMethodWire.Head(default), + "POST" => new HttpMethodWire.Post(default), + "PUT" => new HttpMethodWire.Put(default), + "DELETE" => new HttpMethodWire.Delete(default), + "CONNECT" => new HttpMethodWire.Connect(default), + "OPTIONS" => new HttpMethodWire.Options(default), + "TRACE" => new HttpMethodWire.Trace(default), + "PATCH" => new HttpMethodWire.Patch(default), + _ => new HttpMethodWire.Extension(m), + }; + } + + private static HttpVersionWire ToWireVersion(HttpVersion version) => + version switch + { + HttpVersion.Http09 => HttpVersionWire.Http09, + HttpVersion.Http10 => HttpVersionWire.Http10, + HttpVersion.Http11 => HttpVersionWire.Http11, + HttpVersion.Http2 => HttpVersionWire.Http2, + HttpVersion.Http3 => HttpVersionWire.Http3, + _ => throw new ArgumentOutOfRangeException(nameof(version)), + }; + + private static HttpHeaderPairWire ToWireHeader(HttpHeader header) => + new() { Name = header.Name, Value = header.Value }; + + private static ( + ushort statusCode, + HttpVersion version, + List headers + ) FromWireResponse(HttpResponseWire responseWire) + { + var version = responseWire.Version switch + { + HttpVersionWire.Http09 => HttpVersion.Http09, + HttpVersionWire.Http10 => HttpVersion.Http10, + HttpVersionWire.Http11 => HttpVersion.Http11, + HttpVersionWire.Http2 => HttpVersion.Http2, + HttpVersionWire.Http3 => HttpVersion.Http3, + _ => throw new InvalidOperationException("Invalid HTTP version returned from host"), + }; + + var headers = responseWire + .Headers.Entries.Select(h => new HttpHeader(h.Name, h.Value, false)) + .ToList(); + + return (responseWire.Code, version, headers); + } +} diff --git a/crates/bindings-csharp/Runtime/Internal/FFI.cs b/crates/bindings-csharp/Runtime/Internal/FFI.cs index dec9c8f25df..9cf994e929b 100644 --- a/crates/bindings-csharp/Runtime/Internal/FFI.cs +++ b/crates/bindings-csharp/Runtime/Internal/FFI.cs @@ -41,6 +41,7 @@ public enum Errno : short TRANSACTION_NOT_ANONYMOUS = 18, TRANSACTION_IS_READ_ONLY = 19, TRANSACTION_IS_MUT = 20, + HTTP_ERROR = 21, } #pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff. @@ -144,6 +145,7 @@ public static Exception ToException(Errno status) => Errno.TRANSACTION_NOT_ANONYMOUS => new TransactionNotAnonymousException(), Errno.TRANSACTION_IS_READ_ONLY => new TransactionIsReadOnlyException(), Errno.TRANSACTION_IS_MUT => new TransactionIsMutableException(), + Errno.HTTP_ERROR => new HttpException(), _ => new UnknownException(status), }; } @@ -379,4 +381,20 @@ uint args_len [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_abort_mut_tx")] public static partial Errno procedure_abort_mut_tx(); + + [StructLayout(LayoutKind.Sequential)] + public readonly struct BytesSourcePair + { + public readonly BytesSource A; + public readonly BytesSource B; + } + + [LibraryImport(StdbNamespace10_3, EntryPoint = "procedure_http_request")] + public static partial Errno procedure_http_request( + ReadOnlySpan request, + uint request_len, + ReadOnlySpan body, + uint body_len, + out BytesSourcePair out_ + ); } diff --git a/crates/bindings-csharp/Runtime/Internal/Module.cs b/crates/bindings-csharp/Runtime/Internal/Module.cs index a74b981f37c..c9f528258d8 100644 --- a/crates/bindings-csharp/Runtime/Internal/Module.cs +++ b/crates/bindings-csharp/Runtime/Internal/Module.cs @@ -347,17 +347,7 @@ BytesSink resultSink using var stream = new MemoryStream(args.Consume()); using var reader = new BinaryReader(stream); - var bytes = Array.Empty(); - try - { - bytes = procedures[(int)id].Invoke(reader, ctx); - } - catch (Exception e) - { - var errorBytes = System.Text.Encoding.UTF8.GetBytes(e.ToString()); - resultSink.Write(errorBytes); - return Errno.HOST_CALL_FAILURE; - } + var bytes = procedures[(int)id].Invoke(reader, ctx); if (stream.Position != stream.Length) { throw new Exception("Unrecognised extra bytes in the procedure arguments"); @@ -368,9 +358,11 @@ BytesSink resultSink } catch (Exception e) { - var errorBytes = System.Text.Encoding.UTF8.GetBytes(e.ToString()); - resultSink.Write(errorBytes); - return Errno.HOST_CALL_FAILURE; + // Host contract __call_procedure__ must either return Errno.OK or trap. + // Returning other errno values here can put the host/runtime in an unexpected state, + // so we log and rethrow to trap on any exception. + Log.Error($"Error while invoking procedure: {e}"); + throw; } } diff --git a/crates/bindings-csharp/Runtime/ProcedureContext.cs b/crates/bindings-csharp/Runtime/ProcedureContext.cs index 2c67396bbb2..6939723b151 100644 --- a/crates/bindings-csharp/Runtime/ProcedureContext.cs +++ b/crates/bindings-csharp/Runtime/ProcedureContext.cs @@ -1,7 +1,6 @@ namespace SpacetimeDB; using System.Diagnostics.CodeAnalysis; -using Internal; public readonly struct Result(bool isSuccess, T? value, E? error) where E : Exception @@ -52,6 +51,10 @@ Timestamp time public Timestamp Timestamp { get; private set; } = time; public AuthCtx SenderAuth { get; } = AuthCtx.BuildFromSystemTables(connectionId, sender); + // NOTE: The host rejects procedure HTTP requests while a mut transaction is open + // (WOULD_BLOCK_TRANSACTION). Avoid calling `Http.*` inside WithTx. + public HttpClient Http { get; } = new(); + private Internal.TxContext? txContext; private ProcedureTxContextBase? cachedUserTxContext; diff --git a/crates/bindings-csharp/Runtime/bindings.c b/crates/bindings-csharp/Runtime/bindings.c index 33fa039fa4d..1b55d095713 100644 --- a/crates/bindings-csharp/Runtime/bindings.c +++ b/crates/bindings-csharp/Runtime/bindings.c @@ -122,6 +122,11 @@ IMPORT(int16_t, get_jwt, (const uint8_t* connection_id_ptr, BytesSource* bytes_p IMPORT(uint16_t, procedure_start_mut_tx, (int64_t* micros), (micros)); IMPORT(uint16_t, procedure_commit_mut_tx, (void), ()); IMPORT(uint16_t, procedure_abort_mut_tx, (void), ()); +IMPORT(uint16_t, procedure_http_request, + (const uint8_t* request_ptr, uint32_t request_len, + const uint8_t* body_ptr, uint32_t body_len, + BytesSource* out), + (request_ptr, request_len, body_ptr, body_len, out)); #undef SPACETIME_MODULE_VERSION #ifndef EXPERIMENTAL_WASM_AOT diff --git a/sdks/csharp/examples~/regression-tests/client/Program.cs b/sdks/csharp/examples~/regression-tests/client/Program.cs index b57c47b9ff2..63f030227fa 100644 --- a/sdks/csharp/examples~/regression-tests/client/Program.cs +++ b/sdks/csharp/examples~/regression-tests/client/Program.cs @@ -1,4 +1,4 @@ -/// Regression tests run with a live server. +/// Regression tests run with a live server. /// To run these, run a local SpacetimeDB via `spacetime start`, /// then in a separate terminal run `tools~/run-regression-tests.sh PATH_TO_SPACETIMEDB_REPO_CHECKOUT`. /// This is done on CI in .github/workflows/test.yml. @@ -214,6 +214,42 @@ void OnSubscriptionApplied(SubscriptionEventContext context) Debug.Assert(anonViewRemoteQueryRows.Result.First().Equals(expectedPlayerAndLevel)); // Procedures tests + Log.Debug("Calling ReadMySchemaViaHttp"); + waiting++; + context.Procedures.ReadMySchemaViaHttp((IProcedureEventContext ctx, ProcedureCallbackResult result) => + { + try + { + Debug.Assert(result.IsSuccess, $"ReadMySchemaViaHttp should succeed. Error received: {result.Error}"); + Debug.Assert(result.Value != null, "ReadMySchemaViaHttp should return a string"); + Debug.Assert(result.Value.StartsWith("OK "), $"Expected OK prefix, got: {result.Value}"); + Debug.Assert( + result.Value.Contains("example_data"), + $"Expected schema response to mention example_data, got: {result.Value}" + ); + } + finally + { + waiting--; + } + }); + + Log.Debug("Calling InvalidHttpRequest"); + waiting++; + context.Procedures.InvalidHttpRequest((IProcedureEventContext ctx, ProcedureCallbackResult result) => + { + try + { + Debug.Assert(result.IsSuccess, $"InvalidHttpRequest should succeed. Error received: {result.Error}"); + Debug.Assert(result.Value != null, "InvalidHttpRequest should return a string"); + Debug.Assert(result.Value.StartsWith("ERR "), $"Expected ERR prefix, got: {result.Value}"); + } + finally + { + waiting--; + } + }); + Log.Debug("Calling InsertWithTxRollback"); waiting++; context.Procedures.InsertWithTxRollback((IProcedureEventContext ctx, ProcedureCallbackResult result) => diff --git a/sdks/csharp/examples~/regression-tests/server/Lib.cs b/sdks/csharp/examples~/regression-tests/server/Lib.cs index 924c029b978..06e72581460 100644 --- a/sdks/csharp/examples~/regression-tests/server/Lib.cs +++ b/sdks/csharp/examples~/regression-tests/server/Lib.cs @@ -2,6 +2,7 @@ // Everything we're testing for happens SDK-side so this module is very uninteresting. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using SpacetimeDB; [SpacetimeDB.Type] @@ -174,6 +175,42 @@ public static SpacetimeDB.Unit WillPanic(ProcedureContext ctx) throw new InvalidOperationException("This procedure is expected to panic"); } + [SpacetimeDB.Procedure] + [Experimental("STDB_UNSTABLE")] + public static string ReadMySchemaViaHttp(ProcedureContext ctx) + { + try + { + var moduleIdentity = ProcedureContext.Identity; + var uri = $"http://localhost:3000/v1/database/{moduleIdentity}/schema?version=9"; + var res = ctx.Http.Get(uri, System.TimeSpan.FromSeconds(2)); + return res.IsSuccess + ? "OK " + res.Value!.Body.ToStringUtf8Lossy() + : "ERR " + res.Error!.Message; + } + catch (Exception e) + { + return "EXN " + e; + } + } + + [SpacetimeDB.Procedure] + [Experimental("STDB_UNSTABLE")] + public static string InvalidHttpRequest(ProcedureContext ctx) + { + try + { + var res = ctx.Http.Get("http://foo.invalid/", System.TimeSpan.FromMilliseconds(250)); + return res.IsSuccess + ? "OK " + res.Value!.Body.ToStringUtf8Lossy() + : "ERR " + res.Error!.Message; + } + catch (Exception e) + { + return "EXN " + e; + } + } + #pragma warning disable STDB_UNSTABLE [SpacetimeDB.Procedure] public static void InsertWithTxCommit(ProcedureContext ctx) From 77afc79ca550909b016983dff5b698de9ca91fb7 Mon Sep 17 00:00:00 2001 From: rekhoff Date: Wed, 31 Dec 2025 16:56:59 -0800 Subject: [PATCH 2/2] Updated C# regression test client bindings --- .../Procedures/InvalidHttpRequest.g.cs | 65 +++++++++++++++++++ .../Procedures/ReadMySchemaViaHttp.g.cs | 65 +++++++++++++++++++ .../module_bindings/SpacetimeDBClient.g.cs | 2 +- .../module_bindings/SpacetimeDBClient.g.cs | 2 +- .../module_bindings/SpacetimeDBClient.g.cs | 2 +- 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/InvalidHttpRequest.g.cs create mode 100644 sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/ReadMySchemaViaHttp.g.cs diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/InvalidHttpRequest.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/InvalidHttpRequest.g.cs new file mode 100644 index 00000000000..7e76023b9b8 --- /dev/null +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/InvalidHttpRequest.g.cs @@ -0,0 +1,65 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#nullable enable + +using System; +using SpacetimeDB.ClientApi; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.Types +{ + public sealed partial class RemoteProcedures : RemoteBase + { + public void InvalidHttpRequest(ProcedureCallback callback) + { + // Convert the clean callback to the wrapper callback + InternalInvalidHttpRequest((ctx, result) => + { + if (result.IsSuccess && result.Value != null) + { + callback(ctx, ProcedureCallbackResult.Success(result.Value.Value)); + } + else + { + callback(ctx, ProcedureCallbackResult.Failure(result.Error!)); + } + }); + } + + private void InternalInvalidHttpRequest(ProcedureCallback callback) + { + conn.InternalCallProcedure(new Procedure.InvalidHttpRequestArgs(), callback); + } + + } + + public abstract partial class Procedure + { + [SpacetimeDB.Type] + [DataContract] + public sealed partial class InvalidHttpRequest + { + [DataMember(Name = "Value")] + public string Value; + + public InvalidHttpRequest(string Value) + { + this.Value = Value; + } + + public InvalidHttpRequest() + { + this.Value = ""; + } + } + [SpacetimeDB.Type] + [DataContract] + public sealed partial class InvalidHttpRequestArgs : Procedure, IProcedureArgs + { + string IProcedureArgs.ProcedureName => "InvalidHttpRequest"; + } + + } +} diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/ReadMySchemaViaHttp.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/ReadMySchemaViaHttp.g.cs new file mode 100644 index 00000000000..11e2a8b883f --- /dev/null +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Procedures/ReadMySchemaViaHttp.g.cs @@ -0,0 +1,65 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#nullable enable + +using System; +using SpacetimeDB.ClientApi; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.Types +{ + public sealed partial class RemoteProcedures : RemoteBase + { + public void ReadMySchemaViaHttp(ProcedureCallback callback) + { + // Convert the clean callback to the wrapper callback + InternalReadMySchemaViaHttp((ctx, result) => + { + if (result.IsSuccess && result.Value != null) + { + callback(ctx, ProcedureCallbackResult.Success(result.Value.Value)); + } + else + { + callback(ctx, ProcedureCallbackResult.Failure(result.Error!)); + } + }); + } + + private void InternalReadMySchemaViaHttp(ProcedureCallback callback) + { + conn.InternalCallProcedure(new Procedure.ReadMySchemaViaHttpArgs(), callback); + } + + } + + public abstract partial class Procedure + { + [SpacetimeDB.Type] + [DataContract] + public sealed partial class ReadMySchemaViaHttp + { + [DataMember(Name = "Value")] + public string Value; + + public ReadMySchemaViaHttp(string Value) + { + this.Value = Value; + } + + public ReadMySchemaViaHttp() + { + this.Value = ""; + } + } + [SpacetimeDB.Type] + [DataContract] + public sealed partial class ReadMySchemaViaHttpArgs : Procedure, IProcedureArgs + { + string IProcedureArgs.ProcedureName => "ReadMySchemaViaHttp"; + } + + } +} diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs index 2bd475082ce..6b7df6d91f4 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/SpacetimeDBClient.g.cs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.11.0 (commit 492e591845db8b174ee885b74294cb4ecbf655dc). +// This was generated using spacetimedb cli version 1.11.1 (commit 41eec04ea6150114247ff4ae7cbd7a68b1144bd5). #nullable enable diff --git a/sdks/csharp/examples~/regression-tests/procedure-client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/procedure-client/module_bindings/SpacetimeDBClient.g.cs index 5ab798a5bca..8decfd4c285 100644 --- a/sdks/csharp/examples~/regression-tests/procedure-client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/procedure-client/module_bindings/SpacetimeDBClient.g.cs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.9.0 (commit a722cabfdf0a59d6fd152cf316511a514475c0ca). +// This was generated using spacetimedb cli version 1.11.1 (commit 41eec04ea6150114247ff4ae7cbd7a68b1144bd5). #nullable enable diff --git a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs index adb0e51c5b8..5e9e56dff57 100644 --- a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs +++ b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/SpacetimeDBClient.g.cs @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.9.0 (commit a722cabfdf0a59d6fd152cf316511a514475c0ca). +// This was generated using spacetimedb cli version 1.11.1 (commit 41eec04ea6150114247ff4ae7cbd7a68b1144bd5). #nullable enable