-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebthing.go
202 lines (176 loc) · 5.59 KB
/
webthing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// -*- Mode: Go; indent-tabs-mode: t -*-
// Copyright: 2019-present Samsung Electronics Co., Ltd. and other contributors
// SPDX-License-Identifier: MPL-2.0
package webthing
import (
"encoding/json"
"fmt"
"github.com/julienschmidt/httprouter"
"io"
"net/http"
)
// Value is a multitypes placeholder, only one is used
type Value struct {
boolean bool
integer int
number float64
string string
}
// Property is made of value(s)
type Property struct {
name string
valuetype string
value *Value
handler func(interface{})
}
func (property Property) setValue(value interface{}) {
switch property.valuetype {
case "boolean":
property.value.boolean = (value).(bool)
case "integer":
property.value.integer = (value).(int)
case "number":
property.value.number = (value).(float64)
case "string":
property.value.string = (value).(string)
}
if property.handler != nil {
property.handler(value)
}
}
func (property Property) getValue() interface{} {
switch property.valuetype {
case "boolean":
return property.value.boolean
case "integer":
return property.value.integer
case "number":
return property.value.number
case "string":
return property.value.string
}
return nil
}
// NewProperty contructs and assign value
func NewProperty(name string, valuetype string, value interface{}, handler func(interface{})) *Property {
var property = Property{name: name, valuetype: valuetype, handler: handler}
property.value = &Value{}
property.setValue(value)
return &property
}
// Thing is made of Property(ies)
type Thing struct {
id string
title string
context string
types []string
description string
properties map[string]Property
href string
}
// AddProperty adds property (along values) to thing
func (thing Thing) AddProperty(property *Property) {
thing.properties[property.name] = *property
}
func (thing Thing) getPropertiesDescriptions() map[string]interface{} {
result := make(map[string]interface{})
for name, property := range thing.properties {
description := make(map[string]interface{})
description["type"] = property.valuetype
description["href"] = thing.href + "properties/" + name
result[name] = description
}
return result
}
// NewThing construct without properties
func NewThing(id string, title string, types []string, description string) *Thing {
thing := Thing{
id: id,
title: title,
href: "/",
properties: make(map[string]Property),
types: types,
description: description,
context: "https://iot.mozilla.org/schemas"}
if thing.types == nil {
thing.types = make([]string, 0)
}
return &thing
}
// Server is an HTTP server made for webthings model
type Server struct {
thing *Thing
port int
}
func (server Server) thingHandler(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
description := make(map[string]interface{})
description["id"] = server.thing.id
description["title"] = server.thing.title
description["@context"] = server.thing.context
description["@type"] = server.thing.types
description["properties"] = server.thing.getPropertiesDescriptions()
description["events"] = make(map[string]interface{})
description["links"] = [...]map[string]interface{}{
{"rel": "properties", "href": "/properties"}}
description["description"] = server.thing.description
description["actions"] = make(map[string]interface{})
description["href"] = server.thing.href
// https://github.com/golang/go/issues/28940
scheme := "http"
if req.TLS != nil {
scheme = "https"
}
description["base"] = scheme + "://" + req.Host + req.URL.RequestURI()
description["security"] = "nosec_sc"
description["securityDefinitions"] = make(map[string]interface{})
description["securityDefinitions"].(map[string]interface{})["nosec_sc"] =
map[string]interface{}{"scheme": "nosec"}
var body, _ = json.Marshal(description)
io.WriteString(w, string(body))
}
func (server Server) propertiesHandler(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
description := make(map[string]interface{})
for name, property := range server.thing.properties {
description[name] = property.getValue()
}
var body, _ = json.Marshal(description)
io.WriteString(w, string(body))
}
func (server Server) propertyPutHandler(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
decoder := json.NewDecoder(req.Body)
object := make(map[string]interface{})
err := decoder.Decode(&object)
if err != nil {
fmt.Println(err)
}
name := params.ByName("propertyName")
property := server.thing.properties[name]
property.setValue(object[name])
var body, _ = json.Marshal(object)
io.WriteString(w, string(body))
}
func (server Server) propertyGetHandler(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
name := params.ByName("propertyName")
property := server.thing.properties[name]
object := make(map[string]interface{})
object[name] = property.getValue()
var body, _ = json.Marshal(object)
io.WriteString(w, string(body))
}
// NewServer constructs an http server to be started
func NewServer(thing *Thing, port int) *Server {
return &Server{thing: thing, port: port}
}
// Start listening for incoming requests and process using handlers
func (server Server) Start() {
router := httprouter.New()
router.GET("/", server.thingHandler)
router.GET("/properties", server.propertiesHandler)
router.GET("/properties/:propertyName", server.propertyGetHandler)
router.PUT("/properties/:propertyName", server.propertyPutHandler)
address := fmt.Sprintf(":%d", server.port)
fmt.Print("Listening: ")
fmt.Println(address)
err := http.ListenAndServe(address, router)
fmt.Println(err)
}