SSE impprovements · sdaves/NpgsqlRest@f422b48 · GitHub
Skip to content

Commit f422b48

Browse files
committed
SSE impprovements
1 parent d029084 commit f422b48

15 files changed

Lines changed: 227 additions & 126 deletions

NpgsqlRest/Consts.cs

Lines changed: 0 additions & 1 deletion

NpgsqlRest/Defaults/DefaultCommentParser.cs

Lines changed: 83 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,20 @@ internal static class DefaultCommentParser
165165
"param",
166166
];
167167

168-
private static readonly string[] InfoEventsStreamingPathKey = [
169-
"info_path",
170-
"info_events_path",
171-
"info_streaming_path"
168+
private static readonly string[] SseEventsStreamingPathKey = [
169+
"sse",
170+
"sse_path",
171+
"sse_events_path",
172+
];
173+
174+
private static readonly string[] SseEventsLevelKey = [
175+
"sse_level",
176+
"sse_events_level",
172177
];
173178

174-
private static readonly string[] InfoEventsStreamingScopeKey = [
175-
"info_scope",
176-
"info_events_scope",
177-
"info_streaming_scope",
179+
private static readonly string[] SseEventsStreamingScopeKey = [
180+
"sse_scope",
181+
"sse_events_scope",
178182
];
179183

180184
private static readonly string[] BasicAuthKey = [
@@ -954,55 +958,85 @@ internal static class DefaultCommentParser
954958
}
955959
}
956960
}
957-
958-
// info_path [ true | false | path ]
959-
// info_events_path [ true | false | path ]
960-
// info_streaming_path [ true |false | path ]
961-
else if (haveTag is true && len >= 2 && StrEqualsToArray(wordsLower[0], InfoEventsStreamingPathKey))
961+
962+
// sse path [ path ] [ on info | notice | warning ]
963+
// sse_path [ path ] [ on info | notice | warning ]
964+
// sse_events_path [ path ] [ on info | notice | warning ]
965+
else if (haveTag is true && StrEqualsToArray(wordsLower[0], SseEventsStreamingPathKey))
962966
{
963-
if (bool.TryParse(wordsLower[1], out var parseredStreamingPath))
967+
if (len == 1)
968+
{
969+
routineEndpoint.SseEventsPath =
970+
(routineEndpoint.SseEventNoticeLevel ?? Options.DefaultSseEventNoticeLevel).ToString();
971+
Logger?.CommentSseStreamingPath(description, routineEndpoint.SseEventsPath);
972+
}
973+
else
964974
{
965-
if (parseredStreamingPath is true)
975+
routineEndpoint.SseEventsPath = wordsLower[1];
976+
if (len >= 4 && StrEquals(wordsLower[2], "on"))
977+
{
978+
if (Enum.TryParse<PostgresNoticeLevels>(words[3], true, out var parsedLevel))
979+
{
980+
routineEndpoint.SseEventNoticeLevel = parsedLevel;
981+
Logger?.CommentSseStreamingPathAndLevel(description, routineEndpoint.SseEventsPath, routineEndpoint.SseEventNoticeLevel.Value);
982+
}
983+
else
984+
{
985+
Logger?.LogError("Could not recognize valid value for parameter key {key}. Valid values are: {values}. Provided value is {provided}.",
986+
wordsLower[0], string.Join(", ", Enum.GetNames<PostgresNoticeLevels>()), line);
987+
}
988+
}
989+
else
966990
{
967-
routineEndpoint.InfoEventsStreamingPath = Consts.DefaultInfoPath;
991+
Logger?.CommentSseStreamingPath(description, routineEndpoint.SseEventsPath);
968992
}
969993
}
994+
}
995+
996+
// sse_level [ info | notice | warning ]
997+
// sse_events_level [ info | notice | warning ]
998+
else if (haveTag is true && len >= 2 && StrEqualsToArray(wordsLower[0], SseEventsLevelKey))
999+
{
1000+
if (Enum.TryParse<PostgresNoticeLevels>(words[1], true, out var parsedLevel))
1001+
{
1002+
routineEndpoint.SseEventNoticeLevel = parsedLevel;
1003+
Logger?.CommentSseStreamingLevel(description, routineEndpoint.SseEventNoticeLevel.Value);
1004+
}
9701005
else
9711006
{
972-
routineEndpoint.InfoEventsStreamingPath = wordsLower[1];
1007+
Logger?.LogError("Could not recognize valid value for parameter key {key}. Valid values are: {values}. Provided value is {provided}.",
1008+
wordsLower[0], string.Join(", ", Enum.GetNames<PostgresNoticeLevels>()), line);
9731009
}
974-
Logger?.CommentInfoStreamingPath(description, routineEndpoint.InfoEventsStreamingPath);
9751010
}
976-
977-
// info_scope [ [ self | matching | authorize | all ] | [ authorize [ role1, role2, role3 [, ...] ] ] ]
978-
// info_events_scope [ [ self | matching | authorize | all ] | [ authorize [ role1, role2, role3 [, ...] ] ] ]
979-
// info_streaming_scope [ [ self | matching | authorize | all ] | [ authorize [ role1, role2, role3 [, ...] ] ] ]
980-
else if (haveTag is true && len >= 2 && StrEqualsToArray(wordsLower[0], InfoEventsStreamingScopeKey))
1011+
1012+
// sse_scope [ [ self | matching | authorize | all ] | [ authorize [ role_or_user1, role_or_user1, role_or_user1 [, ...] ] ] ]
1013+
// sse_events_scope [ [ self | matching | authorize | all ] | [ authorize [ role_or_user1, role_or_user1, role_or_user1 [, ...] ] ] ]
1014+
else if (haveTag is true && len >= 2 && StrEqualsToArray(wordsLower[0], SseEventsStreamingScopeKey))
9811015
{
982-
if (wordsLower.Length > 1 && Enum.TryParse<InfoEventsScope>(wordsLower[1], true, out var parsedScope))
1016+
if (wordsLower.Length > 1 && Enum.TryParse<SseEventsScope>(wordsLower[1], true, out var parsedScope))
9831017
{
984-
routineEndpoint.InfoEventsScope = parsedScope;
985-
if (parsedScope == InfoEventsScope.Authorize && wordsLower.Length > 2)
1018+
routineEndpoint.SseEventsScope = parsedScope;
1019+
if (parsedScope == SseEventsScope.Authorize && wordsLower.Length > 2)
9861020
{
987-
routineEndpoint.InfoEventsRoles ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
1021+
routineEndpoint.SseEventsRoles ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
9881022
foreach (var word in wordsLower[2..])
9891023
{
9901024
if (string.IsNullOrWhiteSpace(word) is false)
9911025
{
992-
routineEndpoint.InfoEventsRoles.Add(word);
1026+
routineEndpoint.SseEventsRoles.Add(word);
9931027
}
9941028
}
995-
Logger?.CommentInfoStreamingScopeRoles(description, routineEndpoint.InfoEventsRoles);
1029+
Logger?.CommentSseStreamingScopeRoles(description, routineEndpoint.SseEventsRoles);
9961030
}
9971031
else
9981032
{
999-
Logger?.CommentInfoStreamingScope(description, routineEndpoint.InfoEventsScope);
1033+
Logger?.CommentSseStreamingScope(description, routineEndpoint.SseEventsScope);
10001034
}
10011035
}
10021036
else
10031037
{
10041038
Logger?.LogError("Could not recognize valid value for parameter key {key}. Valid values are: {values}. Provided value is {provided}.",
1005-
wordsLower[0], string.Join(", ", Enum.GetNames<InfoEventsScope>()), line);
1039+
wordsLower[0], string.Join(", ", Enum.GetNames<SseEventsScope>()), line);
10061040
}
10071041
}
10081042

@@ -1165,35 +1199,40 @@ public static void SetCustomParameter(RoutineEndpoint endpoint, string name, str
11651199
}
11661200
}
11671201

1168-
else if (StrEqualsToArray(name, InfoEventsStreamingPathKey))
1202+
else if (StrEqualsToArray(name, SseEventsStreamingPathKey))
11691203
{
11701204
if (bool.TryParse(value, out var parseredStreamingPath))
11711205
{
1172-
if (parseredStreamingPath is true)
1173-
{
1174-
endpoint.InfoEventsStreamingPath = Consts.DefaultInfoPath;
1175-
}
1206+
endpoint.SseEventsPath = parseredStreamingPath is true ? (endpoint.SseEventNoticeLevel ?? Options.DefaultSseEventNoticeLevel).ToString() : null;
11761207
}
11771208
else
11781209
{
1179-
endpoint.InfoEventsStreamingPath = value;
1210+
endpoint.SseEventsPath = value;
1211+
}
1212+
}
1213+
1214+
else if (StrEqualsToArray(name, SseEventsLevelKey))
1215+
{
1216+
if (Enum.TryParse<PostgresNoticeLevels>(value, true, out var parsedLevel))
1217+
{
1218+
endpoint.SseEventNoticeLevel = parsedLevel;
11801219
}
11811220
}
11821221

1183-
else if (StrEqualsToArray(name, InfoEventsStreamingScopeKey))
1222+
else if (StrEqualsToArray(name, SseEventsStreamingScopeKey))
11841223
{
11851224
var words = value.SplitWords();
1186-
if (words.Length > 0 && Enum.TryParse<InfoEventsScope>(words[0], true, out var parsedScope))
1225+
if (words.Length > 0 && Enum.TryParse<SseEventsScope>(words[0], true, out var parsedScope))
11871226
{
1188-
endpoint.InfoEventsScope = parsedScope;
1189-
if (parsedScope == InfoEventsScope.Authorize && words.Length > 1)
1227+
endpoint.SseEventsScope = parsedScope;
1228+
if (parsedScope == SseEventsScope.Authorize && words.Length > 1)
11901229
{
1191-
endpoint.InfoEventsRoles ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
1230+
endpoint.SseEventsRoles ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
11921231
foreach (var word in words[1..])
11931232
{
11941233
if (string.IsNullOrWhiteSpace(word) is false)
11951234
{
1196-
endpoint.InfoEventsRoles.Add(word);
1235+
endpoint.SseEventsRoles.Add(word);
11971236
}
11981237
}
11991238
}
@@ -1202,7 +1241,7 @@ public static void SetCustomParameter(RoutineEndpoint endpoint, string name, str
12021241
else
12031242
{
12041243
Logger?.LogError("Could not recognize valid value for parameter key {key}. Valid values are: {values}. Provided value is {provided}.",
1205-
name, string.Join(", ", Enum.GetNames<InfoEventsScope>()), value);
1244+
name, string.Join(", ", Enum.GetNames<SseEventsScope>()), value);
12061245
}
12071246
}
12081247

NpgsqlRest/Enums.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public enum CommentHeader { None, Simple, Full }
99
public enum TextResponseNullHandling { EmptyString, NullLiteral, NoContent }
1010
public enum QueryStringNullHandling { EmptyString, NullLiteral, Ignore }
1111
public enum SslRequirement { Ignore, Warning, Required }
12+
public enum PostgresNoticeLevels { INFO, NOTICE, WARNING }
1213

1314
public enum ServiceProviderObject
1415
{
@@ -75,7 +76,7 @@ public enum PostgresConnectionNoticeLoggingMode
7576
FullStackAndMessage
7677
}
7778

78-
public enum InfoEventsScope
79+
public enum SseEventsScope
7980
{
8081
/// <summary>
8182
/// Only the session that initiated the request receives the notification (default)

NpgsqlRest/Extensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ public static object GetClaimDbContextParam(this Dictionary<string, object> dict
301301
{
302302
list.Add(claim.Value);
303303
}
304-
else
304+
else if (existing is not null)
305305
{
306306
var newList = new List<string>(4) { (string)existing, claim.Value };
307307
claimValues[claim.Type] = newList;
@@ -383,7 +383,7 @@ public static object GetUserClaimsDbParam(this ClaimsPrincipal user, Dictionary<
383383
}
384384
else
385385
{
386-
sb.Append(PgConverters.SerializeString((string)entry.Value));
386+
sb.Append(entry.Value is not null ? PgConverters.SerializeString((string)entry.Value) : "null");
387387
}
388388
i++;
389389
}
@@ -414,10 +414,10 @@ public static object GetClientIpAddressDbParam(this HttpRequest request)
414414
return request.GetClientIpAddress() as object ?? DBNull.Value;
415415
}
416416

417-
private const string Info = "INFO";
418-
private const string Notice = "NOTICE";
419-
private const string Warning = "WARNING";
420-
417+
private const string Info = nameof(PostgresNoticeLevels.INFO);
418+
private const string Notice = nameof(PostgresNoticeLevels.NOTICE);
419+
private const string Warning = nameof(PostgresNoticeLevels.WARNING);
420+
421421
public static bool IsInfo(this PostgresNotice notice)
422422
{
423423
return string.Equals(notice.Severity, Info, StringComparison.OrdinalIgnoreCase);

NpgsqlRest/Log.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ public static partial class Log
2222

2323
[LoggerMessage(Level = LogLevel.Debug, Message = "Created endpoint {urlInfo}")]
2424
public static partial void EndpointCreated(this ILogger logger, string urlInfo);
25-
26-
[LoggerMessage(Level = LogLevel.Debug, Message = "Endpoint {urlInfo} has INFO notification streaming at path {eventPath}")]
27-
public static partial void EndpointInfoStreamingPath(this ILogger logger, string urlInfo, string eventPath);
28-
25+
2926
[LoggerMessage(Level = LogLevel.Warning, Message = "Invalid URL path segment '{urlPathSegment}' in comment for {description}. Using default '{defaultUrl}'")]
3027
public static partial void InvalidUrlPathSegmentComment(this ILogger logger, string urlPathSegment, string description, string defaultUrl);
3128

@@ -187,15 +184,24 @@ public static partial class Log
187184

188185
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set USER PARAMETERS to TRUE by the comment annotation.")]
189186
public static partial void CommentUserParameters(this ILogger logger, string description);
187+
188+
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set SSE EVENTS STREAMING PATH to {path} by the comment annotation.")]
189+
public static partial void CommentSseStreamingPath(this ILogger logger, string description, string? path);
190+
191+
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set SSE EVENTS STREAMING PATH to {path} ON NOTICE LEVEL {level} by the comment annotation.")]
192+
public static partial void CommentSseStreamingPathAndLevel(this ILogger logger, string description, string? path, PostgresNoticeLevels level);
193+
194+
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set SSE EVENTS NOTICE LEVEL ON {level} by the comment annotation.")]
195+
public static partial void CommentSseStreamingLevel(this ILogger logger, string description, PostgresNoticeLevels level);
196+
197+
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set SSE EVENTS STREAMING SCOPE to {scope} by the comment annotation.")]
198+
public static partial void CommentSseStreamingScope(this ILogger logger, string description, SseEventsScope scope);
190199

191-
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set INFO EVENTS STREAMING PATH to {path} by the comment annotation.")]
192-
public static partial void CommentInfoStreamingPath(this ILogger logger, string description, string? path);
193-
194-
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set INFO EVENTS STREAMING SCOPE to {scope} by the comment annotation.")]
195-
public static partial void CommentInfoStreamingScope(this ILogger logger, string description, InfoEventsScope scope);
196-
197-
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set INFO EVENTS STREAMING SCOPE to AUTHENTICATED with roles {roles} by the comment annotation.")]
198-
public static partial void CommentInfoStreamingScopeRoles(this ILogger logger, string description, HashSet<string> roles);
200+
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has set SSE EVENTS STREAMING SCOPE to AUTHENTICATED with roles {roles} by the comment annotation.")]
201+
public static partial void CommentSseStreamingScopeRoles(this ILogger logger, string description, HashSet<string> roles);
202+
203+
[LoggerMessage(Level = LogLevel.Debug, Message = "Endpoint {urlInfo} has enabled SSE EVENTS PATH to {ssePath} ON NOTICE LEVEL {level}.")]
204+
public static partial void EndpointSsePath(this ILogger logger, string urlInfo, string ssePath, PostgresNoticeLevels? level);
199205

200206
[LoggerMessage(Level = LogLevel.Debug, Message = "{description} has BASIC AUTH enabled by the comment annotation.")]
201207
public static partial void BasicAuthEnabled(this ILogger logger, string description);

NpgsqlRest/NpgsqlRestBuilder.cs

Lines changed: 14 additions & 10 deletions

0 commit comments

Comments
 (0)