saltysystems / overworld

Open source framework for scalable multiplayer games.
Mozilla Public License 2.0
20 stars 3 forks source link

module_info/1 not working for Elixir modules #61

Open cmdrk opened 2 hours ago

cmdrk commented 2 hours ago

When trying to boot Overworld as an Elixir dependency, I get the following error:

04:16:22.145 [notice] Application overworld exited: :ow_app.start(:normal, []) returned an error: shutdown: failed to start child: :ow_protocol
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function Hex.API.module_info/1 is undefined (module Hex.API is not available)
            (hex 2.1.1) Hex.API.module_info(:attributes)
            (overworld 2.0.0) /usr/home/lincoln/chat_ex/deps/overworld/src/ow_protocol.erl:227: :ow_protocol.reg_rpc/2
            (stdlib 6.0.1) lists.erl:2151: :lists.foldl_1/3
            (overworld 2.0.0) /usr/home/lincoln/chat_ex/deps/overworld/src/ow_protocol.erl:447: anonymous fn/2 in :ow_protocol.auto_register/1
            (stdlib 6.0.1) lists.erl:2151: :lists.foldl_1/3
            (overworld 2.0.0) /usr/home/lincoln/chat_ex/deps/overworld/src/ow_protocol.erl:163: :ow_protocol.init/1
            (stdlib 6.0.1) gen_server.erl:2057: :gen_server.init_it/2
            (stdlib 6.0.1) gen_server.erl:2012: :gen_server.init_it/6

I think what's happening here is that we assume module_info/1 exists for the modules. Apparently it is injected at compile time. See https://github.com/elixir-lang/elixir/issues/10444

cmdrk commented 2 hours ago

Seemingly it does work for some modules, but not all. Here's an example where it does work, and how to set them from Elixir:

defmodule ChatEx do
  @moduledoc """
  Documentation for `ChatEx`.
  """

  Module.register_attribute(__MODULE__, :rpc_client_test, accumulate: true, persist: true)

  @doc """
  Hello world.

  ## Examples

      iex> ChatEx.hello()
      :world

  """
  @rpc_client_test [:hello]
  def hello do
    :world
  end
end

Within iex:

iex(1)> ChatEx.__info__(:attributes)
[vsn: [338040932286958303307203238272626022572], rpc_client_test: [:hello]]

Should be able to simply change this to the actual attribute such as rpc_client, but see next comment.

cmdrk commented 2 hours ago

When actually using it, we bomb out pretty quickly due to lack of Protobuf module. See here I changed the code to:

defmodule ChatEx do
  @moduledoc """
  Documentation for `ChatEx`.
  """

  Module.register_attribute(__MODULE__, :rpc_client, accumulate: true, persist: true)

  @doc """
  Hello world.

  ## Examples

      iex> ChatEx.hello()
      :world

  """
  @rpc_client [:hello]
  def hello do
    :world
  end
end

Which results in:

** (Mix) Could not start application overworld: :ow_app.start(:normal, []) returned an error: shutdown: failed to start child: :ow_protocol
    ** (EXIT) an exception was raised:
        ** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not an already existing atom

            :erlang.list_to_existing_atom(~c"chat_ex_pb")
            (overworld 2.0.0) /usr/home/lincoln/overworld/src/ow_protocol.erl:477: :ow_protocol.get_overworld_config/1
            (overworld 2.0.0) /usr/home/lincoln/overworld/src/ow_protocol.erl:459: anonymous fn/2 in :ow_protocol.auto_register/1
            (stdlib 6.0.1) lists.erl:2151: :lists.foldl_1/3
            (overworld 2.0.0) /usr/home/lincoln/overworld/src/ow_protocol.erl:163: :ow_protocol.init/1
            (stdlib 6.0.1) gen_server.erl:2057: :gen_server.init_it/2
            (stdlib 6.0.1) gen_server.erl:2012: :gen_server.init_it/6
            (stdlib 6.0.1) proc_lib.erl:329: :proc_lib.init_p_do_apply/3

This is great in a sense! Overworld sees the attribute and tries to do the right thing. We just don't have the protobuf module compiled yet.