This commit is contained in:
alban 2020-11-11 17:31:08 +01:00
commit 6d70ca0c32
39 changed files with 13735 additions and 0 deletions

46
exports/toNull.py Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
The exporter that drops all traffic !
v0.1.0
A basic exporter
LICENCE : CC
by cocoa
'''
from __future__ import print_function
import sys
import os
import argparse
import redis
import time
argsparser = argparse.ArgumentParser(description="Null exporter LJ")
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
args = argsparser.parse_args()
verbose=args.verbose
name = "exports::toNull"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
try:
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
debug(name,"dumping: "+line)
except EOFError:
debug("break")# no more information

63
exports/toRedis.py Normal file
View file

@ -0,0 +1,63 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
redis exporter
v0.1.0
A basic exporter
LICENCE : CC
by cocoa
'''
from __future__ import print_function
import sys
import os
import argparse
import redis
import time
argsparser = argparse.ArgumentParser(description="Redis exporter LJ")
argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str)
argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str)
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose")
args = argsparser.parse_args()
ip = args.ip
port = args.port
key = args.key
verbose=args.verbose
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
r=redis.StrictRedis(host=ip, port=port, db=0)
try:
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
continue
line = line.rstrip('\n')
line=line[1:-1]
line = line.replace("[",'(')
line = line.replace("]",')')
line = "[{}]".format(line)
if line == "[]":
line="[(400.0,400.0,0),(400.0,400.0,0),(400.0,400.0,0),(400.0,400.0,0)]"
continue
if r.set(key,line)==True:
debug("exports::redis set("+str(key)+") to "+line)
except EOFError:
debug("break")# no more information

84
exports/toUDP.py Normal file
View file

@ -0,0 +1,84 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
toUDP
v0.1.0
A basic exporter
LICENCE : CC
by cocoa
'''
from __future__ import print_function
import sys
import os
import argparse
import time
import socket
import ast
argsparser = argparse.ArgumentParser(description="toUDP v0.1b help mode")
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)",default="9003",type=str)
args = argsparser.parse_args()
verbose = args.verbose
ip = args.ip
port = int(args.port)
verbose = args.verbose
name = "exports::toUDP"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
def ClientStart(ip, port):
global sockclient
sockclient = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
def ClientSend(msgFromClient):
bytesToSend = str.encode(str(msgFromClient))
serverAddressPort = (ip, port)
bufferSize = 1024
# Send to server using created UDP socket
sockclient.sendto(bytesToSend, serverAddressPort)
'''
# If reply :
msgFromServer = sockclient.recvfrom(bufferSize)
msg = "Message from Server {}".format(msgFromServer[0])
print(msg)
'''
try:
ClientStart(ip, port)
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
line = line.rstrip('\n')
#pointsList = ast.literal_eval(line)
debug(name,": "+line)
ClientSend(line)
except EOFError:
debug("break")# no more information

115
exports/toWS.py Normal file
View file

@ -0,0 +1,115 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
toWS
exporter to LJ via WebSocket
v0.1b
'''
from __future__ import print_function
import websocket
import time
import argparse
import traceback
import sys
try:
import thread
except ImportError:
import _thread as thread
print("")
print("toWS v0.1b")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="toWS v0.1b help mode")
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
args = argsparser.parse_args()
key = args.key
verbose=args.verbose
name = "exports::toWS"
# Server name
if args.server:
serverIP = args.server
else:
serverIP = "127.0.0.1"
# ORCA destination device
if args.port:
wsPORT = args.port
else:
wsPORT = 9001
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
def GetTime():
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
def on_message(ws, message):
debug(message)
def on_error(ws, error):
debug(error)
def on_close(ws):
debug("### closed ###")
def on_open(ws):
def run(*args):
try:
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.01)
line = line.rstrip('\n')
line=line[1:-1]
line = line.replace("[",'(')
line = line.replace("]",')')
#debug(line)
line = "[{}]".format(line)
ws.send(str(key)+' "'+line+'"')
debug("exports::ws "+str(key)+" "+line)
except EOFError:
debug("break")# no more information
finally:
ws.close()
print("sendWS terminating...")
thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://"+str(serverIP)+":"+str(wsPORT),
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()

158
exports/tonano.py Normal file
View file

@ -0,0 +1,158 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
tonano
exporter to LJ nano
v0.1b
'''
from __future__ import print_function
import websocket
import time
import argparse
import traceback
import sys
import random
from websocket_server import WebsocketServer
from socket import *
try:
import thread
except ImportError:
import _thread as thread
name = "exports::tonano"
def debug(*args, **kwargs):
if( verbose == False ):
return
print(*args, file=sys.stderr, **kwargs)
argsparser = argparse.ArgumentParser(description="tonano v0.1b help mode")
argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
argsparser.add_argument("-s","--server",help="WS server IP (127.0.0.1 by default)", type=str)
argsparser.add_argument("-p","--port",help="WS port to bind to (9001 by default)", type=str)
argsparser.add_argument("-k","--key",help="Redis key to update",default="0",type=str)
args = argsparser.parse_args()
key = args.key
if args.verbose:
verbose = True
else:
verbose = False
if args.server:
serverIP = args.server
else:
serverIP = "127.0.0.1"
if args.port:
wsPORT = args.port
else:
wsPORT = 9001
debug("")
debug("tonano v0.1b")
points0 = "[(150.0, 230.0, 65280), (170.0, 170.0, 65280), (230.0, 170.0, 65280), (210.0, 230.0, 65280), (150.0, 230.0, 65280)]"
points1 = "[(180.0, 230.0, 65280), (200.0, 170.0, 65280), (180.0, 230.0, 65280)]"
points2 = "[(170.0, 190.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (230.0, 200.0, 65280), (170.0, 230.0, 65280), (230.0, 230.0, 65280)]"
points3 = "[(170.0, 170.0, 65280), (200.0, 170.0, 65280), (230.0, 190.0, 65280), (200.0, 200.0, 65280), (230.0, 210.0, 65280), (200.0, 230.0, 65280), (170.0, 230.0, 65280)]"
points = [points0, points1, points2, points3]
LaserNumber = 1
SceneNumber = 0
Laser = 0
def sendbroadcast():
debug("Sending broadcast")
cs = socket(AF_INET, SOCK_DGRAM)
cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
cs.sendto("LJ tonano 0.1".encode(), ("255.255.255.255", 54545))
#
# CLI websocket client -> WS server (nanoLJ) -> webpage
#
def on_message(ws, message):
if random.randint(0,100)>95:
sendbroadcast()
#debug("CLI WS client received and dropped "+message)
def on_error(ws, error):
debug("CLI WS client got error :"+str(error))
def on_close(ws):
debug("### CLI WS client WS closed ###")
def on_open(ws):
def run(*args):
try:
while True:
line = sys.stdin.readline()
if line == "":
time.sleep(0.005)
#debug("CLI string", line)
line = line.rstrip('\n')
line=line[1:-1]
line = line.replace("[",'(')
line = line.replace("]",')')
#debug(line)
line = "[{}]".format(line)
debug("CLI proccess sending : /simul" +" "+ line)
#sendWSall("/simul" +" "+ str(points[laserid].decode('ascii')))
ws.send("/simul "+line)
#debug("exports::tosimuCLIent "+str(key)+" "+line)
except EOFError:
debug("tonano break")# no more information
finally:
ws.close()
debug("tonano WS terminating...")
thread.start_new_thread(run, ())
def handle_timeout(self):
self.timed_out = True
#
# Launch WS CLI client
#
if __name__ == "__main__":
try:
# CLI Websocket client
debug("Launching tosimu CLI websocket client...")
#websocket.enableTrace(True)
websocket.enableTrace(False)
print("ws://"+str(serverIP)+":"+str(wsPORT))
ws = websocket.WebSocketApp("ws://"+str(serverIP)+":"+str(wsPORT),
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
except Exception:
debug("tonano Exception")
traceback.print_exc()

388
exports/websocket_server.py Normal file
View file

@ -0,0 +1,388 @@
# Author: Johan Hanssen Seferidis
# License: MIT
'''
Custom version
with clients_list()
For 2 clients :
[{'id': 1, 'handler': <websocket_server.WebSocketHandler object at 0x114d35880>, 'address': ('127.0.0.1', 62718)}, {'id': 2, 'handler': <websocket_server.WebSocketHandler object at 0x114d35d60>, 'address': ('127.0.0.1', 62720)}]
def client_list():
clients = wserver.clients()
for client in clients:
print(client['id'])
'''
import sys
import struct
from base64 import b64encode
from hashlib import sha1
import logging
from socket import error as SocketError
import errno
if sys.version_info[0] < 3:
from SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandler
else:
from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
logger = logging.getLogger(__name__)
logging.basicConfig()
'''
+-+-+-+-+-------+-+-------------+-------------------------------+
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| Payload Data continued ... |
+---------------------------------------------------------------+
'''
FIN = 0x80
OPCODE = 0x0f
MASKED = 0x80
PAYLOAD_LEN = 0x7f
PAYLOAD_LEN_EXT16 = 0x7e
PAYLOAD_LEN_EXT64 = 0x7f
OPCODE_CONTINUATION = 0x0
OPCODE_TEXT = 0x1
OPCODE_BINARY = 0x2
OPCODE_CLOSE_CONN = 0x8
OPCODE_PING = 0x9
OPCODE_PONG = 0xA
# -------------------------------- API ---------------------------------
class API():
def run_forever(self):
try:
logger.info("Listening on port %d for clients.." % self.port)
self.serve_forever()
except KeyboardInterrupt:
self.server_close()
logger.info("Server terminated.")
except Exception as e:
logger.error(str(e), exc_info=True)
exit(1)
def new_client(self, client, server):
pass
def client_left(self, client, server):
pass
def message_received(self, client, server, message):
pass
def set_fn_new_client(self, fn):
self.new_client = fn
def set_fn_client_left(self, fn):
self.client_left = fn
def set_fn_message_received(self, fn):
self.message_received = fn
def send_message(self, client, msg):
self._unicast_(client, msg)
def send_message_to_all(self, msg):
self._multicast_(msg)
def clients_list(self):
return self.clients
# ------------------------- Implementation -----------------------------
class WebsocketServer(ThreadingMixIn, TCPServer, API):
"""
A websocket server waiting for clients to connect.
Args:
port(int): Port to bind to
host(str): Hostname or IP to listen for connections. By default 127.0.0.1
is being used. To accept connections from any client, you should use
0.0.0.0.
loglevel: Logging level from logging module to use for logging. By default
warnings and errors are being logged.
Properties:
clients(list): A list of connected clients. A client is a dictionary
like below.
{
'id' : id,
'handler' : handler,
'address' : (addr, port)
}
"""
allow_reuse_address = True
daemon_threads = True # comment to keep threads alive until finished
clients = []
id_counter = 0
def __init__(self, port, host='127.0.0.1', loglevel=logging.WARNING):
logger.setLevel(loglevel)
TCPServer.__init__(self, (host, port), WebSocketHandler)
self.port = self.socket.getsockname()[1]
def _message_received_(self, handler, msg):
self.message_received(self.handler_to_client(handler), self, msg)
def _ping_received_(self, handler, msg):
handler.send_pong(msg)
def _pong_received_(self, handler, msg):
pass
def _new_client_(self, handler):
self.id_counter += 1
client = {
'id': self.id_counter,
'handler': handler,
'address': handler.client_address
}
self.clients.append(client)
self.new_client(client, self)
def _client_left_(self, handler):
client = self.handler_to_client(handler)
self.client_left(client, self)
if client in self.clients:
self.clients.remove(client)
def _unicast_(self, to_client, msg):
to_client['handler'].send_message(msg)
def _multicast_(self, msg):
for client in self.clients:
self._unicast_(client, msg)
def handler_to_client(self, handler):
for client in self.clients:
if client['handler'] == handler:
return client
class WebSocketHandler(StreamRequestHandler):
def __init__(self, socket, addr, server):
self.server = server
StreamRequestHandler.__init__(self, socket, addr, server)
def setup(self):
StreamRequestHandler.setup(self)
self.keep_alive = True
self.handshake_done = False
self.valid_client = False
def handle(self):
while self.keep_alive:
if not self.handshake_done:
self.handshake()
elif self.valid_client:
self.read_next_message()
def read_bytes(self, num):
# python3 gives ordinal of byte directly
bytes = self.rfile.read(num)
if sys.version_info[0] < 3:
return map(ord, bytes)
else:
return bytes
def read_next_message(self):
try:
b1, b2 = self.read_bytes(2)
except SocketError as e: # to be replaced with ConnectionResetError for py3
if e.errno == errno.ECONNRESET:
logger.info("Client closed connection.")
print("Error: {}".format(e))
self.keep_alive = 0
return
b1, b2 = 0, 0
except ValueError as e:
b1, b2 = 0, 0
fin = b1 & FIN
opcode = b1 & OPCODE
masked = b2 & MASKED
payload_length = b2 & PAYLOAD_LEN
if opcode == OPCODE_CLOSE_CONN:
logger.info("Client asked to close connection.")
self.keep_alive = 0
return
if not masked:
logger.warn("Client must always be masked.")
self.keep_alive = 0
return
if opcode == OPCODE_CONTINUATION:
logger.warn("Continuation frames are not supported.")
return
elif opcode == OPCODE_BINARY:
logger.warn("Binary frames are not supported.")
return
elif opcode == OPCODE_TEXT:
opcode_handler = self.server._message_received_
elif opcode == OPCODE_PING:
opcode_handler = self.server._ping_received_
elif opcode == OPCODE_PONG:
opcode_handler = self.server._pong_received_
else:
logger.warn("Unknown opcode %#x." % opcode)
self.keep_alive = 0
return
if payload_length == 126:
payload_length = struct.unpack(">H", self.rfile.read(2))[0]
elif payload_length == 127:
payload_length = struct.unpack(">Q", self.rfile.read(8))[0]
masks = self.read_bytes(4)
message_bytes = bytearray()
for message_byte in self.read_bytes(payload_length):
message_byte ^= masks[len(message_bytes) % 4]
message_bytes.append(message_byte)
opcode_handler(self, message_bytes.decode('utf8'))
def send_message(self, message):
self.send_text(message)
def send_pong(self, message):
self.send_text(message, OPCODE_PONG)
def send_text(self, message, opcode=OPCODE_TEXT):
"""
Important: Fragmented(=continuation) messages are not supported since
their usage cases are limited - when we don't know the payload length.
"""
# Validate message
if isinstance(message, bytes):
message = try_decode_UTF8(message) # this is slower but ensures we have UTF-8
if not message:
logger.warning("Can\'t send message, message is not valid UTF-8")
return False
elif sys.version_info < (3,0) and (isinstance(message, str) or isinstance(message, unicode)):
pass
elif isinstance(message, str):
pass
else:
logger.warning('Can\'t send message, message has to be a string or bytes. Given type is %s' % type(message))
return False
header = bytearray()
payload = encode_to_UTF8(message)
payload_length = len(payload)
# Normal payload
if payload_length <= 125:
header.append(FIN | opcode)
header.append(payload_length)
# Extended payload
elif payload_length >= 126 and payload_length <= 65535:
header.append(FIN | opcode)
header.append(PAYLOAD_LEN_EXT16)
header.extend(struct.pack(">H", payload_length))
# Huge extended payload
elif payload_length < 18446744073709551616:
header.append(FIN | opcode)
header.append(PAYLOAD_LEN_EXT64)
header.extend(struct.pack(">Q", payload_length))
else:
raise Exception("Message is too big. Consider breaking it into chunks.")
return
self.request.send(header + payload)
def read_http_headers(self):
headers = {}
# first line should be HTTP GET
http_get = self.rfile.readline().decode().strip()
assert http_get.upper().startswith('GET')
# remaining should be headers
while True:
header = self.rfile.readline().decode().strip()
if not header:
break
head, value = header.split(':', 1)
headers[head.lower().strip()] = value.strip()
return headers
def handshake(self):
headers = self.read_http_headers()
try:
assert headers['upgrade'].lower() == 'websocket'
except AssertionError:
self.keep_alive = False
return
try:
key = headers['sec-websocket-key']
except KeyError:
logger.warning("Client tried to connect but was missing a key")
self.keep_alive = False
return
response = self.make_handshake_response(key)
self.handshake_done = self.request.send(response.encode())
self.valid_client = True
self.server._new_client_(self)
@classmethod
def make_handshake_response(cls, key):
return \
'HTTP/1.1 101 Switching Protocols\r\n'\
'Upgrade: websocket\r\n' \
'Connection: Upgrade\r\n' \
'Sec-WebSocket-Accept: %s\r\n' \
'\r\n' % cls.calculate_response_key(key)
@classmethod
def calculate_response_key(cls, key):
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
hash = sha1(key.encode() + GUID.encode())
response_key = b64encode(hash.digest()).strip()
return response_key.decode('ASCII')
def finish(self):
self.server._client_left_(self)
def encode_to_UTF8(data):
try:
return data.encode('UTF-8')
except UnicodeEncodeError as e:
logger.error("Could not encode data to UTF-8 -- %s" % e)
return False
except Exception as e:
raise(e)
return False
def try_decode_UTF8(data):
try:
return data.decode('utf-8')
except UnicodeDecodeError:
return False
except Exception as e:
raise(e)