Пример #1
0
            public async Task SetUp()
            {
                var handMapped = new ActorRouteMapping(typeof(IHandMappedActor), "TestActor");

                handMapped.Register(typeof(SetText), "SetText");
                handMapped.Register(typeof(GetText), "GetText", typeof(GetText.Result));

                var autoMapped = ActorRouteMapping.From(typeof(IAutoMappedActor));

                mapper = new ActorRouteMapper();
                mapper.Register(handMapped);
                mapper.Register(autoMapped);

                system = TestActorSystem.Instance;

                httpClient = new HttpClient {
                    BaseAddress = baseAddress
                };
                httpSystem = new HttpActorSystem(httpClient, serializer, mapper);

                var builder = Host.CreateDefaultBuilder();

                host = builder.ConfigureWebHostDefaults(web =>
                {
                    web.UseUrls("http://*:9090");
                    web.ConfigureServices(services =>
                    {
                        services.AddSingleton(system);
                        services.AddSingleton(serializer);
                        services.AddSingleton(mapper);
                    });
                    web.Configure(app =>
                    {
                        app.UseRouting();
                        app.UseEndpoints(e => e.MapActors(prefix));
                    });
                })
                       .Build();

                await host.StartAsync();

                handMappedActor = httpSystem.ActorOf <IHandMappedActor>(Guid.NewGuid().ToString());
                autoMappedActor = httpSystem.TypedActorOf <IAutoMappedActor>(Guid.NewGuid().ToString());
            }
Пример #2
0
        public static void MapActors(
            this IEndpointRouteBuilder routes,
            IActorSystem system,
            JsonSerializerOptions serializer,
            ActorRouteMapper mapper,
            string prefix = "")
        {
            routes.Map($"{prefix}/{{actor}}/{{id}}/{{message}}", async context =>
            {
                try
                {
                    await ProcessRequest();
                }
                catch (ActorRouteException ex)
                {
                    await RespondNotFound(ex.Message);
                }
                catch (Exception ex)
                {
                    await RespondError(ex.Message);
                }

                async Task ProcessRequest()
                {
                    var actor   = FindActor();
                    var message = FindMessage(actor);

                    var request  = await ReadRequest(message);
                    var response = await Send(actor, request);

                    if (response != null)
                    {
                        await WriteResponse(response);
                    }
                }

                string ActorRouteValue() => context.Request.RouteValues["actor"].ToString();
                string IdRouteValue() => context.Request.RouteValues["id"].ToString();
                string MessageRouteValue() => context.Request.RouteValues["message"].ToString();

                ActorRouteMapping FindActor()
                {
                    var actor = mapper.FindByRoute(ActorRouteValue());
                    return(actor ?? throw new ActorRouteException($"Can't find actor with key: {ActorRouteValue()}"));
                }

                MessageRouteMapping FindMessage(ActorRouteMapping actor)
                {
                    var message = actor.Find(MessageRouteValue());
                    return(message ?? throw new ActorRouteException($"Can't find message '{MessageRouteValue()}' for actor '{ActorRouteValue()}'"));
                }

                async Task RespondNotFound(string error)
                {
                    context.Response.StatusCode = (int)HttpStatusCode.NotFound;
                    await context.Response.WriteAsync(error);
                }

                async Task RespondError(string error)
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    await context.Response.WriteAsync(error);
                }

                async Task <object> Send(ActorRouteMapping route, object message)
                {
                    var actor = system.ActorOf(route.Interface, IdRouteValue());
                    return(await actor.Ask <object>(message));
                }

                async Task <object> ReadRequest(MessageRouteMapping message)
                {
                    if (context.Request.Method == HttpMethod.Get.ToString())
                    {
                        return(Activator.CreateInstance(message.Request));
                    }

                    if (context.Request.Method == HttpMethod.Post.ToString())
                    {
                        return(await Deserialize(context.Request.BodyReader, message.Request, context.RequestAborted));
                    }

                    throw new ActorRouteException("Unsupported http verb: " + context.Request.Method);
                }

                async ValueTask WriteResponse(object result)
                {
                    await Serialize(result, context.Response.BodyWriter);
                }
            });

            async ValueTask <object> Deserialize(PipeReader reader, Type type, CancellationToken cancellationToken)
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var frame = await reader.ReadAsync(cancellationToken);

                    var buffer = frame.Buffer;

                    var message = JsonSerializer.Deserialize(buffer.FirstSpan, type, serializer);
                    reader.AdvanceTo(buffer.Start, buffer.End);

                    if (frame.IsCompleted)
                    {
                        return(message);
                    }
                }

                return(null);
            }

            async ValueTask Serialize(object obj, PipeWriter writer)
            {
                await JsonSerializer.SerializeAsync(writer.AsStream(), obj, obj.GetType(), serializer);
            }
        }