Packages
spawn
0.6.3
2.0.0-RC9
2.0.0-RC8
2.0.0-RC7
2.0.0-RC6
2.0.0-RC5
2.0.0-RC4
2.0.0-RC3
2.0.0-RC2
2.0.0-RC14
2.0.0-RC13
2.0.0-RC12
2.0.0-RC11
2.0.0-RC10
2.0.0-RC1
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc3
1.0.0-rc16
1.0.0-rc1
1.0.0-rc.38
1.0.0-rc.37
1.0.0-rc.36
1.0.0-rc.35
1.0.0-rc.34
1.0.0-rc.33
1.0.0-rc.32
1.0.0-rc.31
1.0.0-rc.30
1.0.0-rc.29
1.0.0-rc.28
1.0.0-rc.27
1.0.0-rc.26
1.0.0-rc.25
1.0.0-rc.24
1.0.0-rc.23
1.0.0-rc.22
1.0.0-rc.21
1.0.0-rc.20
1.0.0-rc.19
1.0.0-rc.18
1.0.0-rc.17
1.0.0-rc.2
0.6.3
0.6.2
0.6.1
0.6.0
0.5.5
0.5.4
0.5.3
0.5.1
0.5.0
0.5.0-rc.13
0.5.0-rc.12
0.5.0-rc.11
0.5.0-rc.10
0.5.0-rc.9
0.5.0-rc.8
0.5.0-rc.7
0.5.0-rc.6
0.5.0-rc.5
0.5.0-rc.3
0.5.0-alpha.13
0.5.0-alpha.12
0.5.0-alpha.11
0.5.0-alpha.10
0.5.0-alpha.9
0.5.0-alpha.8
0.5.0-alpha.7
0.5.0-alpha.6
0.5.0-alpha.5
0.5.0-alpha.4
0.5.0-alpha.3
0.5.0-alpha.2
0.5.0-alpha.1
0.1.0
Spawn is the core lib for Spawn Actors System
Current section
Files
Jump to
Current section
Files
lib/actors/actor/interface/http.ex
defmodule Actors.Actor.Interface.Http do
@moduledoc """
`Http` is responsible for the communication between the Proxy and the Host application
when using the HTTP protocol.
"""
use Actors.Actor.Interface
require Logger
alias Actors.{
Actor.Entity.EntityState,
Node.Client
}
alias Eigr.Functions.Protocol.Actors.{
Actor,
ActorId
}
alias Eigr.Functions.Protocol.{
Context,
ActorInvocation,
ActorInvocationResponse
}
alias Google.Protobuf.Any
@impl true
def invoke_host(
%ActorInvocation{
command_name: command
} = payload,
%EntityState{
actor: %Actor{commands: commands}
} = state,
default_actions
) do
if Enum.member?(default_actions, command) and
not Enum.any?(default_actions, fn action -> contains_action?(commands, action) end) do
resp = do_invoke_default_action(payload, state)
{:ok, resp, state}
else
do_invoke_host(payload, state)
end
end
defp do_invoke_default_action(
%ActorInvocation{
actor: %ActorId{name: name, system: system},
caller: caller
} = _payload,
%EntityState{
actor: %Actor{state: actor_state, id: actor_id}
} = _state
) do
current_state = Map.get(actor_state || %{}, :state)
current_tags = Map.get(actor_state || %{}, :tags, %{})
context =
if is_nil(current_state),
do: %Context{caller: caller, self: actor_id, state: Any.new(), tags: current_tags},
else: %Context{caller: caller, self: actor_id, state: current_state, tags: current_tags}
ActorInvocationResponse.new(
actor_name: name,
actor_system: system,
updated_context: context,
payload: current_state
)
end
defp do_invoke_host(payload, state) do
payload
|> ActorInvocation.encode()
|> Client.invoke_host_actor()
|> case do
{:ok, %Tesla.Env{body: ""}} ->
Logger.error("User Function Actor response Invocation body is empty")
{:error, :no_content, state}
{:ok, %Tesla.Env{body: nil}} ->
Logger.error("User Function Actor response Invocation body is nil")
{:error, :no_content, state}
{:ok, %Tesla.Env{body: body}} ->
case ActorInvocationResponse.decode(body) do
%ActorInvocationResponse{
updated_context: %Context{} = user_ctx
} = resp ->
{:ok, resp, update_state(state, user_ctx)}
error ->
Logger.error("Error on parse response #{inspect(error)}")
{:error, :invalid_content, state}
end
{:error, reason} ->
Logger.error("User Function Actor Invocation Unknown Error: #{inspect(reason)}")
{:error, reason, state}
end
end
defp contains_action?(commands, action), do: Enum.any?(commands, fn c -> c.name == action end)
defp update_state(%EntityState{} = state, %Context{} = ctx) do
actor = state.actor
actor_state = actor.state
if is_nil(actor_state) do
state
else
new_actor_state =
actor_state
|> Map.put(:state, ctx.state || actor_state.state)
|> Map.put(:tags, ctx.tags || actor_state.tags || %{})
%{state | actor: %{actor | state: new_actor_state}}
end
end
end