凤凰频道从项目外的客户端发送消息
Phoenix Channel sending messages from a client outside the project
我想向我的 Phoenix 应用程序的用户频道发送消息。我在 user_channel.ex
中加入了一个 user_token,频道为 users:user_token
。我通过调用广播方法从另一个名为 toy_controller
的控制器成功地做到了这一点。广播方式在用户频道。我写了一个 jQuery 文件来处理事件。我一直在寻找可以从项目外部向同一频道发送消息的东西,因为我想做一些物联网的事情。我已经尝试了一个名为 occamy.socket
的 python 模块和它在内部使用的 Phoenix 的 JS 客户端。然后,我总是发现断开连接。我无法弄清楚 Phoenix 的 websocket 连接的确切地址。如果我在该项目文件夹本身中使用 Phoenix npm 库进行尝试,它总是显示 ReferenceError: window is not defined
。而且,我认为这是因为 web/static/js/socket.js
文件中套接字的初始化部分被写为
let socket = new Socket("/socket", {params: {token: window.userToken}})
,但我不确定。我试过的东西在
下面
var Socket = require("phoenix-socket").Socket;
var socket = new Socket("ws://localhost:4000/socket");
在python客户端中,我也试图连接到这个地址,但出现断开连接错误。我想出于物联网目的这样做,我想在其中监视用户的传感器数据。每个用户都将拥有自己的传感器进行监控。因此,我已将频道 topic:subtopic
频道配置为 users:user_token
。我需要使用用户的那些唯一令牌将消息从我的 raspberry pi 发送到该频道。我的 user_channel、user.js、app.js 和 socket.js 如下所示。
//web/static/js/socket.js
import {Socket} from "phoenix"
let socket = new Socket("/socket", {params: {token: window.userToken}})
socket.connect()
export default socket
//web/static/app.js
import "phoenix_html"
import user from "./user"
#web/channels/user_channel.ex
defmodule Tworit.UserChannel do
use Tworit.Web, :channel
def join("users:" <> user_token, payload, socket) do
if authorized?(payload) do
{:ok, "Joined To User:#{user_token}", socket}
else
{:error, %{reason: "unauthorized"}}
end
end
def handle_in("ping", payload, socket) do
{:reply, {:ok, payload}, socket}
end
def handle_in("shout", payload, socket) do
broadcast socket, "shout", payload
{:noreply, socket}
end
def handle_out(event, payload, socket) do
push socket, event, payload
{:noreply, socket}
end
defp authorized?(_payload) do
true
end
def broadcast_change(toy, current_user) do
payload = %{
"name" => toy.name,
"body" => toy.body
}
Tworit.Endpoint.broadcast("users:#{current_user.token}", "change", payload)
end
end
//web/static/js/user.js
import socket from "./socket"
$(function() {
let ul = $("ul#em")
if (ul.length) {
var token = ul.data("id")
var topic = "users:" + token
// Join the topic
let channel = socket.channel(topic, {})
channel.join()
.receive("ok", data => {
console.log("Joined topic", topic)
})
.receive("error", resp => {
console.log("Unable to join topic", topic)
})
channel.on("change", toy => {
console.log("Change:", toy);
$("#message").append(toy["name"])
})
}
});
最后,我能够从 python 程序异步发送和接收消息。它使用来自 python 的 websockets asyncio 模块。我想出了凤凰频道所需的各种事件,比如 'phx_join' 加入一个主题等等。因此,以下程序有效。
import asyncio
import websockets
import json
import time
from random import randint
import serial
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyACM1')
it = util.Iterator(board)
it.start()
board.analog[0].enable_reporting()
board.analog[1].enable_reporting()
board.analog[2].enable_reporting()
board.analog[3].enable_reporting()
import RPi.GPIO as gpio
gpio.setmode(gpio.BCM)
gpio.setup(14, gpio.OUT)
async def main():
async with websockets.connect('ws://IP_addr:4000/socket/websocket') as websocket:
data = dict(topic="users:user_token", event="phx_join", payload={}, ref=None)
#this method joins the phoenix channel
await websocket.send(json.dumps(data))
print("Joined")
while True:
msg = await retrieve() # waits for data from arduino analog pins
await websocket.send(json.dumps(msg)) # sends the sensor output to phoenix channel
print("sent")
call = await websocket.recv() # waits for anything from the phoenix server
control = json.loads(call)
# I have sent values from 2 buttons for swicthing a led with event 'control'
if(control['event'] == "control"):
event(control['payload']['val']) #swiches the led as per the input from event 'control'
print("< {}".format(call))
def event(val):
if(val == "on"):
gpio.output(14, True)
if(val == "off"):
gpio.output(14, False)
async def retrieve():
#analog read
load = board.analog[0].read()
pf = board.analog[1].read()
reading = board.analog[2].read()
thd = board.analog[3].read()
output = {"load": load, "pf": pf, "reading": reading,"thd": thd}
msg = dict(topic="users:user_token", event="sensor_output", payload=output, ref=None) # with
#event "sensor_outputs"
#the phoenix server displays the data on to a page.
print(msg)
return(msg)
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().run_forever()
我想向我的 Phoenix 应用程序的用户频道发送消息。我在 user_channel.ex
中加入了一个 user_token,频道为 users:user_token
。我通过调用广播方法从另一个名为 toy_controller
的控制器成功地做到了这一点。广播方式在用户频道。我写了一个 jQuery 文件来处理事件。我一直在寻找可以从项目外部向同一频道发送消息的东西,因为我想做一些物联网的事情。我已经尝试了一个名为 occamy.socket
的 python 模块和它在内部使用的 Phoenix 的 JS 客户端。然后,我总是发现断开连接。我无法弄清楚 Phoenix 的 websocket 连接的确切地址。如果我在该项目文件夹本身中使用 Phoenix npm 库进行尝试,它总是显示 ReferenceError: window is not defined
。而且,我认为这是因为 web/static/js/socket.js
文件中套接字的初始化部分被写为
let socket = new Socket("/socket", {params: {token: window.userToken}})
,但我不确定。我试过的东西在
下面var Socket = require("phoenix-socket").Socket;
var socket = new Socket("ws://localhost:4000/socket");
在python客户端中,我也试图连接到这个地址,但出现断开连接错误。我想出于物联网目的这样做,我想在其中监视用户的传感器数据。每个用户都将拥有自己的传感器进行监控。因此,我已将频道 topic:subtopic
频道配置为 users:user_token
。我需要使用用户的那些唯一令牌将消息从我的 raspberry pi 发送到该频道。我的 user_channel、user.js、app.js 和 socket.js 如下所示。
//web/static/js/socket.js
import {Socket} from "phoenix"
let socket = new Socket("/socket", {params: {token: window.userToken}})
socket.connect()
export default socket
//web/static/app.js
import "phoenix_html"
import user from "./user"
#web/channels/user_channel.ex
defmodule Tworit.UserChannel do
use Tworit.Web, :channel
def join("users:" <> user_token, payload, socket) do
if authorized?(payload) do
{:ok, "Joined To User:#{user_token}", socket}
else
{:error, %{reason: "unauthorized"}}
end
end
def handle_in("ping", payload, socket) do
{:reply, {:ok, payload}, socket}
end
def handle_in("shout", payload, socket) do
broadcast socket, "shout", payload
{:noreply, socket}
end
def handle_out(event, payload, socket) do
push socket, event, payload
{:noreply, socket}
end
defp authorized?(_payload) do
true
end
def broadcast_change(toy, current_user) do
payload = %{
"name" => toy.name,
"body" => toy.body
}
Tworit.Endpoint.broadcast("users:#{current_user.token}", "change", payload)
end
end
//web/static/js/user.js
import socket from "./socket"
$(function() {
let ul = $("ul#em")
if (ul.length) {
var token = ul.data("id")
var topic = "users:" + token
// Join the topic
let channel = socket.channel(topic, {})
channel.join()
.receive("ok", data => {
console.log("Joined topic", topic)
})
.receive("error", resp => {
console.log("Unable to join topic", topic)
})
channel.on("change", toy => {
console.log("Change:", toy);
$("#message").append(toy["name"])
})
}
});
最后,我能够从 python 程序异步发送和接收消息。它使用来自 python 的 websockets asyncio 模块。我想出了凤凰频道所需的各种事件,比如 'phx_join' 加入一个主题等等。因此,以下程序有效。
import asyncio
import websockets
import json
import time
from random import randint
import serial
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyACM1')
it = util.Iterator(board)
it.start()
board.analog[0].enable_reporting()
board.analog[1].enable_reporting()
board.analog[2].enable_reporting()
board.analog[3].enable_reporting()
import RPi.GPIO as gpio
gpio.setmode(gpio.BCM)
gpio.setup(14, gpio.OUT)
async def main():
async with websockets.connect('ws://IP_addr:4000/socket/websocket') as websocket:
data = dict(topic="users:user_token", event="phx_join", payload={}, ref=None)
#this method joins the phoenix channel
await websocket.send(json.dumps(data))
print("Joined")
while True:
msg = await retrieve() # waits for data from arduino analog pins
await websocket.send(json.dumps(msg)) # sends the sensor output to phoenix channel
print("sent")
call = await websocket.recv() # waits for anything from the phoenix server
control = json.loads(call)
# I have sent values from 2 buttons for swicthing a led with event 'control'
if(control['event'] == "control"):
event(control['payload']['val']) #swiches the led as per the input from event 'control'
print("< {}".format(call))
def event(val):
if(val == "on"):
gpio.output(14, True)
if(val == "off"):
gpio.output(14, False)
async def retrieve():
#analog read
load = board.analog[0].read()
pf = board.analog[1].read()
reading = board.analog[2].read()
thd = board.analog[3].read()
output = {"load": load, "pf": pf, "reading": reading,"thd": thd}
msg = dict(topic="users:user_token", event="sensor_output", payload=output, ref=None) # with
#event "sensor_outputs"
#the phoenix server displays the data on to a page.
print(msg)
return(msg)
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().run_forever()