XMPP bot with Phoenix on Raspberry Pi
This is basically the recreation of this article “Hands on XMPP(MongooseIM) connection from Phoenix/Elixir using Hedwig” with latest version of Phoenix framework.
First, create new phoenix project with mix phx.new phxchat
. It will also install dependencies.
Adjust config/dev.exs
and create database by mix ecto.create .
Now, you can start phoenix with iex -S mix phx.server
and check the page at http://localhost:4000
Add hedwig_xmpp as dependencies:
@@ -20,6 +20,7 @@ defmodule Phxchat.MixProject do
def application do
[
mod: {Phxchat.Application, []},
+ application: [:hedwig_xmpp],
extra_applications: [:logger, :runtime_tools]
]
end
@@ -42,7 +43,8 @@ defmodule Phxchat.MixProject do
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
- {:plug_cowboy, "~> 2.0"}
+ {:plug_cowboy, "~> 2.0"},
+ {:romeo, git: "https://github.com/scrogson/romeo", override: true},
+ {:hedwig_xmpp, "~>1.0"}
]
end
We also need the git version of romeo to avoid a bug on OTP 20. Run mix deps.get
again to install dependencies.
Let’s create Phoenix channel for communication between browser and server first.
In lib/phxchat_web/channels/user_socket.ex, uncomment channel room
## Channels
channel "room:*", PhxchatWeb.RoomChannel
Also uncomment socket.js in assets/js/app.js
import socket from "./socket"
Create lib/phxchat_web/channels/room_channel.ex as
defmodule PhxchatWeb.RoomChannel do
use Phoenix.Channel def join("room:lobby", auth_msg, socket) do
{:ok, socket}
end
end
Change the channel to “room:lobby” in assets/js/socket.js
let channel = socket.channel("room:lobby", {})
Now, check http://localhost:4000 again with web console opened. It would show ‘joined successfully’
To start using Hedwig, add this into config/config.exs
config :hedwig, Phxchat.Handlers.Echo,
adapter: Hedwig.Adapters.XMPP,
name: "hedwig",
aka: "/",
jid: "user@domain.com",
password: "password",
nickname: "user",
rooms: [
{"user@domain.com", []}
],
handlers: [{Phxchat.Handlers.Echo, %{}}]
Create the echo handler at lib/handlers/echo_handler.ex
defmodule Phxchat.Handlers.Echo do
use Hedwig.Robot, otp_app: :hedwig
require Logger def handle_connect(%{name: name} = state) do
if :undefined == :global.whereis_name(name) do
:yes = :global.register_name(name, self())
end
{:ok, state}
end def handle_disconnect(_reason, state) do
{:reconnect, 5000, state}
end def handle_in(%Hedwig.Message{} = msg, state) do
Logger.info(inspect msg)
PhxchatWeb.Endpoint.broadcast! "room:lobby", "message", %{text: msg.text, type: msg.type}
{:dispatch, msg, state}
end def handle_in(_msg, state) do
{:noreply, state}
end
end
Start this handler in lib/phxchat/application.ex
def start(_type, _args) do
# List all child processes to be supervised
children = [
# Start the Ecto repository
Phxchat.Repo,
# Start the endpoint when the application starts
PhxchatWeb.Endpoint,
# Starts a worker by calling: Phxchat.Worker.start_link(arg)
# {Phxchat.Worker, arg},
{Phxchat.Handlers.Echo, []}
]
And finally output the receiving messages at web console by add this code in assets/js/socket.js
let channel = socket.channel("room:lobby", {})
channel.join()
.receive("ok", resp => { console.log("Joined successfully", resp) })
.receive("error", resp => { console.log("Unable to join", resp) })channel.on("message", (msg) => {
console.log(msg);
})
You can use another user to talk to this bot now and receive message from phoenix.