Phoenix Channel отправляет сообщения от клиента вне проекта

Я хотел отправить сообщение на свой пользовательский канал моего приложения Phoenix. Я присоединился к user_token с каналом как users:user_token в user_channel.ex. Мне удалось сделать это с другого контроллера, названного toy_controller, вызвав метод широковещательной рассылки. Метод трансляции - в пользовательском канале. И я написал файл jQuery для обработки событий. Я искал что-то, что могло бы отправлять сообщения на тот же канал извне проекта, потому что я хотел делать некоторые вещи IoT. Я пробовал модуль Python под названием occamy.socket и клиент JS Phoenix, который он использует для внутренних целей. Затем я всегда обнаруживал отключение. Я не могу определить точный адрес подключения к веб-сокету от Phoenix. Если я пробую использовать эту библиотеку 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"])
    })
  }
});


person CfourPiO    schedule 07.07.2016    source источник


Ответы (1)


Наконец, я могу отправлять и получать сообщения асинхронно из программы на Python. Он использует модуль asyncio websockets от python. Я выяснил различные события, необходимые для каналов Phoenix, такие как 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()
person CfourPiO    schedule 30.07.2016