You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

189 lines
6.4 KiB

  1. """Client utilities for accessing NILM database via HTTP"""
  2. from __future__ import absolute_import
  3. import nilmdb
  4. from nilmdb.printf import *
  5. import time
  6. import sys
  7. import re
  8. import os
  9. import json
  10. import urlparse
  11. import urllib2
  12. from urllib2 import urlopen, HTTPError
  13. import pycurl
  14. class ClientError(Exception):
  15. def __init__(self, code, message):
  16. Exception.__init__(self, message)
  17. self.code = code
  18. def __str__(self):
  19. return sprintf("[%03d] %s", self.code, self.message)
  20. class MyCurl(object):
  21. def __init__(self, baseurl = ""):
  22. """If baseurl is supplied, all other functions that take
  23. a URL can be given a relative URL instead."""
  24. self.baseurl = baseurl
  25. self.curl = pycurl.Curl()
  26. self.curl.setopt(pycurl.SSL_VERIFYHOST, 2)
  27. self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
  28. self.curl.setopt(pycurl.MAXREDIRS, 5)
  29. def _setup_url(self, url, params):
  30. url = urlparse.urljoin(self.baseurl, url)
  31. if params:
  32. url = urlparse.urljoin(url, "?" + urllib.urlencode(params, True))
  33. self.curl.setopt(pycurl.URL, url)
  34. return url
  35. def getjson(self, url, params = None):
  36. """Simple GET that returns JSON string"""
  37. self._setup_url(url, params)
  38. self._body = ""
  39. def body_callback(x):
  40. self._body += x
  41. self.curl.setopt(pycurl.WRITEFUNCTION, body_callback)
  42. try:
  43. self.curl.perform()
  44. except pycurl.error as e:
  45. raise ClientError(500, e[1])
  46. code = self.curl.getinfo(pycurl.RESPONSE_CODE)
  47. if code != 200:
  48. raise ClientError(code, "HTTP error")
  49. return json.loads(self._body)
  50. class Client(object):
  51. def __init__(self, url):
  52. self.curl = MyCurl(url)
  53. def version(self):
  54. return self.curl.getjson("version")
  55. def stream_list(self, path = None, layout = None):
  56. params = {}
  57. if path is not None:
  58. params["path"] = path
  59. if layout is not None:
  60. params["layout"] = layout
  61. return self.curl.getjson("stream/list", params)
  62. def stream_get_metadata(self, path, keys = None):
  63. params = { "path": path }
  64. if keys is not None:
  65. params["key"] = keys
  66. return self.curl.getjson("stream/get_metadata", params)
  67. def stream_set_metadata(self):
  68. raise NotImplementedError
  69. def stream_update_metadata(self):
  70. raise NotImplementedError
  71. def stream_create(self):
  72. raise NotImplementedError
  73. def stream_insert(self, path):
  74. params = { "path": path }
  75. return self.curl.getjson("stream/insert", params)
  76. # eq_(db.stream_list(), [])
  77. # # Bad path
  78. # with assert_raises(ValueError):
  79. # db.stream_create("foo/bar/baz", "PrepData")
  80. # with assert_raises(ValueError):
  81. # db.stream_create("/foo", "PrepData")
  82. # # Bad layout type
  83. # with assert_raises(KeyError):
  84. # db.stream_create("/newton/prep", "NoSuchLayout")
  85. # # Bad index columns
  86. # with assert_raises(KeyError):
  87. # db.stream_create("/newton/prep", "PrepData", ["nonexistant"])
  88. # db.stream_create("/newton/prep", "PrepData")
  89. # db.stream_create("/newton/raw", "RawData")
  90. # db.stream_create("/newton/zzz/rawnotch", "RawNotchedData")
  91. # # Verify we got 3 streams
  92. # eq_(db.stream_list(), [ ("/newton/prep", "PrepData"),
  93. # ("/newton/raw", "RawData"),
  94. # ("/newton/zzz/rawnotch", "RawNotchedData")
  95. # ])
  96. # # Match just one type
  97. # eq_(db.stream_list(layout="RawData"), [ ("/newton/raw", "RawData") ])
  98. # # Verify that columns were made right
  99. # eq_(len(db.h5file.getNode("/newton/prep").cols), 9)
  100. # eq_(len(db.h5file.getNode("/newton/raw").cols), 7)
  101. # eq_(len(db.h5file.getNode("/newton/zzz/rawnotch").cols), 10)
  102. # assert(db.h5file.getNode("/newton/prep").colindexed["timestamp"])
  103. # assert(not db.h5file.getNode("/newton/prep").colindexed["p1"])
  104. # # Set / get metadata
  105. # eq_(db.stream_get_metadata("/newton/prep"), {})
  106. # eq_(db.stream_get_metadata("/newton/raw"), {})
  107. # meta1 = { "description": "The Data",
  108. # "v_scale": "1.234" }
  109. # meta2 = { "description": "The Data" }
  110. # meta3 = { "v_scale": "1.234" }
  111. # db.stream_set_metadata("/newton/prep", meta1)
  112. # db.stream_update_metadata("/newton/prep", {})
  113. # db.stream_update_metadata("/newton/raw", meta2)
  114. # db.stream_update_metadata("/newton/raw", meta3)
  115. # eq_(db.stream_get_metadata("/newton/prep"), meta1)
  116. # eq_(db.stream_get_metadata("/newton/raw"), meta1)
  117. # streams = getjson("/stream/list")
  118. # eq_(streams, [
  119. # ['/newton/prep', 'PrepData'],
  120. # ['/newton/raw', 'RawData'],
  121. # ['/newton/zzz/rawnotch', 'RawNotchedData'],
  122. # ])
  123. # streams = getjson("/stream/list?layout=RawData")
  124. # eq_(streams, [['/newton/raw', 'RawData']])
  125. # streams = getjson("/stream/list?layout=NoSuchLayout")
  126. # eq_(streams, [])
  127. # with assert_raises(HTTPError) as e:
  128. # getjson("/stream/get_metadata?path=foo")
  129. # eq_(e.exception.code, 404)
  130. # data = getjson("/stream/get_metadata?path=/newton/prep")
  131. # eq_(data, {'description': 'The Data', 'v_scale': '1.234'})
  132. # data = getjson("/stream/get_metadata?path=/newton/prep"
  133. # "&key=v_scale")
  134. # eq_(data, {'v_scale': '1.234'})
  135. # data = getjson("/stream/get_metadata?path=/newton/prep"
  136. # "&key=v_scale&key=description")
  137. # eq_(data, {'description': 'The Data', 'v_scale': '1.234'})
  138. # data = getjson("/stream/get_metadata?path=/newton/prep"
  139. # "&key=v_scale&key=foo")
  140. # eq_(data, {'foo': None, 'v_scale': '1.234'})
  141. # data = getjson("/stream/get_metadata?path=/newton/prep"
  142. # "&key=foo")
  143. # eq_(data, {'foo': None})
  144. # def test_insert(self):
  145. # # invalid path first
  146. # with assert_raises(HTTPError) as e:
  147. # getjson("/stream/insert?path=/newton/")
  148. # eq_(e.exception.code, 404)
  149. # # XXX TODO
  150. # with assert_raises(HTTPError) as e:
  151. # getjson("/stream/insert?path=/newton/prep")
  152. # eq_(e.exception.code, 501)