slicerNetwork.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import qt
  2. import urllib2
  3. import ssl
  4. import cookielib
  5. import xml.etree.ElementTree as ET
  6. import re
  7. import StringIO
  8. import slicer
  9. import shutil
  10. import distutils
  11. import os
  12. class slicerNetwork:
  13. def __init__(self,parent):
  14. parent.title = "slicerNetwork"
  15. self.parent=parent
  16. class labkeyURIHandler(slicer.vtkURIHandler):
  17. def __init__(self):
  18. slicer.vtkURIHandler.__init__(self)
  19. self.className="labkeyURIHandler"
  20. slicer.mrmlScene.AddURIHandler(self)
  21. try:
  22. self.localCacheDirectory=os.path.join(
  23. os.environ["HOME"],"labkeyCache")
  24. except:
  25. #in windows, the variable is called HOMEPATH
  26. fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
  27. self.localCacheDirectory=os.path.join(fhome,"labkeyCache")
  28. def CanHandleURI(self,uri):
  29. print "labkeyURIHandler::CanHandleURI({0})".format(uri)
  30. if uri.find('labkey://')==0:
  31. return 1
  32. return 0
  33. def GetClassName(self):
  34. return self.className
  35. def GetHostName(self):
  36. return self.hostname
  37. def SetHostName(self,host):
  38. self.hostname=host
  39. def SetLocalCahceDirectory(self,dir):
  40. self.localCacheDirectory=dir
  41. def GetLocalCacheDirectory(self):
  42. return self.localCacheDirectory
  43. def GetLocalPath(self,source):
  44. relativePath=re.sub('labkey://','',source)
  45. sp=os.sep.encode('string-escape')
  46. print "Substituting / with {0} in {1}".format(sp,relativePath)
  47. relativePath=re.sub('/',sp,relativePath)
  48. return os.path.join(self.localCacheDirectory,relativePath)
  49. def GetFile(self,source):
  50. # check for file in cache. If available, use, if not, download
  51. localPath=self.GetLocalPath(source)
  52. if os.path.isfile(localPath):
  53. return localPath
  54. self.StageFileRead(source,localPath)
  55. return localPath
  56. def StageFileRead(self,source,dest):
  57. print "labkeyURIHandler::StageFileRead({0},{1})".format(
  58. source,dest)
  59. labkeyPath=re.sub('labkey://','',source)
  60. remote=self.readFile(self.hostname,labkeyPath)
  61. #make all necessary directories
  62. path=os.path.dirname(dest)
  63. try:
  64. os.makedirs(path)
  65. except:
  66. if not os.path.isdir(path):
  67. raise
  68. local=open(dest,'wb')
  69. #make sure we are at the begining of the file
  70. #check file size
  71. remote.seek(0,2)
  72. sz=remote.tell()
  73. print "Remote size: {0}".format(sz)
  74. remote.seek(0)
  75. shutil.copyfileobj(remote,local)
  76. print "Local size: {0}".format(local.tell())
  77. local.close()
  78. def StageFileWrite(self,source,dest):
  79. print "labkeyURIHandler::StageFileWrite({0},{1}) not implemented yet".format(
  80. source,dest)
  81. def fileTypesAvailable(self):
  82. return ('VolumeFile','SegmentationFile','TransformFile')
  83. #mimic slicer.util.loadNodeFromFile
  84. def loadNodeFromFile(self, filename, filetype, properties={}, returnNode=False):
  85. #this is the only relevant part - file must be downloaded to cache
  86. localPath=self.GetFile(filename)
  87. slicer.util.loadNodeFromFile(localPath,filetype,properties,returnNode)
  88. #remove retrieved file
  89. try:
  90. if not(properties['keepCachedFile']) :
  91. os.remove(localPath)
  92. except:
  93. pass
  94. def loadVolume(self,filename, properties={}, returnNode=False):
  95. filetype = 'VolumeFile'
  96. #redirect to self.loadNodeFromFile first to get the cached file
  97. return self.loadNodeFromFile(filename,filetype, properties,returnNode)
  98. def loadSegmentation(self,filename,properties={},returnNode=False):
  99. filetype='SegmentationFile'
  100. #redirect to self.loadNodeFromFile first to get the cached file
  101. return self.loadNodeFromFile(filename,filetype, properties,returnNode)
  102. #add others if needed
  103. def configureSSL(self,cert,key,pwd,cacert):
  104. #do this first
  105. self.ctx=ssl.SSLContext(ssl.PROTOCOL_SSLv23)
  106. self.ctx.load_cert_chain(cert,key,pwd)
  107. self.ctx.verify_mode=ssl.CERT_REQUIRED
  108. self.ctx.load_verify_locations(cacert)
  109. def connectRemote(self,serverUrl,uname,pwd):
  110. https_handler=urllib2.HTTPSHandler(context=self.ctx)
  111. self.SetHostName(serverUrl)
  112. #cookie part
  113. cj=cookielib.CookieJar()
  114. cookie_handler=urllib2.HTTPCookieProcessor(cj)
  115. self.opener=urllib2.build_opener(https_handler,cookie_handler)
  116. loginUrl=serverUrl+"/labkey/login/login.post"
  117. r=urllib2.Request(str(loginUrl))
  118. print "Connecting to {0}".format(loginUrl)
  119. r.add_header('ContentType','application/x-www-form-urlencoded')
  120. data="email="+uname+"&password="+pwd
  121. r.add_data(data)
  122. self.opener.open(r)
  123. #cj in opener contains the cookies
  124. def get(self,url):
  125. #r1=urllib2.Request('https://merlin.fmf.uni-lj.si/labkey/query/motionData/selectRows.api?schemaName=core&query.queryName=Users')
  126. r=urllib2.Request(url)
  127. return self.opener.open(r)
  128. #f contains json as a return value
  129. def post(self,url,data):
  130. r=urllib2.Request(url)
  131. #makes it a post
  132. r.add_data(data)
  133. r.add_header("content-type","application/json")
  134. f=self.opener.open(r)
  135. #f contains json as a return value
  136. def listDir(self,dir):
  137. print "Listing for {0}".format(dir)
  138. dirUrl=self.hostname+"/labkey/_webdav"+"/"+dir
  139. r=propfindRequest(dirUrl)
  140. PROPFIND=u"""<?xml version="1.0" encoding="utf-8"?>\n
  141. <propfind xmlns="DAV:">\n
  142. <prop>\n
  143. <getetag/>\n
  144. </prop>\n
  145. </propfind>"""
  146. r.add_header('content-type','text/xml; charset="utf-8"')
  147. r.add_header('content-length',str(len(PROPFIND)))
  148. r.add_header('Depth','1')
  149. r.add_data(PROPFIND)
  150. f=self.opener.open(r)
  151. tree=ET.XML(f.read())
  152. rps=tree.findall('{DAV:}response')
  153. dirs=[]
  154. for r in rps:
  155. hr=r.find('{DAV:}href')
  156. dirent=hr.text
  157. dirent=re.sub('/labkey/_webdav/','',dirent)
  158. dirs.append(dirent)
  159. del dirs[0]
  160. return dirs
  161. def toRelativePath(self,dirs):
  162. flist1=[]
  163. for d in dirs:
  164. if d[-1]=='/':
  165. d=d[:-1]
  166. if d.rfind('/')>-1:
  167. d=d[d.rfind('/')+1:]
  168. flist1.append(d)
  169. return flist1
  170. def readFile(self, serverUrl, path):
  171. dirUrl=serverUrl+"/labkey/_webdav"+"/"+path
  172. f=self.get(dirUrl)
  173. return StringIO.StringIO(f.read())
  174. def loadDir(self, path):
  175. #dirURL=serverUrl+"/labkey/_webdav/"+path
  176. files=self.listDir(path)
  177. for f in files:
  178. #returns local path
  179. try:
  180. self.GetFile(f)
  181. except:
  182. #fails if there is a subdirectory; go recursively
  183. self.readDir(f)
  184. class propfindRequest(urllib2.Request):
  185. """
  186. This request subclass allows explicit specification of
  187. the HTTP request method. Basic urllib2.Request class
  188. chooses GET or POST depending on self.has_data()
  189. """
  190. def __init__(self, *args, **kwargs):
  191. #self.method = 'Propfind'
  192. urllib2.Request.__init__(self, *args, **kwargs)
  193. def get_method(self):
  194. return 'PROPFIND'