EventGhost/EventGhost

View on GitHub
plugins/Broadcaster/__init__.py

Summary

Maintainability
A
3 hrs
Test Coverage
# -*- coding: utf-8 -*-
#
# This file is a plugin for EventGhost.
# Copyright © 2005-2020 EventGhost Project <http://www.eventghost.net/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

import eg

eg.RegisterPlugin(
    name = "Broadcaster",
    author = (
        "Kingtd",
        "Bitmonster",
    ),
    version = "2.2.501",
    description = (
        "Listens for and Transmits UDP Broadcasts"
    ),
    guid = "{5E8DA56B-24AC-4092-9521-169343C5171C}",
    icon = (
        "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeT"
        "AAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH1gEECzsZ7j1DbAAAAu1JREFUOMul"
        "kztsW3UUxn////Xb1684NXbzsOskA6UiklWCCOmCCiKwsCDBjBShThVCDICYgCIxMHgC"
        "BhYYkbJAhaIoIBCKKvUBhArHGLexaar4/bj2ffjey0CboagTZ/l0jo5+Ovp0PvifJR4c"
        "5F64NOMX7kcoyrppOwmBwOcRHTGZXBk7YuPW5bfrDwWcWv/gdSFlcWEp55mZyxCJhBGA"
        "ruvcqd+lXKpOsMxLpW/ffe8/gNz6h6/FYuFP184VlNO5E8yfTJEKu2QSQbojk51rt7nx"
        "Z4Pr124Sks7HP3918S0ACfDJlz+ueBRZfPaZJ5R3Xinw3HKKx7MRCgtTzCaDRAMKwjJo"
        "N1qcWX6Uu93xm/nn358/Bmzt7r+RX8wG4kGFdm+MGo3h93lojaCnO5RrbZpjQXYmSSrq"
        "Y2EpJ7zC/QLAA1Ctt5568lxeDHULTYaYQtLUwCOh3dX47Osr9EcG0qOgjUzyi1lq1drK"
        "MWBs2ul4LMLiXJxkSHLQNvB5PWiWzfZuid5wjGnZGMMxXr+faFTFmNihY4DANXyK9L28"
        "NkejM6J5NET4VSa2jaqGkIrEtWxsx0EfaAC47r/my3vN3mg4sAcjk0wyTLvR4vL31zls"
        "9FG8Pp5eXWZm9hEmtoMQgn5/iILbPr4AIbaq1b+Xd/ZmQ/WDO5QPWmSmIzQ6A8aWjTY2"
        "SSdVMoVTBFSVq7/XXOHY3wEoAPGl8+VWq3fBDai+W0ea2K8c0hxa5OdPoOAQUCRnl6bZ"
        "eKnASLf49ZdSM51OvvrH7mZXAeiWtweR3FrvqNF7Mb8wh5QSfzjEYVujdtRnYtuczk4x"
        "HQ3gdQwrEZxs39j6fKdSqbSU+5/Y++uHsieateuHg9VYPCpTqSSp6QSJmIqhm+z9VnJu"
        "V6o9Jv2beq++WywWf3IcZ/hgmNKh9JnVk4+d31CCyRXDljEAx9T6zrC+dzYrribCcn9z"
        "c/ObTqdzALjiIQmNArF76gcMYAB0gT7g3l/+ByWIP9hU8ktfAAAAAElFTkSuQmCC"
    ),
)

import wx
import os
import asyncore
import socket


class Server(asyncore.dispatcher):

    def __init__(self, port, listenAddr, selfBroadcast, payDelim, plugin):
        self.selfBroadcast=selfBroadcast
        self.plugin=plugin
        self.addresses = socket.gethostbyname_ex(socket.gethostname())[2]
        self.addresses.sort(key=lambda a: [int(b) for b in a.split('.', 4)])
        self.port=port
        self.payDelim=payDelim

        if listenAddr in self.addresses:
            self.listenAddr = listenAddr
        else:
            addrs = socket.gethostbyname_ex(socket.gethostname())[2]
            self.listenAddr = addrs[0]

        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
        eg.RestartAsyncore()
        self.set_reuse_addr()
        self.bind((self.listenAddr, self.port))

    def handle_connect(self):
        print "%s %s:%s. %s %s."  % (self.plugin.text.message_1, self.listenAddr, str(self.port), self.plugin.text.message_2, str(self.selfBroadcast))
        pass

    def handle_read(self):
        data, addr = self.socket.recvfrom(1024)

        # Check if the sending address is any of our interfaces
        my_addr = addr[0] in self.addresses

        if (not my_addr) or self.selfBroadcast:
            data = data.decode(eg.systemEncoding)

            bits = data.split(self.payDelim);

            commandSize=len(bits)
            if commandSize==1:
                self.plugin.TriggerEvent(bits[0])
            if commandSize==2:
                self.plugin.TriggerEvent(bits[0],bits[1])
            if commandSize>2:
                self.plugin.TriggerEvent(bits[0],bits[1:])

    def writable(self):
        return False  # we don't have anything to send !


class BroadcastListener(eg.PluginBase):

    class Text:
        eventPrefix = "Event prefix:"
        zone = "Broadcast zone:"
        port = "UDP port:"
        listenAddr = "Listening address:"
        selfBroadcast = "Respond to self broadcast"
        delim = "Payload delimiter"
        message_1 = "Broadcast listener on"
        message_2 = "Self broadcast is"

    text = Text
    canMultiLoad = True

    def __init__(self):
        self.AddAction(Broadcast)

    def __start__(self, prefix=None, zone="255.255.255.255", port=33333, selfBroadcast=False, payDelim="&&", listenAddr=""):
        self.info.eventPrefix = prefix
        self.port = port
        self.payDelim=payDelim
        self.zone = zone
        self.listenAddr = listenAddr
        self.selfBroadcast=selfBroadcast

        try:
            self.server = Server(self.port, self.listenAddr, self.selfBroadcast, self.payDelim, self)
        except socket.error, exc:
            raise self.Exception(exc[1].decode(eg.systemEncoding))

    def __stop__(self):
        if self.server:
            self.server.close()
        self.server = None

    def Configure(self, prefix="Broadcast", zone="255.255.255.255", port=33333, selfBroadcast=False, payDelim="&&", listenAddr=""):
        text = self.text
        panel = eg.ConfigPanel(self)

        addrs = socket.gethostbyname_ex(socket.gethostname())[2]
        addrs.sort(key=lambda a: [int(b) for b in a.split('.', 4)])

        try:
            addr = addrs.index(listenAddr)
        except ValueError:
            addr = 0

        editCtrl = panel.TextCtrl(prefix)
        zoneCtrl = panel.TextCtrl(zone)
        portCtrl = panel.SpinIntCtrl(port, min=1, max=65535)
        listenAddrCtrl = panel.Choice(addr, addrs)
        selfBroadcastCtrl=panel.CheckBox(selfBroadcast)
        payDelimCtrl = panel.TextCtrl(payDelim)

        panel.AddLine(text.eventPrefix, editCtrl)
        panel.AddLine(text.zone, zoneCtrl)
        panel.AddLine(text.port, portCtrl)

        panel.AddLine(text.listenAddr, listenAddrCtrl)
        panel.AddLine(text.selfBroadcast,selfBroadcastCtrl)
        panel.AddLine(text.delim, payDelimCtrl)

        while panel.Affirmed():
            panel.SetResult(
                editCtrl.GetValue(),
                zoneCtrl.GetValue(),
                int(portCtrl.GetValue()),
                selfBroadcastCtrl.GetValue(),
                payDelimCtrl.GetValue(),
                addrs[listenAddrCtrl.GetValue()]
            )


class Broadcast(eg.ActionWithStringParameter):

    class Text:
        sendport = "UDP port: (0 = default)"
        command = "Command:"
        payload="Payload:"

    text = Text

    def __call__(self, mesg, payload="",port=0):
        res = self.bcastSend(mesg, payload,port)
        return res

    def bcastSend(self, eventString, payload="", port=0):
        if (port==None):
            sendToPort=self.plugin.port
        else:
            sendToPort=int(port)

        addr = (self.plugin.zone, sendToPort)
        UDPSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Create socket
        UDPSock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        if (payload==None):
            UDPSock.sendto(eg.ParseString(eventString).encode(eg.systemEncoding),addr)
        else:
            bits = payload.split(self.plugin.payDelim);
            bits = [eg.ParseString(bit) for bit in bits];

            payload = self.plugin.payDelim.join(bits).encode(eg.systemEncoding);

            UDPSock.sendto(eg.ParseString(eventString).encode(eg.systemEncoding) + self.plugin.payDelim.encode(eg.systemEncoding) + payload,addr)
        UDPSock.close()

    def Configure(self, command="", payload="", port=0):
        text = self.text
        panel = eg.ConfigPanel(self)

        commandCtrl = panel.TextCtrl(command)
        payloadCtrl = panel.TextCtrl(payload)
        portCtrl = panel.SpinIntCtrl(port, min=0, max=65535)
        commandlabel = panel.StaticText(text.command)
        payloadlabel = panel.StaticText(text.payload)
        portlabel =panel.StaticText(text.sendport)
        panel.sizer.Add(commandlabel,0,wx.EXPAND)
        panel.sizer.Add(commandCtrl,0,wx.EXPAND)
        panel.sizer.Add((20, 20))
        panel.sizer.Add(payloadlabel,0,wx.EXPAND)
        panel.sizer.Add(payloadCtrl,0,wx.EXPAND)
        panel.sizer.Add((20, 20))
        panel.sizer.Add(portlabel,0)
        panel.sizer.Add(portCtrl,0)
        panel.sizer.Add((20, 20))


        while panel.Affirmed():
            panel.SetResult(commandCtrl.GetValue(), payloadCtrl.GetValue(), portCtrl.GetValue())