Add javascript client
Add server cli options
This commit is contained in:
parent
e2c5aee5cc
commit
d81f12480a
2 changed files with 215 additions and 13 deletions
186
client.js
Normal file
186
client.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// Install nodejs nodejs-legacy
|
||||
// Install npm
|
||||
// with npm install jspack
|
||||
// with npm install sleep
|
||||
|
||||
// imports
|
||||
var dgram = require('dgram');
|
||||
var struct = require('jspack')['jspack'];
|
||||
var sleep = require('sleep');
|
||||
|
||||
// static vars
|
||||
var PROTOCOL_PREAMBLE = 'pixelvloed';
|
||||
var DISCOVER_PORT = 5006;
|
||||
var MAX_PROTOCOL_VERSION = 1;
|
||||
var MAX_PIXELS = 140;
|
||||
var UDP_PORT = 5005;
|
||||
|
||||
PixelVloedClient = {
|
||||
/*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
|
||||
*/
|
||||
discoverysock: null,
|
||||
sock: null,
|
||||
sleep: 100,
|
||||
debug: true,
|
||||
width: 640,
|
||||
height: 480,
|
||||
effect: null,
|
||||
alpha: false,
|
||||
|
||||
init: function(firstserver, debug,
|
||||
ip, port,
|
||||
width, height,
|
||||
effect, alpha){
|
||||
|
||||
if(debug){ this.debug = debug; }
|
||||
if(effect){ this.effect = effect; }
|
||||
if(alpha){ this.alpha = alpha; }
|
||||
|
||||
if (ip){
|
||||
this.ipaddress = ip;
|
||||
this.port = (port?port:UDP_PORT);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.start();
|
||||
} else {
|
||||
this.DiscoverServers(firstserver)
|
||||
}
|
||||
},
|
||||
|
||||
start: function(){
|
||||
this.sock = dgram.createSocket('udp4');
|
||||
if (this.debug){
|
||||
console.log('displaying on '+this.ipaddress+':'+this.port+', '+this.width+'*'+this.height+'px');
|
||||
}
|
||||
this.effect();
|
||||
},
|
||||
|
||||
Sleep: function(duration){
|
||||
// Sleeps the designated amount of time
|
||||
sleep.usleep((duration?duration:this.sleep) * 1000);
|
||||
},
|
||||
|
||||
SendPacket: function(message, delay){
|
||||
/*Sends the message to the udp server
|
||||
|
||||
Arguments:
|
||||
message: (str, 140)
|
||||
sleep: (bool) True, should the client sleep for a while?
|
||||
*/
|
||||
this.sock.send(message, 0, message.length,
|
||||
this.port, this.ipaddress,
|
||||
this.effect.bind(this));
|
||||
if (delay){
|
||||
sleep.usleep(this.sleep);
|
||||
}
|
||||
},
|
||||
|
||||
DiscoverServers: function (){
|
||||
//Discover servers that send out the pixelvloed preample
|
||||
this.discoverysock = dgram.createSocket("udp4");
|
||||
this.discoverysock.on("message", this.handleDiscoveryPacket.bind(this));
|
||||
|
||||
this.discoverysock.on('error', function (err) {
|
||||
console.error(err);
|
||||
process.exit(0);
|
||||
});
|
||||
this.discoverysock.bind(DISCOVER_PORT);
|
||||
},
|
||||
|
||||
handleDiscoveryPacket: function (data, rinfo) {
|
||||
data = String(data);
|
||||
console.log("server got: " + typeof String(data) + " from " + rinfo.address + ":" + rinfo.port);
|
||||
if (data.startsWith(PROTOCOL_PREAMBLE)){
|
||||
var dataset = data.split(' ');
|
||||
if (dataset[0].split(':')[1] <= MAX_PROTOCOL_VERSION){
|
||||
this.ipaddress = dataset[1].split(':')[0];
|
||||
this.port = parseInt(dataset[1].split(':')[1], 10);
|
||||
this.width = parseInt(dataset[2].split('*')[0], 10);
|
||||
this.height = parseInt(dataset[2].split('*')[1], 10);
|
||||
this.discoverysock.close();
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function NewMessage(alpha){
|
||||
// Creates a new message with the correct max size, rgb mode and version
|
||||
var message = new Buffer((MAX_PIXELS*(alpha?8:7))+2);
|
||||
message.fill(0);
|
||||
//MaxSizeList(+2);
|
||||
message[0] = SetRGBAMode(alpha);
|
||||
message[1] = SetVersionBit(1);
|
||||
return message;
|
||||
}
|
||||
|
||||
function RGBPixel(message, offset, x, y, r, g, b, a){
|
||||
// Generates the packed data for a pixel
|
||||
message.writeUInt16LE(x, offset);
|
||||
message.writeUInt16LE(y, offset+2);
|
||||
message.writeUInt8(r, offset+4);
|
||||
message.writeUInt8(g, offset+5);
|
||||
message.writeUInt8(b, offset+6);
|
||||
if (a){
|
||||
message.writeUInt8(a, offset+7);
|
||||
}
|
||||
}
|
||||
|
||||
function SetRGBAMode(mode){
|
||||
// Generate the rgb/rgba bit
|
||||
return struct.Pack("<B", [mode]);
|
||||
}
|
||||
|
||||
function SetVersionBit(protocol){
|
||||
// Generate the Version bit
|
||||
return struct.Pack("<B", [protocol]);
|
||||
}
|
||||
|
||||
function RandomFill(width, height){
|
||||
// Generates a random number of pixels with a random color
|
||||
var msg = NewMessage();
|
||||
for(var i=0; i<getRandomIntInclusive(10, MAX_PIXELS); i++){
|
||||
RGBPixel(msg, (i*(this.alpha?8:7))+2,
|
||||
getRandomIntInclusive(0, width),
|
||||
getRandomIntInclusive(0, height),
|
||||
getRandomIntInclusive(0, 255),
|
||||
getRandomIntInclusive(0, 255),
|
||||
getRandomIntInclusive(0, 255),
|
||||
(this.alpha?getRandomIntInclusive(0, 255):null))
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Create a new client instance
|
||||
var client = PixelVloedClient;
|
||||
// bind the effect
|
||||
client.effect = function(err, bytes){
|
||||
if (err) throw err;
|
||||
var msg = RandomFill(client.width, client.height);
|
||||
client.SendPacket(msg);
|
||||
}
|
||||
// Init the clients autodetection
|
||||
client.init();
|
||||
|
||||
// helpers
|
||||
function getRandomIntInclusive(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
// polyfills
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function(searchString, position){
|
||||
position = position || 0;
|
||||
return this.substr(position, searchString.length) === searchString;
|
||||
};
|
||||
}
|
||||
42
vloed.py
42
vloed.py
|
|
@ -26,24 +26,26 @@ PROTOCOL_VERSION = 1
|
|||
MAX_PROTOCOL_VERSION = 1
|
||||
PROTOCOL_PREAMBLE = "pixelvloed"
|
||||
MAX_PIXELS = 140
|
||||
DEFAULT_WIDTH = 786
|
||||
DEFAULT_HEIGHT = 1366
|
||||
|
||||
class Canvas(object):
|
||||
"""PixelVloed display class"""
|
||||
|
||||
def __init__(self, queue, width=1366, height=768, debug=False):
|
||||
def __init__(self, queue, options):
|
||||
"""Init the pixelVloed server"""
|
||||
self.debug = debug
|
||||
self.debug = options.debug if options.debug else False
|
||||
self.pixeloffset = 2
|
||||
self.fps = 30
|
||||
self.screen = None
|
||||
self.udp_ip = UDP_IP
|
||||
self.udp_port = UDP_PORT
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.width = options.width if options.width else DEFAULT_WIDTH
|
||||
self.height = options.height if options.height else DEFAULT_HEIGHT
|
||||
self.canvas()
|
||||
self.set_title()
|
||||
self.queue = queue
|
||||
self.limit = MAX_PIXELS
|
||||
self.limit = options.maxpixels if options.maxpixels else 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)
|
||||
|
|
@ -87,8 +89,7 @@ class Canvas(object):
|
|||
|
||||
def CanvasUpdate(self):
|
||||
"""Updates the screen according to self.fps"""
|
||||
lasttime = time.time()
|
||||
lastbroadcast = time.time()
|
||||
lasttime = lastbroadcast = time.time()
|
||||
changed = False
|
||||
while True:
|
||||
changed = self.Draw() or changed
|
||||
|
|
@ -167,8 +168,9 @@ class PixelVloedServer(DatagramServer):
|
|||
def __init__(self, *args, **kwargs):
|
||||
"""Set up some vars for this instance"""
|
||||
self.queue = Queue()
|
||||
pixelcanvas = Canvas(self.queue)
|
||||
pixelcanvas = Canvas(self.queue, kwargs['options'])
|
||||
__request_processing_greenlet = spawn(pixelcanvas.CanvasUpdate)
|
||||
del (kwargs['options'])
|
||||
DatagramServer.__init__(self, *args, **kwargs)
|
||||
|
||||
def handle(self, data, _address):
|
||||
|
|
@ -208,7 +210,7 @@ class PixelVloedClient(object):
|
|||
servers[0])
|
||||
else:
|
||||
self.ipaddress = ip
|
||||
self.port = port if port else UDP_IP
|
||||
self.port = port if port else UDP_PORT
|
||||
self.width = width
|
||||
self.height = height
|
||||
if self.debug:
|
||||
|
|
@ -275,7 +277,7 @@ def NewMessage():
|
|||
|
||||
def RGBPixel(x, y, r, g, b, a=None): # pylint: disable=C0103
|
||||
"""Generates the packed data for a pixel"""
|
||||
if a:
|
||||
if a is not None:
|
||||
return struct.pack("<2H4B", x, y, r, g, b, a)
|
||||
return struct.pack("<2H3B", x, y, r, g, b)
|
||||
|
||||
|
|
@ -304,9 +306,23 @@ class MaxSizeList(list):
|
|||
raise IndexError('max size reached')
|
||||
super(MaxSizeList, self).append(item)
|
||||
|
||||
def RunServer():
|
||||
def RunServer(options):
|
||||
"""Runs a pixelvloed server"""
|
||||
PixelVloedServer('%s:%d' %(UDP_IP, UDP_PORT)).serve_forever()
|
||||
PixelVloedServer('%s:%d' %(options.ip, options.port),
|
||||
options=options).serve_forever()
|
||||
|
||||
if __name__ == '__main__':
|
||||
RunServer()
|
||||
import optparse
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('-v', action="store_true", dest="debug", default=False)
|
||||
parser.add_option('-i', action="store", dest="ip", default=UDP_IP)
|
||||
parser.add_option('-p', action="store", dest="port", default=UDP_PORT,
|
||||
type="int")
|
||||
parser.add_option('-x', action="store", dest="width", default=DEFAULT_WIDTH,
|
||||
type="int")
|
||||
parser.add_option('-y', action="store", dest="height", default=DEFAULT_HEIGHT,
|
||||
type="int")
|
||||
parser.add_option('-m', action="store", dest="maxpixels", default=MAX_PIXELS,
|
||||
type="int")
|
||||
options, remainder = parser.parse_args()
|
||||
RunServer(options)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue