Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
optional TTL, updated errors, bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
farshidtz committed Feb 28, 2020
1 parent b68b2d6 commit 043655d
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 43 deletions.
50 changes: 27 additions & 23 deletions catalog/catalogapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

type ThingsCollection struct {
Context string `json:"@context,omitempty"`
Context string `json:"@context"`
Things []ThingDescription `json:"things"`
ID string `json:"id"`
Page int `json:"page"`
Expand All @@ -21,16 +21,14 @@ type ThingsCollection struct {

// Read-only catalog api
type HTTPAPI struct {
controller CatalogController
ctxPath string
description string
controller CatalogController
id string
}

func NewHTTPAPI(controller CatalogController, description string) *HTTPAPI {
func NewHTTPAPI(controller CatalogController, serviceID string) *HTTPAPI {
return &HTTPAPI{
controller: controller,
// TODO ctxPath: staticLocation + CtxPath,
description: description,
id: serviceID,
}
}

Expand All @@ -50,18 +48,18 @@ func (a *HTTPAPI) Post(w http.ResponseWriter, req *http.Request) {
}

if td.ID != "" {
ErrorResponse(w, http.StatusBadRequest, "Creating a device with defined ID is not possible using a POST request.")
ErrorResponse(w, http.StatusBadRequest, "Registering with defined ID is not possible using a POST request.")
return
}

id, err := a.controller.add(td)
if err != nil {
switch err.(type) {
case *ConflictError:
ErrorResponse(w, http.StatusConflict, "Error creating the registration:", err.Error())
ErrorResponse(w, http.StatusConflict, "Error creating the resource:", err.Error())
return
case *BadRequestError:
ErrorResponse(w, http.StatusBadRequest, "Invalid device registration:", err.Error())
ErrorResponse(w, http.StatusBadRequest, "Invalid registration:", err.Error())
return
default:
ErrorResponse(w, http.StatusInternalServerError, "Error creating the registration:", err.Error())
Expand All @@ -85,7 +83,7 @@ func (a *HTTPAPI) Get(w http.ResponseWriter, req *http.Request) {
ErrorResponse(w, http.StatusNotFound, err.Error())
return
default:
ErrorResponse(w, http.StatusInternalServerError, "Error retrieving the device:", err.Error())
ErrorResponse(w, http.StatusInternalServerError, "Error retrieving the registration:", err.Error())
return
}
}
Expand Down Expand Up @@ -126,21 +124,27 @@ func (a *HTTPAPI) Put(w http.ResponseWriter, req *http.Request) {
td.ID = params["id"]
_, err := a.controller.add(td)
if err != nil {
ErrorResponse(w, http.StatusInternalServerError, "Error creating the registration:", err.Error())
return
switch err.(type) {
case *ConflictError:
ErrorResponse(w, http.StatusConflict, "Error creating the registration:", err.Error())
return
case *BadRequestError:
ErrorResponse(w, http.StatusBadRequest, "Invalid registration:", err.Error())
return
default:
ErrorResponse(w, http.StatusInternalServerError, "Error creating the registration:", err.Error())
return
}
}
w.Header().Set("Content-Type", "application/ld+json;version="+ApiVersion)
w.Header().Set("Location", td.ID)
w.WriteHeader(http.StatusCreated)
return
case *ConflictError:
ErrorResponse(w, http.StatusConflict, "Error updating the device:", err.Error())
return
case *BadRequestError:
ErrorResponse(w, http.StatusBadRequest, "Invalid device registration:", err.Error())
ErrorResponse(w, http.StatusBadRequest, "Invalid registration:", err.Error())
return
default:
ErrorResponse(w, http.StatusInternalServerError, "Error updating the device:", err.Error())
ErrorResponse(w, http.StatusInternalServerError, "Error updating the registration:", err.Error())
return
}
}
Expand All @@ -160,7 +164,7 @@ func (a *HTTPAPI) Delete(w http.ResponseWriter, req *http.Request) {
ErrorResponse(w, http.StatusNotFound, err.Error())
return
default:
ErrorResponse(w, http.StatusInternalServerError, "Error deleting the device:", err.Error())
ErrorResponse(w, http.StatusInternalServerError, "Error deleting the registration:", err.Error())
return
}
}
Expand Down Expand Up @@ -190,8 +194,8 @@ func (a *HTTPAPI) List(w http.ResponseWriter, req *http.Request) {
}

coll := &ThingsCollection{
Context: a.ctxPath,
// TODO ID: "",
Context: ContextURL,
ID: a.id,
Things: tds,
Page: page,
PerPage: perPage,
Expand Down Expand Up @@ -234,8 +238,8 @@ func (a *HTTPAPI) Filter(w http.ResponseWriter, req *http.Request) {
}

coll := &ThingsCollection{
Context: a.ctxPath,
// TODO ID: a.apiLocation,
Context: ContextURL,
ID: a.id,
Things: tds,
Page: page,
PerPage: perPage,
Expand Down
19 changes: 7 additions & 12 deletions catalog/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,11 @@
package catalog

const (
DNSSDServiceType = "_linksmart-rc._tcp"
MaxPerPage = 100
ApiVersion = "1.0.0"
ApiName = "ResourceCatalog"
ApiDeviceCollectionType = "Devices"
ApiResourceCollectionType = "Resources"
ApiDeviceType = "Device"
ApiResourceType = "Resource"
CatalogBackendMemory = "memory"
CatalogBackendLevelDB = "leveldb"
StaticLocation = "/static"
loggerPrefix = "[catalog] "
ContextURL = "TBA"
DNSSDServiceType = "_linksmart-rc._tcp"
MaxPerPage = 100
ApiVersion = "1.0.0"
CatalogBackendMemory = "memory"
CatalogBackendLevelDB = "leveldb"
loggerPrefix = "[catalog] "
)
15 changes: 11 additions & 4 deletions catalog/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
uuid "github.com/satori/go.uuid"
)

var controllerExpiryCleanupInterval = 60 * time.Second // to be modified in unit tests

type Controller struct {
storage Storage
}
Expand Down Expand Up @@ -55,6 +57,9 @@ func (c *Controller) update(id string, td ThingDescription) error {
return &BadRequestError{err.Error()}
}

td.ID = id
td.Modified = time.Now().UTC()

err := c.storage.update(id, &td)
if err != nil {
return err
Expand Down Expand Up @@ -119,13 +124,15 @@ func (c *Controller) total() (int, error) {
}

func (c *Controller) cleanExpired() {
for t := range time.Tick(5 * time.Second) {
for t := range time.Tick(controllerExpiryCleanupInterval) {
var expiredServices []*ThingDescription

for td := range c.storage.iterator() {
// remove if expiry is overdue by half-TTL
if t.After(td.Modified.Add(time.Duration(td.TTL+td.TTL/2) * time.Second)) {
expiredServices = append(expiredServices, td)
if td.TTL != 0 {
// remove if expiry is overdue by half-TTL
if t.After(td.Modified.Add(time.Duration(td.TTL+td.TTL/2) * time.Second)) {
expiredServices = append(expiredServices, td)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type StorageConfig struct {
}

var supportedBackends = map[string]bool{
utils.CatalogBackendMemory: true,
utils.CatalogBackendMemory: false,
utils.CatalogBackendLevelDB: true,
}

Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func setupRouter(config *Config) (*router, func() error, error) {
// Create catalog API object
api := catalog.NewHTTPAPI(
controller,
config.Description,
config.ServiceID,
)

commonHandlers := alice.New(
Expand Down
3 changes: 2 additions & 1 deletion registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ func registerInServiceCatalog(conf *Config) (func() error, error) {
service := sc.Service{
ID: conf.ServiceID,
Type: "_linksmart-rc._tcp",
Description: "LinkSmart Resource Catalog",
Title: "LinkSmart Resource Catalog",
Description: conf.Description,
APIs: []sc.API{{
ID: "things",
Title: "Things API",
Expand Down
2 changes: 1 addition & 1 deletion wot/thing_description.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ type SecurityScheme struct {
Descriptions map[string]string `json:"descriptions,omitempty"`

// URI of the proxy server this security configuration provides access to. If not given, the corresponding security configuration is for the endpoint.
Proxy AnyURI `json:"proxy"`
Proxy AnyURI `json:"proxy,omitempty"`

*BasicSecurityScheme
*DigestSecurityScheme
Expand Down

0 comments on commit 043655d

Please sign in to comment.