Skip to content

Commit 6822ba4

Browse files
author
Thomas Goodwin
committed
Preparing 2.0.5 compatible beta release
1 parent 2002ed1 commit 6822ba4

19 files changed

Lines changed: 828 additions & 113 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
apps/*/
33
.virtualenv/
44
bower_components
5+
*.*~

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Contains the REDHAWK python implementation of the generic REST API.
66

7-
Please visit [the Wiki](https://github.com/Geontech/rest-python/wiki) for more detailed instructions on the changes made to this repository and how it can be used for UI development.
7+
Please visit [the Wiki](https://github.com/Geontech/rest-python/wiki) for more detailed instructions on the changes made to this repository and how it can be used for development of external control interfaces, data bridges, and graphical user interfaces without having to install REDHAWK on the target system.
88

99
## REDHAWK Documentation
1010

@@ -35,3 +35,4 @@ For a more permanent solution, consult the `requirements.txt` and run the follow
3535
can be found at `deploy/rest-python-supervisor.conf`.
3636

3737
Once running the REST Interface can be tested at `http://localhost:<desired_port>/rh/rest/domains`.
38+

model/_utils/tasking.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@
2121
from tornado import gen, concurrent
2222
from tornado import ioloop
2323

24-
# Suppressed known DeprecationWarning for the futures backport
25-
import warnings, exceptions
26-
warnings.filterwarnings("ignore", "The futures package has been deprecated.*", exceptions.DeprecationWarning, "futures")
27-
import futures
28-
2924
import logging
3025
import sys
31-
from futures import ThreadPoolExecutor
26+
27+
# Suppressed known DeprecationWarning for the futures backport
28+
try:
29+
import warnings, exceptions
30+
warnings.filterwarnings("ignore", "The futures package has been deprecated.*", exceptions.DeprecationWarning, "futures")
31+
import futures
32+
from futures import ThreadPoolExecutor
33+
except:
34+
from concurrent.futures import ThreadPoolExecutor
3235

3336
EXECUTOR = ThreadPoolExecutor(100)
3437

model/domain.py

Lines changed: 210 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@
2222
"""
2323

2424
import logging
25+
from ossie.cf import CF # For AllocationRequests
2526
from ossie.cf import StandardEvent # For the EventHelper
2627
from ossie.utils import redhawk
2728
from ossie.events import GenericEventConsumer
29+
import struct
2830
import traceback
2931

3032
from tornado.websocket import WebSocketClosedError
3133

3234
from functools import partial
3335
import uuid
3436

35-
3637
def scan_domains():
3738
return redhawk.scan()
3839

@@ -62,6 +63,22 @@ def __init__(self, name='Unknown', msg=''):
6263
def __str__(self):
6364
return "Not able to release waveform '%s'. %s" % (self.name, self.msg)
6465

66+
class AllocateError(Exception):
67+
def __init__(self, id='', msg=''):
68+
self.id = id
69+
self.msg = msg
70+
71+
def __str__(self):
72+
return "Not able to allocate allocation '%s'. %s" % (self.id, self.msg)
73+
74+
class DeallocateError(Exception):
75+
def __init__(self, id='', msg=''):
76+
self.id = id
77+
self.msg = msg
78+
79+
def __str__(self):
80+
return "Not able to deallocate allocation '%s'. %s" % (self.id, self.msg)
81+
6582
# Helper class to convert the enumeration fields to something JSON serializable
6683
class EventHelper(object):
6784
ENUM_MAP = {
@@ -86,10 +103,10 @@ def format_event(event):
86103
formattedEvent[k] = []
87104
for item in v:
88105
formattedEvent[k].append(EventHelper.format_event(item))
106+
elif k == "sourceIOR":
107+
formattedEvent[k] = str(event)
89108
else:
90109
formattedEvent[k] = EventHelper.format_event(v)
91-
elif str(type(event)) == "<type 'instance'>":
92-
formattedEvent = str(event)
93110
else:
94111
formattedEvent = event
95112

@@ -135,7 +152,9 @@ def rm_listener(self, callbackFn):
135152

136153

137154
class Domain:
155+
allocationMgr_ptr = None
138156
domMgr_ptr = None
157+
fileMgr_ptr = None
139158
odmListener = None
140159
topicHandlers = None
141160
name = None
@@ -189,19 +208,92 @@ def rm_event_listener(self, callbackFn, topic=None):
189208
def _establish_domain(self):
190209
redhawk.setTrackApps(False)
191210
self.domMgr_ptr = redhawk.attach(str(self.name))
211+
self.allocationMgr_ptr = self.domMgr_ptr.ref._get_allocationMgr()
212+
self.fileMgr_ptr = self.domMgr_ptr._get_fileMgr()
192213

193214
def properties(self):
194-
props = self.domMgr_ptr.query([]) # TODO: self.domMgr_ptr._properties
215+
props = self.domMgr_ptr._properties
195216
return props
196217

197-
def event_channels(self): # TODO: Check the event service for names.
198-
return self.topicHandlers.keys()
218+
def event_channels(self, number):
219+
return self.domMgr_ptr.getEventChannelMgr().listChannels(int(number))[0]
220+
221+
def get_allocation_info(self):
222+
if self.allocationMgr_ptr:
223+
return self.allocationMgr_ptr
224+
raise ResourceNotFound('allocation manager', self.name)
199225

200226
def get_domain_info(self):
201227
if self.domMgr_ptr:
202228
return self.domMgr_ptr
203229
raise ResourceNotFound('domain', self.name)
204230

231+
def get_path(self, path):
232+
fileInfos = self.fileMgr_ptr.list(path)
233+
234+
contents = ''
235+
directories = []
236+
files = []
237+
238+
# Iterate over the files at this path
239+
for fileInfoType in fileInfos:
240+
executable = False
241+
readOnly = True
242+
243+
for fileProp in fileInfoType.fileProperties:
244+
if fileProp.id == 'READ_ONLY':
245+
readOnly = fileProp.value.value()
246+
elif fileProp.id == 'EXECUTABLE':
247+
executable = fileProp.value.value()
248+
249+
newObject = {
250+
'executable': executable,
251+
'name': str(fileInfoType.name),
252+
'read_only': readOnly,
253+
'size': fileInfoType.size
254+
}
255+
256+
if str(fileInfoType.kind) == 'DIRECTORY':
257+
directories.append(newObject)
258+
elif str(fileInfoType.kind) == 'PLAIN':
259+
files.append(newObject)
260+
261+
# No need to read the file if there are directories
262+
if len(directories) != 0:
263+
return {'contents': contents, 'directories': directories, 'files': files}
264+
265+
# No need to read the file if there are multiple files
266+
if len(files) != 1:
267+
return {'contents': contents, 'directories': directories, 'files': files}
268+
269+
# Don't return the contents of the file if this is a directory path
270+
if path.endswith('/'):
271+
return {'contents': contents, 'directories': directories, 'files': files}
272+
273+
# Read the file to the user
274+
fileToRead = self.fileMgr_ptr.open(path, True)
275+
276+
contents = fileToRead.read(fileToRead.sizeOf())
277+
278+
if not path.endswith(('.py', '.m', '.xml')):
279+
contents = struct.unpack(str(fileToRead.sizeOf()) + 'B', contents)
280+
281+
fileToRead.close()
282+
283+
return {'contents': str(contents), 'directories': directories, 'files': files}
284+
285+
def find_allocation(self, allocation_id=None):
286+
_allocationMgr = self.get_allocation_info()
287+
allocations = _allocationMgr.localAllocations([])
288+
289+
if not allocation_id:
290+
return allocations
291+
292+
for allocation in allocations:
293+
if allocation.allocationID == allocation_id:
294+
return allocation
295+
raise ResourceNotFound('allocation', allocation_id)
296+
205297
def find_app(self, app_id=None):
206298
_dom = self.get_domain_info()
207299
apps = _dom.apps
@@ -258,6 +350,43 @@ def find_service(self, device_manager_id, service_id=None):
258350
return svc
259351
raise ResourceNotFound('service', service_id)
260352

353+
def allocate(self, allocation_id, device_ids, properties, source_id):
354+
_dom = self.get_domain_info()
355+
allocationMgr = self.get_allocation_info()
356+
357+
if not device_ids or len(device_ids) == 0:
358+
device_ids = [device._id for device in _dom.devices]
359+
360+
device_refs = [device.ref for device in _dom.devices]
361+
allocationRequest = CF.AllocationManager.AllocationRequestType(str(allocation_id), properties, device_ids, device_refs, str(source_id))
362+
363+
try:
364+
allocationMgr.allocate([allocationRequest])
365+
return allocation_id
366+
except Exception, e:
367+
raise AllocateError(allocation_id, str(e))
368+
369+
def allocations(self):
370+
allocations_dict = []
371+
allocations = self.find_allocation()
372+
for allocation in allocations:
373+
allocations_dict.append({'id': allocation.allocationID, 'deviceId': allocation.allocatedDevice._get_identifier()})
374+
return allocations_dict
375+
376+
def append(self, path, contents):
377+
if not self.fileMgr_ptr.exists(path):
378+
return {'status': 'failure', 'message': 'file does not exist'}
379+
380+
fileToAppend = self.fileMgr_ptr.open(path, False)
381+
382+
fileToAppend.setFilePointer(fileToAppend.sizeOf())
383+
384+
fileToAppend.write(contents)
385+
386+
fileToAppend.close()
387+
388+
return {'status': 'success'}
389+
261390
def apps(self):
262391
apps_dict = []
263392
apps = self.find_app()
@@ -272,6 +401,39 @@ def components(self, app_id):
272401
comps_dict.append({'name': comp.name, 'id': comp._get_identifier()})
273402
return comps_dict
274403

404+
def create(self, path, contents, read_only):
405+
if self.fileMgr_ptr.exists(path):
406+
return {'status': 'failure', 'message': 'file already exists'}
407+
408+
fileType = 'DIRECTORY'
409+
410+
if not path.endswith('/'):
411+
fileType = 'FILE'
412+
413+
if contents or fileType == 'FILE':
414+
newFile = self.fileMgr_ptr.create(path)
415+
else:
416+
self.fileMgr_ptr.mkdir(path)
417+
return {'status': 'success'}
418+
419+
if contents:
420+
if type(contents) == list:
421+
contents = struct.pack(str(len(contents)) + 'B', *contents)
422+
423+
newFile.write(contents)
424+
425+
newFile.close()
426+
427+
return {'status': 'success'}
428+
429+
def deallocate(self, allocation_ids):
430+
allocationMgr = self.get_allocation_info()
431+
try:
432+
allocationMgr.deallocate([str(allocation_id) for allocation_id in allocation_ids])
433+
return allocation_ids
434+
except Exception, e:
435+
raise DeallocateError(allocation_ids, str(e))
436+
275437
def launch(self, app_name):
276438
_dom = self.get_domain_info()
277439
try:
@@ -280,6 +442,17 @@ def launch(self, app_name):
280442
except Exception, e:
281443
raise WaveformLaunchError(app_name, str(e))
282444

445+
def move(self, from_path, to_path, keep_original):
446+
if not self.fileMgr_ptr.exists(from_path):
447+
return {'status': 'failure', 'message': 'from path does not exist'}
448+
449+
if keep_original:
450+
self.fileMgr_ptr.copy(from_path, to_path)
451+
return {'status': 'success'}
452+
else:
453+
self.fileMgr_ptr.move(from_path, to_path)
454+
return {'status': 'success'}
455+
283456
def release(self, app_id):
284457
app = self.find_app(app_id)
285458
try:
@@ -288,6 +461,36 @@ def release(self, app_id):
288461
except Exception, e:
289462
raise ApplicationReleaseError(app_id, str(e))
290463

464+
def remove(self, path):
465+
if not self.fileMgr_ptr.exists(path):
466+
return {'status': 'failure', 'message': 'file does not exist'}
467+
468+
fileType = 'DIRECTORY'
469+
470+
if not path.endswith('/'):
471+
fileType = 'FILE'
472+
473+
if fileType == 'FILE':
474+
self.fileMgr_ptr.remove(path)
475+
else:
476+
self.fileMgr_ptr.rmdir(path)
477+
478+
return {'status': 'success'}
479+
480+
def replace(self, path, contents):
481+
if not self.fileMgr_ptr.exists(path):
482+
return {'status': 'failure', 'message': 'file does not exist'}
483+
484+
self.fileMgr_ptr.remove(path)
485+
486+
fileToCreate = self.fileMgr_ptr.create(path)
487+
488+
fileToCreate.write(contents)
489+
490+
fileToCreate.close()
491+
492+
return {'status': 'success'}
493+
291494
def available_apps(self):
292495
_dom = self.get_domain_info()
293496
sads_full_path = _dom.catalogSads()
@@ -319,4 +522,4 @@ def services(self, dev_mgr_id):
319522
ret_dict = []
320523
for svc in svcs:
321524
ret_dict.append({'name': svc.name, 'id': svc._id})
322-
return ret_dict
525+
return ret_dict

0 commit comments

Comments
 (0)