code refactoring

This commit is contained in:
speyrefitte
2014-06-20 17:11:39 +02:00
parent 3d9deca110
commit 39b1638b6a
12 changed files with 372 additions and 235 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.pyc *.pyc
.project .project
.pydevproject .pydevproject
README.md~

View File

@@ -1,6 +1,6 @@
# RDPY # RDPY
## Remote Desktop Protoc in Python Remote Desktop Protocol in Twisted Python
## Requirements ## Requirements
* python2.7 * python2.7

View File

@@ -1,13 +0,0 @@
# RDPY
## Remote Desktop Protoc in Python
## Requirements
* python2.7
* python-twisted
## Requirements for examples
* python-qt4
* python-qt4reactor
this project is still in progress.

View File

@@ -2,22 +2,15 @@
@author: sylvain @author: sylvain
''' '''
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from rdpy.protocol.rfb.rfb import RfbObserver from rdpy.protocol.rfb.rfb import RFBClientObserver
from rdpy.protocol.rdp.rdp import RDPObserver from rdpy.protocol.rdp.rdp import RDPClientObserver
from rdpy.network.error import UnRegistredObject
class QAdaptor(object): class QAdaptor(object):
''' '''
adaptor model with link beetween protocol adaptor model with link between protocol
and qt widget and qt widget
''' '''
def __init__(self, qRemoteDesktop):
'''
constructor
must set qRemoteDesktop attribute
'''
#qwidget use for render
self._qRemoteDesktop = qRemoteDesktop
self._qRemoteDesktop._adaptor = self
def sendMouseEvent(self, e): def sendMouseEvent(self, e):
''' '''
@@ -34,38 +27,40 @@ class QAdaptor(object):
@param e: qEvent @param e: qEvent
''' '''
pass pass
def getWidget(self):
'''
@return: widget use for render
'''
pass
class RfbAdaptor(RfbObserver, QAdaptor): class RFBClientQt(RFBClientObserver, QAdaptor):
''' '''
QAdaptor for specific RFB protocol stack QAdaptor for specific RFB protocol stack
is to an RFB observer is to an RFB observer
''' '''
def __init__(self, qRemoteDesktop): def __init__(self):
''' '''
ctor ctor
@param qRemoteDesktop: widget use for render
''' '''
QAdaptor.__init__(self, qRemoteDesktop) self._widget = QRemoteDesktop(self)
self._rfb = None
def setProtocol(self, rfb): def getWidget(self):
''' '''
inherit from RfbObserver @return: widget use for render
init protocol settings
''' '''
#set RFB observer to return self._widget
self._rfb = rfb
def notifyFramebufferUpdate(self, width, height, x, y, pixelFormat, encoding, data): def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
''' '''
implement RfbAdaptor interface implement RFBClientObserver interface
@param width: width of new image @param width: width of new image
@param height: height of new image @param height: height of new image
@param x: x position of new image @param x: x position of new image
@param y: y position of new image @param y: y position of new image
@param pixelFormat: pixefFormat structure in rfb.message.PixelFormat @param pixelFormat: pixefFormat structure in rfb.message.PixelFormat
@param encoding: encoding type rfb.message.Encoding @param encoding: encoding type rfb.message.Encoding
@param data: image data in accordance with pixelformat and encoding @param data: image data in accordance with pixel format and encoding
''' '''
imageFormat = None imageFormat = None
if pixelFormat.BitsPerPixel.value == 32 and pixelFormat.RedShift.value == 16: if pixelFormat.BitsPerPixel.value == 32 and pixelFormat.RedShift.value == 16:
@@ -75,44 +70,47 @@ class RfbAdaptor(RfbObserver, QAdaptor):
return return
image = QtGui.QImage(data, width, height, imageFormat) image = QtGui.QImage(data, width, height, imageFormat)
self._qRemoteDesktop.notifyImage(x, y, image) self._widget.notifyImage(x, y, image)
def sendMouseEvent(self, e): def sendMouseEvent(self, e):
''' '''
convert qt mouse event to rfb mouse event convert qt mouse event to RFB mouse event
send mouse event to rfb protocol stack
@param e: qMouseEvent @param e: qMouseEvent
''' '''
button = e.button() button = e.button()
mask = 0 buttonNumber = 0
if button == QtCore.Qt.LeftButton: if button == QtCore.Qt.LeftButton:
mask = 1 buttonNumber = 1
elif button == QtCore.Qt.MidButton: elif button == QtCore.Qt.MidButton:
mask = 1 << 1 buttonNumber = 2
elif button == QtCore.Qt.RightButton: elif button == QtCore.Qt.RightButton:
mask = 1 << 2 buttonNumber = 3
self._rfb.sendPointerEvent(mask, e.pos().x(), e.pos().y()) self.mouseEvent(buttonNumber, e.pos().x(), e.pos().y())
def sendKeyEvent(self, e): def sendKeyEvent(self, e):
''' '''
convert qt key press event to rfb press event convert Qt key press event to RFB press event
send key event to protocol stack
@param e: qKeyEvent @param e: qKeyEvent
''' '''
self._rfb.sendKeyEvent(True, e.nativeVirtualKey()) self.keyEvent(True, e.nativeVirtualKey())
class RDPAdaptor(RDPObserver, QAdaptor): class RDPClientQt(RDPClientObserver, QAdaptor):
''' '''
Adaptor for RDP client Adaptor for RDP client
''' '''
def __init__(self, qRemoteDesktop): def __init__(self):
''' '''
constructor constructor
@param qRemoteDesktop: widget use for render
''' '''
QAdaptor.__init__(self, qRemoteDesktop) self._widget = QRemoteDesktop(self)
def getWidget(self):
'''
@return: widget use for render
'''
return self._widget
def notifyBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
''' '''
notify bitmap update notify bitmap update
@param destLeft: xmin position @param destLeft: xmin position
@@ -141,19 +139,20 @@ class RDPAdaptor(RDPObserver, QAdaptor):
return return
image = QtGui.QImage(data, width, height, imageFormat) image = QtGui.QImage(data, width, height, imageFormat)
self._qRemoteDesktop.notifyImage(destLeft, destTop, image) self._widget.notifyImage(destLeft, destTop, image)
class QRemoteDesktop(QtGui.QWidget): class QRemoteDesktop(QtGui.QWidget):
''' '''
qt display widget qt display widget
''' '''
def __init__(self): def __init__(self, adaptor):
''' '''
constructor constructor
''' '''
super(QRemoteDesktop, self).__init__() super(QRemoteDesktop, self).__init__()
#set by adaptor #adaptor use to send
self._adaptor = None self._adaptor = adaptor
#refresh stack of image #refresh stack of image
#because we can update image only in paint #because we can update image only in paint
#event function. When protocol receive image #event function. When protocol receive image
@@ -208,7 +207,8 @@ class QRemoteDesktop(QtGui.QWidget):
@param event: qMouseEvent @param event: qMouseEvent
''' '''
if self._adaptor is None: if self._adaptor is None:
print "No adaptor to send mouse press event" raise UnRegistredObject("No adaptor to send mouse press event")
self._adaptor.sendMouseEvent(event) self._adaptor.sendMouseEvent(event)
def keyPressEvent(self, event): def keyPressEvent(self, event):
@@ -217,5 +217,7 @@ class QRemoteDesktop(QtGui.QWidget):
@param event: qKeyEvent @param event: qKeyEvent
''' '''
if self._adaptor is None: if self._adaptor is None:
print "No adaptor to send key press event" raise UnRegistredObject("No adaptor to send key press event")
self._adaptor.sendKeyEvent(event)
self._adaptor.sendKeyEvent(event)

View File

@@ -3,4 +3,23 @@
@file: implement run length encoding algorithm use in RDP protocol to compress bit @file: implement run length encoding algorithm use in RDP protocol to compress bit
@see: http://msdn.microsoft.com/en-us/library/dd240593.aspx @see: http://msdn.microsoft.com/en-us/library/dd240593.aspx
''' '''
from rdpy.network.type import UInt8
def extractCodeId(data):
'''
Read first unsigned char
'''
res = UInt8()
data.readType(res)
return res
def decode(dst, src, rowDelta):
insertFgPel = False
firstLine = True
while src.dataLen() > 0:
if firstLine:
firstLine = False
insertFgPel = False

View File

@@ -1,109 +0,0 @@
'''
@author: citronneur
'''
import sys
import os
# Change path so we find rdpy
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
from PyQt4 import QtGui
from rdpy.display.qt import RDPAdaptor, RfbAdaptor, QRemoteDesktop
from rdpy.protocol.rdp import rdp
from rdpy.protocol.rfb import rfb
class RDPClientQtFactory(rdp.ClientFactory):
'''
Factory create a RDP GUI client
'''
def __init__(self):
'''
ctor that init qt context and protocol needed
'''
#create qt widget
self._w = QRemoteDesktop()
self._w.resize(1024, 800)
self._w.setWindowTitle('rdpyclient-rdp')
self._w.show()
#build protocol
rdp.ClientFactory.__init__(self, RDPAdaptor(self._w))
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
'''
connection lost event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason)
reactor.stop()
app.exit()
def clientConnectionFailed(self, connector, reason):
'''
connection failed event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason)
reactor.stop()
app.exit()
class RFBClientQtFactory(rfb.ClientFactory):
'''
Factory create a VNC GUI client
'''
def __init__(self):
'''
ctor that init qt context and protocol needed
'''
#create qt widget
self._w = QRemoteDesktop()
self._w.resize(1024, 800)
self._w.setWindowTitle('rdpyclient-vnc')
self._w.show()
rfb.ClientFactory.__init__(self, RfbAdaptor(self._w))
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
'''
connection lost event
@param connector: twisted connector use for vnc connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason)
reactor.stop()
app.exit()
def clientConnectionFailed(self, connector, reason):
'''
connection failed event
@param connector: twisted connector use for vnc connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason)
reactor.stop()
app.exit()
if __name__ == '__main__':
#create application
app = QtGui.QApplication(sys.argv)
#add qt4 reactor
import qt4reactor
qt4reactor.install()
if sys.argv[3] == 'rdp':
factory = RDPClientQtFactory()
else:
factory = RFBClientQtFactory()
from twisted.internet import reactor
reactor.connectTCP(sys.argv[1], int(sys.argv[2]), factory)
reactor.runReturn()
app.exec_()
reactor.stop()

View File

@@ -0,0 +1,65 @@
'''
@author: citronneur
'''
import sys
import os
# Change path so we find rdpy
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
from PyQt4 import QtGui
from rdpy.display.qt import RDPClientQt
from rdpy.protocol.rdp import rdp
class RDPClientQtFactory(rdp.ClientFactory):
'''
Factory create a RDP GUI client
'''
def buildObserver(self):
'''
build RFB observer
'''
#create client observer
client = RDPClientQt()
#create qt widget
self._w = client.getWidget()
self._w.resize(1024, 800)
self._w.setWindowTitle('rdpyclient-vnc')
self._w.show()
return client
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
'''
connection lost event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason)
reactor.stop()
app.exit()
def clientConnectionFailed(self, connector, reason):
'''
connection failed event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason)
reactor.stop()
app.exit()
if __name__ == '__main__':
#create application
app = QtGui.QApplication(sys.argv)
#add qt4 reactor
import qt4reactor
qt4reactor.install()
from twisted.internet import reactor
reactor.connectTCP(sys.argv[1], int(sys.argv[2]), RDPClientQtFactory())
reactor.runReturn()
app.exec_()
reactor.stop()

View File

@@ -0,0 +1,65 @@
'''
@author: citronneur
'''
import sys
import os
# Change path so we find rdpy
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
from PyQt4 import QtGui
from rdpy.display.qt import RFBClientQt
from rdpy.protocol.rfb import rfb
class RFBClientQtFactory(rfb.ClientFactory):
'''
Factory create a VNC GUI client
'''
def buildObserver(self):
'''
build RFB observer
'''
#create client observer
client = RFBClientQt()
#create qt widget
self._w = client.getWidget()
self._w.resize(1024, 800)
self._w.setWindowTitle('rdpyclient-vnc')
self._w.show()
return client
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
'''
connection lost event
@param connector: twisted connector use for vnc connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Lost connection : %s"%reason)
reactor.stop()
app.exit()
def clientConnectionFailed(self, connector, reason):
'''
connection failed event
@param connector: twisted connector use for vnc connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
'''
QtGui.QMessageBox.warning(self._w, "Warning", "Connection failed : %s"%reason)
reactor.stop()
app.exit()
if __name__ == '__main__':
#create application
app = QtGui.QApplication(sys.argv)
#add qt4 reactor
import qt4reactor
qt4reactor.install()
from twisted.internet import reactor
reactor.connectTCP(sys.argv[1], int(sys.argv[2]), RFBClientQtFactory())
reactor.runReturn()
app.exec_()
reactor.stop()

View File

@@ -66,4 +66,26 @@ class ErrorReportedFromPeer(Exception):
constructor with message constructor with message
@param message: message show when exception is raised @param message: message show when exception is raised
''' '''
Exception.__init__(self, message) Exception.__init__(self, message)
class DisconnectLayer(Exception):
'''
raise when try to send on unconnect layer
'''
def __init__(self, message = ""):
'''
constructor with message
@param message: message show when exception is raised
'''
Exception.__init__(self, message)
class UnRegistredObject(Exception):
'''
raise when an object is not registred in other objet
'''
def __init__(self, message = ""):
'''
constructor with message
@param message: message show when exception is raised
'''
Exception.__init__(self, message)

View File

@@ -11,6 +11,7 @@ from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPe
import gcc import gcc
import lic import lic
import caps import caps
import rdp
@ConstAttributes @ConstAttributes
@TypeAttributes(UInt16Le) @TypeAttributes(UInt16Le)
@@ -701,9 +702,10 @@ class PDU(LayerAutomata):
Global channel for mcs that handle session Global channel for mcs that handle session
identification user, licensing management, and capabilities exchange identification user, licensing management, and capabilities exchange
''' '''
def __init__(self, mode, ordersManager): def __init__(self, mode):
''' '''
Constructor Constructor
@param mode: LayerMode
''' '''
LayerAutomata.__init__(self, mode, None) LayerAutomata.__init__(self, mode, None)
#logon info send from client to server #logon info send from client to server
@@ -742,8 +744,15 @@ class PDU(LayerAutomata):
#share id between client and server #share id between client and server
self._shareId = UInt32Le() self._shareId = UInt32Le()
#rdp observer #rdp controller
self._ordersManager = ordersManager self._controller = rdp.RDPController(self)
def getController(self):
'''
Getter for RDP controller
@return: return rdp controller
'''
return self._controller
def connect(self): def connect(self):
''' '''
@@ -871,7 +880,7 @@ class PDU(LayerAutomata):
''' '''
dataPDU = self.readDataPDU(data) dataPDU = self.readDataPDU(data)
if dataPDU.shareDataHeader.pduType2 == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData._value.updateType == UpdateType.UPDATETYPE_BITMAP: if dataPDU.shareDataHeader.pduType2 == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData._value.updateType == UpdateType.UPDATETYPE_BITMAP:
self._ordersManager.recvBitmapUpdateDataPDU(dataPDU.pduData._value.updateData._value) self._controller.recvBitmapUpdateDataPDU(dataPDU.pduData._value.updateData._value)
def sendConfirmActivePDU(self): def sendConfirmActivePDU(self):

View File

@@ -5,16 +5,18 @@ from twisted.internet import protocol
import tpkt, tpdu, mcs, pdu import tpkt, tpdu, mcs, pdu
from rdpy.network.layer import LayerMode from rdpy.network.layer import LayerMode
class RDPOrdersManager(object): class RDPController(object):
''' '''
use to decode and dispatch to observer PDU messages and orders use to decode and dispatch to observer PDU messages and orders
''' '''
def __init__(self): def __init__(self, pduLayer):
''' '''
ctor ctor
''' '''
#list of observer #list of observer
self._observers = [] self._observers = []
#transport layer
self._pduLayer = pduLayer
def addObserver(self, observer): def addObserver(self, observer):
''' '''
@@ -22,6 +24,7 @@ class RDPOrdersManager(object):
@param observer: new observer to add @param observer: new observer to add
''' '''
self._observers.append(observer) self._observers.append(observer)
observer._controller = self
def recvBitmapUpdateDataPDU(self, bitmapUpdateData): def recvBitmapUpdateDataPDU(self, bitmapUpdateData):
''' '''
@@ -31,32 +34,39 @@ class RDPOrdersManager(object):
for observer in self._observers: for observer in self._observers:
#for each rectangle in update PDU #for each rectangle in update PDU
for rectangle in bitmapUpdateData.rectangles._array: for rectangle in bitmapUpdateData.rectangles._array:
observer.notifyBitmapUpdate(rectangle.destLeft.value, rectangle.destTop.value, rectangle.destRight.value, rectangle.destBottom.value, rectangle.width.value, rectangle.height.value, rectangle.bitsPerPixel.value, (rectangle.flags & pdu.BitmapFlag.BITMAP_COMPRESSION).value, rectangle.bitmapDataStream.value) observer.onBitmapUpdate(rectangle.destLeft.value, rectangle.destTop.value, rectangle.destRight.value, rectangle.destBottom.value, rectangle.width.value, rectangle.height.value, rectangle.bitsPerPixel.value, (rectangle.flags & pdu.BitmapFlag.BITMAP_COMPRESSION).value, rectangle.bitmapDataStream.value)
class ClientFactory(protocol.Factory): class ClientFactory(protocol.Factory):
''' '''
Factory of Client RDP protocol Factory of Client RDP protocol
''' '''
def __init__(self, observer):
'''
ctor
@param observer: observer use by rdp protocol to handle events must implement RDPObserver
'''
self._observer = observer
def buildProtocol(self, addr): def buildProtocol(self, addr):
''' '''
Function call from twisted and build rdp protocol stack Function call from twisted and build rdp protocol stack
@param addr: destination address
''' '''
rdpOrdersManager = RDPOrdersManager() pduLayer = pdu.PDU(LayerMode.CLIENT)
rdpOrdersManager.addObserver(self._observer) pduLayer.getController().addObserver(self.buildObserver())
return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pdu.PDU(LayerMode.CLIENT, rdpOrdersManager)))); return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pduLayer)));
def buildObserver(self):
'''
build observer use for connection
'''
pass
class RDPObserver(object):
class RDPClientObserver(object):
''' '''
class use to inform all rdp event handle by RDPY class use to inform all rdp event handle by RDPY
''' '''
def notifyBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def __init__(self):
'''
ctor
'''
self._controller = None
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
''' '''
notify bitmap update notify bitmap update
@param destLeft: xmin position @param destLeft: xmin position

View File

@@ -5,6 +5,7 @@ from twisted.internet import protocol
from rdpy.network.layer import RawLayer, LayerMode from rdpy.network.layer import RawLayer, LayerMode
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType from rdpy.network.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType
from rdpy.network.const import ConstAttributes, TypeAttributes from rdpy.network.const import ConstAttributes, TypeAttributes
from rdpy.network.error import UnRegistredObject, InvalidValue
@ConstAttributes @ConstAttributes
@TypeAttributes(String) @TypeAttributes(String)
@@ -79,7 +80,6 @@ class PixelFormat(CompositeType):
self.GreenShift = UInt8(8) self.GreenShift = UInt8(8)
self.BlueShift = UInt8(0) self.BlueShift = UInt8(0)
self.padding = (UInt16Be(), UInt8()) self.padding = (UInt16Be(), UInt8())
class ServerInit(CompositeType): class ServerInit(CompositeType):
''' '''
@@ -121,21 +121,21 @@ class KeyEvent(CompositeType):
''' '''
key event structure message key event structure message
''' '''
def __init__(self, downFlag = False, key = 0): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.downFlag = UInt8(downFlag) self.downFlag = UInt8(False)
self.padding = UInt16Be() self.padding = UInt16Be()
self.key = UInt32Be(key) self.key = UInt32Be()
class PointerEvent(CompositeType): class PointerEvent(CompositeType):
''' '''
pointer event structure message pointer event structure message
''' '''
def __init__(self, mask = 0, x = 0, y = 0): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.mask = UInt8(mask) self.mask = UInt8()
self.x = UInt16Be(x) self.x = UInt16Be()
self.y = UInt16Be(y) self.y = UInt16Be()
class ClientCutText(CompositeType): class ClientCutText(CompositeType):
''' '''
@@ -152,9 +152,10 @@ class Rfb(RawLayer):
implements rfb protocol implements rfb protocol
''' '''
def __init__(self, mode, ordersManager): def __init__(self, mode):
''' '''
constructor constructor
@param mode: LayerMode client or server
''' '''
RawLayer.__init__(self, mode) RawLayer.__init__(self, mode)
#usefull for rfb protocol #usefull for rfb protocol
@@ -177,14 +178,14 @@ class Rfb(RawLayer):
#current rectangle header #current rectangle header
self._currentRect = Rectangle() self._currentRect = Rectangle()
#client or server adaptor #client or server adaptor
self._ordersManager = ordersManager self._controller = RFBController(self)
def addObserver(self, observer): def getController(self):
''' '''
add observer for input/ouput events Getter for controller
@param observer: RfbObserver interface implementation @return: RFBController use by rfb layer
''' '''
self._observer.append(observer) return self._controller
def expectWithHeader(self, expectedHeaderLen, callbackBody): def expectWithHeader(self, expectedHeaderLen, callbackBody):
''' '''
@@ -355,7 +356,7 @@ class Rfb(RawLayer):
''' '''
read body of rect read body of rect
''' '''
self._ordersManager.recvRectangle(self._currentRect, self._pixelFormat, data.getvalue()) self._controller.recvRectangle(self._currentRect, self._pixelFormat, data.getvalue())
self._nbRect = self._nbRect - 1 self._nbRect = self._nbRect - 1
#if there is another rect to read #if there is another rect to read
@@ -392,17 +393,19 @@ class Rfb(RawLayer):
''' '''
self.send((ClientToServerMessages.FRAME_BUFFER_UPDATE_REQUEST, FrameBufferUpdateRequest(incremental, x, y, width, height))) self.send((ClientToServerMessages.FRAME_BUFFER_UPDATE_REQUEST, FrameBufferUpdateRequest(incremental, x, y, width, height)))
def sendKeyEvent(self, downFlag, key): def sendKeyEvent(self, keyEvent):
''' '''
write key event packet write key event packet
@param keyEvent: KeyEvent struct to send
''' '''
self.send((ClientToServerMessages.KEY_EVENT, KeyEvent(downFlag, key))) self.send((ClientToServerMessages.KEY_EVENT, keyEvent))
def sendPointerEvent(self, mask, x, y): def sendPointerEvent(self, pointerEvent):
''' '''
write pointer event packet write pointer event packet
@param pointerEvent: PointerEvent struct use
''' '''
self.send((ClientToServerMessages.POINTER_EVENT, PointerEvent(mask, x, y))) self.send((ClientToServerMessages.POINTER_EVENT, pointerEvent))
def sendClientCutText(self, text): def sendClientCutText(self, text):
''' '''
@@ -410,15 +413,18 @@ class Rfb(RawLayer):
''' '''
self.send((ClientToServerMessages.CUT_TEXT, ClientCutText(text))) self.send((ClientToServerMessages.CUT_TEXT, ClientCutText(text)))
class RFBOrderManager(object): class RFBController(object):
''' '''
class use to manage rfb order and dispatch throw observers class use to manage rfb order and dispatch throw observers
''' '''
def __init__(self): def __init__(self, rfbLayer):
''' '''
ctor ctor
@param rfbLayer: network layer
''' '''
self._observers = [] self._observers = []
#rfb layer to send client orders
self._rfbLayer = rfbLayer
def addObserver(self, observer): def addObserver(self, observer):
''' '''
@@ -426,44 +432,111 @@ class RFBOrderManager(object):
@param observer: new observer @param observer: new observer
''' '''
self._observers.append(observer) self._observers.append(observer)
observer._controller = self
def recvRectangle(self, rectangle, pixelFormat, data): def recvRectangle(self, rectangle, pixelFormat, data):
''' '''
receive rectangle order receive rectangle order
Main update order type
@param rectangle: Rectangle type header of packet @param rectangle: Rectangle type header of packet
@param pixelFormat: pixelFormat struct of current session @param pixelFormat: pixelFormat struct of current session
@param data: image data @param data: image data
''' '''
for observer in self._observers: for observer in self._observers:
observer.notifyFramebufferUpdate(rectangle.width.value, rectangle.height.value, rectangle.x.value, rectangle.y.value, self._pixelFormat, rectangle.encoding, data) observer.onUpdate(rectangle.width.value, rectangle.height.value, rectangle.x.value, rectangle.y.value, pixelFormat, rectangle.encoding, data)
def sendKeyEvent(self, isDown, key):
'''
send a key event throw RFB protocol
@param isDown: boolean notify if key is pressed or not (True if key is pressed)
@param key: ascii code of key
'''
try:
event = KeyEvent()
event.downFlag.value = isDown
event.key.value = key
self._rfbLayer.sendKeyEvent(event)
except InvalidValue:
print "Try to send an invalid key event"
def sendPointerEvent(self, mask, x, y):
'''
Send an pointer event throw RFB protocol
@param mask: mask of button if button 1 and 3 are pressed then mask is 00000101
@param x: x coordinate of mouse pointer
@param y: y pointer of mouse pointer
'''
try:
event = PointerEvent()
event.mask.value = mask
event.x.value = x
event.y.value = y
self._rfbLayer.sendPointerEvent(event)
except InvalidValue:
print "Try to send an invalid pointer event"
class ClientFactory(protocol.Factory): class ClientFactory(protocol.Factory):
''' '''
Factory of RFB protocol Factory of RFB protocol
''' '''
def __init__(self, observer):
'''
save mode and adapter
@param adapter: graphic client adapter
'''
self._observer = observer
def buildProtocol(self, addr): def buildProtocol(self, addr):
''' '''
function call by twisted on connection function call by twisted on connection
@param addr: adress where client try to connect @param addr: address where client try to connect
''' '''
orderManager = RFBOrderManager() protocol = Rfb(LayerMode.CLIENT)
orderManager.addObserver(self._observer) protocol.getController().addObserver(self.buildObserver())
protocol = Rfb(LayerMode.CLIENT, orderManager)
self._observer.setProtocol(protocol)
return protocol return protocol
def buildObserver(self):
'''
build an RFB observer object
'''
pass
class RfbObserver(object): class RFBClientObserver(object):
''' '''
Rfb protocol obserser RFB client protocol observer
''' '''
def notifyFramebufferUpdate(self, width, height, x, y, pixelFormat, encoding, data): def __init__(self):
'''
ctor
'''
self._controller = None
def keyEvent(self, isPressed, key):
'''
send a key event
@param isPressed: state of key
@param key: ascii code of key
'''
if self._controller is None:
raise UnRegistredObject("RFBClientObserver need to be registred to a RFBController object")
self._controller.sendKeyEvent(isPressed, key)
def mouseEvent(self, button, x, y):
'''
send a mouse event to RFB Layer
@param button: button number which is pressed (0,1,2,3,4,5,6,7,8)
@param x: x coordinate of mouse pointer
@param y: y coordinate of mouse pointer
'''
if self._controller is None:
raise UnRegistredObject("RFBClientObserver need to be registred to a RFBController object")
mask = 0
if button == 1:
mask = 1
elif button > 1:
mask = 1 << button - 1
self._controller.sendPointerEvent(mask, x, y)
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
''' '''
recv framebuffer update recv framebuffer update
@param width : width of image @param width : width of image
@@ -475,10 +548,3 @@ class RfbObserver(object):
@param data : in respect of dataFormat and pixelFormat @param data : in respect of dataFormat and pixelFormat
''' '''
pass pass
def setProtocol(self, rfbLayer):
'''
call when observer is added to an rfb layer
@param: rfbLayer layer inform the observer
'''
pass