220 lines
7.0 KiB
Python
Executable File
220 lines
7.0 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import json
|
|
import sys
|
|
import copy
|
|
from collections import OrderedDict, deque
|
|
import tcp_lineserver as lineserver
|
|
import uuid
|
|
import traceback
|
|
|
|
class Group(object):
|
|
def __init__(self, name):
|
|
self.name = name
|
|
self.title = name
|
|
self.components = []
|
|
|
|
class Component(object):
|
|
def __init__(self, name, g):
|
|
self.name = name
|
|
self.group = g
|
|
self.value = None
|
|
self.properties = {}
|
|
|
|
init_values = ['device name', 'device stick_name']
|
|
|
|
def set_value(c, value):
|
|
c.value = value
|
|
print 'set',c.name,c.value,c.group
|
|
for n in init_values:
|
|
if c.name == n:
|
|
init(cindex['device name'].value)
|
|
break
|
|
for client in clients.values():
|
|
client.send_msg(dict(type='update', updates=[dict(name=c.name, value=c.value)]))
|
|
|
|
|
|
def history_add(item):
|
|
history.append(item)
|
|
id, is_cmd, line = item
|
|
for cid, client in console_clients.items():
|
|
client.send_msg(dict(
|
|
type = 'command' if is_cmd else 'reply',
|
|
origin = 'self' if cid == id else 'other',
|
|
line = line
|
|
))
|
|
|
|
class ClientType:
|
|
GROUP = 1
|
|
CONSOLE = 2
|
|
MAINUPDATE = 3
|
|
|
|
class DummyHandler(lineserver.LineHandler):
|
|
def __init__(self, *args, **kwargs):
|
|
lineserver.LineHandler.__init__(self, *args, **kwargs)
|
|
self.id = None
|
|
|
|
def send_msg(self, msg):
|
|
print '<', msg
|
|
self.send_line(json.dumps(msg))
|
|
|
|
def handle_line(self, line):
|
|
print '>', line
|
|
msg = json.loads(line)
|
|
msgtype = msg['type']
|
|
if msgtype == 'init':
|
|
id = msg.get('id', '0')
|
|
if self.id != msg['id']:
|
|
self.id = msg['id']
|
|
clients[self.id] = self
|
|
self.title = ""
|
|
global main_update
|
|
main_update.append(self)
|
|
#self.send_msg({'type': 'accept-mainupdate'})
|
|
init(cindex['device name'].value)
|
|
elif msgtype == 'getblock':
|
|
path = msg['path']
|
|
grp = path.split(",")[-1]
|
|
g = groups[grp]
|
|
clist = []
|
|
for c in g.components:
|
|
cdict = copy.deepcopy(c.properties)
|
|
cdict['name'] = c.name
|
|
clist.append(cdict)
|
|
self.send_msg(dict(type='draw', path=path, title=g.title, components=clist))
|
|
elif msgtype == 'updateblock':
|
|
path = msg['path']
|
|
grp = path.split(",")[-1]
|
|
g = groups[grp]
|
|
clist = []
|
|
updates = []
|
|
for c in g.components:
|
|
if c.properties.get('type','') != 'group':
|
|
updates.append(dict(name=c.name, value=c.value))
|
|
self.send_msg(dict(type='accept-block'))
|
|
self.send_msg(dict(type='update', updates=updates))
|
|
elif msgtype == 'console':
|
|
print '*** make console ',self.id,self
|
|
self.send_msg(dict(type='accept-console'))
|
|
console_clients[self.id] = self
|
|
for item in history:
|
|
id, is_cmd, line = item
|
|
self.send_msg(dict(
|
|
type = 'command' if is_cmd else 'reply',
|
|
origin = 'self' if self.id == id else 'other',
|
|
line = line
|
|
))
|
|
elif msgtype == 'sendcommand':
|
|
cmd = msg['command'].split(' ')
|
|
history_add((self.id, True, msg['command']))
|
|
if len(cmd) == 1:
|
|
name = cmd[0]
|
|
c = cindex.get(name, None)
|
|
val = None
|
|
else:
|
|
name = cmd[0] + " " + cmd[1]
|
|
try:
|
|
c = cindex[name]
|
|
except KeyError:
|
|
try:
|
|
c = cindex[cmd[0]]
|
|
except KeyError:
|
|
c = None
|
|
else:
|
|
name = cmd[0]
|
|
val = " ".join(cmd[1:])
|
|
else:
|
|
if len(cmd) == 2:
|
|
val = None
|
|
else:
|
|
val = " ".join(cmd[2:])
|
|
if c == None:
|
|
history_add((self.id, False, "ERROR: " + name + " not found"))
|
|
elif val == None:
|
|
history_add((self.id, False, name + " = " + c.value))
|
|
else:
|
|
set_value(c, val)
|
|
history_add((self.id, False, "OK: " + name + " = " + c.value))
|
|
self.send_msg(dict(type = 'accept-command'))
|
|
|
|
def handle_close(self):
|
|
try:
|
|
print 'close client', self
|
|
del clients[self.id]
|
|
except KeyError:
|
|
print 'can not remove client'
|
|
try:
|
|
del console_clients[self.id]
|
|
print '*** removed console client',self.id,self
|
|
except KeyError:
|
|
print '*** console client already closed',self.id,self
|
|
self.close()
|
|
|
|
def init(device):
|
|
global cindex, groups, actual_device
|
|
if device != actual_device:
|
|
print 'INIT', actual_device, device
|
|
actual_device = device
|
|
cindex = {} # component index
|
|
groups = {}
|
|
groupsfile = device + ".json"
|
|
with open(groupsfile) as fil:
|
|
groupdict = json.load(fil)
|
|
for grp in groupdict:
|
|
gdict = groupdict[grp]
|
|
g = find_group(grp)
|
|
g.title = gdict.get('title', grp)
|
|
for cdict in gdict['components']:
|
|
cname = cdict['name']
|
|
c = Component(cname, g)
|
|
g.components.append(c)
|
|
cindex[cname] = c
|
|
c.properties = dict((k, v) for k, v in cdict.items() if k != 'name' and k != 'value')
|
|
c.value = cdict.get('value','')
|
|
if c.properties.get('type','') == 'group':
|
|
gg = find_group(cname)
|
|
if 'title' in cdict:
|
|
if gg.title == gg.name:
|
|
gg.title = cdict['title']
|
|
else:
|
|
c.properties['title'] = gg.title
|
|
devlist = [cindex[n].value for n in init_values]
|
|
device_title = "DUMMY " + "/".join(devlist)
|
|
print 'ENDINIT', device_title
|
|
for m in main_update:
|
|
if m.title != device_title:
|
|
m.title=device_title
|
|
m.send_msg(dict(type='id', id=m.id, title=device_title))
|
|
|
|
def find_group(grp):
|
|
if grp in groups:
|
|
g = groups[grp]
|
|
else:
|
|
g = Group(grp)
|
|
groups[grp] = g
|
|
return g
|
|
|
|
if __name__ == "__main__":
|
|
console_clients = {}
|
|
clients = {}
|
|
cindex = {} # component index
|
|
groups = {}
|
|
history = deque(maxlen=50)
|
|
console_id = 0
|
|
main_update = []
|
|
actual_device = ''
|
|
|
|
try:
|
|
device = sys.argv[2]
|
|
except IndexError:
|
|
device = "dummy1"
|
|
try:
|
|
port = int(sys.argv[1])
|
|
except IndexError:
|
|
port = 5001
|
|
|
|
init(device)
|
|
|
|
server = lineserver.LineServer('localhost', port, DummyHandler)
|
|
server.loop()
|