# BreazeChat

This is the repo for the chat system backend. This app is deployed as a microservice with docker-compose and the front-end connects to it via web sockets.

[Phoenix](http://www.phoenixframework.org/) was selected as the framework for the chat system backend because of it's performance, ability to scale, and it's native implemenataion of web
sockets and channels. Phoenix is implemented with a high performance functional language called [Elixir](http://elixir-lang.github.io/). Elixir transpiles to Erlang and leverages the
Erlang virtual machine.

## To start the Phoenix server:

  * Install dependencies with `mix deps.get`
  * Start Phoenix endpoint with `mix phoenix.server`

__NOTE:__ This app needs to connect to the same database as the django API since it saves the messages to the `user_message` table.

## Serving images

At startup breaze-chat will read and environment variable called `IMAGE_BASE_URL` which by default is set to `http://localhost:4000/uploads/` which works well in development. In production
this variables needs to be set the url where the images are being served from.

To change the location where images are written you need to modify the `save_image` function in the message model:

```elixir
def save_image(message, base64_image, extension) do
    binary = Base.decode64!(base64_image)
    File.write!("uploads/#{message.id}.#{extension}", binary)
end
```

You also need to tell [Plug](https://hexdocs.pm/plug/readme.html) that you need to serve static assets from that location. You do that by adding a plug to `/lib/breaze_chat/endpoint.ex`:
```elixir
...

  plug Plug.Static,
    at: "/", from: :breaze_chat, gzip: false,
    only: ~w(css fonts images js favicon.ico robots.txt)

  plug Plug.Static,
    at: "/uploads", from: Path.expand("./uploads"), gzip: false

...
```

__TODO:__ It would be nice to have the location of the chat images in an ENV variable.

## Sockets and channels

The front end communicates with this app through web sockets. The protocol used is `ws` or `wss` for secure sockets. Every time a user logs in a socket connection is established with this
server and the user is also subscribed to the lobby channel, which was introduced in BreazeHome 3.0. A user can be subscribed to many channels with the same socket. This allows for easy
implementation of new features like one-to-one private messages or user-agent communication, now introduced in BreazeHome 5.0.

## User Channel

A user by defaults joins a user channel, which can be thought of a user's own personal lobby where he can received unread_messages from other users. If the user has any unread messages upon
joining the user channel, they will then be redirected to a private channel where the other user is at.

## Private Channel

A user will join the private channel if they have started a chat event with the agent. The event calls the method `connectToPrivateChannel: (channel)`, which the socket gets validated first,
then the join event. The user id and agent id gets sorted in the room attribute of `user_message` (ex. 3:5).

## Presences

Two presences has been developed so far, which are the user online status, and the typing indicator. When the join event is called, `after_join` is executed, which the Phoenix Presence track
the user by id. The Presences uses two events: `phoenix_state` and `phoenix_diff`.`Phoenix_state` is called the first time the user joins a channel. `Phoenix_diff` gets called each time the user
joins or leaves a channel.

```elixir
...
  def handle_info(:after_join, socket) do
    push socket, "presence_state", Presence.list(socket)

    {:ok, _} = Presence.track(socket, "user:#{socket.assigns.current_user.id}", %{
      typing: false,
      user_id: socket.assigns.current_user.id,
      username: socket.assigns.current_user.username
    })

    {:noreply, socket}
  end
```

More information about the Phoenix Presence is explained in this documentation link: https://hexdocs.pm/phoenix/Phoenix.Presence.html

## Secrets
Secrets are stored under `/config` directory and each `*.secret.exs` file as well as `test.exs` file all use the same environment variables inside the `env` file in the `breazehome_dev folder`;
the `breazehome_dev folder` is part of `breaze-vagrant`.

Here is how `dev.secret.exs` file looks like

```elixir
use Mix.Config

config :breaze_chat, BreazeChat.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: System.get_env("POSTGRES_USER"),
  password: System.get_env("POSTGRES_PASSWORD"),
  host: System.get_env("POSTGRES_HOST"),
  port: System.get_env("POSTGRES_PORT"),
  database: System.get_env("POSTGRES_DB"),
  pool_size: 10
```

## ENV variables
ENV variables can be read using:
```elixir
System.get_env("NAME_OF_VAR")
```

Another option is to add a custom config block in your secret file as follows:
```elixir
use Mix.Config

# Rest of configuration
...

config :breaze_chat, :env,
  image_base_url: "http://localhost:4000/uploads/"

...
```
Then you can access `image_base_url` var like so:
```elixir
Application.get_env(:breaze_chat, :env)[:image_base_url]
```

## Learn more

  * Official website: http://www.phoenixframework.org/
  * Guides: http://phoenixframework.org/docs/overview
  * Docs: https://hexdocs.pm/phoenix
  * Source: https://github.com/phoenixframework/phoenix
