Skip to content

Commit a7139bf

Browse files
committed
initial commit with in memory implementation
0 parents  commit a7139bf

File tree

16 files changed

+548
-0
lines changed

16 files changed

+548
-0
lines changed

.gitignore

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
2+
# Created by https://www.gitignore.io/api/go,vim,macos,intellij+all
3+
# Edit at https://www.gitignore.io/?templates=go,vim,macos,intellij+all
4+
5+
### Go ###
6+
# Binaries for programs and plugins
7+
*.exe
8+
*.exe~
9+
*.dll
10+
*.so
11+
*.dylib
12+
13+
# Test binary, built with `go test -c`
14+
*.test
15+
16+
# Output of the go coverage tool, specifically when used with LiteIDE
17+
*.out
18+
19+
# Dependency directories (remove the comment below to include it)
20+
# vendor/
21+
22+
### Go Patch ###
23+
/vendor/
24+
/Godeps/
25+
26+
### Intellij+all ###
27+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
28+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
29+
30+
# User-specific stuff
31+
.idea/**/workspace.xml
32+
.idea/**/tasks.xml
33+
.idea/**/usage.statistics.xml
34+
.idea/**/dictionaries
35+
.idea/**/shelf
36+
37+
# Generated files
38+
.idea/**/contentModel.xml
39+
40+
# Sensitive or high-churn files
41+
.idea/**/dataSources/
42+
.idea/**/dataSources.ids
43+
.idea/**/dataSources.local.xml
44+
.idea/**/sqlDataSources.xml
45+
.idea/**/dynamic.xml
46+
.idea/**/uiDesigner.xml
47+
.idea/**/dbnavigator.xml
48+
49+
# Gradle
50+
.idea/**/gradle.xml
51+
.idea/**/libraries
52+
53+
# Gradle and Maven with auto-import
54+
# When using Gradle or Maven with auto-import, you should exclude module files,
55+
# since they will be recreated, and may cause churn. Uncomment if using
56+
# auto-import.
57+
# .idea/modules.xml
58+
# .idea/*.iml
59+
# .idea/modules
60+
# *.iml
61+
# *.ipr
62+
63+
# CMake
64+
cmake-build-*/
65+
66+
# Mongo Explorer plugin
67+
.idea/**/mongoSettings.xml
68+
69+
# File-based project format
70+
*.iws
71+
72+
# IntelliJ
73+
out/
74+
75+
# mpeltonen/sbt-idea plugin
76+
.idea_modules/
77+
78+
# JIRA plugin
79+
atlassian-ide-plugin.xml
80+
81+
# Cursive Clojure plugin
82+
.idea/replstate.xml
83+
84+
# Crashlytics plugin (for Android Studio and IntelliJ)
85+
com_crashlytics_export_strings.xml
86+
crashlytics.properties
87+
crashlytics-build.properties
88+
fabric.properties
89+
90+
# Editor-based Rest Client
91+
.idea/httpRequests
92+
93+
# Android studio 3.1+ serialized cache file
94+
.idea/caches/build_file_checksums.ser
95+
96+
### Intellij+all Patch ###
97+
# Ignores the whole .idea folder and all .iml files
98+
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
99+
100+
.idea/
101+
102+
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
103+
104+
*.iml
105+
modules.xml
106+
.idea/misc.xml
107+
*.ipr
108+
109+
# Sonarlint plugin
110+
.idea/sonarlint
111+
112+
### macOS ###
113+
# General
114+
.DS_Store
115+
.AppleDouble
116+
.LSOverride
117+
118+
# Icon must end with two \r
119+
Icon
120+
121+
# Thumbnails
122+
._*
123+
124+
# Files that might appear in the root of a volume
125+
.DocumentRevisions-V100
126+
.fseventsd
127+
.Spotlight-V100
128+
.TemporaryItems
129+
.Trashes
130+
.VolumeIcon.icns
131+
.com.apple.timemachine.donotpresent
132+
133+
# Directories potentially created on remote AFP share
134+
.AppleDB
135+
.AppleDesktop
136+
Network Trash Folder
137+
Temporary Items
138+
.apdisk
139+
140+
### Vim ###
141+
# Swap
142+
[._]*.s[a-v][a-z]
143+
[._]*.sw[a-p]
144+
[._]s[a-rt-v][a-z]
145+
[._]ss[a-gi-z]
146+
[._]sw[a-p]
147+
148+
# Session
149+
Session.vim
150+
Sessionx.vim
151+
152+
# Temporary
153+
.netrwhist
154+
*~
155+
156+
# Auto-generated tag files
157+
tags
158+
159+
# Persistent undo
160+
[._]*.un~
161+
162+
# Coc configuration directory
163+
.vim
164+
165+
# End of https://www.gitignore.io/api/go,vim,macos,intellij+all

cmd/server/main.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
add_device "iot-demo/pkg/add-device"
6+
add_metrics "iot-demo/pkg/add-metrics"
7+
"iot-demo/pkg/ingestion"
8+
query_metrics "iot-demo/pkg/query-metrics"
9+
"iot-demo/pkg/registry"
10+
"iot-demo/pkg/storage/memory"
11+
"iot-demo/pkg/tokenizer"
12+
"time"
13+
)
14+
15+
func main() {
16+
registryRepository := memory.NewRegistry()
17+
registryService := registry.NewService(registryRepository)
18+
19+
ingestionRepository := memory.NewIngestion()
20+
ingestionService := ingestion.NewDecimalService(ingestionRepository)
21+
22+
jwtConfig := tokenizer.Config{Secret: []byte("hello-world")}
23+
jwt := tokenizer.NewJWT(jwtConfig)
24+
25+
deviceAdder := add_device.NewService(registryService, tokenizer.DeviceJWT(jwt))
26+
metricAdder := add_metrics.NewService(ingestionService)
27+
metricQuerier := query_metrics.NewService(ingestionService)
28+
29+
device, token, err := deviceAdder.Register("asd", "aasd", time.Now())
30+
fmt.Printf("device: %v, token: %v, err: %v\n", device, token, err)
31+
32+
got, ok := registryRepository.Get(device.ID)
33+
fmt.Printf("got device: %v, ok: %v\n", got, ok)
34+
35+
metrics := []*ingestion.DecimalMetricValue{
36+
{0, ingestion.Time(time.Now())},
37+
{1, ingestion.Time(time.Now())},
38+
{1, ingestion.Time(time.Now())},
39+
{1, ingestion.Time(time.Now())},
40+
}
41+
42+
err = metricAdder.Add(device.ID, metrics)
43+
fmt.Printf("insert err: %v\n", err)
44+
45+
gotm, err := metricQuerier.Query(device.ID)
46+
fmt.Printf("queried metrics: %v, err: %v\n", gotm, err)
47+
}

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module iot-demo
2+
3+
go 1.13
4+
5+
require github.com/dgrijalva/jwt-go v3.2.0+incompatible

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
2+
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=

pkg/add-device/add-device.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package add_device
2+
3+
import (
4+
"iot-demo/pkg/auth"
5+
"iot-demo/pkg/registry"
6+
"time"
7+
)
8+
9+
type Registerer interface {
10+
Register(serialNumber string, firmwareVersion string, registrationDate time.Time) (*registry.Device, error)
11+
}
12+
13+
type Tokenizer interface {
14+
Create(authInfo *auth.DeviceCredential) (auth.Token, error)
15+
}
16+
17+
type Service struct {
18+
registerer Registerer
19+
tokenizer Tokenizer
20+
}
21+
22+
func (s *Service) Register(serialNumber string, firmwareVersion string, registrationDate time.Time) (*registry.Device, auth.Token, error) {
23+
device, err := s.registerer.Register(serialNumber, firmwareVersion, registrationDate)
24+
if err != nil {
25+
return nil, "", err
26+
}
27+
28+
authInfo := auth.DeviceCredential{DeviceID: device.ID}
29+
token, err := s.tokenizer.Create(&authInfo)
30+
if err != nil {
31+
return nil, "", err
32+
}
33+
34+
return device, token, nil
35+
}
36+
37+
func NewService(registerer Registerer, tokenizer Tokenizer) *Service {
38+
return &Service{
39+
registerer: registerer,
40+
tokenizer: tokenizer,
41+
}
42+
}

pkg/add-metrics/add-metrics.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package add_metrics
2+
3+
import (
4+
"iot-demo/pkg/ingestion"
5+
)
6+
7+
type Inserter interface {
8+
Insert(deviceID int, metricsToInsert []*ingestion.DecimalMetricValue) error
9+
}
10+
11+
type Service struct {
12+
inserter Inserter
13+
}
14+
15+
func (s *Service) Add(deviceID int, metricsToInsert []*ingestion.DecimalMetricValue) error {
16+
return s.inserter.Insert(deviceID, metricsToInsert)
17+
}
18+
19+
func NewService(inserter Inserter) *Service {
20+
return &Service{inserter: inserter}
21+
}
22+

pkg/auth/device.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package auth
2+
3+
type Token string
4+
5+
type DeviceCredential struct {
6+
DeviceID int `json:"id"`
7+
}

pkg/ingestion/metric.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ingestion
2+
3+
type DecimalMetricValue struct {
4+
Value float64 `json:"value"`
5+
// Epoch timestamp in seconds
6+
Time Time `json:"time" swaggertype:"primitive,integer" example:"1578859629"`
7+
}
8+
9+
type DecimalRepository interface {
10+
Insert(deviceID int, metricsToInsert []*DecimalMetricValue) error
11+
Query(deviceID int) ([]*DecimalMetricValue, error)
12+
}
13+
14+
type DecimalService struct {
15+
repository DecimalRepository
16+
}
17+
18+
// insert metrics into the backing repository, notify all listeners
19+
func (ss *DecimalService) Insert(deviceID int, metricsToInsert []*DecimalMetricValue) error {
20+
err := ss.repository.Insert(deviceID, metricsToInsert)
21+
if err != nil {
22+
return err
23+
}
24+
25+
return nil
26+
}
27+
28+
func (ss *DecimalService) Query(deviceID int) ([]*DecimalMetricValue, error) {
29+
return ss.repository.Query(deviceID)
30+
}
31+
32+
func NewDecimalService(repository DecimalRepository) *DecimalService {
33+
return &DecimalService{repository: repository}
34+
}

pkg/ingestion/time.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ingestion
2+
3+
import (
4+
"strconv"
5+
"time"
6+
)
7+
8+
// Time defines a timestamp encoded as epoch seconds in JSON
9+
type Time time.Time
10+
11+
// MarshalJSON is used to convert the timestamp to JSON
12+
func (t Time) MarshalJSON() ([]byte, error) {
13+
return []byte(strconv.FormatInt(time.Time(t).Unix(), 10)), nil
14+
}
15+
16+
// UnmarshalJSON is used to convert the timestamp from JSON
17+
func (t *Time) UnmarshalJSON(s []byte) (err error) {
18+
r := string(s)
19+
q, err := strconv.ParseInt(r, 10, 64)
20+
if err != nil {
21+
return err
22+
}
23+
*(*time.Time)(t) = time.Unix(q, 0)
24+
return nil
25+
}
26+
27+
// Unix returns t as a Unix time, the number of seconds elapsed
28+
// since January 1, 1970 UTC. The result does not depend on the
29+
// location associated with t.
30+
func (t Time) Unix() int64 {
31+
return time.Time(t).Unix()
32+
}
33+
34+
// Time returns the JSON time as a time.Time instance in UTC
35+
func (t Time) Time() time.Time {
36+
return time.Time(t).UTC()
37+
}
38+
39+
// String returns t as a formatted string
40+
func (t Time) String() string {
41+
return t.Time().String()
42+
}

pkg/query-metrics/query-metrics.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package query_metrics
2+
3+
import (
4+
"iot-demo/pkg/ingestion"
5+
)
6+
7+
type Querier interface {
8+
Query(deviceID int) ([]*ingestion.DecimalMetricValue, error)
9+
}
10+
11+
type Service struct {
12+
querier Querier
13+
}
14+
15+
func (s *Service) Query(deviceID int) ([]*ingestion.DecimalMetricValue, error) {
16+
return s.querier.Query(deviceID)
17+
}
18+
19+
func NewService(querier Querier) *Service {
20+
return &Service{querier: querier}
21+
}
22+

0 commit comments

Comments
 (0)