quick base to try and help flesh out documentation under core.*

This commit is contained in:
Blake J. Harnden 2017-05-03 09:30:49 -07:00
parent 8f45e5c4da
commit 4ae7958a63
15 changed files with 1956 additions and 292 deletions

View file

@ -22,32 +22,39 @@ from core.misc import nodeutils
logger = log.get_logger(__name__)
class Bunch:
# TODO: A named tuple may be more appropriate, than abusing a class dict like this
class Bunch(object):
"""
Helper class for recording a collection of attributes.
"""
def __init__(self, **kwds):
"""
Create a Bunch instance.
:param dict kwds: keyword arguments
:return:
"""
self.__dict__.update(kwds)
class Sdt(object):
"""
Helper class for exporting session objects to NRL's SDT3D.
Helper class for exporting session objects to NRL"s SDT3D.
The connect() method initializes the display, and can be invoked
when a node position or link has changed.
"""
DEFAULT_SDT_URL = "tcp://127.0.0.1:50000/"
# default altitude (in meters) for flyto view
DEFAULT_ALT = 2500
# TODO: read in user's nodes.conf here; below are default node types from the GUI
# TODO: read in user"s nodes.conf here; below are default node types from the GUI
DEFAULT_SPRITES = [
('router', 'router.gif'), ('host', 'host.gif'),
('PC', 'pc.gif'), ('mdr', 'mdr.gif'),
('prouter', 'router_green.gif'), ('xen', 'xen.gif'),
('hub', 'hub.gif'), ('lanswitch', 'lanswitch.gif'),
('wlan', 'wlan.gif'), ('rj45', 'rj45.gif'),
('tunnel', 'tunnel.gif'),
("router", "router.gif"), ("host", "host.gif"),
("PC", "pc.gif"), ("mdr", "mdr.gif"),
("prouter", "router_green.gif"), ("xen", "xen.gif"),
("hub", "hub.gif"), ("lanswitch", "lanswitch.gif"),
("wlan", "wlan.gif"), ("rj45", "rj45.gif"),
("tunnel", "tunnel.gif"),
]
def __init__(self, session):
@ -55,7 +62,6 @@ class Sdt(object):
Creates a Sdt instance.
:param core.session.Session session: session this manager is tied to
:return: nothing
"""
self.session = session
self.sock = None
@ -69,23 +75,28 @@ class Sdt(object):
def is_enabled(self):
"""
Check for 'enablesdt' session option. Return False by default if
Check for "enablesdt" session option. Return False by default if
the option is missing.
:return: True if enabled, False otherwise
:rtype: bool
"""
if not hasattr(self.session.options, 'enablesdt'):
if not hasattr(self.session.options, "enablesdt"):
return False
enabled = self.session.options.enablesdt
if enabled in ('1', 'true', 1, True):
if enabled in ("1", "true", 1, True):
return True
return False
def seturl(self):
"""
Read 'sdturl' from session options, or use the default value.
Read "sdturl" from session options, or use the default value.
Set self.url, self.address, self.protocol
:return: nothing
"""
url = None
if hasattr(self.session.options, 'sdturl'):
if hasattr(self.session.options, "sdturl"):
if self.session.options.sdturl != "":
url = self.session.options.sdturl
if url is None or url == "":
@ -97,6 +108,9 @@ class Sdt(object):
def connect(self, flags=0):
"""
Connect to the SDT address/port if enabled.
:return: True if connected, False otherwise
:rtype: bool
"""
if not self.is_enabled():
return False
@ -109,7 +123,7 @@ class Sdt(object):
logger.info("connecting to SDT at %s://%s" % (self.protocol, self.address))
if self.sock is None:
try:
if self.protocol.lower() == 'udp':
if self.protocol.lower() == "udp":
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.connect(self.address)
else:
@ -133,17 +147,25 @@ class Sdt(object):
"""
Load icon sprites, and fly to the reference point location on
the virtual globe.
:return: initialize command status
:rtype: bool
"""
if not self.cmd('path "%s/icons/normal"' % constants.CORE_DATA_DIR):
if not self.cmd("path \"%s/icons/normal\"" % constants.CORE_DATA_DIR):
return False
# send node type to icon mappings
for type, icon in self.DEFAULT_SPRITES:
if not self.cmd('sprite %s image %s' % (type, icon)):
if not self.cmd("sprite %s image %s" % (type, icon)):
return False
(lat, long) = self.session.location.refgeo[:2]
return self.cmd('flyto %.6f,%.6f,%d' % (long, lat, self.DEFAULT_ALT))
return self.cmd("flyto %.6f,%.6f,%d" % (long, lat, self.DEFAULT_ALT))
def disconnect(self):
"""
Disconnect from SDT.
:return: nothing
"""
if self.sock:
try:
self.sock.close()
@ -157,8 +179,10 @@ class Sdt(object):
def shutdown(self):
"""
Invoked from Session.shutdown() and Session.checkshutdown().
:return: nothing
"""
self.cmd('clear all')
self.cmd("clear all")
self.disconnect()
self.showerror = True
@ -167,6 +191,10 @@ class Sdt(object):
Send an SDT command over a UDP socket. socket.sendall() is used
as opposed to socket.sendto() because an exception is raised when
there is no socket listener.
:param str cmdstr: command to send
:return: True if command was successful, False otherwise
:rtype: bool
"""
if self.sock is None:
return False
@ -183,59 +211,84 @@ class Sdt(object):
def updatenode(self, nodenum, flags, x, y, z, name=None, type=None, icon=None):
"""
Node is updated from a Node Message or mobility script.
:param int nodenum: node id to update
:param flags: update flags
:param x: x position
:param y: y position
:param z: z position
:param str name: node name
:param type: node type
:param icon: node icon
:return: nothing
"""
if not self.connect():
return
if flags & MessageFlags.DELETE.value:
self.cmd('delete node,%d' % nodenum)
self.cmd("delete node,%d" % nodenum)
return
if x is None or y is None:
return
(lat, long, alt) = self.session.location.getgeo(x, y, z)
lat, long, alt = self.session.location.getgeo(x, y, z)
pos = "pos %.6f,%.6f,%.6f" % (long, lat, alt)
if flags & MessageFlags.ADD.value:
if icon is not None:
type = name
icon = icon.replace("$CORE_DATA_DIR", constants.CORE_DATA_DIR)
icon = icon.replace("$CORE_CONF_DIR", constants.CORE_CONF_DIR)
self.cmd('sprite %s image %s' % (type, icon))
self.cmd('node %d type %s label on,"%s" %s' % (nodenum, type, name, pos))
self.cmd("sprite %s image %s" % (type, icon))
self.cmd("node %d type %s label on,\"%s\" %s" % (nodenum, type, name, pos))
else:
self.cmd('node %d %s' % (nodenum, pos))
self.cmd("node %d %s" % (nodenum, pos))
def updatenodegeo(self, nodenum, lat, long, alt):
"""
Node is updated upon receiving an EMANE Location Event.
TODO: received Node Message with lat/long/alt.
:param int nodenum: node id to update geospatial for
:param lat: latitude
:param long: longitude
:param alt: altitude
:return: nothing
"""
# TODO: received Node Message with lat/long/alt.
if not self.connect():
return
pos = "pos %.6f,%.6f,%.6f" % (long, lat, alt)
self.cmd('node %d %s' % (nodenum, pos))
self.cmd("node %d %s" % (nodenum, pos))
def updatelink(self, node1num, node2num, flags, wireless=False):
"""
Link is updated from a Link Message or by a wireless model.
:param int node1num: node one id
:param int node2num: node two id
:param flags: link flags
:param bool wireless: flag to check if wireless or not
:return: nothing
"""
if node1num is None or node2num is None:
return
if not self.connect():
return
if flags & MessageFlags.DELETE.value:
self.cmd('delete link,%s,%s' % (node1num, node2num))
self.cmd("delete link,%s,%s" % (node1num, node2num))
elif flags & MessageFlags.ADD.value:
attr = ""
if wireless:
attr = " line green,2"
else:
attr = " line red,2"
self.cmd('link %s,%s%s' % (node1num, node2num, attr))
self.cmd("link %s,%s%s" % (node1num, node2num, attr))
def sendobjs(self):
"""
Session has already started, and the SDT3D GUI later connects.
Send all node and link objects for display. Otherwise, nodes and
links will only be drawn when they have been updated (e.g. moved).
:return: nothing
"""
nets = []
with self.session._objects_lock:
@ -251,7 +304,7 @@ class Sdt(object):
obj.name, obj.type, obj.icon)
for nodenum in sorted(self.remotes.keys()):
r = self.remotes[nodenum]
(x, y, z) = r.pos
x, y, z = r.pos
self.updatenode(nodenum, MessageFlags.ADD.value, x, y, z,
r.name, r.type, r.icon)
@ -276,22 +329,30 @@ class Sdt(object):
for n2num, wl in r.links:
self.updatelink(n1num, n2num, MessageFlags.ADD.value, wl)
# TODO: remove the need for this
def handledistributed(self, message):
"""
Broker handler for processing CORE API messages as they are
received. This is used to snoop the Node messages and update
node positions.
:param message: message to handle
:return: replies
"""
if message.message_type == MessageTypes.LINK.value:
return self.handlelinkmsg(message)
elif message.message_type == MessageTypes.NODE.value:
return self.handlenodemsg(message)
# TODO: remove the need for this
def handlenodemsg(self, msg):
"""
Process a Node Message to add/delete or move a node on
the SDT display. Node properties are found in session._objs or
self.remotes for remote nodes (or those not yet instantiated).
:param msg: node message to handle
:return: nothing
"""
# for distributed sessions to work properly, the SDT option should be
# enabled prior to starting the session
@ -344,11 +405,15 @@ class Sdt(object):
remote.pos = (x, y, z)
self.updatenode(nodenum, msg.flags, x, y, z, name, type, icon)
# TODO: remove the need for this
def handlelinkmsg(self, msg):
"""
Process a Link Message to add/remove links on the SDT display.
Links are recorded in the remotes[nodenum1].links set for updating
the SDT display at a later time.
:param msg: link message to handle
:return: nothing
"""
if not self.is_enabled():
return False
@ -370,8 +435,11 @@ class Sdt(object):
def wlancheck(self, nodenum):
"""
Helper returns True if a node number corresponds to a WlanNode
or EmaneNode.
Helper returns True if a node number corresponds to a WlanNode or EmaneNode.
:param int nodenum: node id to check
:return: True if node is wlan or emane, False otherwise
:rtype: bool
"""
if nodenum in self.remotes:
type = self.remotes[nodenum].type