輪處處理桌子進程了。桌子進程拋開消息發送,基本上就是table的轉調用。api
無謂測試驅動先仍是寫代碼先,反正怎麼順就怎麼搞。ide
defmodule TableServer do use GenServer, restart: :temporary, start: {__MODULE__, :start_link, []} def start_link(table) do GenServer.start_link(__MODULE__, table, name: register_name(table)) end def init(table) do {:ok, table} end def register_name(%{} = table), do: register_name(table |> SimpleTable.get_id) def register_name(id), do: {:via, Registry, {LocalRegistry, {Table, id}}} def exist?(table) do key = {Table, table |> SimpleTable.get_id} case Registry.lookup(LocalRegistry, key) do [{_pid, _}] -> true [] -> false end end def create(player) do table = SimpleTable.init |> SimpleTable.set_id(player |> Player.get_id) |> SimpleTable.set_creator(player) |> SimpleTable.add_seat(player) TableSupervisor.start_table(table) end def join(table, player), do: GenServer.cast(table, {:join, player: player}) def quit(table, player), do: GenServer.cast(table, {:quit, player: player}) def dismiss(table, player), do: GenServer.cast(table, {:dismiss, player: player}) def start(table, player), do: GenServer.cast(table, {:start, player: player}) def open(table, player), do: GenServer.cast(table, {:open, player: player}) def makeup(table, player), do: GenServer.cast(table, {:makeup, player: player}) def handle_cast(request, table) do {:ok, table} = inner_handle_cast(request, table) {:noreply, table} end def send_error(_player, _error) do end def inner_handle_cast({:join, player: player}, table) do with {:ok, table} <- table |> SimpleTable.join(player) do seat = SimpleTable.find_seat(table, player) broadcast_join(table, seat) else {:error, error} -> send_error(player, error) end {:ok, table} end def inner_handle_cast({:quit, player: player}, table) do with {:ok, table} <- table |> SimpleTable.quit(player) do broadcast_quit(table, player) else {:error, error} -> send_error(player, error) end {:ok, table} end def inner_handle_cast({:dismiss, player: player}, table) do with {:ok, table} <- table |> SimpleTable.dismiss(player) do broadcast_dismiss(table) else {:error, error} -> send_error(player, error) end {:ok, table} end def inner_handle_cast({:start, player: player}, table) do with {:ok, table} <- table |> SimpleTable.start(player) do broadcast_start(table) else {:error, error} -> send_error(player, error) end {:ok, table} end def inner_handle_cast({:open, player: player}, table) do with {:ok, table} <- table |> SimpleTable.open(player) do send_open(table, player) else {:error, error} -> send_error(player, error) end {:ok, table} end def inner_handle_cast({:makeup, player: player}, table) do with {:ok, table} <- table |> SimpleTable.make_up(player) do send_makeup(table, player) else {:error, error} -> send_error(player, error) end {:ok, table} end def broadcast_join(_table, _seat) do end def broadcast_quit(_table, _player) do end def broadcast_dismiss(_table) do end def broadcast_start(_table) do end def send_open(_table, _player) do end def send_makeup(_table, _player) do end end
雖然table_server 很簡單,但我仍是花了點時間在上面。函數
主要在考慮下面的問題:測試
1. 要不要用exactor 庫簡化api接口ui
後來沒有用, exactor 仍是適合於速錯模式用, 而遊戲咱們一般要try catch,若是要用,須要包裝exactor的宏,麻煩。spa
固然若是把table存到ets裏, 就能夠比較方便的崩潰恢復, 也許這比較適合用exactor。rest
2. inner_handle_cast 應該是怎麼樣的接口才方便修改code
想來想去,用 {cmd, keyword_list} 比較方便, 直觀且容易修改server
3. 消息發送怎麼樣才方便以及直觀blog
一開始是嘗試 broadcast_table, 誘惑是凡是發消息就調用該接口。
但明顯感受有2個缺陷
一個是粒度太大(結果是該函數裏好比要有不一樣分支)
一個沒法直觀每一個操做的具體影響
因此最後改爲,須要發送什麼,就搞個api發送什麼, 這就有broadcast_join broadcast_quit 等等,
感受就清晰不少,天然不少,而且粒度小了發送的信息也少了。
下回增長相關的測試和代碼吧