Skip to content

Commit 3f807fc

Browse files
Clean up
1 parent fa37113 commit 3f807fc

10 files changed

Lines changed: 259 additions & 269 deletions

src/Temporalio/Nexus/ITemporalNexusClient.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public interface ITemporalNexusClient
4545
/// <typeparam name="TWorkflow">Workflow class type.</typeparam>
4646
/// <typeparam name="TResult">Workflow result type.</typeparam>
4747
/// <param name="workflowRunCall">Invocation of workflow run method with a result.</param>
48-
/// <param name="options">Start workflow options. ID and TaskQueue are required.</param>
48+
/// <param name="options">Start workflow options. ID is required; TaskQueue defaults to
49+
/// the operation's task queue when omitted.</param>
4950
/// <returns>An async operation result containing the workflow-run token.</returns>
5051
Task<TemporalOperationResult<TResult>> StartWorkflowAsync<TWorkflow, TResult>(
5152
Expression<Func<TWorkflow, Task<TResult>>> workflowRunCall, WorkflowOptions options);
@@ -56,7 +57,8 @@ Task<TemporalOperationResult<TResult>> StartWorkflowAsync<TWorkflow, TResult>(
5657
/// </summary>
5758
/// <typeparam name="TWorkflow">Workflow class type.</typeparam>
5859
/// <param name="workflowRunCall">Invocation of workflow run method with no result.</param>
59-
/// <param name="options">Start workflow options. ID and TaskQueue are required.</param>
60+
/// <param name="options">Start workflow options. ID is required; TaskQueue defaults to
61+
/// the operation's task queue when omitted.</param>
6062
/// <returns>An async operation result containing the workflow-run token.</returns>
6163
Task<TemporalOperationResult<NoValue>> StartWorkflowAsync<TWorkflow>(
6264
Expression<Func<TWorkflow, Task>> workflowRunCall, WorkflowOptions options);
@@ -68,7 +70,8 @@ Task<TemporalOperationResult<NoValue>> StartWorkflowAsync<TWorkflow>(
6870
/// <typeparam name="TResult">Workflow result type.</typeparam>
6971
/// <param name="workflow">Workflow type name.</param>
7072
/// <param name="args">Arguments for the workflow.</param>
71-
/// <param name="options">Start workflow options. ID and TaskQueue are required.</param>
73+
/// <param name="options">Start workflow options. ID is required; TaskQueue defaults to
74+
/// the operation's task queue when omitted.</param>
7275
/// <returns>An async operation result containing the workflow-run token.</returns>
7376
Task<TemporalOperationResult<TResult>> StartWorkflowAsync<TResult>(
7477
string workflow, IReadOnlyCollection<object?> args, WorkflowOptions options);

src/Temporalio/Nexus/NexusActivityExecutionHandle.cs

Lines changed: 0 additions & 152 deletions
This file was deleted.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
5+
namespace Temporalio.Nexus
6+
{
7+
/// <summary>
8+
/// Internal helper for building and parsing activity-execution operation tokens used by the
9+
/// generic <see cref="TemporalOperationHandler"/> when an operation is backed by a standalone
10+
/// activity.
11+
/// </summary>
12+
internal static class NexusActivityExecutionToken
13+
{
14+
/// <summary>
15+
/// Token-type value identifying an activity-execution operation token.
16+
/// </summary>
17+
internal const int OperationTokenType = 2;
18+
19+
/// <summary>
20+
/// Build a base64url-encoded activity-execution operation token.
21+
/// </summary>
22+
/// <param name="namespace_">Activity namespace.</param>
23+
/// <param name="activityId">Activity ID.</param>
24+
/// <returns>Base64url-encoded operation token.</returns>
25+
internal static string Build(string namespace_, string activityId) =>
26+
NexusWorkflowRunHandle.Base64UrlEncode(JsonSerializer.SerializeToUtf8Bytes(
27+
new Token(namespace_, activityId, null),
28+
NexusWorkflowRunHandle.TokenSerializerOptions));
29+
30+
/// <summary>
31+
/// Parse an activity-execution operation token into its underlying fields.
32+
/// </summary>
33+
/// <param name="token">Base64url-encoded token string.</param>
34+
/// <returns>Parsed token fields.</returns>
35+
/// <exception cref="ArgumentException">If the token is invalid.</exception>
36+
internal static Token Parse(string token)
37+
{
38+
byte[] bytes;
39+
try
40+
{
41+
bytes = NexusWorkflowRunHandle.Base64UrlDecode(token);
42+
}
43+
catch (FormatException)
44+
{
45+
throw new ArgumentException("Token invalid");
46+
}
47+
Token? tokenObj;
48+
try
49+
{
50+
tokenObj = JsonSerializer.Deserialize<Token>(
51+
bytes, NexusWorkflowRunHandle.TokenSerializerOptions);
52+
}
53+
catch (JsonException e)
54+
{
55+
throw new ArgumentException("Token invalid", e);
56+
}
57+
if (tokenObj == null)
58+
{
59+
throw new ArgumentException("Token invalid");
60+
}
61+
if (tokenObj.Type != OperationTokenType)
62+
{
63+
throw new ArgumentException(
64+
$"Invalid activity execution token type: {tokenObj.Type}, " +
65+
$"expected: {OperationTokenType}");
66+
}
67+
if (tokenObj.Version != null && tokenObj.Version != 0)
68+
{
69+
throw new ArgumentException($"Unsupported token version: {tokenObj.Version}");
70+
}
71+
if (string.IsNullOrEmpty(tokenObj.ActivityId))
72+
{
73+
throw new ArgumentException("Token invalid: missing activity ID (aid)");
74+
}
75+
return tokenObj;
76+
}
77+
78+
/// <summary>
79+
/// Represents the fields of an activity-execution operation token.
80+
/// </summary>
81+
internal record Token(
82+
[property: JsonPropertyName("ns")]
83+
string Namespace,
84+
[property: JsonPropertyName("aid")]
85+
string ActivityId,
86+
[property: JsonPropertyName("v")]
87+
int? Version,
88+
[property: JsonPropertyName("t")]
89+
int Type = OperationTokenType);
90+
}
91+
}

src/Temporalio/Nexus/NexusActivityStartHelper.cs

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Threading.Tasks;
5-
using Microsoft.Extensions.Logging;
64
using NexusRpc.Handlers;
75
using Temporalio.Api.Common.V1;
86
using Temporalio.Client;
@@ -15,8 +13,6 @@ namespace Temporalio.Nexus
1513
/// </summary>
1614
internal static class NexusActivityStartHelper
1715
{
18-
private const string NexusOperationTokenHeader = "Nexus-Operation-Token";
19-
2016
/// <summary>
2117
/// Start a standalone activity and return the activity-execution operation token. This
2218
/// handles all Nexus plumbing: cloning options, defaulting task queue / ID, processing
@@ -59,7 +55,7 @@ internal static async Task<string> StartActivityAndGetTokenAsync(
5955
var activityId = options.Id!;
6056

6157
// Generate the token before starting the activity (needed for callback header)
62-
var token = new NexusActivityExecutionHandle(namespace_, activityId, 0).ToToken();
58+
var token = NexusActivityExecutionToken.Build(namespace_, activityId);
6359

6460
if (options.IdConflictPolicy == Api.Enums.V1.ActivityIdConflictPolicy.UseExisting)
6561
{
@@ -70,45 +66,14 @@ internal static async Task<string> StartActivityAndGetTokenAsync(
7066
AttachRequestId = true,
7167
};
7268
}
73-
if (nexusStartContext.InboundLinks.Count > 0)
69+
if (NexusOperationStartCommon.BuildInboundLinks(
70+
nexusStartContext, temporalContext) is { } links)
7471
{
75-
options.Links = nexusStartContext.InboundLinks.Select(link =>
76-
{
77-
try
78-
{
79-
return new Link { WorkflowEvent = link.ToWorkflowEvent() };
80-
}
81-
catch (ArgumentException e)
82-
{
83-
temporalContext.Logger.LogWarning(e, "Invalid Nexus link: {Url}", link.Uri);
84-
return null;
85-
}
86-
}).OfType<Link>().ToList();
72+
options.Links = links;
8773
}
88-
if (nexusStartContext.CallbackUrl is { } callbackUrl)
74+
if (NexusOperationStartCommon.BuildCallback(
75+
nexusStartContext, token, options.Links) is { } callback)
8976
{
90-
var callback = new Callback() { Nexus = new() { Url = callbackUrl } };
91-
var callbackHeadersHasToken = false;
92-
if (nexusStartContext.CallbackHeaders is { } callbackHeaders)
93-
{
94-
foreach (var kv in callbackHeaders)
95-
{
96-
callback.Nexus.Header.Add(kv.Key, kv.Value);
97-
if (string.Equals(
98-
kv.Key, NexusOperationTokenHeader, StringComparison.OrdinalIgnoreCase))
99-
{
100-
callbackHeadersHasToken = true;
101-
}
102-
}
103-
}
104-
if (!callbackHeadersHasToken)
105-
{
106-
callback.Nexus.Header[NexusOperationTokenHeader] = token;
107-
}
108-
if (options.Links is { } links)
109-
{
110-
callback.Links.AddRange(links);
111-
}
11277
options.CompletionCallbacks = new[] { callback };
11378
}
11479
options.RequestId = nexusStartContext.RequestId;

0 commit comments

Comments
 (0)