Add pylintrc file
Move client functions to vloed module, simplify client file for newbee's, Make sure the server module only starts operating when actually initialised
This commit is contained in:
parent
562ae26d7f
commit
b9ba710848
3 changed files with 503 additions and 114 deletions
109
client.py
109
client.py
|
|
@ -5,48 +5,15 @@ Inspired by the PixelFlut beamer on eth0:winter 2016 and
|
|||
code from https://github.com/defnull/pixelflut/
|
||||
"""
|
||||
|
||||
__version__ = 0.2
|
||||
__version__ = 0.3
|
||||
__author__ = "Jan Klopper <jan@underdark.nl>"
|
||||
|
||||
MAX_PROTOCOL_VERSION = 1;
|
||||
PROTOCOL_PREAMBLE = 'pixelvloed'
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import random
|
||||
import time
|
||||
from vloed import PixelVloedClient, NewMessage, RGBPixel
|
||||
|
||||
class MaxSizeList(list):
|
||||
|
||||
def __init__(self, maxcount=100):
|
||||
self.maxsize = maxcount
|
||||
super( MaxSizeList, self ).__init__()
|
||||
|
||||
def append(self, item):
|
||||
super( MaxSizeList, self ).append(item)
|
||||
if self.__len__() == self.maxsize:
|
||||
raise IndexError('max size reached')
|
||||
|
||||
def RGBPixel(x, y, r, g, b, a=None): # pylint: disable=C0103
|
||||
"""Generates the packed data for a pixel"""
|
||||
if a:
|
||||
return struct.pack("<2H4B", x, y, r, g, b, a)
|
||||
return struct.pack("<2H3B", x, y, r, g, b)
|
||||
|
||||
def SetRGBAMode(mode):
|
||||
"""Generate the rgb/rgba bit"""
|
||||
return struct.pack("<?", mode)
|
||||
|
||||
def SetVersionBit(protocol=1):
|
||||
"""Generate the Version bit"""
|
||||
return struct.pack("<B", protocol)
|
||||
|
||||
def RandomFill(width=640, height=480):
|
||||
def RandomFill(message, width, height):
|
||||
"""Generates a random number of pixels with a random color"""
|
||||
message = MaxSizeList(140)
|
||||
message.append(SetRGBAMode(False))
|
||||
message.append(SetVersionBit())
|
||||
for pixel in xrange(0, random.randint(10, 100)):
|
||||
for pixel in xrange(0, random.randint(10, 140)):
|
||||
pixel = RGBPixel(random.randint(0, width),
|
||||
random.randint(0, height),
|
||||
random.randint(0, 255),
|
||||
|
|
@ -57,57 +24,29 @@ def RandomFill(width=640, height=480):
|
|||
except IndexError:
|
||||
yield ''.join(message)
|
||||
message[2:] = []
|
||||
message.append(pixel)
|
||||
yield ''.join(message)
|
||||
|
||||
def SendPacket(ipaddress, port, message):
|
||||
"""Sends the message to the udp server"""
|
||||
sock = socket.socket(socket.AF_INET, # Internet
|
||||
socket.SOCK_DGRAM) # UDP
|
||||
sock.sendto(message, (ipaddress, port))
|
||||
|
||||
def DiscoverServers(discoveryport, timeout=5):
|
||||
"""Discover servers that send out the pixelfvloed preample"""
|
||||
DiscoverySock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
DiscoverySock.bind(('', discoveryport))
|
||||
starttime = time.time()
|
||||
servers = []
|
||||
foundhash = {}
|
||||
while (time.time() - timeout) < starttime:
|
||||
data, addr = DiscoverySock.recvfrom(1024)
|
||||
try:
|
||||
if data.startswith(PROTOCOL_PREAMBLE):
|
||||
dataset = data.split(' ')
|
||||
if float(dataset[0].split(':')[1]) <= MAX_PROTOCOL_VERSION:
|
||||
ip = dataset[1].split(':')[0]
|
||||
port = int(dataset[1].split(':')[1])
|
||||
width = int(dataset[2].split('*')[0])
|
||||
height = int(dataset[2].split('*')[1])
|
||||
if data not in foundhash:
|
||||
newserver = {'ip': ip,
|
||||
'port': port,
|
||||
'width': width,
|
||||
'height': height}
|
||||
foundhash[data] = True
|
||||
print 'New pixelvloed screen found: %r' % newserver
|
||||
servers.append(newserver)
|
||||
except:
|
||||
pass
|
||||
if servers:
|
||||
return servers
|
||||
return False
|
||||
|
||||
def main():
|
||||
def RunClient():
|
||||
"""Discover the servers and start sending to the first one"""
|
||||
discoveryport = 5006
|
||||
servers = False
|
||||
while servers == False:
|
||||
servers = DiscoverServers(discoveryport)
|
||||
print 'displaying on %(ip)s:%(port)d, %(width)d*%(height)dpx' % servers[0]
|
||||
|
||||
client = PixelVloedClient(True, # start as soon as we find a server
|
||||
False, # show debugging output
|
||||
None, # ip of the server, None for autodetect
|
||||
None, # port of the server None for autodetect
|
||||
None, # Screen pixels wide, or Autodetect
|
||||
None # Screen pixels height, or Autodetect
|
||||
)
|
||||
message = NewMessage() #create a new message that buffers the output etc
|
||||
|
||||
# loop the effect untill we cancel by pressing ctrl+c / exit the program
|
||||
while True:
|
||||
for packet in RandomFill(servers[0]['width'], servers[0]['height']):
|
||||
time.sleep(0.01)
|
||||
SendPacket(servers[0]['ip'], servers[0]['port'], packet)
|
||||
# create a new message and send if everytime the buffer is full
|
||||
# the width/height are read from the client's config
|
||||
for packet in RandomFill(message, client.width, client.height):
|
||||
# send the message we just filled with random pixelfs
|
||||
client.SendPacket(packet)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
# if this script is called from the commandline, and thus not imported
|
||||
# Start a client and start sending messages
|
||||
RunClient()
|
||||
|
|
|
|||
311
pylintrc
Normal file
311
pylintrc
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
# lint Python modules using external checkers.
|
||||
#
|
||||
# This is the main checker controling the other ones and the reports
|
||||
# generation. It is itself both a raw checker and an astng checker in order
|
||||
# to:
|
||||
# * handle message activation / deactivation at the module level
|
||||
# * handle some basic but necessary stats'data (number of classes, methods...)
|
||||
#
|
||||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=CVS
|
||||
ignore=.hg
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Set the cache size for astng objects.
|
||||
cache-size=500
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Enable only checker(s) with the given id(s). This option conflicts with the
|
||||
# disable-checker option
|
||||
#enable-checker=
|
||||
|
||||
# Enable all checker(s) except those with the given id(s). This option
|
||||
# conflicts with the enable-checker option
|
||||
#disable-checker=
|
||||
|
||||
# Enable all messages in the listed categories.
|
||||
#enable-msg-cat=
|
||||
|
||||
# Disable all messages in the listed categories.
|
||||
#disable-msg-cat=
|
||||
|
||||
# Enable the message(s) with the given id(s).
|
||||
#enable-msg=
|
||||
|
||||
# Disable the message(s) with the given id(s).
|
||||
# W0142: Used * or ** magic -- this is in fact a very Pythonic approach.
|
||||
# E1103: %s %r has no %r member (but some types could not be inferred)
|
||||
# This is generally not an actual problem, and causes false positives
|
||||
disable-msg=W0403, W0142, E1103
|
||||
disable=W0403, W0142, E1103
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=colorized
|
||||
|
||||
# Include message's id in output
|
||||
include-ids=yes
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells wether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note).You have access to the variables errors warning, statement which
|
||||
# respectivly contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (R0004).
|
||||
evaluation=10.0 - (5.0 * error + warning + refactor + convention) / statement * 10
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (R0004).
|
||||
comment=yes
|
||||
|
||||
# Enable the report(s) with the given id(s).
|
||||
#enable-report=
|
||||
|
||||
# Disable the report(s) with the given id(s).
|
||||
# R0801 is the "similar lines" report, which is not used.
|
||||
disable-report=R0801
|
||||
|
||||
|
||||
# checks for
|
||||
# * unused variables / imports
|
||||
# * undefined variables
|
||||
# * redefinition of variable from builtins or from an outer scope
|
||||
# * use of variable before assigment
|
||||
#
|
||||
[VARIABLES]
|
||||
|
||||
# Tells wether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching names used for dummy variables (i.e. not used).
|
||||
dummy-variables-rgx=_.*$
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
# try to find bugs in the code using type inference
|
||||
#
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells wether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# When zope mode is activated, consider the acquired-members option to ignore
|
||||
# access to some undefined attributes.
|
||||
zope=no
|
||||
|
||||
# List of members which are usually get through zope's acquisition mecanism and
|
||||
# so shouldn't trigger E0201 when accessed (need zope=yes to be considered).
|
||||
acquired-members=REQUEST,acl_users,aq_parent
|
||||
|
||||
|
||||
# checks for :
|
||||
# * doc strings
|
||||
# * modules / classes / functions / methods / arguments / variables name
|
||||
# * number of arguments, local variables, branchs, returns and statements in
|
||||
# functions, methods
|
||||
# * required module attributes
|
||||
# * dangerous default values as arguments
|
||||
# * redefinition of function / method / class
|
||||
# * uses of the global statement
|
||||
#
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
required-attributes=__author__, __version__
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=_.*$
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=([A-Z_][a-zA-Z0-9_]{2,30})|(main)$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=([a-zA-Z_][a-zA-Z0-9_]{2,30})|(test.*)$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,n
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=filter,apply,input
|
||||
|
||||
|
||||
# checks for
|
||||
# * external modules dependencies
|
||||
# * relative / wildcard imports
|
||||
# * cyclic imports
|
||||
# * uses of deprecated modules
|
||||
#
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report R0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report R0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report R0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
# checks for :
|
||||
# * methods without self as first argument
|
||||
# * overridden methods signature
|
||||
# * access only to existant members via self
|
||||
# * attributes not defined in the __init__ method
|
||||
# * supported interfaces implementation
|
||||
# * unreachable code
|
||||
#
|
||||
[CLASSES]
|
||||
|
||||
# List of interface methods to ignore, separated by a comma. This is used for
|
||||
# instance to not check methods defines in Zope's Interface base class.
|
||||
ignore-iface-methods=
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp,run
|
||||
|
||||
|
||||
# checks for sign of poor/misdesign:
|
||||
# * number of methods, attributes, local variables...
|
||||
# * size, complexity of functions, methods
|
||||
#
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=8
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=20
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=40
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=12
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=10
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=0
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
# checks for:
|
||||
# * warning notes in the code like FIXME, XXX
|
||||
# * PEP 263: source code with non ascii character but no encoding declaration
|
||||
#
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
# checks for :
|
||||
# * unauthorized constructions
|
||||
# * strict indentation
|
||||
# * line length
|
||||
# * use of <> instead of !=
|
||||
#
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=80
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
# checks for similarities and duplicated code. This computation may be
|
||||
# memory / CPU intensive, so you should disable it if you experiments some
|
||||
# problems.
|
||||
#
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
197
vloed.py
197
vloed.py
|
|
@ -5,31 +5,32 @@ Inspired by the PixelFlut beamer on eth0:winter 2016 and
|
|||
code from https://github.com/defnull/pixelflut/
|
||||
"""
|
||||
|
||||
__version__ = 0.2
|
||||
__version__ = 0.3
|
||||
__author__ = "Jan Klopper <jan@underdark.nl>"
|
||||
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from pygame import locals as pygamelocals
|
||||
import struct
|
||||
import time
|
||||
from gevent import spawn, socket, monkey
|
||||
import socket
|
||||
|
||||
from gevent import spawn, monkey
|
||||
from gevent.server import DatagramServer
|
||||
from gevent.queue import Queue
|
||||
|
||||
monkey.patch_all()
|
||||
UDP_IP = "127.0.0.1"
|
||||
UDP_PORT= 5005
|
||||
UDP_PORT = 5005
|
||||
DISCOVER_PORT = 5006
|
||||
PROTOCOL_VERSION = 1
|
||||
MAX_PROTOCOL_VERSION = 1
|
||||
PROTOCOL_PREAMBLE = "pixelvloed"
|
||||
|
||||
def main():
|
||||
"""Runs a pixelvloed server"""
|
||||
PixelVloed(':%d' %(UDP_PORT)).serve_forever()
|
||||
MAX_PIXELS = 140
|
||||
|
||||
class Canvas(object):
|
||||
"""PixelVloed server class"""
|
||||
"""PixelVloed display class"""
|
||||
|
||||
def __init__(self, queue, width=1366, height=768, debug=True):
|
||||
def __init__(self, queue, width=1366, height=768, debug=False):
|
||||
"""Init the pixelVloed server"""
|
||||
self.debug = debug
|
||||
self.pixeloffset = 2
|
||||
|
|
@ -42,10 +43,11 @@ class Canvas(object):
|
|||
self.canvas()
|
||||
self.set_title()
|
||||
self.queue = queue
|
||||
self.limit = 140
|
||||
self.broadcastSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
self.broadcastSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.limit = MAX_PIXELS
|
||||
self.pixels = None
|
||||
self.broadcastsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.broadcastsocket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
self.broadcastsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
@staticmethod
|
||||
def set_title(text=None):
|
||||
|
|
@ -59,8 +61,8 @@ class Canvas(object):
|
|||
"""Init the pygame canvas"""
|
||||
pygame.init()
|
||||
pygame.mixer.quit()
|
||||
flags = DOUBLEBUF
|
||||
self.screen = pygame.display.set_mode((self.width, self.height), flags)
|
||||
self.screen = pygame.display.set_mode((self.width, self.height),
|
||||
pygamelocals.DOUBLEBUF)
|
||||
|
||||
def clear(self, r=0, g=0, b=0): # pylint: disable=C0103
|
||||
""" Fill the entire screen with a solid colour (default: black)"""
|
||||
|
|
@ -115,7 +117,7 @@ class Canvas(object):
|
|||
pixelcount = min(((len(data)-1) / pixellength),
|
||||
self.limit)
|
||||
if self.debug:
|
||||
print '%d pixels received, protocol V %d ' % (pixelcount, protocol)
|
||||
print '%d pixels received, protocol V %d' % (pixelcount, protocol)
|
||||
for i in xrange(0, pixelcount):
|
||||
pixel = struct.unpack_from(
|
||||
packetformat,
|
||||
|
|
@ -124,36 +126,173 @@ class Canvas(object):
|
|||
if self.debug:
|
||||
print pixel
|
||||
self.Pixel(*pixel)
|
||||
except Exception as e:
|
||||
except Exception as error:
|
||||
if self.debug:
|
||||
# All exceptions will be printed, but won't result in a crash.
|
||||
print e
|
||||
print error
|
||||
# indicate that we have been drawing stuff
|
||||
return True
|
||||
|
||||
def SendDiscoveryPacket(self):
|
||||
"""Lets send out our ip/port/resolution to any listening clients"""
|
||||
self.broadcastSocket.sendto(
|
||||
self.broadcastsocket.sendto(
|
||||
'%s:%f %s:%d %d*%d' % (PROTOCOL_PREAMBLE, PROTOCOL_VERSION,
|
||||
UDP_IP, UDP_PORT,
|
||||
self.width, self.height),
|
||||
('<broadcast>', UDP_PORT+1))
|
||||
('<broadcast>', DISCOVER_PORT))
|
||||
if self.debug:
|
||||
print 'sending discovery packet'
|
||||
|
||||
def __del__(self):
|
||||
"""Clean up any sockets we created"""
|
||||
self.broadcastSocket.close()
|
||||
self.broadcastsocket.close()
|
||||
|
||||
class PixelVloed(DatagramServer):
|
||||
class PixelVloedServer(DatagramServer):
|
||||
"""PixelVloed server class"""
|
||||
queue = Queue()
|
||||
pixelcanvas = Canvas(queue)
|
||||
__request_processing_greenlet = spawn(pixelcanvas.CanvasUpdate)
|
||||
|
||||
def handle(self, data, address):
|
||||
"""Is called by the DataGramServer whenever a package is received"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Set up some vars for this instance"""
|
||||
self.queue = Queue()
|
||||
pixelcanvas = Canvas(self.queue)
|
||||
__request_processing_greenlet = spawn(pixelcanvas.CanvasUpdate)
|
||||
DatagramServer.__init__(self, *args, **kwargs)
|
||||
|
||||
def handle(self, data, _address):
|
||||
"""Is called by the DataGramServer whenever an udp package is received"""
|
||||
self.queue.put(data)
|
||||
|
||||
class PixelVloedClient(object):
|
||||
"""Sets up a client
|
||||
|
||||
Arguments:
|
||||
firstserver: (bool) False, select the first server immediately
|
||||
debug: (bool) False
|
||||
ip: (str) None
|
||||
port: (int) None
|
||||
width: (int) 640
|
||||
height: (int) 480
|
||||
|
||||
Listens for servers if no ip is given
|
||||
"""
|
||||
|
||||
def __init__(self, firstserver=False, debug=False,
|
||||
ip=None, port=None,
|
||||
width=640, height=480):
|
||||
self.sleep = 0.01
|
||||
self.debug = debug
|
||||
if not ip:
|
||||
servers = False
|
||||
while servers == False:
|
||||
servers = self.DiscoverServers(firstserver)
|
||||
self.ipaddress = servers[0]['ip']
|
||||
self.port = servers[0]['port']
|
||||
self.width = servers[0]['width']
|
||||
self.height = servers[0]['height']
|
||||
|
||||
if self.debug:
|
||||
print ('displaying on %(ip)s:%(port)d, %(width)d*%(height)dpx' %
|
||||
servers[0])
|
||||
else:
|
||||
self.ipaddress = ip
|
||||
self.port = port
|
||||
self.width = width
|
||||
self.height = height
|
||||
if self.debug:
|
||||
print ('displaying on %(ip)s:%(port)d, %(width)d*%(height)dpx' %
|
||||
self)
|
||||
self.sock = socket.socket(socket.AF_INET, # Internet
|
||||
socket.SOCK_DGRAM) # UDP
|
||||
|
||||
def Sleep(self, duration=None):
|
||||
"""Sleeps the designated amount of time"""
|
||||
time.sleep(duration if duration else self.sleep)
|
||||
|
||||
def SendPacket(self, message, sleep=True):
|
||||
"""Sends the message to the udp server
|
||||
|
||||
Arguments:
|
||||
message: (str, 140)
|
||||
sleep: (bool) True, should the client sleep for a while?
|
||||
"""
|
||||
self.sock.sendto(message, (self.ipaddress, self.port))
|
||||
if sleep:
|
||||
self.Sleep()
|
||||
|
||||
@staticmethod
|
||||
def DiscoverServers(returnfirst=False, timeout=5):
|
||||
"""Discover servers that send out the pixelfvloed preample"""
|
||||
discoverysock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
discoverysock.bind(('', DISCOVER_PORT))
|
||||
starttime = time.time()
|
||||
servers = []
|
||||
foundhash = {}
|
||||
while (time.time() - timeout) < starttime:
|
||||
data, _addr = discoverysock.recvfrom(1024)
|
||||
try:
|
||||
if data.startswith(PROTOCOL_PREAMBLE):
|
||||
dataset = data.split(' ')
|
||||
if float(dataset[0].split(':')[1]) <= MAX_PROTOCOL_VERSION:
|
||||
ipaddress = dataset[1].split(':')[0]
|
||||
port = int(dataset[1].split(':')[1])
|
||||
width = int(dataset[2].split('*')[0])
|
||||
height = int(dataset[2].split('*')[1])
|
||||
if data not in foundhash:
|
||||
newserver = {'ip': ipaddress,
|
||||
'port': port,
|
||||
'width': width,
|
||||
'height': height}
|
||||
foundhash[data] = True
|
||||
print 'New pixelvloed screen found: %r' % newserver
|
||||
servers.append(newserver)
|
||||
if returnfirst:
|
||||
return servers
|
||||
except:
|
||||
pass
|
||||
if servers:
|
||||
return servers
|
||||
return False
|
||||
|
||||
def NewMessage():
|
||||
"""Creates a new message with the correct max size, rgb mode and version"""
|
||||
message = MaxSizeList(MAX_PIXELS+2)
|
||||
message.append(SetRGBAMode(False))
|
||||
message.append(SetVersionBit())
|
||||
return message
|
||||
|
||||
def RGBPixel(x, y, r, g, b, a=None): # pylint: disable=C0103
|
||||
"""Generates the packed data for a pixel"""
|
||||
if a:
|
||||
return struct.pack("<2H4B", x, y, r, g, b, a)
|
||||
return struct.pack("<2H3B", x, y, r, g, b)
|
||||
|
||||
def SetRGBAMode(mode):
|
||||
"""Generate the rgb/rgba bit"""
|
||||
return struct.pack("<?", mode)
|
||||
|
||||
def SetVersionBit(protocol=1):
|
||||
"""Generate the Version bit"""
|
||||
return struct.pack("<B", protocol)
|
||||
|
||||
class MaxSizeList(list):
|
||||
"""A list that raises an indexError when it reaches the designated max size"""
|
||||
def __init__(self, maxcount=100):
|
||||
"""Inits a list with a maxcount
|
||||
|
||||
Arguments:
|
||||
maxcount: (int) 100
|
||||
"""
|
||||
self.maxsize = maxcount
|
||||
super(MaxSizeList, self).__init__()
|
||||
|
||||
def append(self, item):
|
||||
"""Appends an item to the list"""
|
||||
super(MaxSizeList, self).append(item)
|
||||
if self.__len__() == self.maxsize:
|
||||
raise IndexError('max size reached')
|
||||
|
||||
def RunServer():
|
||||
"""Runs a pixelvloed server"""
|
||||
PixelVloedServer('%s:%d' %(UDP_IP, UDP_PORT)).serve_forever()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
RunServer()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue