Pusher service basis

This commit is contained in:
2025-07-12 22:15:18 +08:00
parent 33f56c4ef5
commit e1b47bc7d1
22 changed files with 1117 additions and 104 deletions

View File

@@ -20,6 +20,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7"/>
<PackageReference Include="NetTopologySuite" Version="2.6.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
<PackageReference Include="NodaTime" Version="3.2.2" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.2.0"/>
<PackageReference Include="NodaTime.Serialization.Protobuf" Version="2.0.2"/>
<PackageReference Include="StackExchange.Redis" Version="2.8.41"/>

View File

@@ -0,0 +1,89 @@
using Google.Protobuf.Collections;
using Google.Protobuf.WellKnownTypes;
using Newtonsoft.Json;
namespace DysonNetwork.Shared.Proto;
public abstract class GrpcTypeHelper
{
private static readonly JsonSerializerSettings SerializerSettings = new()
{
PreserveReferencesHandling = PreserveReferencesHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
public static MapField<string, Value> ConvertToValueMap(Dictionary<string, object> source)
{
var result = new MapField<string, Value>();
foreach (var kvp in source)
{
result[kvp.Key] = kvp.Value switch
{
string s => Value.ForString(s),
int i => Value.ForNumber(i),
long l => Value.ForNumber(l),
float f => Value.ForNumber(f),
double d => Value.ForNumber(d),
bool b => Value.ForBool(b),
null => Value.ForNull(),
_ => Value.ForString(JsonConvert.SerializeObject(kvp.Value, SerializerSettings)) // fallback to JSON string
};
}
return result;
}
public static Dictionary<string, object?> ConvertFromValueMap(MapField<string, Value> source)
{
var result = new Dictionary<string, object?>();
foreach (var kvp in source)
{
var value = kvp.Value;
switch (value.KindCase)
{
case Value.KindOneofCase.StringValue:
try
{
// Try to parse as JSON object or primitive
result[kvp.Key] = JsonConvert.DeserializeObject(value.StringValue);
}
catch
{
// Fallback to raw string
result[kvp.Key] = value.StringValue;
}
break;
case Value.KindOneofCase.NumberValue:
result[kvp.Key] = value.NumberValue;
break;
case Value.KindOneofCase.BoolValue:
result[kvp.Key] = value.BoolValue;
break;
case Value.KindOneofCase.NullValue:
result[kvp.Key] = null;
break;
case Value.KindOneofCase.StructValue:
result[kvp.Key] = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value.StructValue.Fields.ToDictionary(f => f.Key, f => ConvertField(f.Value)), SerializerSettings));
break;
case Value.KindOneofCase.ListValue:
result[kvp.Key] = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value.ListValue.Values.Select(ConvertField).ToList(), SerializerSettings));
break;
default:
result[kvp.Key] = null;
break;
}
}
return result;
}
private static object? ConvertField(Value value)
{
return value.KindCase switch
{
Value.KindOneofCase.StringValue => value.StringValue,
Value.KindOneofCase.NumberValue => value.NumberValue,
Value.KindOneofCase.BoolValue => value.BoolValue,
Value.KindOneofCase.NullValue => null,
_ => JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value, SerializerSettings))
};
}
}

View File

@@ -8,6 +8,7 @@ import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
import 'file.proto';
@@ -83,7 +84,7 @@ message AccountAuthFactor {
string id = 1;
AccountAuthFactorType type = 2;
google.protobuf.StringValue secret = 3; // Omitted from JSON serialization in original
map<string, string> config = 4; // Omitted from JSON serialization in original
map<string, google.protobuf.Value> config = 4; // Omitted from JSON serialization in original
int32 trustworthy = 5;
google.protobuf.Timestamp enabled_at = 6;
google.protobuf.Timestamp expired_at = 7;
@@ -107,7 +108,7 @@ message AccountBadge {
string type = 2; // Type/category of the badge
google.protobuf.StringValue label = 3; // Display name of the badge
google.protobuf.StringValue caption = 4; // Optional description of the badge
map<string, string> meta = 5; // Additional metadata for the badge
map<string, google.protobuf.Value> meta = 5; // Additional metadata for the badge
google.protobuf.Timestamp activated_at = 6; // When the badge was activated
google.protobuf.Timestamp expired_at = 7; // Optional expiration time
string account_id = 8; // ID of the account this badge belongs to
@@ -118,7 +119,7 @@ message AccountConnection {
string id = 1;
string provider = 2;
string provided_identifier = 3;
map<string, string> meta = 4;
map<string, google.protobuf.Value> meta = 4;
google.protobuf.StringValue access_token = 5; // Omitted from JSON serialization
google.protobuf.StringValue refresh_token = 6; // Omitted from JSON serialization
google.protobuf.Timestamp last_used_at = 7;
@@ -127,19 +128,30 @@ message AccountConnection {
// VerificationMark represents verification status
message VerificationMark {
bool verified = 1;
string method = 2;
google.protobuf.Timestamp verified_at = 3;
VerificationMarkType type = 1;
string title = 2;
string description = 3;
string verified_by = 4;
}
enum VerificationMarkType {
VERIFICATION_MARK_TYPE_UNSPECIFIED = 0;
OFFICIAL = 1;
INDIVIDUAL = 2;
ORGANIZATION = 3;
GOVERNMENT = 4;
CREATOR = 5;
DEVELOPER = 6;
PARODY = 7;
}
// BadgeReferenceObject represents a reference to a badge with minimal information
message BadgeReferenceObject {
string id = 1; // Unique identifier for the badge
string type = 2; // Type/category of the badge
google.protobuf.StringValue label = 3; // Display name of the badge
google.protobuf.StringValue caption = 4; // Optional description of the badge
map<string, string> meta = 5; // Additional metadata for the badge
map<string, google.protobuf.Value> meta = 5; // Additional metadata for the badge
google.protobuf.Timestamp activated_at = 6; // When the badge was activated
google.protobuf.Timestamp expired_at = 7; // Optional expiration time
string account_id = 8; // ID of the account this badge belongs to

View File

@@ -0,0 +1,68 @@
syntax = "proto3";
package proto;
option csharp_namespace = "DysonNetwork.Shared.Proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
// Represents a user session
message AuthSession {
string id = 1;
google.protobuf.StringValue label = 2;
google.protobuf.Timestamp last_granted_at = 3;
google.protobuf.Timestamp expired_at = 4;
string account_id = 5;
string challenge_id = 6;
AuthChallenge challenge = 7;
google.protobuf.StringValue app_id = 8;
}
// Represents an authentication challenge
message AuthChallenge {
string id = 1;
google.protobuf.Timestamp expired_at = 2;
int32 step_remain = 3;
int32 step_total = 4;
int32 failed_attempts = 5;
ChallengePlatform platform = 6;
ChallengeType type = 7;
repeated string blacklist_factors = 8;
repeated string audiences = 9;
repeated string scopes = 10;
google.protobuf.StringValue ip_address = 11;
google.protobuf.StringValue user_agent = 12;
google.protobuf.StringValue device_id = 13;
google.protobuf.StringValue nonce = 14;
// Point location is omitted as there is no direct proto equivalent.
string account_id = 15;
}
// Enum for challenge types
enum ChallengeType {
CHALLENGE_TYPE_UNSPECIFIED = 0;
LOGIN = 1;
OAUTH = 2;
OIDC = 3;
}
// Enum for challenge platforms
enum ChallengePlatform {
CHALLENGE_PLATFORM_UNSPECIFIED = 0;
UNIDENTIFIED = 1;
WEB = 2;
IOS = 3;
ANDROID = 4;
MACOS = 5;
WINDOWS = 6;
LINUX = 7;
}
service AuthService {
rpc Authenticate(AuthenticateRequest) returns (AuthSession) {}
}
message AuthenticateRequest {
string token = 1;
}