Deliverable for D3.2

data.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package api
  2. import (
  3. "net/http"
  4. "time"
  5. validator "gopkg.in/validator.v2"
  6. restful "github.com/emicklei/go-restful"
  7. restfulspec "github.com/emicklei/go-restful-openapi"
  8. redis_client "github.com/garyburd/redigo/redis"
  9. )
  10. // ErrorResponse signals error messages back to the client
  11. type ErrorResponse struct {
  12. Error string `json:"error" description:"error message if any"`
  13. }
  14. // Data is a value to save to storage
  15. type Data struct {
  16. Value interface{} `json:"value" description:"data to save" validate:"nonzero" type:"object"`
  17. Bucket string `json:"bucket" description:"unique bucket to save value to" validate:"nonzero"`
  18. }
  19. // DataResponse is the saved value with the time it was saved
  20. type DataResponse struct {
  21. Value interface{} `json:"value" description:"saved value" type:"object"`
  22. Timestamp time.Time `json:"ts" description:"when the item was saved"`
  23. }
  24. type dataResource struct {
  25. pool *redis_client.Pool
  26. }
  27. func NewDataService(pool *redis_client.Pool) dataResource {
  28. return dataResource{
  29. pool: pool,
  30. }
  31. }
  32. func (e dataResource) WebService() *restful.WebService {
  33. ws := new(restful.WebService)
  34. ws.
  35. Path("/data").
  36. Consumes(restful.MIME_JSON).
  37. Produces(restful.MIME_JSON)
  38. tags := []string{"data"}
  39. ws.Route(ws.GET("/").To(e.getAll).
  40. Doc("returns all of the data stored in a logical 'bucket' in the last 24 hours.").
  41. Param(ws.QueryParameter("bucket-uid", "name of the 'bucket' of data").DataType("string")).
  42. Metadata(restfulspec.KeyOpenAPITags, tags).
  43. Writes([]DataResponse{}).
  44. Returns(http.StatusOK, "OK", []DataResponse{}).
  45. Returns(http.StatusNotFound, "Not Found", nil).
  46. Returns(http.StatusInternalServerError, "Something went wrong", ErrorResponse{}))
  47. ws.Route(ws.PUT("/").To(e.append).
  48. Doc("append data to a bucket, will create the bucket if it does not exist.").
  49. Metadata(restfulspec.KeyOpenAPITags, tags).
  50. Reads(Data{}).
  51. Returns(http.StatusCreated, "Data was accepted", nil).
  52. Returns(http.StatusBadRequest, "error validating request", ErrorResponse{}).
  53. Returns(http.StatusInternalServerError, "Something went wrong", ErrorResponse{}))
  54. return ws
  55. }
  56. func (e dataResource) getAll(request *restful.Request, response *restful.Response) {
  57. prefix := request.QueryParameter("bucket-uid")
  58. timestep := time.Second
  59. expiry := time.Duration(time.Hour * 24)
  60. ts := NewTimeSeries(prefix, timestep, expiry, e.pool)
  61. // TODO : review should this be UTC?
  62. to := time.Now()
  63. from := to.Add(-(time.Hour * 24))
  64. data := []*DataResponse{}
  65. err := ts.FetchRange(from, to, &data)
  66. if err != nil {
  67. response.WriteHeaderAndEntity(http.StatusInternalServerError, ErrorResponse{Error: err.Error()})
  68. return
  69. }
  70. response.WriteEntity(data)
  71. }
  72. func (e dataResource) append(request *restful.Request, response *restful.Response) {
  73. data := Data{}
  74. if err := request.ReadEntity(&data); err != nil {
  75. response.WriteHeaderAndEntity(http.StatusBadRequest, ErrorResponse{Error: err.Error()})
  76. return
  77. }
  78. if errs := validator.Validate(data); errs != nil {
  79. response.WriteHeaderAndEntity(http.StatusBadRequest, ErrorResponse{Error: errs.Error()})
  80. return
  81. }
  82. prefix := data.Bucket
  83. timestep := time.Second
  84. expiry := time.Duration(time.Hour * 24)
  85. ts := NewTimeSeries(prefix, timestep, expiry, e.pool)
  86. // TODO : should this be UTC
  87. now := time.Now()
  88. err := ts.Add(&DataResponse{Value: data.Value, Timestamp: now}, now)
  89. if err != nil {
  90. response.WriteHeaderAndEntity(http.StatusInternalServerError, ErrorResponse{Error: err.Error()})
  91. return
  92. }
  93. response.WriteHeader(http.StatusCreated)
  94. }