feat(rcf): id support

This commit is contained in:
Swann
2019-02-14 15:30:35 +01:00
parent 886befeb14
commit b2e6d27ec7
3 changed files with 54 additions and 32 deletions

View File

@ -7,7 +7,7 @@ import random
import struct import struct
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.INFO)
# TODO: Add message time and author stamp for reliabilty # TODO: Add message time and author stamp for reliabilty
@ -15,18 +15,21 @@ class RCFMessage(object):
""" """
Message is formatted on wire as 2 frames: Message is formatted on wire as 2 frames:
frame 0: key (0MQ string) // property path frame 0: key (0MQ string) // property path
frame 1: mtype (0MQ string) // property path frame 1: id (0MQ string) // property path
frame 2: body (blob) // Could be any data frame 2: mtype (0MQ string) // property path
frame 3: body (blob) // Could be any data
""" """
key = None # key (string) key = None # key (string)
id = None # User (string)
mtype = None # data mtype (string) mtype = None # data mtype (string)
body = None # data blob body = None # data blob
def __init__(self, key=None, mtype=None, body=None): def __init__(self, key=None, id=None, mtype=None, body=None):
self.key = key self.key = key
self.mtype = mtype self.mtype = mtype
self.body = body self.body = body
self.id = id
def store(self, dikt): def store(self, dikt):
"""Store me in a dict if I have anything to store""" """Store me in a dict if I have anything to store"""
@ -40,17 +43,18 @@ class RCFMessage(object):
key = '' if self.key is None else self.key.encode() key = '' if self.key is None else self.key.encode()
mtype = '' if self.mtype is None else self.mtype.encode() mtype = '' if self.mtype is None else self.mtype.encode()
body = '' if self.body is None else umsgpack.packb(self.body) body = '' if self.body is None else umsgpack.packb(self.body)
socket.send_multipart([key,mtype, body]) socket.send_multipart([key,self.id,mtype, body])
@classmethod @classmethod
def recv(cls, socket): def recv(cls, socket):
"""Reads key-value message from socket, returns new kvmsg instance.""" """Reads key-value message from socket, returns new kvmsg instance."""
key,mtype, body = socket.recv_multipart(zmq.NOBLOCK) key,id,mtype, body = socket.recv_multipart(zmq.NOBLOCK)
key = key.decode() if key else None key = key.decode() if key else None
id = id if id else None
mtype = mtype.decode() if body else None mtype = mtype.decode() if body else None
body = umsgpack.unpackb(body) if body else None body = umsgpack.unpackb(body) if body else None
return cls(key=key,mtype=mtype, body=body) return cls(key=key,id=id,mtype=mtype, body=body)
def dump(self): def dump(self):
if self.body is None: if self.body is None:
@ -123,18 +127,18 @@ class Client():
rcfmsg = RCFMessage.recv(self.pull_sock) rcfmsg = RCFMessage.recv(self.pull_sock)
rcfmsg.store(self.property_map) rcfmsg.store(self.property_map)
rcfmsg.dump() # rcfmsg.dump()
for f in self.recv_callback: for f in self.recv_callback:
f(rcfmsg) f(rcfmsg)
def push_update(self, key,mtype,body): def push_update(self, key,mtype,body):
rcfmsg = RCFMessage(key,mtype,body) rcfmsg = RCFMessage(key,self.id,mtype,body)
rcfmsg.send(self.push_sock) rcfmsg.send(self.push_sock)
# self.push_sock.send_multipart() # self.push_sock.send_multipart()
def stop(self): def stop(self):
logger.info("Stopping client") logger.debug("Stopping client")
self.poller.unregister(self.pull_sock) self.poller.unregister(self.pull_sock)
self.req_sock.close() self.req_sock.close()
self.push_sock.close() self.push_sock.close()
@ -182,7 +186,7 @@ class Server():
while True: while True:
# TODO: find a better way # TODO: find a better way
await asyncio.sleep(0.016) await asyncio.sleep(0.0001)
try: try:
socks = dict(self.poller.poll(1)) socks = dict(self.poller.poll(1))
@ -202,7 +206,7 @@ class Server():
self.pub_sock.send_multipart(msg) self.pub_sock.send_multipart(msg)
def stop(self): def stop(self):
logger.info("Stopping server") logger.debug("Stopping server")
self.poller.unregister(self.request_sock) self.poller.unregister(self.request_sock)
self.pub_sock.close() self.pub_sock.close()
self.request_sock.close() self.request_sock.close()

View File

@ -23,7 +23,7 @@ VECTOR_TYPES = (
# TODO: Less ugly method # TODO: Less ugly method
def from_bpy(value): def from_bpy(value):
print(' casting from bpy') logger.debug(' casting from bpy')
value_type = type(value) value_type = type(value)
value_casted = None value_casted = None
@ -59,17 +59,29 @@ def resolve_bpy_path(path):
obj = None obj = None
attribute = path[2] attribute = path[2]
logger.info("resolving {}".format(path)) logger.debug("resolving {}".format(path))
try: try:
obj = getattr(bpy.data,path[0])[path[1]] obj = getattr(bpy.data,path[0])[path[1]]
attribute = getattr(obj,path[2]) attribute = getattr(obj,path[2])
logger.info("done {} : {}".format(obj,attribute)) logger.debug("done {} : {}".format(obj,attribute))
except AttributeError: except AttributeError:
print(" Attribute not found") logger.debug(" Attribute not found")
return obj, attribute return obj, attribute
def observer(scene):
global client
for key,values in client.property_map.items():
# if values.id == client.id:
obj, attr = resolve_bpy_path(key)
if attr != to_bpy(client.property_map[key]):
value_type, value = from_bpy(attr)
client.push_update(key,value_type,value)
# CLIENT-SERVER # CLIENT-SERVER
def refresh_window(msg): def refresh_window(msg):
import bpy import bpy
@ -77,25 +89,30 @@ def refresh_window(msg):
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
def patch_scene(msg): def patch_scene(msg):
value = None global client
obj, attr = resolve_bpy_path(msg.key) if msg.id != client.id:
attr_name = msg.key.split('/')[2] value = None
value = to_bpy(msg) obj, attr = resolve_bpy_path(msg.key)
print("Updating scene:\n object: {} attribute: {} , value: {}".format(obj, attr_name, value)) attr_name = msg.key.split('/')[2]
try:
setattr(obj,attr_name,value)
except:
pass
value = to_bpy(msg)
logger.debug("Updating scene:\n object: {} attribute: {} , value: {}".format(obj, attr_name, value))
try:
setattr(obj,attr_name,value)
except:
pass
else:
logger.debug('no need to update scene on our own')
def vector2array(v): def vector2array(v):
return [v.x,v.y,v.z] return [v.x,v.y,v.z]
def array2vector(a): def array2vector(a):
print(mathutils.Vector((a[0],a[1],a[2]))) logger.debug(mathutils.Vector((a[0],a[1],a[2])))
return mathutils.Vector((a[0],a[1],a[2])) return mathutils.Vector((a[0],a[1],a[2]))
class session_join(bpy.types.Operator): class session_join(bpy.types.Operator):
@ -112,9 +129,9 @@ class session_join(bpy.types.Operator):
global client global client
username = str(context.scene.session_settings.username) username = str(context.scene.session_settings.username)
callbacks=[refresh_window,patch_scene] callbacks=[patch_scene]
client = net_components.Client(id=username ,recv_callback=callbacks) client = net_components.Client(id=username,recv_callback=callbacks)
time.sleep(1) time.sleep(1)
bpy.ops.asyncio.loop() bpy.ops.asyncio.loop()
@ -162,7 +179,7 @@ class session_create(bpy.types.Operator):
global client global client
username = str(context.scene.session_settings.username) username = str(context.scene.session_settings.username)
callbacks=[refresh_window,patch_scene] callbacks=[patch_scene]
server = net_components.Server() server = net_components.Server()
client = net_components.Client(id=username,recv_callback=callbacks) client = net_components.Client(id=username,recv_callback=callbacks)
@ -198,7 +215,7 @@ class session_stop(bpy.types.Operator):
client = None client = None
bpy.ops.asyncio.stop() bpy.ops.asyncio.stop()
else: else:
logger.info("No server/client running.") logger.debug("No server/client running.")
return {"FINISHED"} return {"FINISHED"}
@ -225,6 +242,7 @@ def register():
register_class(cls) register_class(cls)
bpy.types.Scene.session_settings = bpy.props.PointerProperty(type=session_settings) bpy.types.Scene.session_settings = bpy.props.PointerProperty(type=session_settings)
bpy.app.handlers.depsgraph_update_post.append(observer)
def unregister(): def unregister():
from bpy.utils import unregister_class from bpy.utils import unregister_class

View File

@ -35,7 +35,7 @@ class SessionPanel(bpy.types.Panel):
area_msg = row.box() area_msg = row.box()
if len(net_operators.client.property_map) > 0: if len(net_operators.client.property_map) > 0:
for key,values in net_operators.client.property_map.items(): for key,values in net_operators.client.property_map.items():
area_msg.label(text="{} ({})".format(key, values.mtype)) area_msg.label(text="{} ({}) - ".format(key, values.mtype, values.id.decode()))
else: else:
area_msg.label(text="Empty") area_msg.label(text="Empty")