From a2957fdb0b495a2e698a857990fbd74cfcbc2079 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 12:12:57 +0200 Subject: [PATCH 01/12] Add some logs on game_socket_handler --- apps/arena/lib/arena/game_socket_handler.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/arena/lib/arena/game_socket_handler.ex b/apps/arena/lib/arena/game_socket_handler.ex index 78aba7665..75e9ad103 100644 --- a/apps/arena/lib/arena/game_socket_handler.ex +++ b/apps/arena/lib/arena/game_socket_handler.ex @@ -58,6 +58,7 @@ defmodule Arena.GameSocketHandler do Process.send_after(self(), :send_ping, @ping_interval_ms) + Logger.info("Sending GameJoined") {:reply, {:binary, encoded_msg}, state} end @@ -81,6 +82,8 @@ defmodule Arena.GameSocketHandler do end def websocket_handle({:binary, message}, state) do + Logger.info("Received message from client") + Serialization.GameAction.decode(message) |> handle_decoded_message(state) @@ -220,6 +223,7 @@ defmodule Arena.GameSocketHandler do %{block_movement: false} = state ) when action in [:move] do + Logger.info("Received MOVE action") case message do %{action_type: {:move, %{direction: direction}}, timestamp: timestamp} -> GameUpdater.move( From f568ccddd1fa0f67e12123c98da58829a3b2cfe8 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 17:09:47 +0200 Subject: [PATCH 02/12] Log status --- apps/arena/lib/arena/game_updater.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index 98760bea7..c938964b7 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -644,7 +644,7 @@ defmodule Arena.GameUpdater do killfeed: state.killfeed, damage_taken: state.damage_taken, damage_done: state.damage_done, - status: state.status, + status: IO.inspect(state.status), start_game_timestamp: state.start_game_timestamp, obstacles: complete_entities(state.obstacles), crates: complete_entities(state.crates), From 18aae8f1ec8474e56ab8cf21fa646df68fa3cde1 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 17:33:52 +0200 Subject: [PATCH 03/12] log timestamp --- apps/arena/lib/arena/game_updater.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index c938964b7..d33d3c622 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -626,6 +626,7 @@ defmodule Arena.GameUpdater do end defp broadcast_game_update(state) do + Logger.info("Game update #{state.status} #{state.server_timestamp}") encoded_state = GameEvent.encode(%GameEvent{ event: @@ -644,7 +645,7 @@ defmodule Arena.GameUpdater do killfeed: state.killfeed, damage_taken: state.damage_taken, damage_done: state.damage_done, - status: IO.inspect(state.status), + status: state.status, start_game_timestamp: state.start_game_timestamp, obstacles: complete_entities(state.obstacles), crates: complete_entities(state.crates), From 96831b63adf8a3a798140c6bb4d937803a5d5ed7 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 17:38:47 +0200 Subject: [PATCH 04/12] logger --- apps/arena/lib/arena/game_updater.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index d33d3c622..25dfa9e7e 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -4,6 +4,7 @@ defmodule Arena.GameUpdater do (player websocket). """ + require Logger use GenServer alias Arena.Game.Obstacle alias Arena.GameBountiesFetcher From b3884ece76725e50664da8d7e39120c090801181 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 17:55:19 +0200 Subject: [PATCH 05/12] Log game status change --- apps/arena/lib/arena/game_socket_handler.ex | 3 --- apps/arena/lib/arena/game_updater.ex | 13 ++++++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/arena/lib/arena/game_socket_handler.ex b/apps/arena/lib/arena/game_socket_handler.ex index 75e9ad103..184d359d3 100644 --- a/apps/arena/lib/arena/game_socket_handler.ex +++ b/apps/arena/lib/arena/game_socket_handler.ex @@ -82,8 +82,6 @@ defmodule Arena.GameSocketHandler do end def websocket_handle({:binary, message}, state) do - Logger.info("Received message from client") - Serialization.GameAction.decode(message) |> handle_decoded_message(state) @@ -223,7 +221,6 @@ defmodule Arena.GameSocketHandler do %{block_movement: false} = state ) when action in [:move] do - Logger.info("Received MOVE action") case message do %{action_type: {:move, %{direction: direction}}, timestamp: timestamp} -> GameUpdater.move( diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index 25dfa9e7e..11496ec26 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -235,6 +235,14 @@ defmodule Arena.GameUpdater do # Obstacles |> handle_obstacles_transitions() + game_state = + if game_state.status != game_state.current_status do + put_in(game_state, [:current_status], game_state.status) + |> put_in([:print_state], true) + else + game_state + |> put_in([:print_state], false) + end broadcast_game_update(game_state) game_state = %{game_state | killfeed: [], damage_taken: %{}, damage_done: %{}} @@ -627,7 +635,9 @@ defmodule Arena.GameUpdater do end defp broadcast_game_update(state) do - Logger.info("Game update #{state.status} #{state.server_timestamp}") + if state.print_state do + Logger.info("Game update #{state.status} #{state.server_timestamp}") + end encoded_state = GameEvent.encode(%GameEvent{ event: @@ -721,6 +731,7 @@ defmodule Arena.GameUpdater do config.game.bounty_pick_time_ms }) |> Map.put(:status, :PREPARING) + |> Map.put(:current_status, nil) |> Map.put( :start_game_timestamp, initial_timestamp + config.game.start_game_time_ms + config.game.bounty_pick_time_ms From 4a71a0c1c07b136a402fe0ab611248683c006147 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 18:23:24 +0200 Subject: [PATCH 06/12] short bounty selection --- apps/arena/lib/arena/game_updater.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/arena/lib/arena/game_updater.ex b/apps/arena/lib/arena/game_updater.ex index 11496ec26..b0b8ea02e 100644 --- a/apps/arena/lib/arena/game_updater.ex +++ b/apps/arena/lib/arena/game_updater.ex @@ -250,7 +250,7 @@ defmodule Arena.GameUpdater do end def handle_info(:selecting_bounty, state) do - Process.send_after(self(), :game_start, state.game_config.game.start_game_time_ms) + Process.send_after(self(), :game_start, 1000) {:noreply, put_in(state, [:game_state, :status], :SELECTING_BOUNTY)} end From 358da0b63e4185aef42c29e8f98837b8daecb405 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Tue, 16 Jul 2024 18:53:53 +0200 Subject: [PATCH 07/12] Movement message log --- apps/arena/lib/arena/game_socket_handler.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/arena/lib/arena/game_socket_handler.ex b/apps/arena/lib/arena/game_socket_handler.ex index 184d359d3..bfc3e2953 100644 --- a/apps/arena/lib/arena/game_socket_handler.ex +++ b/apps/arena/lib/arena/game_socket_handler.ex @@ -221,6 +221,7 @@ defmodule Arena.GameSocketHandler do %{block_movement: false} = state ) when action in [:move] do + Logger.info("Handling move") case message do %{action_type: {:move, %{direction: direction}}, timestamp: timestamp} -> GameUpdater.move( From 322550cf262dd25e0c72c24b3c87936c2052343c Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Wed, 17 Jul 2024 11:59:11 +0200 Subject: [PATCH 08/12] Websocket mock client and more --- apps/arena/lib/arena/game_bounties_fetcher.ex | 2 +- .../lib/game_client/game_test_handler.ex | 44 +++++++++++++++++++ .../lib/game_client/test_handler.ex | 44 +++++++++++++++++++ apps/game_client/mix.exs | 3 +- config/config.exs | 4 +- config/dev.exs | 5 ++- 6 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 apps/game_client/lib/game_client/game_test_handler.ex create mode 100644 apps/game_client/lib/game_client/test_handler.ex diff --git a/apps/arena/lib/arena/game_bounties_fetcher.ex b/apps/arena/lib/arena/game_bounties_fetcher.ex index a60018662..8f492ac92 100644 --- a/apps/arena/lib/arena/game_bounties_fetcher.ex +++ b/apps/arena/lib/arena/game_bounties_fetcher.ex @@ -2,7 +2,7 @@ defmodule Arena.GameBountiesFetcher do @moduledoc false use GenServer - @update_interval_ms 30_000 + @update_interval_ms 300_000 # API def start_link(_) do diff --git a/apps/game_client/lib/game_client/game_test_handler.ex b/apps/game_client/lib/game_client/game_test_handler.ex new file mode 100644 index 000000000..0fa01504b --- /dev/null +++ b/apps/game_client/lib/game_client/game_test_handler.ex @@ -0,0 +1,44 @@ +defmodule GameTestHandler do + @moduledoc """ + GameClient socket handler. + It handles the communication with the server. + """ + + use WebSockex, restart: :transient + require Logger + alias Arena.Serialization + + def start_link(gateway_jwt, player_id, game_id) do + ws_url = ws_url(gateway_jwt, player_id, game_id) + + WebSockex.start_link(ws_url, __MODULE__, %{}) + end + + def handle_connect(_, state) do + Logger.info("Game connected") + {:ok, state} + end + + def handle_frame({:binary, event}, state) do + decoded = Serialization.GameEvent.decode(event) + case decoded.event do + {:update, game_update} -> + Logger.info("Received update", %{server_timestamp: game_update.server_timestamp, status: game_update.status}) + {:ok, state} + _ -> + {:ok, state} + end + end + + def terminate(close_reason, _state) do + Logger.info("Game socket closed: #{inspect(close_reason)}") + :ok + end + + defp ws_url(gateway_jwt, player_id, game_id) do + # FIX ME Remove hardcoded host + # host = "localhost:4000" + host = "arena-brazil-testing.curseofmirra.com" + "wss://#{host}/play/#{game_id}/#{player_id}?gateway_jwt=#{gateway_jwt}" + end +end diff --git a/apps/game_client/lib/game_client/test_handler.ex b/apps/game_client/lib/game_client/test_handler.ex new file mode 100644 index 000000000..087924b19 --- /dev/null +++ b/apps/game_client/lib/game_client/test_handler.ex @@ -0,0 +1,44 @@ +defmodule TestHandler do + @moduledoc """ + GameClient socket handler. + It handles the communication with the server. + """ + + use WebSockex, restart: :transient + require Logger + alias Arena.Serialization + + @gateway_jwt "eyJhbGciOiJFZDI1NTE5IiwidHlwIjoiSldUIn0.eyJkZXYiOiJhaUJWOTN1NkhBdmpJV3h2R2plQWlrTXVuM0xURVBwcmhMelFMb1VOR0ljPSIsImV4cCI6MTcyMTIxNDA0OSwiaWF0IjoxNzIxMjA2ODQ5LCJqdGkiOiIydmhmOTBsc3FoNmxhNzN1YXMwMDFnN2giLCJuYmYiOjE3MjEyMDY4NDksInN1YiI6IjU1MWJhNzMxLWU2YmUtNDgzNi1hNjk2LTQ5NzE1MDQyMDViMyJ9.dvm3I5PlEiEVIQCtn0C9q1WZVKWpugkuhoPexoNMKeaiGizrAGFP38pVJ-EzgMcLc7HihDUxJVZkYSUGT2xlAw" + @player_id "551ba731-e6be-4836-a696-4971504205b3" + + def start_link() do + ws_url = ws_url(@gateway_jwt, @player_id) + + WebSockex.start_link(ws_url, __MODULE__, %{}) + end + + def handle_frame({:binary, event}, state) do + decoded = Serialization.LobbyEvent.decode(event) + case decoded.event do + {:joined, _} -> + Logger.info("Joined lobby") + {:ok, state} + {:game, %{game_id: game_id}} -> + Logger.info("Moving to game") + GameTestHandler.start_link(@gateway_jwt, @player_id, game_id) + {:ok, state} + end + end + + def terminate(close_reason, _state) do + Logger.info("Closing matchmaking socket: #{inspect(close_reason)}") + :ok + end + + defp ws_url(gateway_jwt, player_id) do + # FIX ME Remove hardcoded host + # host = "localhost:4000" + host = "arena-brazil-testing.curseofmirra.com" + "wss://#{host}/join/#{player_id}/muflus/amin?gateway_jwt=#{gateway_jwt}" + end +end diff --git a/apps/game_client/mix.exs b/apps/game_client/mix.exs index 138196ba1..6d6b8c126 100644 --- a/apps/game_client/mix.exs +++ b/apps/game_client/mix.exs @@ -57,7 +57,8 @@ defmodule GameClient.MixProject do {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:websockex, "~> 0.4.3"}, {:exbase58, "~> 1.0.2"}, - {:ueberauth_google, "~> 0.10"} + {:ueberauth_google, "~> 0.10"}, + {:arena, in_umbrella: true} ] end diff --git a/config/config.exs b/config/config.exs index 3bfbad31e..8c1d1fa79 100644 --- a/config/config.exs +++ b/config/config.exs @@ -29,8 +29,8 @@ import Config # Configures Elixir's Logger config :logger, :console, - format: "$time $metadata[$level] $message\n", - metadata: [:request_id] + format: "$time [$level] $message $metadata\n", + metadata: [:status, :server_timestamp, :request_id] # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason diff --git a/config/dev.exs b/config/dev.exs index 8716c5d64..3711883ee 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -5,7 +5,10 @@ import Config ########################## # Do not include metadata nor timestamps in development logs -config :logger, :console, format: "[$level] $message\n" +# config :logger, :console, format: "[$level] $message\n" +config :logger, :console, + format: "$time [$level] $message $metadata\n", + metadata: [:status, :server_timestamp] # Set a higher stacktrace during development. Avoid configuring such # in production as building large stacktraces may be expensive. From b0bb76acfdd2adc4023db469ade53ffd4b5853b7 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Thu, 18 Jul 2024 15:59:30 +0200 Subject: [PATCH 09/12] More testing handlers --- apps/arena/lib/arena/server_socket_handler.ex | 34 +++++++++++++++ apps/arena/lib/arena/tester.ex | 41 +++++++++++++++++++ apps/arena/mix.exs | 1 + config/config.exs | 3 +- config/dev.exs | 6 +-- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 apps/arena/lib/arena/server_socket_handler.ex create mode 100644 apps/arena/lib/arena/tester.ex diff --git a/apps/arena/lib/arena/server_socket_handler.ex b/apps/arena/lib/arena/server_socket_handler.ex new file mode 100644 index 000000000..a24c3581a --- /dev/null +++ b/apps/arena/lib/arena/server_socket_handler.ex @@ -0,0 +1,34 @@ +defmodule Arena.ServerSocketHandler do + @moduledoc """ + Module that handles cowboy websocket requests + """ + require Logger + + @behaviour :cowboy_websocket + + @impl true + def init(req, _opts) do + {:cowboy_websocket, req, %{}} + end + + @impl true + def websocket_init(state) do + {:ok, state} + end + + @impl true + def websocket_info(_any, state) do + {:ok, state} + end + + @impl true + def websocket_handle({:text, msg}, state) do + handle_msg(Jason.decode!(msg), state) + end + + defp handle_msg(%{"action" => "check_ping", "client_timestamp" => client_timestamp}, state) do + now = DateTime.utc_now() |> DateTime.to_unix() + Logger.info("Message received", %{server_timestamp: now, client_timestamp: client_timestamp}) + {:reply, {:text, Jason.encode!(%{action: "response_ping", server_timestamp: now, client_timestamp: client_timestamp})}, state} + end +end diff --git a/apps/arena/lib/arena/tester.ex b/apps/arena/lib/arena/tester.ex new file mode 100644 index 000000000..563a5c0dc --- /dev/null +++ b/apps/arena/lib/arena/tester.ex @@ -0,0 +1,41 @@ +defmodule Tester do + @moduledoc """ + GameClient socket handler. + It handles the communication with the server. + """ + + use WebSockex, restart: :transient + require Logger + + def start_link() do + host = "arena-brazil-testing.curseofmirra.com" + ws_url = "wss://#{host}/testing" + + WebSockex.start_link(ws_url, __MODULE__, %{}) + end + + def handle_connect(_, state) do + Logger.info("Game connected") + send(self(), :check_ping) + {:ok, state} + end + + def handle_frame({:text, msg}, state) do + msg = Jason.decode!(msg, keys: :atoms) + metadata = Map.merge(msg, %{latency_ms: (msg.server_timestamp - msg.client_timestamp)}) + Logger.info("Received frame", metadata) + {:ok, state} + end + + def handle_info(:check_ping, state) do + now = DateTime.utc_now() |> DateTime.to_unix() + Logger.info("Sending check_ping", %{timestamp: now}) + Process.send_after(self(), :check_ping, 30) + {:reply, {:text, Jason.encode!(%{"action" => "check_ping", "client_timestamp" => now})}, state} + end + + def terminate(close_reason, _state) do + Logger.info("Socket closed: #{inspect(close_reason)}") + :ok + end +end diff --git a/apps/arena/mix.exs b/apps/arena/mix.exs index 4a26e2bb2..9f473c65d 100644 --- a/apps/arena/mix.exs +++ b/apps/arena/mix.exs @@ -52,6 +52,7 @@ defmodule Arena.MixProject do {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:plug_cowboy, "~> 2.5"}, {:toxiproxy_ex, "~> 1.1.1"}, + {:websockex, "~> 0.4.3"}, {:joken, "~> 2.6"} ] end diff --git a/config/config.exs b/config/config.exs index 8c1d1fa79..bda07c224 100644 --- a/config/config.exs +++ b/config/config.exs @@ -30,7 +30,7 @@ import Config # Configures Elixir's Logger config :logger, :console, format: "$time [$level] $message $metadata\n", - metadata: [:status, :server_timestamp, :request_id] + metadata: [:status, :action, :latency_ms, :server_timestamp, :client_timestamp] # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason @@ -87,6 +87,7 @@ config :joken, # Configures the endpoint dispatch = [ _: [ + {"/testing", Arena.ServerSocketHandler, []}, {"/play/:game_id/:client_id", Arena.GameSocketHandler, []}, {"/join/:client_id/:character_name/:player_name", Arena.SocketHandler, []}, {"/quick_game/:client_id/:character_name/:player_name", Arena.QuickGameHandler, []}, diff --git a/config/dev.exs b/config/dev.exs index 3711883ee..e93e9f6eb 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -6,9 +6,9 @@ import Config # Do not include metadata nor timestamps in development logs # config :logger, :console, format: "[$level] $message\n" -config :logger, :console, - format: "$time [$level] $message $metadata\n", - metadata: [:status, :server_timestamp] +# config :logger, :console, +# format: "$time [$level] $message $metadata\n", +# metadata: [:status, :action, :server_timestamp, :client_timestamp] # Set a higher stacktrace during development. Avoid configuring such # in production as building large stacktraces may be expensive. From 0ebe9c4069d9c7a3a95fe459b5e8d2758ca01cc4 Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Fri, 19 Jul 2024 15:40:57 +0200 Subject: [PATCH 10/12] Allow deploying arena to brazil-client server --- .github/workflows/loadtest-brazil-client-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/loadtest-brazil-client-deploy.yml b/.github/workflows/loadtest-brazil-client-deploy.yml index a0e37d6f7..8845a396a 100644 --- a/.github/workflows/loadtest-brazil-client-deploy.yml +++ b/.github/workflows/loadtest-brazil-client-deploy.yml @@ -8,6 +8,7 @@ on: options: - bot_manager - arena_load_test + - arena required: true target_server: type: choice From b15c55e8e8f4c6deabd852faffa92df22c553e2a Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Fri, 19 Jul 2024 16:57:18 +0200 Subject: [PATCH 11/12] Add missing env vars --- .github/workflows/loadtest-brazil-client-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/loadtest-brazil-client-deploy.yml b/.github/workflows/loadtest-brazil-client-deploy.yml index 8845a396a..0509f622f 100644 --- a/.github/workflows/loadtest-brazil-client-deploy.yml +++ b/.github/workflows/loadtest-brazil-client-deploy.yml @@ -67,6 +67,7 @@ jobs: PHX_SERVER: ${{ vars.PHX_SERVER }} PHX_HOST: ${{ vars.LOADTEST_CLIENT_HOST }} PORT: ${{ vars.ARENA_PORT }} + BOT_MANAGER_HOST: ${{ vars.LOADTEST_CLIENT_HOST }} BOT_MANAGER_PORT: ${{ vars.BOT_MANAGER_PORT }} DATABASE_URL: ${{ secrets.DATABASE_URL }} SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }} @@ -74,6 +75,7 @@ jobs: NEWRELIC_KEY: ${{ secrets.NEWRELIC_KEY }} DBUS_SESSION_BUS_ADDRESS: ${{ vars.DBUS_SESSION_BUS_ADDRESS }} BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + GATEWAY_URL: ${{ vars.GATEWAY_URL }} run: | set -ex ssh ${SSH_USERNAME}@${SSH_HOST} \ From 0b9e47f25356f8ba43e68c537d30df06ee6d675f Mon Sep 17 00:00:00 2001 From: Amin Arria Date: Fri, 19 Jul 2024 17:06:44 +0200 Subject: [PATCH 12/12] Fix fix missing env vars --- .github/workflows/loadtest-brazil-client-deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/loadtest-brazil-client-deploy.yml b/.github/workflows/loadtest-brazil-client-deploy.yml index 0509f622f..cf30a9564 100644 --- a/.github/workflows/loadtest-brazil-client-deploy.yml +++ b/.github/workflows/loadtest-brazil-client-deploy.yml @@ -89,10 +89,12 @@ jobs: PHX_SERVER=${PHX_SERVER} \ PHX_HOST=${PHX_HOST} \ PORT=${PORT} \ + BOT_MANAGER_HOST=${BOT_MANAGER_HOST} \ BOT_MANAGER_PORT=${BOT_MANAGER_PORT} \ DATABASE_URL=${DATABASE_URL} \ SECRET_KEY_BASE=${SECRET_KEY_BASE} \ NEWRELIC_APP_NAME=${NEWRELIC_APP_NAME} \ NEWRELIC_KEY=${NEWRELIC_KEY} \ DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS} \ + GATEWAY_URL=${GATEWAY_URL} \ /home/${SSH_USERNAME}/deploy-script/deploy.sh