Ryan Sweet edbd20167b
bring back grpc service (#5377)
Restoring the grpc + Orleans server into the project

## Why are these changes needed?

This is the distributed agent runtime for .NET that can manage routing
messages amongst a fleet of grpc agent runtimes.

## Related issue number

## Checks

- [ ] I've included any doc changes needed for
https://microsoft.github.io/autogen/. See
https://microsoft.github.io/autogen/docs/Contribute#documentation to
build and test documentation locally.
- [x] I've added tests (if relevant) corresponding to the changes
introduced in this PR.
- [x] I've made sure all auto checks have passed.

---------

Co-authored-by: Jack Gerrits <jack@jackgerrits.com>
Co-authored-by: Jacob Alber <jaalber@microsoft.com>
2025-02-07 19:28:55 -05:00

71 lines
3.5 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved.
// ReflectionHelper.cs
using System.Reflection;
using Google.Protobuf;
using Google.Protobuf.Reflection;
using Microsoft.AutoGen.Contracts;
using Microsoft.AutoGen.Core;
namespace Microsoft.AutoGen.RuntimeGateway.Grpc.Tests;
public sealed class ReflectionHelper
{
public static bool IsSubclassOfGeneric(Type type, Type genericBaseType)
{
while (type != null && type != typeof(object))
{
if (genericBaseType == (type.IsGenericType ? type.GetGenericTypeDefinition() : type))
{
return true;
}
if (type.BaseType == null)
{
return false;
}
type = type.BaseType;
}
return false;
}
public static AgentsMetadata GetAgentsMetadata(params Assembly[] assemblies)
{
var interfaceType = typeof(IMessage);
var pairs = assemblies
.SelectMany(assembly => assembly.GetTypes())
.Where(type => interfaceType.IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
.Select(t => (t, GetMessageDescriptor(t)));
var descriptors = pairs.Select(t => t.Item2);
var typeRegistry = TypeRegistry.FromMessages(descriptors);
var types = pairs.ToDictionary(item => item.Item2?.FullName ?? "", item => item.t);
var eventsMap = assemblies
.SelectMany(assembly => assembly.GetTypes())
.Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
.Select(t => (t, t.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>))
.Select(i => GetMessageDescriptor(i.GetGenericArguments().First())?.FullName ?? "").ToHashSet()))
.ToDictionary(item => item.t, item => item.Item2);
var topicsMap = assemblies
.SelectMany(assembly => assembly.GetTypes())
.Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
.Select(t => (t, t.GetCustomAttributes<TypeSubscriptionAttribute>().Select(a => a.Topic).ToHashSet()))
.ToDictionary(item => item.t, item => item.Item2);
var topicsPrefixMap = assemblies
.SelectMany(assembly => assembly.GetTypes())
.Where(type => IsSubclassOfGeneric(type, typeof(BaseAgent)) && !type.IsAbstract)
.Select(t => (t, t.GetCustomAttributes<TypePrefixSubscriptionAttribute>().Select(a => a.Topic).ToHashSet()))
.ToDictionary(item => item.t, item => item.Item2);
return new AgentsMetadata(typeRegistry, types, eventsMap, topicsMap, topicsPrefixMap);
}
/// <summary>
/// Gets the message descriptor for the specified type.
/// </summary>
/// <param name="type">The type to get the message descriptor for.</param>
/// <returns>The message descriptor if found; otherwise, <c>null</c>.</returns>
public static MessageDescriptor? GetMessageDescriptor(Type type)
{
var property = type.GetProperty("Descriptor", BindingFlags.Static | BindingFlags.Public);
return property?.GetValue(null) as MessageDescriptor;
}
}