summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimponic <loganhunt@simponic.xyz>2023-01-04 00:03:38 -0700
committerSimponic <loganhunt@simponic.xyz>2023-01-04 00:03:38 -0700
commit93ae544684b29db30c6c65a5ba5e7cb51972123c (patch)
tree70ea4e1c8fe43a60434d38ec44cb58a9499f3bbc
parent720a110c957a9ac1399ca3d2324b5b2cf8bbf3c6 (diff)
downloadchessh-93ae544684b29db30c6c65a5ba5e7cb51972123c.tar.gz
chessh-93ae544684b29db30c6c65a5ba5e7cb51972123c.zip
Create a Screen module behaviour, some ascii character arts, handle_input does stuff now
-rw-r--r--config/config.exs7
-rw-r--r--lib/chessh/ssh/client.ex43
-rw-r--r--lib/chessh/ssh/renderers/menu.ex35
-rw-r--r--lib/chessh/ssh/screens/board.ex15
-rw-r--r--lib/chessh/ssh/screens/menu.ex79
-rw-r--r--lib/chessh/ssh/screens/screen.ex15
-rw-r--r--mix.exs3
-rw-r--r--mix.lock1
-rw-r--r--priv/ascii_chars.json184
9 files changed, 320 insertions, 62 deletions
diff --git a/config/config.exs b/config/config.exs
index a12949b..2e20647 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -8,13 +8,14 @@ config :chessh,
ecto_repos: [Chessh.Repo],
key_dir: Path.join(Path.dirname(__DIR__), "priv/keys"),
port: 42_069,
- max_sessions: 255
+ max_sessions: 255,
+ ascii_chars_json_file: Path.join(Path.dirname(__DIR__), "priv/ascii_chars.json")
config :chessh, RateLimits,
jail_timeout_ms: 5 * 60 * 1000,
jail_attempt_threshold: 15,
max_concurrent_user_sessions: 5,
- player_session_message_burst_ms: 3_000,
- player_session_message_burst_rate: 15
+ player_session_message_burst_ms: 1_000,
+ player_session_message_burst_rate: 8
import_config "#{config_env()}.exs"
diff --git a/lib/chessh/ssh/client.ex b/lib/chessh/ssh/client.ex
index 4eceb38..dfa222c 100644
--- a/lib/chessh/ssh/client.ex
+++ b/lib/chessh/ssh/client.ex
@@ -1,6 +1,6 @@
defmodule Chessh.SSH.Client do
alias IO.ANSI
-
+ alias Chessh.SSH.Client.Menu
require Logger
use GenServer
@@ -26,7 +26,7 @@ defmodule Chessh.SSH.Client do
height: 0,
player_session: nil,
buffer: [],
- state_stack: [{&Chessh.SSH.Client.Menu.render/2, []}]
+ state_stack: [{Menu, %Menu.State{}}]
end
@impl true
@@ -61,13 +61,21 @@ defmodule Chessh.SSH.Client do
end
end
- def handle({:data, data}, %State{tui_pid: tui_pid} = state) do
- new_state =
- keymap(data)
- |> keypress(state)
+ def handle(
+ {:data, data},
+ %State{tui_pid: tui_pid, state_stack: [{module, _screen_state} | _tail]} = state
+ ) do
+ action = keymap(data)
- send(tui_pid, {:send_data, render(new_state)})
- {:noreply, new_state}
+ if action == :quit do
+ {:stop, :normal, state}
+ else
+ new_state = module.handle_input(action, state)
+
+ send(tui_pid, {:send_data, render(new_state)})
+
+ {:noreply, new_state}
+ end
end
def handle({:resize, {width, height}}, %State{tui_pid: tui_pid} = state) do
@@ -80,18 +88,6 @@ defmodule Chessh.SSH.Client do
{:noreply, new_state}
end
- def keypress(:up, state), do: state
- def keypress(:right, state), do: state
- def keypress(:down, state), do: state
- def keypress(:left, state), do: state
-
- def keypress(:quit, state) do
- send(self(), :quit)
- state
- end
-
- def keypress(_, state), do: state
-
def keymap(key) do
case key do
# Exit keys - C-c and C-d
@@ -106,17 +102,18 @@ defmodule Chessh.SSH.Client do
end
end
- @spec terminal_size_allowed(any, any) :: boolean
def terminal_size_allowed(width, height) do
Enum.member?(@min_terminal_width..@max_terminal_width, width) &&
Enum.member?(@min_terminal_height..@max_terminal_height, height)
end
- defp render(%{width: width, height: height, state_stack: [{render_fn, args} | _tail]} = state) do
+ defp render(
+ %State{width: width, height: height, state_stack: [{module, _screen_state}]} = state
+ ) do
if terminal_size_allowed(width, height) do
[
@clear_codes ++
- render_fn.(state, args)
+ module.render(state)
]
else
@terminal_bad_dim_msg
diff --git a/lib/chessh/ssh/renderers/menu.ex b/lib/chessh/ssh/renderers/menu.ex
deleted file mode 100644
index c3c3646..0000000
--- a/lib/chessh/ssh/renderers/menu.ex
+++ /dev/null
@@ -1,35 +0,0 @@
-defmodule Chessh.SSH.Client.Menu do
- alias Chessh.SSH.Client.State
- alias Chessh.Utils
-
- alias IO.ANSI
-
- @logo " Simponic's
-
- dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM
- 88 M mmmmm..M M mmmmm..M M MMMMM MM
-.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M
-88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM
-88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM
-`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM
- MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM"
-
- def render(
- %State{width: width, height: height, state_stack: [_current_state | _tail]} = _state,
- _args
- ) do
- {logo_width, logo_height} = Utils.text_dim(@logo)
-
- split = String.split(@logo, "\n")
-
- Enum.flat_map(
- Enum.zip(0..(length(split) - 1), split),
- fn {i, x} ->
- [
- ANSI.cursor(div(height - logo_height, 2) + i, div(width - logo_width, 2)),
- "#{x}\n"
- ]
- end
- )
- end
-end
diff --git a/lib/chessh/ssh/screens/board.ex b/lib/chessh/ssh/screens/board.ex
new file mode 100644
index 0000000..7b22052
--- /dev/null
+++ b/lib/chessh/ssh/screens/board.ex
@@ -0,0 +1,15 @@
+defmodule Chessh.SSH.Client.Board do
+ use Chessh.SSH.Client.Screen
+ alias Chessh.SSH.Client.State
+
+ def render(%State{} = _state) do
+ @ascii_chars["pieces"]["white"]["knight"]
+ end
+
+ def handle_input(action, state) do
+ case action do
+ "q" -> state
+ _ -> state
+ end
+ end
+end
diff --git a/lib/chessh/ssh/screens/menu.ex b/lib/chessh/ssh/screens/menu.ex
new file mode 100644
index 0000000..22aba85
--- /dev/null
+++ b/lib/chessh/ssh/screens/menu.ex
@@ -0,0 +1,79 @@
+defmodule Chessh.SSH.Client.Menu do
+ alias Chessh.SSH.Client
+ alias Chessh.Utils
+ alias IO.ANSI
+
+ require Logger
+
+ defmodule State do
+ defstruct y: 0,
+ x: 0
+ end
+
+ use Chessh.SSH.Client.Screen
+
+ @logo " Simponic's
+
+ dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM
+ 88 M mmmmm..M M mmmmm..M M MMMMM MM
+.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M
+88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM
+88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM
+`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM
+ MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM"
+
+ def render(%Client.State{
+ width: width,
+ height: height,
+ state_stack: [{_this_module, %State{y: y, x: x}} | _tail]
+ }) do
+ {logo_width, logo_height} = Utils.text_dim(@logo)
+
+ split = String.split(@logo, "\n")
+
+ Enum.flat_map(
+ Enum.zip(0..(length(split) - 1), split),
+ fn {i, line} ->
+ [
+ ANSI.cursor(div(height - logo_height, 2) + i + y, div(width - logo_width, 2) + x),
+ "#{line}\n"
+ ]
+ end
+ )
+ end
+
+ def handle_input(
+ data,
+ %Client.State{state_stack: [{this_module, %State{y: y, x: x} = screen_state} | tail]} =
+ state
+ ) do
+ case data do
+ :left ->
+ %Client.State{
+ state
+ | state_stack: [{this_module, %State{screen_state | x: x - 1}} | tail]
+ }
+
+ :right ->
+ %Client.State{
+ state
+ | state_stack: [{this_module, %State{screen_state | x: x + 1}} | tail]
+ }
+
+ :up ->
+ %Client.State{
+ state
+ | state_stack: [{this_module, %State{screen_state | y: y - 1}} | tail]
+ }
+
+ :down ->
+ %Client.State{
+ state
+ | state_stack: [{this_module, %State{screen_state | y: y + 1}} | tail]
+ }
+
+ _ ->
+ state
+ end
+ end
+end
diff --git a/lib/chessh/ssh/screens/screen.ex b/lib/chessh/ssh/screens/screen.ex
new file mode 100644
index 0000000..be6e00e
--- /dev/null
+++ b/lib/chessh/ssh/screens/screen.ex
@@ -0,0 +1,15 @@
+defmodule Chessh.SSH.Client.Screen do
+ @callback render(state :: Chessh.SSH.Client.State.t() | any()) :: any()
+ @callback handle_input(action :: any(), state :: Chessh.SSH.Client.State.t()) ::
+ Chessh.SSH.Client.State.t()
+
+ defmacro __using__(_) do
+ quote do
+ @behaviour Chessh.SSH.Client.Screen
+
+ @ascii_chars Application.compile_env!(:chessh, :ascii_chars_json_file)
+ |> File.read!()
+ |> Jason.decode!()
+ end
+ end
+end
diff --git a/mix.exs b/mix.exs
index 6066333..fd5a4b8 100644
--- a/mix.exs
+++ b/mix.exs
@@ -33,7 +33,8 @@ defmodule Chessh.MixProject do
{:postgrex, "~> 0.16.5"},
{:bcrypt_elixir, "~> 3.0"},
{:hammer, "~> 6.1"},
- {:syn, "~> 3.3"}
+ {:syn, "~> 3.3"},
+ {:jason, "~> 1.3"}
]
end
diff --git a/mix.lock b/mix.lock
index c376f97..48fe5e1 100644
--- a/mix.lock
+++ b/mix.lock
@@ -11,6 +11,7 @@
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"esshd": {:hex, :esshd, "0.2.1", "cded6a329c32bc3b3c15828bcd34203227bbef310db3c39a6f3c55cf5b29cd34", [:mix], [], "hexpm", "b058b56af53aba1c23522d72a3c39ab7f302e509af1c0ba1a748f00d93053c4d"},
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
+ "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"syn": {:hex, :syn, "3.3.0", "4684a909efdfea35ce75a9662fc523e4a8a4e8169a3df275e4de4fa63f99c486", [:rebar3], [], "hexpm", "e58ee447bc1094bdd21bf0acc102b1fbf99541a508cd48060bf783c245eaf7d6"},
diff --git a/priv/ascii_chars.json b/priv/ascii_chars.json
new file mode 100644
index 0000000..e50be22
--- /dev/null
+++ b/priv/ascii_chars.json
@@ -0,0 +1,184 @@
+{
+ "letters": {
+ "a": [
+ " ",
+ " /\\ ",
+ "/--\\"
+ ],
+ "b": [
+ " __ ",
+ "|__)",
+ "|__)"
+ ],
+ "c": [
+ " __ ",
+ "/ ",
+ "\\__ "
+ ],
+ "d": [
+ " __ ",
+ "| \\",
+ "|__/"
+ ],
+ "e": [
+ " __ ",
+ "|_ ",
+ "|__ "
+ ],
+ "f": [
+ " __ ",
+ "|_ ",
+ "| "
+ ],
+ "g": [
+ " __ ",
+ "/ _ ",
+ "\\__\\"
+ ],
+ "h": [
+ "| |",
+ "|__|",
+ "| |"
+ ]
+ },
+ "numbers": {
+ "0": [
+ " _ ",
+ "| |",
+ "|_|"
+ ],
+ "1": [
+ " ",
+ " /|",
+ " |"
+ ],
+ "2": [
+ " _ ",
+ " )",
+ " /_"
+ ],
+ "3": [
+ " _ ",
+ " _)",
+ " _)"
+ ],
+ "4": [
+ " .",
+ " /|",
+ "'-|"
+ ],
+ "5": [
+ " _ ",
+ "|_ ",
+ " _)"
+ ],
+ "6": [
+ " ",
+ " / ",
+ "(_)"
+ ],
+ "7": [
+ " __",
+ " /",
+ " / "
+ ],
+ "8": [
+ " _ ",
+ "(_)",
+ "(_)"
+ ],
+ "9": [
+ " _ ",
+ "(_)",
+ " )"
+ ]
+ },
+ "pieces": {
+ "white": {
+ "rook": [
+ " ",
+ " [`'`'] ",
+ " | | ",
+ " |__| ",
+ " "
+ ],
+ "knight": [
+ " _ _ ",
+ " \\` '/ ",
+ " (o o) ",
+ " \\ / \\",
+ " ^ "
+ ],
+ "queen": [
+ " /\\+/\\ ",
+ " /(o o)\\ ",
+ " (_) ",
+ " "
+ ],
+ "king": [
+ " ",
+ " |`+'| ",
+ " (o o) ",
+ " (_) ",
+ " "
+ ],
+ "bishop": [
+ " ",
+ " |v| ",
+ " (0 o) ",
+ " (_) ",
+ " "
+ ],
+ "pawn": [
+ " _ ",
+ " ( ) ",
+ " | | ",
+ " |_| ",
+ " "
+ ]
+ },
+ "black": {
+ "rook": [
+ " ",
+ " [`'`'] ",
+ " |::| ",
+ " |::| ",
+ " "
+ ],
+ "knight": [
+ " _ _ ",
+ " \\`.'/ ",
+ " (o:o) ",
+ " \\:/:\\",
+ " ^ "
+ ],
+ "queen": [
+ " /\\+/\\ ",
+ " /(o:o)\\ ",
+ " (:) ",
+ " "
+ ],
+ "king": [
+ " ",
+ " |`+'| ",
+ " (o:o) ",
+ " (:) ",
+ " "
+ ],
+ "bishop": [
+ " ",
+ " |v| ",
+ " (o:o) ",
+ " (:) ",
+ " "
+ ],
+ "pawn": [
+ " _ ",
+ " (:) ",
+ " |:| ",
+ " |_| ",
+ " "
+ ]
+ }
+ }
+}