xen-vtx-unstable
annotate tools/python/xen/xend/server/controller.py @ 2397:daf585a98004
bitkeeper revision 1.1159.1.113 (4136e90fOr8_LyqJ85kTqL-uFrO_xw)
Remove debug prints and turn logging to stderr off by default.
Remove debug prints and turn logging to stderr off by default.
author | mjw@wray-m-3.hpl.hp.com |
---|---|
date | Thu Sep 02 09:34:07 2004 +0000 (2004-09-02) |
parents | 5f62249f3584 |
children | 03bd2991dbd4 |
rev | line source |
---|---|
mjw@1654 | 1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com> |
mjw@1719 | 2 """General support for controllers, which handle devices |
mjw@1719 | 3 for a domain. |
mjw@1719 | 4 """ |
mjw@1654 | 5 |
mjw@1623 | 6 from twisted.internet import defer |
mjw@1721 | 7 #defer.Deferred.debug = 1 |
mjw@1623 | 8 |
mjw@1623 | 9 import channel |
mjw@1719 | 10 from messages import msgTypeName, printMsg |
mjw@1623 | 11 |
mjw@2397 | 12 DEBUG = 0 |
mjw@1677 | 13 |
mjw@1677 | 14 class Responder: |
mjw@1719 | 15 """Handler for a response to a message with a specified id. |
mjw@1677 | 16 """ |
mjw@1677 | 17 |
mjw@1677 | 18 def __init__(self, mid, deferred): |
mjw@1677 | 19 """Create a responder. |
mjw@1677 | 20 |
mjw@1719 | 21 @param mid: message id of response to handle |
mjw@1719 | 22 @type mid: int |
mjw@1719 | 23 @param deferred: deferred object holding the callbacks |
mjw@1719 | 24 @type deferred: Deferred |
mjw@1677 | 25 """ |
mjw@1677 | 26 self.mid = mid |
mjw@1677 | 27 self.deferred = deferred |
mjw@1677 | 28 |
mjw@1677 | 29 def responseReceived(self, msg): |
mjw@1719 | 30 """Entry point called when a response message with the right id arrives. |
mjw@1719 | 31 Calls callback on I{self.deferred} with the message. |
mjw@1719 | 32 |
mjw@1719 | 33 @param msg: response message |
mjw@1719 | 34 @type msg: xu message |
mjw@1719 | 35 """ |
mjw@1677 | 36 if self.deferred.called: return |
mjw@1677 | 37 self.deferred.callback(msg) |
mjw@1677 | 38 |
mjw@1677 | 39 def error(self, err): |
mjw@1719 | 40 """Entry point called when there has been an error. |
mjw@1719 | 41 Calls errback on I{self.deferred} with the error. |
mjw@1719 | 42 |
mjw@1719 | 43 @param err: error |
mjw@1719 | 44 @type err: Exception |
mjw@1719 | 45 """ |
mjw@1677 | 46 if self.deferred.called: return |
mjw@1677 | 47 self.deferred.errback(err) |
mjw@1677 | 48 |
mjw@1623 | 49 class CtrlMsgRcvr: |
mjw@1623 | 50 """Abstract class for things that deal with a control interface to a domain. |
mjw@1719 | 51 Once I{registerChannel} has been called, our message types are registered |
mjw@1719 | 52 with the channel to the domain. The channel will call I{requestReceived} |
mjw@1719 | 53 when a request arrives, or I{responseReceived} when a response arrives, |
mjw@1719 | 54 if they have one of our message types. |
mjw@1654 | 55 |
mjw@1719 | 56 @ivar dom: the domain we are a control interface for |
mjw@1719 | 57 @type dom: int |
mjw@1719 | 58 @ivar majorTypes: major message types we are interested in |
mjw@2224 | 59 @type majorTypes: {int:{int:method}} |
mjw@1719 | 60 @ivar timeout: timeout (in seconds) for message handlers |
mjw@1719 | 61 @type timeout: int |
mjw@1654 | 62 |
mjw@1719 | 63 @ivar channel: channel to the domain |
mjw@1719 | 64 @type channel: Channel |
mjw@1719 | 65 @ivar idx: channel index |
mjw@1719 | 66 @ivar idx: string |
mjw@1719 | 67 @ivar responders: table of message response handlers |
mjw@1719 | 68 @type responders: {int:Responder} |
mjw@1623 | 69 """ |
mjw@1623 | 70 |
mjw@1623 | 71 def __init__(self): |
mjw@1623 | 72 self.channelFactory = channel.channelFactory() |
mjw@2224 | 73 self.majorTypes = {} |
mjw@1623 | 74 self.dom = None |
mjw@1623 | 75 self.channel = None |
mjw@1623 | 76 self.idx = None |
mjw@1728 | 77 self.responders = {} |
mjw@1677 | 78 self.timeout = 10 |
mjw@1677 | 79 |
mjw@1677 | 80 def setTimeout(self, timeout): |
mjw@1677 | 81 self.timeout = timeout |
mjw@1623 | 82 |
mjw@2224 | 83 def getMethod(self, type, subtype): |
mjw@2224 | 84 """Get the method for a type and subtype. |
mjw@2224 | 85 |
mjw@2224 | 86 @param type: major message type |
mjw@2224 | 87 @param subtype: minor message type |
mjw@2224 | 88 @return: method or None |
mjw@2224 | 89 """ |
mjw@2224 | 90 method = None |
mjw@2224 | 91 subtypes = self.majorTypes.get(type) |
mjw@2224 | 92 if subtypes: |
mjw@2224 | 93 method = subtypes.get(subtype) |
mjw@2224 | 94 return method |
mjw@2224 | 95 |
mjw@2224 | 96 def addMethod(self, type, subtype, method): |
mjw@2224 | 97 """Add a method to handle a message type and subtype. |
mjw@2224 | 98 |
mjw@2224 | 99 @param type: major message type |
mjw@2224 | 100 @param subtype: minor message type |
mjw@2224 | 101 @param method: method |
mjw@2224 | 102 """ |
mjw@2224 | 103 subtypes = self.majorTypes.get(type) |
mjw@2224 | 104 if not subtypes: |
mjw@2224 | 105 subtypes = {} |
mjw@2224 | 106 self.majorTypes[type] = subtypes |
mjw@2224 | 107 subtypes[subtype] = method |
mjw@2224 | 108 |
mjw@2224 | 109 def getMajorTypes(self): |
mjw@2224 | 110 """Get the list of major message types handled. |
mjw@2224 | 111 """ |
mjw@2224 | 112 return self.majorTypes.keys() |
mjw@2224 | 113 |
mjw@1623 | 114 def requestReceived(self, msg, type, subtype): |
mjw@1719 | 115 """Dispatch a request message to handlers. |
mjw@1719 | 116 Called by the channel for requests with one of our types. |
mjw@1654 | 117 |
mjw@1719 | 118 @param msg: message |
mjw@1719 | 119 @type msg: xu message |
mjw@1719 | 120 @param type: major message type |
mjw@1719 | 121 @type type: int |
mjw@1719 | 122 @param subtype: minor message type |
mjw@1719 | 123 @type subtype: int |
mjw@1654 | 124 """ |
mjw@1677 | 125 if DEBUG: |
mjw@1719 | 126 print 'requestReceived>', |
mjw@1719 | 127 printMsg(msg, all=1) |
mjw@2265 | 128 responded = 0 |
mjw@2224 | 129 method = self.getMethod(type, subtype) |
mjw@1623 | 130 if method: |
mjw@2265 | 131 responded = method(msg, 1) |
mjw@1677 | 132 elif DEBUG: |
mjw@1623 | 133 print ('requestReceived> No handler: Message type %s %d:%d' |
mjw@1623 | 134 % (msgTypeName(type, subtype), type, subtype)), self |
mjw@2265 | 135 return responded |
mjw@1623 | 136 |
mjw@1623 | 137 def responseReceived(self, msg, type, subtype): |
mjw@1654 | 138 """Dispatch a response to handlers. |
mjw@1719 | 139 Called by the channel for responses with one of our types. |
mjw@1719 | 140 |
mjw@1719 | 141 First looks for a message responder for the message's id. |
mjw@1719 | 142 See L{callResponders}, L{addResponder}. |
mjw@1719 | 143 If there is no responder, looks for a message handler for |
mjw@1719 | 144 the message type/subtype. |
mjw@1654 | 145 |
mjw@1719 | 146 @param msg: message |
mjw@1719 | 147 @type msg: xu message |
mjw@1719 | 148 @param type: major message type |
mjw@1719 | 149 @type type: int |
mjw@1719 | 150 @param subtype: minor message type |
mjw@1719 | 151 @type subtype: int |
mjw@1654 | 152 """ |
mjw@1677 | 153 if DEBUG: |
mjw@1719 | 154 print 'responseReceived>', |
mjw@1719 | 155 printMsg(msg, all=1) |
mjw@1677 | 156 if self.callResponders(msg): |
mjw@1677 | 157 return |
mjw@2224 | 158 method = self.getMethod(type, subtype) |
mjw@1623 | 159 if method: |
mjw@1623 | 160 method(msg, 0) |
mjw@1677 | 161 elif DEBUG: |
mjw@1623 | 162 print ('responseReceived> No handler: Message type %s %d:%d' |
mjw@1623 | 163 % (msgTypeName(type, subtype), type, subtype)), self |
mjw@1623 | 164 |
mjw@1677 | 165 def addResponder(self, mid, deferred): |
mjw@1677 | 166 """Add a responder for a message id. |
mjw@1719 | 167 The I{deferred} is called with callback(msg) when a response |
mjw@1728 | 168 with message id I{mid} arrives. |
mjw@1677 | 169 |
mjw@1719 | 170 Responders have a timeout set and I{deferred} will error |
mjw@1719 | 171 on expiry. |
mjw@1677 | 172 |
mjw@1719 | 173 @param mid: message id of response expected |
mjw@1719 | 174 @type mid: int |
mjw@1719 | 175 @param deferred: handler for the response |
mjw@1719 | 176 @type deferred: Deferred |
mjw@1719 | 177 @return: responder |
mjw@1719 | 178 @rtype: Responder |
mjw@1677 | 179 """ |
mjw@1728 | 180 resp = Responder(mid, deferred) |
mjw@1728 | 181 self.responders[resp.mid] = resp |
mjw@1677 | 182 if self.timeout > 0: |
mjw@1677 | 183 deferred.setTimeout(self.timeout) |
mjw@1677 | 184 return resp |
mjw@1677 | 185 |
mjw@1677 | 186 def callResponders(self, msg): |
mjw@1677 | 187 """Call any waiting responders for a response message. |
mjw@1719 | 188 Looks for a responder registered for the message's id. |
mjw@1719 | 189 See L{addResponder}. |
mjw@1677 | 190 |
mjw@1719 | 191 @param msg: response message |
mjw@1719 | 192 @type msg: xu message |
mjw@1719 | 193 @return: 1 if there was a responder for the message, 0 otherwise |
mjw@1719 | 194 @rtype : bool |
mjw@1677 | 195 """ |
mjw@1677 | 196 hdr = msg.get_header() |
mjw@1677 | 197 mid = hdr['id'] |
mjw@1677 | 198 handled = 0 |
mjw@1728 | 199 resp = self.responders.get(mid) |
mjw@1728 | 200 if resp: |
mjw@1728 | 201 handled = 1 |
mjw@1728 | 202 resp.responseReceived(msg) |
mjw@1728 | 203 del self.responders[mid] |
mjw@1728 | 204 # Clean up called responders. |
mjw@1728 | 205 for resp in self.responders.values(): |
mjw@1728 | 206 if resp.deferred.called: |
mjw@1728 | 207 del self.responders[resp.mid] |
mjw@1677 | 208 return handled |
mjw@1677 | 209 |
mjw@1623 | 210 def lostChannel(self): |
mjw@1654 | 211 """Called when the channel to the domain is lost. |
mjw@1654 | 212 """ |
mjw@1623 | 213 pass |
mjw@1623 | 214 |
mjw@1623 | 215 def registerChannel(self): |
mjw@1654 | 216 """Register interest in our major message types with the |
mjw@1719 | 217 channel to our domain. Once we have registered, the channel |
mjw@1719 | 218 will call requestReceived or responseReceived for our messages. |
mjw@1654 | 219 """ |
mjw@1623 | 220 self.channel = self.channelFactory.domChannel(self.dom) |
mjw@1623 | 221 self.idx = self.channel.getIndex() |
mjw@1623 | 222 if self.majorTypes: |
mjw@2224 | 223 self.channel.registerDevice(self.getMajorTypes(), self) |
mjw@1623 | 224 |
mjw@1623 | 225 def deregisterChannel(self): |
mjw@1654 | 226 """Deregister interest in our major message types with the |
mjw@1719 | 227 channel to our domain. After this the channel won't call |
mjw@1719 | 228 us any more. |
mjw@1654 | 229 """ |
mjw@1623 | 230 if self.channel: |
mjw@1623 | 231 self.channel.deregisterDevice(self) |
mjw@1893 | 232 self.channel = None |
mjw@1623 | 233 |
mjw@1623 | 234 def produceRequests(self): |
mjw@1654 | 235 """Produce any queued requests. |
mjw@1654 | 236 |
mjw@1719 | 237 @return: number produced |
mjw@1719 | 238 @rtype: int |
mjw@1654 | 239 """ |
mjw@1623 | 240 return 0 |
mjw@1623 | 241 |
mjw@1677 | 242 def writeRequest(self, msg, response=None): |
mjw@1654 | 243 """Write a request to the channel. |
mjw@1677 | 244 |
mjw@1719 | 245 @param msg: request message |
mjw@1719 | 246 @type msg: xu message |
mjw@1719 | 247 @param response: response handler |
mjw@1719 | 248 @type response: Deferred |
mjw@1654 | 249 """ |
mjw@1623 | 250 if self.channel: |
mjw@1719 | 251 if DEBUG: |
mjw@1719 | 252 print 'CtrlMsgRcvr>writeRequest>', |
mjw@1719 | 253 printMsg(msg, all=1) |
mjw@1677 | 254 if response: |
mjw@1677 | 255 self.addResponder(msg.get_header()['id'], response) |
mjw@1623 | 256 self.channel.writeRequest(msg) |
mjw@1623 | 257 else: |
mjw@1623 | 258 print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self |
mjw@1623 | 259 |
mjw@1623 | 260 def writeResponse(self, msg): |
mjw@1719 | 261 """Write a response to the channel. This acknowledges |
mjw@1719 | 262 a request message. |
mjw@1719 | 263 |
mjw@1719 | 264 @param msg: message |
mjw@1719 | 265 @type msg: xu message |
mjw@1654 | 266 """ |
mjw@1623 | 267 if self.channel: |
mjw@1719 | 268 if DEBUG: |
mjw@1719 | 269 print 'CtrlMsgRcvr>writeResponse>', |
mjw@1719 | 270 printMsg(msg, all=0) |
mjw@1623 | 271 self.channel.writeResponse(msg) |
mjw@1623 | 272 else: |
mjw@1623 | 273 print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self |
mjw@1623 | 274 |
mjw@2225 | 275 class ControllerFactory: |
mjw@1719 | 276 """Abstract class for factories creating controllers for a domain. |
mjw@2332 | 277 Maintains a table of controllers. |
mjw@1654 | 278 |
mjw@2332 | 279 @ivar controllers: mapping of index to controller instance |
mjw@2332 | 280 @type controllers: {String: Controller} |
mjw@1719 | 281 @ivar dom: domain |
mjw@1719 | 282 @type dom: int |
mjw@1623 | 283 """ |
mjw@1623 | 284 |
mjw@1623 | 285 def __init__(self): |
mjw@2332 | 286 self.controllers = {} |
mjw@1623 | 287 |
mjw@2332 | 288 def addController(self, controller): |
mjw@1654 | 289 """Add a controller instance (under its index). |
mjw@1654 | 290 """ |
mjw@2332 | 291 self.controllers[controller.idx] = controller |
mjw@1623 | 292 |
mjw@2332 | 293 def getControllers(self): |
mjw@2332 | 294 """Get a list of all controllers. |
mjw@1654 | 295 """ |
mjw@2332 | 296 return self.controllers.values() |
mjw@1623 | 297 |
mjw@2332 | 298 def getControllerByIndex(self, idx): |
mjw@2332 | 299 """Get a controller from its index. |
mjw@1654 | 300 """ |
mjw@2332 | 301 return self.controllers.get(idx) |
mjw@1623 | 302 |
mjw@2332 | 303 def getControllerByDom(self, dom): |
mjw@2332 | 304 """Get the controller for the given domain. |
mjw@2185 | 305 |
mjw@2185 | 306 @param dom: domain id |
mjw@2185 | 307 @type dom: int |
mjw@2185 | 308 @return: controller or None |
mjw@1654 | 309 """ |
mjw@2332 | 310 for inst in self.controllers.values(): |
mjw@1623 | 311 if inst.dom == dom: |
mjw@1623 | 312 return inst |
mjw@1623 | 313 return None |
mjw@1623 | 314 |
mjw@2332 | 315 def getController(self, dom): |
mjw@2332 | 316 """Create or find the controller for a domain. |
mjw@2185 | 317 |
mjw@2332 | 318 @param dom: domain |
mjw@2332 | 319 @return: controller |
mjw@1654 | 320 """ |
mjw@2332 | 321 ctrl = self.getControllerByDom(dom) |
mjw@2332 | 322 if ctrl is None: |
mjw@2332 | 323 ctrl = self.createController(dom) |
mjw@2332 | 324 self.addController(ctrl) |
mjw@2332 | 325 return ctrl |
mjw@2332 | 326 |
mjw@2332 | 327 def createController(self, dom): |
mjw@2332 | 328 """Create a controller. Define in a subclass. |
mjw@1719 | 329 |
mjw@1719 | 330 @param dom: domain |
mjw@1719 | 331 @type dom: int |
mjw@2185 | 332 @return: controller instance |
mjw@2185 | 333 @rtype: Controller (or subclass) |
mjw@1654 | 334 """ |
mjw@1623 | 335 raise NotImplementedError() |
mjw@1623 | 336 |
mjw@2332 | 337 def delController(self, controller): |
mjw@2332 | 338 """Delete a controller instance from the table. |
mjw@2332 | 339 |
mjw@2332 | 340 @param controller: controller instance |
mjw@2332 | 341 """ |
mjw@2332 | 342 if controller.idx in self.controllers: |
mjw@2332 | 343 del self.controllers[controller.idx] |
mjw@2332 | 344 |
mjw@2332 | 345 def controllerClosed(self, controller): |
mjw@2332 | 346 """Callback called when a controller is closed (usually by the controller). |
mjw@2185 | 347 |
mjw@2332 | 348 @param controller: controller instance |
mjw@1654 | 349 """ |
mjw@2332 | 350 self.delController(controller) |
mjw@1623 | 351 |
mjw@1623 | 352 class Controller(CtrlMsgRcvr): |
mjw@1623 | 353 """Abstract class for a device controller attached to a domain. |
mjw@2185 | 354 |
mjw@2185 | 355 @ivar factory: controller factory |
mjw@2185 | 356 @type factory: ControllerFactory |
mjw@2185 | 357 @ivar dom: domain |
mjw@2185 | 358 @type dom: int |
mjw@2185 | 359 @ivar channel: channel to the domain |
mjw@2185 | 360 @type channel: Channel |
mjw@2185 | 361 @ivar idx: channel index |
mjw@2185 | 362 @type idx: String |
mjw@1623 | 363 """ |
mjw@1623 | 364 |
mjw@1623 | 365 def __init__(self, factory, dom): |
mjw@1623 | 366 CtrlMsgRcvr.__init__(self) |
mjw@1623 | 367 self.factory = factory |
mjw@1623 | 368 self.dom = int(dom) |
mjw@1623 | 369 self.channel = None |
mjw@1623 | 370 self.idx = None |
mjw@1623 | 371 |
mjw@1623 | 372 def close(self): |
mjw@1654 | 373 """Close the controller. |
mjw@1654 | 374 """ |
mjw@1623 | 375 self.lostChannel() |
mjw@1623 | 376 |
mjw@1623 | 377 def lostChannel(self): |
mjw@1654 | 378 """The controller channel has been lost. |
mjw@1654 | 379 """ |
mjw@1664 | 380 self.deregisterChannel() |
mjw@2332 | 381 self.factory.controllerClosed(self) |
mjw@2332 | 382 |
mjw@2332 | 383 class SplitControllerFactory(ControllerFactory): |
mjw@2332 | 384 """Abstract class for factories creating split controllers for a domain. |
mjw@2332 | 385 Maintains a table of backend controllers. |
mjw@2332 | 386 """ |
mjw@2332 | 387 |
mjw@2332 | 388 def __init__(self): |
mjw@2332 | 389 ControllerFactory.__init__(self) |
mjw@2332 | 390 self.backendControllers = {} |
mjw@2332 | 391 |
mjw@2332 | 392 def getBackendControllers(self): |
mjw@2332 | 393 return self.backendControllers.values() |
mjw@2332 | 394 |
mjw@2332 | 395 def getBackendControllerByDomain(self, dom): |
mjw@2332 | 396 """Get the backend controller for a domain if there is one. |
mjw@2332 | 397 |
mjw@2332 | 398 @param dom: backend domain |
mjw@2332 | 399 @return: backend controller |
mjw@2332 | 400 """ |
mjw@2332 | 401 return self.backendControllers.get(dom) |
mjw@2332 | 402 |
mjw@2332 | 403 def getBackendController(self, dom): |
mjw@2332 | 404 """Get the backend controller for a domain, creating |
mjw@2332 | 405 if necessary. |
mjw@1623 | 406 |
mjw@2332 | 407 @param dom: backend domain |
mjw@2332 | 408 @return: backend controller |
mjw@2332 | 409 """ |
mjw@2332 | 410 b = self.getBackendControllerByDomain(dom) |
mjw@2332 | 411 if b is None: |
mjw@2332 | 412 b = self.createBackendController(dom) |
mjw@2332 | 413 self.backendControllers[b.dom] = b |
mjw@2332 | 414 return b |
mjw@2332 | 415 |
mjw@2332 | 416 def createBackendController(self, dom): |
mjw@2332 | 417 """Create a backend controller. Define in a subclass. |
mjw@2332 | 418 |
mjw@2332 | 419 @param dom: backend domain |
mjw@2332 | 420 @return: backend controller |
mjw@2332 | 421 """ |
mjw@2332 | 422 raise NotImplementedError() |
mjw@2332 | 423 |
mjw@2332 | 424 def delBackendController(self, ctrlr): |
mjw@2332 | 425 """Remove a backend controller. |
mjw@2332 | 426 |
mjw@2332 | 427 @param ctrlr: backend controller |
mjw@2332 | 428 """ |
mjw@2332 | 429 if ctrlr.dom in self.backendControllers: |
mjw@2332 | 430 del self.backendControllers[ctrlr.dom] |
mjw@2332 | 431 |
mjw@2332 | 432 def backendControllerClosed(self, ctrlr): |
mjw@2332 | 433 """Callback called when a backend is closed. |
mjw@2332 | 434 """ |
mjw@2332 | 435 self.delBackendController(ctrlr) |
mjw@2332 | 436 |
mjw@2332 | 437 def createBackendInterface(self, ctrl, dom, handle): |
mjw@2332 | 438 """Create a backend interface. Define in a subclass. |
mjw@2332 | 439 |
mjw@2332 | 440 @param ctrl: frontend controller |
mjw@2332 | 441 @param dom: backend domain |
mjw@2332 | 442 @return: backend interface |
mjw@2332 | 443 """ |
mjw@2332 | 444 raise NotImplementedError() |
mjw@2332 | 445 |
mjw@2332 | 446 class BackendController(Controller): |
mjw@2267 | 447 """Abstract class for a backend device controller attached to a domain. |
mjw@2267 | 448 |
mjw@2332 | 449 @ivar factory: backend controller factory |
mjw@2332 | 450 @type factory: BackendControllerFactory |
mjw@2332 | 451 @ivar dom: backend domain |
mjw@2267 | 452 @type dom: int |
mjw@2267 | 453 @ivar channel: channel to the domain |
mjw@2267 | 454 @type channel: Channel |
mjw@2267 | 455 """ |
mjw@2267 | 456 |
mjw@2225 | 457 |
mjw@2332 | 458 def __init__(self, factory, dom): |
mjw@2267 | 459 CtrlMsgRcvr.__init__(self) |
mjw@2332 | 460 self.factory = factory |
mjw@2267 | 461 self.dom = int(dom) |
mjw@2267 | 462 self.channel = None |
mjw@2332 | 463 self.backendInterfaces = {} |
mjw@2267 | 464 |
mjw@2267 | 465 def close(self): |
mjw@2267 | 466 self.lostChannel() |
mjw@2225 | 467 |
mjw@2267 | 468 def lostChannel(self): |
mjw@2267 | 469 self.deregisterChannel() |
mjw@2332 | 470 self.backend.backendClosed(self) |
mjw@2332 | 471 |
mjw@2332 | 472 def registerInterface(self, intf): |
mjw@2332 | 473 key = intf.getInterfaceKey() |
mjw@2332 | 474 self.backendInterfaces[key] = intf |
mjw@2332 | 475 |
mjw@2332 | 476 def deregisterInterface(self, intf): |
mjw@2332 | 477 key = intf.getInterfaceKey() |
mjw@2332 | 478 if key in self.backendInterfaces: |
mjw@2332 | 479 del self.backendInterfaces[key] |
mjw@2332 | 480 |
mjw@2332 | 481 def getInterface(self, dom, handle): |
mjw@2332 | 482 key = (dom, handle) |
mjw@2332 | 483 return self.backendInterfaces.get(key) |
mjw@2332 | 484 |
mjw@2332 | 485 |
mjw@2332 | 486 def createBackendInterface(self, ctrl, dom, handle): |
mjw@2332 | 487 """Create a backend interface. Define in a subclass. |
mjw@2332 | 488 |
mjw@2332 | 489 @param ctrl: controller |
mjw@2332 | 490 @param dom: backend domain |
mjw@2332 | 491 @param handle: backend handle |
mjw@2332 | 492 """ |
mjw@2332 | 493 raise NotImplementedError() |
mjw@2332 | 494 |
mjw@2332 | 495 |
mjw@2332 | 496 class BackendInterface: |
mjw@2332 | 497 """Abstract class for a domain's interface onto a backend controller. |
mjw@2332 | 498 """ |
mjw@2332 | 499 |
mjw@2332 | 500 def __init__(self, controller, dom, handle): |
mjw@2332 | 501 """ |
mjw@2332 | 502 |
mjw@2332 | 503 @param controller: front-end controller |
mjw@2332 | 504 @param dom: back-end domain |
mjw@2332 | 505 @param handle: back-end interface handle |
mjw@2332 | 506 """ |
mjw@2332 | 507 self.factory = controller.factory |
mjw@2332 | 508 self.controller = controller |
mjw@2332 | 509 self.dom = int(dom) |
mjw@2332 | 510 self.handle = handle |
mjw@2332 | 511 self.backend = self.getBackendController() |
mjw@2332 | 512 |
mjw@2332 | 513 def registerInterface(self): |
mjw@2332 | 514 self.backend.registerInterface(self) |
mjw@2332 | 515 |
mjw@2332 | 516 def getInterfaceKey(self): |
mjw@2332 | 517 return (self.controller.dom, self.handle) |
mjw@2332 | 518 |
mjw@2332 | 519 def getBackendController(self): |
mjw@2332 | 520 return self.factory.getBackendController(self.dom) |
mjw@2332 | 521 |
mjw@2332 | 522 def writeRequest(self, msg, response=None): |
mjw@2332 | 523 return self.backend.writeRequest(msg, response=response) |
mjw@2332 | 524 |
mjw@2332 | 525 def close(self): |
mjw@2332 | 526 self.backend.deregisterInterface(self) |
mjw@2332 | 527 self.controller.backendInterfaceClosed(self) |
mjw@2267 | 528 |
mjw@2267 | 529 class SplitController(Controller): |
mjw@2267 | 530 """Abstract class for a device controller attached to a domain. |
mjw@2332 | 531 A SplitController manages a BackendInterface for each backend domain |
mjw@2267 | 532 it has at least one device for. |
mjw@2267 | 533 """ |
mjw@2225 | 534 |
mjw@2267 | 535 def __init__(self, factory, dom): |
mjw@2267 | 536 Controller.__init__(self, factory, dom) |
mjw@2332 | 537 self.backendInterfaces = {} |
mjw@2267 | 538 self.backendHandle = 0 |
mjw@2225 | 539 |
mjw@2332 | 540 def getBackendInterfaces(self): |
mjw@2332 | 541 return self.backendInterfaces.values() |
mjw@2267 | 542 |
mjw@2332 | 543 def getBackendInterfaceByHandle(self, handle): |
mjw@2332 | 544 for b in self.getBackendInterfaces(): |
mjw@2267 | 545 if b.handle == handle: |
mjw@2267 | 546 return b |
mjw@2267 | 547 return None |
mjw@2267 | 548 |
mjw@2332 | 549 def getBackendInterfaceByDomain(self, dom): |
mjw@2332 | 550 return self.backendInterfaces.get(dom) |
mjw@2267 | 551 |
mjw@2332 | 552 def getBackendInterface(self, dom): |
mjw@2332 | 553 """Get the backend interface for a domain. |
mjw@2225 | 554 |
mjw@2225 | 555 @param dom: domain |
mjw@2225 | 556 @return: backend controller |
mjw@2225 | 557 """ |
mjw@2332 | 558 b = self.getBackendInterfaceByDomain(dom) |
mjw@2267 | 559 if b is None: |
mjw@2267 | 560 handle = self.backendHandle |
mjw@2267 | 561 self.backendHandle += 1 |
mjw@2332 | 562 b = self.factory.createBackendInterface(self, dom, handle) |
mjw@2332 | 563 b.registerInterface() |
mjw@2332 | 564 self.backendInterfaces[b.dom] = b |
mjw@2267 | 565 return b |
mjw@2225 | 566 |
mjw@2332 | 567 def delBackendInterface(self, ctrlr): |
mjw@2225 | 568 """Remove a backend controller. |
mjw@2225 | 569 |
mjw@2225 | 570 @param ctrlr: backend controller |
mjw@2225 | 571 """ |
mjw@2332 | 572 if ctrlr.dom in self.backendInterfaces: |
mjw@2332 | 573 del self.backendInterfaces[ctrlr.dom] |
mjw@2225 | 574 |
mjw@2332 | 575 def backendInterfaceClosed(self, ctrlr): |
mjw@2225 | 576 """Callback called when a backend is closed. |
mjw@2225 | 577 """ |
mjw@2332 | 578 self.delBackendInterface(ctrlr) |
mjw@2225 | 579 |
mjw@1623 | 580 class Dev: |
mjw@1654 | 581 """Abstract class for a device attached to a device controller. |
mjw@2185 | 582 |
mjw@2185 | 583 @ivar idx: identifier |
mjw@2185 | 584 @type idx: String |
mjw@2185 | 585 @ivar controller: device controller |
mjw@2185 | 586 @type controller: DeviceController |
mjw@2185 | 587 @ivar props: property table |
mjw@2185 | 588 @type props: { String: value } |
mjw@1654 | 589 """ |
mjw@1654 | 590 |
mjw@1975 | 591 def __init__(self, idx, controller): |
mjw@1975 | 592 self.idx = str(idx) |
mjw@1623 | 593 self.controller = controller |
mjw@1623 | 594 self.props = {} |
mjw@1623 | 595 |
mjw@1975 | 596 def getidx(self): |
mjw@1975 | 597 return self.idx |
mjw@1975 | 598 |
mjw@1623 | 599 def setprop(self, k, v): |
mjw@1623 | 600 self.props[k] = v |
mjw@1623 | 601 |
mjw@1623 | 602 def getprop(self, k, v=None): |
mjw@1623 | 603 return self.props.get(k, v) |
mjw@1623 | 604 |
mjw@1623 | 605 def hasprop(self, k): |
mjw@1623 | 606 return k in self.props |
mjw@1623 | 607 |
mjw@1623 | 608 def delprop(self, k): |
mjw@1623 | 609 if k in self.props: |
mjw@1623 | 610 del self.props[k] |
mjw@1623 | 611 |
mjw@1623 | 612 def sxpr(self): |
mjw@2185 | 613 """Get the s-expression for the deivice. |
mjw@2185 | 614 Implement in a subclass. |
mjw@2185 | 615 |
mjw@2185 | 616 @return: sxpr |
mjw@2185 | 617 """ |
mjw@1623 | 618 raise NotImplementedError() |
mjw@1623 | 619 |
mjw@2267 | 620 class SplitDev(Dev): |
mjw@2267 | 621 |
mjw@2267 | 622 def __init__(self, idx, controller): |
mjw@2267 | 623 Dev.__init__(self, idx, controller) |
mjw@2267 | 624 self.backendDomain = 0 |
mjw@2267 | 625 |
mjw@2332 | 626 def getBackendInterface(self): |
mjw@2332 | 627 return self.controller.getBackendInterface(self.backendDomain) |
mjw@2267 | 628 |
mjw@2267 | 629 |
mjw@2267 | 630 |
mjw@1623 | 631 |