Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/SchematicHQ.Client/Datastream/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ private void HandleMessageResponse(DataStreamResponse? message)
case EntityType.Flags:
HandleFlagsMessage(message);
break;
case EntityType.Flag:
HandleFlagMessage(message);
break;
case EntityType.User:
HandleUserMessage(message);
break;
Expand Down Expand Up @@ -460,6 +463,89 @@ private void HandleFlagsMessage(DataStreamResponse response)
}
}

private void HandleFlagMessage(DataStreamResponse response)
{
try
{
if (response.Data == null)
{
_logger.Warn("Received empty flag data");
return;
}

var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
// This REPLACES the existing converter with one that has the right settings
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower, false) }
};

var jsonString = response.Data.ToString() ?? string.Empty;

if (response.MessageType == MessageType.Delete)
{
// Handle single flag deletion
var deleteData = JsonSerializer.Deserialize<dynamic>(jsonString, options);
string? flagKey = null;

// Try to extract the flag key from the delete message
if (deleteData != null)
{
var deleteDict = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString, options);
if (deleteDict != null)
{
if (deleteDict.TryGetValue("key", out var keyValue))
{
flagKey = keyValue?.ToString();
}
else if (deleteDict.TryGetValue("id", out var idValue))
{
flagKey = idValue?.ToString();
}
}
}

if (!string.IsNullOrEmpty(flagKey))
{
var deleteCacheKey = FlagCacheKey(flagKey);
_flagsCache.Delete(deleteCacheKey);
_logger.Debug("Deleted single flag from cache: {0}", flagKey);
}
else
{
_logger.Warn("Could not extract flag key from delete message");
}

return;
}

// Handle single flag creation/update
var flag = JsonSerializer.Deserialize<Flag>(jsonString, options);

if (flag == null)
{
_logger.Warn("Received null flag data");
return;
}

if (string.IsNullOrEmpty(flag.Key))
{
_logger.Debug("Flag key is null, skipping flag: {0}", flag.Id);
return;
}

var cacheKey = FlagCacheKey(flag.Key);
_flagsCache.Set(cacheKey, flag);
_logger.Debug("Cached single flag: {0}", flag.Key);

// Note: Unlike bulk flags processing, we do NOT call DeleteMissing for single flag updates
}
catch (Exception ex)
{
_logger.Error("Failed to handle single flag message: {0}", ex.Message);
}
}

/// <summary>
/// Helper method to notify pending requests with a success result
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/SchematicHQ.Client/Datastream/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public enum EntityType
Company,
[JsonStringEnumMemberName("rulesengine.Flags")]
Flags,
[JsonStringEnumMemberName("rulesengine.Flag")]
Flag,
[JsonStringEnumMemberName("rulesengine.User")]
User
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Auto-generated code - do not modify
// Generated on Wed Aug 13 11:31:39 MDT 2025
// This file is automatically generated based on model file changes

namespace SchematicHQ.Client.RulesEngine.Utils
{
Expand All @@ -10,10 +10,5 @@ public static class GeneratedModelHash
/// This value changes whenever any model file is modified.
/// </summary>
public const string Value = "298b6b90";

/// <summary>
/// The timestamp when this hash was generated
/// </summary>
public static readonly System.DateTime GeneratedAt = new System.DateTime(638907030990000000L, System.DateTimeKind.Utc);
}
}
11 changes: 1 addition & 10 deletions src/SchematicHQ.Client/generate-schema-hash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,12 @@ else
HASH=$(cat $FILES | sha256sum | cut -c1-8)
fi

# Current timestamp in ticks (C# compatible)
TICKS=$(date +%s)
TICKS_CSHARP=$((TICKS * 10000000 + 621355968000000000))

# Generate the C# file
echo "Generating file: $OUTPUT_FILE with hash: $HASH"

cat > "$OUTPUT_FILE" << EOF
// Auto-generated code - do not modify
// Generated on $(date)
// This file is automatically generated based on model file changes

namespace SchematicHQ.Client.RulesEngine.Utils
{
Expand All @@ -53,11 +49,6 @@ namespace SchematicHQ.Client.RulesEngine.Utils
/// This value changes whenever any model file is modified.
/// </summary>
public const string Value = "$HASH";

/// <summary>
/// The timestamp when this hash was generated
/// </summary>
public static readonly System.DateTime GeneratedAt = new System.DateTime(${TICKS_CSHARP}L, System.DateTimeKind.Utc);
}
}
EOF
Expand Down
Loading