mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 15:25:48 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cacf5708b | |||
| ad5c66fad2 | |||
| d89e91143b | |||
| 96bcc4cff4 | |||
| a8eb7ae039 | |||
| 6eade2c1d0 | |||
| 148c1aca0a | |||
| 70517bd907 | |||
| d5f0d7d225 | |||
| b20a846071 | |||
| 6600d26ef1 | |||
| 3de34062db | |||
| 8e9d7b4fdb | |||
| 5757380a63 | |||
| c944205080 | |||
| d825174ccb | |||
| 6408b8a9d3 | |||
| 845b69a4ac | |||
| 0c77d84176 | |||
| 970c1c86ca | |||
| 902630fb14 | |||
| 4ca443038d | |||
| 47c56cbac9 | |||
| 0fd0e6a13f | |||
| 8a86593dc3 | |||
| effade00aa | |||
| 8edf6907bc | |||
| 507bd2ee84 | |||
| 86f0d8e0d6 | |||
| 6461761985 | |||
| ec03d877f0 | |||
| 4e137a3214 | |||
| af281da430 | |||
| 1683d17830 | |||
| 7e83b2d612 | |||
| 312d30fd69 | |||
| 2c988c19b0 | |||
| 455fedf075 | |||
| 58cdf2cddc | |||
| 6d48446c16 | |||
| 29d146636a | |||
| f3f14e803d | |||
| b090aa3e02 | |||
| 0b954847fd | |||
| 44f5a7241f | |||
| b694f08ea2 | |||
| f1537528f9 | |||
| 344eed7976 | |||
| d8357b500c | |||
| 993398b8ab | |||
| 426f59d392 |
@@ -0,0 +1,15 @@
|
||||
Pull request title should be `MF-XXX - description` or `NOISSUE - description` where XXX is ID of issue that this PR relate to.
|
||||
Please review the [CONTRIBUTING.md](./CONTRIBUTING.md) file for detailed contributing guidelines.
|
||||
|
||||
### What does this do?
|
||||
|
||||
### Which issue(s) does this PR fix/relate to?
|
||||
Put here `Resolves #XXX` to auto-close the issue that your PR fixes (if such)
|
||||
|
||||
### List any changes that modify/break current functionality
|
||||
|
||||
### Have you included tests for your changes?
|
||||
|
||||
### Did you document any new/modified functionality?
|
||||
|
||||
### Notes
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
build
|
||||
*.pb.go
|
||||
|
||||
site/
|
||||
|
||||
|
||||
Generated
+125
-7
@@ -34,6 +34,12 @@
|
||||
packages = ["quantile"]
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/buger/jsonparser"
|
||||
packages = ["."]
|
||||
revision = "2cac668e8456b4284edb0715e17e2af02d3ec993"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/cenkalti/backoff"
|
||||
packages = ["."]
|
||||
@@ -76,6 +82,12 @@
|
||||
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
|
||||
version = "v0.3.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-kit/kit"
|
||||
packages = [
|
||||
@@ -96,6 +108,21 @@
|
||||
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-redis/redis"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
"internal/consistenthash",
|
||||
"internal/hashtag",
|
||||
"internal/pool",
|
||||
"internal/proto",
|
||||
"internal/singleflight",
|
||||
"internal/util"
|
||||
]
|
||||
revision = "f3bba01df2026fc865f7782948845db9cf44cf23"
|
||||
version = "v6.14.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
@@ -108,6 +135,17 @@
|
||||
revision = "fd0aebc74e908868b09ac140fb5a53cb363884c1"
|
||||
version = "1.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gocql/gocql"
|
||||
packages = [
|
||||
".",
|
||||
"internal/lru",
|
||||
"internal/murmur",
|
||||
"internal/streams"
|
||||
]
|
||||
revision = "651d6b1f343c6e168e45d119dcfe8f71e5bafb32"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = ["proto"]
|
||||
@@ -126,12 +164,35 @@
|
||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hailocab/go-hostpool"
|
||||
packages = ["."]
|
||||
revision = "e80d13ce29ede4452c43dea11e79b9bc8a15b478"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hokaccha/go-prettyjson"
|
||||
packages = ["."]
|
||||
revision = "e6b9231a2b1cc5798b336fdbf99c16cd8ad1e0c9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/influxdata/influxdb"
|
||||
packages = [
|
||||
@@ -157,6 +218,18 @@
|
||||
]
|
||||
revision = "d34b9ff171c21ad295489235aec8b6626023cd04"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
@@ -171,28 +244,52 @@
|
||||
"bson/decimal",
|
||||
"bson/elements",
|
||||
"bson/objectid",
|
||||
"core/addr",
|
||||
"bson/parser",
|
||||
"bson/parser/ast",
|
||||
"core/address",
|
||||
"core/auth",
|
||||
"core/auth/internal/gssapi",
|
||||
"core/command",
|
||||
"core/compressor",
|
||||
"core/connection",
|
||||
"core/connstring",
|
||||
"core/description",
|
||||
"core/dispatch",
|
||||
"core/options",
|
||||
"core/event",
|
||||
"core/option",
|
||||
"core/readconcern",
|
||||
"core/readpref",
|
||||
"core/result",
|
||||
"core/session",
|
||||
"core/tag",
|
||||
"core/topology",
|
||||
"core/uuid",
|
||||
"core/version",
|
||||
"core/wiremessage",
|
||||
"core/writeconcern",
|
||||
"internal",
|
||||
"mongo"
|
||||
"mongo",
|
||||
"mongo/aggregateopt",
|
||||
"mongo/changestreamopt",
|
||||
"mongo/clientopt",
|
||||
"mongo/collectionopt",
|
||||
"mongo/countopt",
|
||||
"mongo/dbopt",
|
||||
"mongo/deleteopt",
|
||||
"mongo/distinctopt",
|
||||
"mongo/dropcollopt",
|
||||
"mongo/findopt",
|
||||
"mongo/indexopt",
|
||||
"mongo/insertopt",
|
||||
"mongo/listcollectionopt",
|
||||
"mongo/listdbopt",
|
||||
"mongo/mongoopt",
|
||||
"mongo/replaceopt",
|
||||
"mongo/runcmdopt",
|
||||
"mongo/updateopt"
|
||||
]
|
||||
revision = "29a4d7d5b648e5b0b60e03e3bd71c11703f0c203"
|
||||
version = "v0.0.5"
|
||||
revision = "8df56f107cdd485351eb2523992c3364114b4b2e"
|
||||
version = "v0.0.10"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/nats-io/go-nats"
|
||||
@@ -340,9 +437,24 @@
|
||||
revision = "e9556a45379ef1da12e54847edb2fb3d7d566f36"
|
||||
version = "0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
packages = [
|
||||
"assert",
|
||||
"require"
|
||||
]
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
@@ -456,6 +568,12 @@
|
||||
revision = "c87af80f3cc5036b55b83d77171e156791085e2e"
|
||||
version = "v1.7.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
|
||||
version = "v0.9.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/ory-am/dockertest.v3"
|
||||
packages = ["."]
|
||||
@@ -465,6 +583,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "6010ae4c4f91c30b3a63789cc280466ce56d50f387c1e4d11c49df1302f083da"
|
||||
inputs-digest = "1f18adf44738d8f5c48b2f0576ab90c2f2c549f13a846b8f3c95aabaebe8efb4"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
+16
@@ -10,6 +10,10 @@
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "3.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/color"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-kit/kit"
|
||||
version = "0.6.0"
|
||||
@@ -22,6 +26,10 @@
|
||||
name = "github.com/golang/protobuf"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hokaccha/go-prettyjson"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/lib/pq"
|
||||
@@ -42,6 +50,10 @@
|
||||
name = "github.com/sony/gobreaker"
|
||||
version = "0.3.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.1"
|
||||
@@ -70,6 +82,10 @@
|
||||
name = "github.com/mongodb/mongo-go-driver"
|
||||
version = "0.0.5"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/gocql/gocql"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
+14
-13
@@ -7,7 +7,7 @@
|
||||
|
||||
[[drasko]]
|
||||
Name = "Drasko DRASKOVIC"
|
||||
Email = "drasko.draskovic@mainflux.com"
|
||||
Email = "drasko@mainflux.com"
|
||||
GitHub = "drasko"
|
||||
|
||||
# However, this role serves only in dead-lock events, or in a special and very rare cases
|
||||
@@ -24,22 +24,23 @@
|
||||
|
||||
[maintainers]
|
||||
|
||||
[[aleksandar]]
|
||||
Name = "Aleksandar NOVAKOVIC"
|
||||
Email = "aleksandar@mainflux.com"
|
||||
GitHub = "anovakovic01"
|
||||
|
||||
[[dusan]]
|
||||
Name = "Dusan BOROVCANIN"
|
||||
Email = "dusan@mainflux.com"
|
||||
GitHub = "dusanb94"
|
||||
|
||||
[[manuel]]
|
||||
Name = "Manuel IMPERIALE"
|
||||
Email = "manuel.imperiale@gmail.com"
|
||||
Email = "manuel@mainflux.com"
|
||||
GitHub = "manuIO"
|
||||
|
||||
[[janko]]
|
||||
Name = "Janko ISIDOROVIC"
|
||||
Email = "janko.isidorovic@mainflux.com"
|
||||
GitHub = "janko-isidorovic"
|
||||
|
||||
[[nikola]]
|
||||
Name = "Nikola MARCETIC"
|
||||
Email = "nikola.marcetic@mainflux.com"
|
||||
Email = "nikola@mainflux.com"
|
||||
GitHub = "nmarcetic"
|
||||
|
||||
[[dejan]]
|
||||
Name = "Dejan MIJIC"
|
||||
Email = "dejan.mijic@mainflux.com"
|
||||
GitHub = "mijicd"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
BUILD_DIR = build
|
||||
SERVICES = users things http normalizer ws influxdb mongodb
|
||||
SERVICES = users things http normalizer ws influxdb-writer influxdb-reader mongodb-writer mongodb-reader cassandra-writer cassandra-reader cli
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
CGO_ENABLED ?= 0
|
||||
GOOS ?= linux
|
||||
|
||||
@@ -9,23 +10,31 @@ define compile_service
|
||||
endef
|
||||
|
||||
define make_docker
|
||||
docker build --build-arg SVC_NAME=$(subst docker_,,$(1)) --tag=mainflux/$(subst docker_,,$(1)) -f docker/Dockerfile .
|
||||
docker build --no-cache --build-arg SVC_NAME=$(subst docker_,,$(1)) --tag=mainflux/$(subst docker_,,$(1)) -f docker/Dockerfile .
|
||||
endef
|
||||
|
||||
all: $(SERVICES)
|
||||
define make_docker_dev
|
||||
docker build --build-arg SVC_NAME=$(subst docker_dev_,,$(1)) --tag=mainflux/$(subst docker_dev_,,$(1)) -f docker/Dockerfile.dev ./build
|
||||
endef
|
||||
|
||||
.PHONY: all $(SERVICES) dockers latest release
|
||||
all: $(SERVICES) mqtt
|
||||
|
||||
.PHONY: all $(SERVICES) dockers dockers_dev latest release mqtt
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILD_DIR}
|
||||
rm -rf mqtt/node_modules
|
||||
|
||||
install:
|
||||
cp ${BUILD_DIR}/* $(GOBIN)
|
||||
|
||||
test:
|
||||
GOCACHE=off go test -v -race -tags test $(shell go list ./... | grep -v 'vendor\|cmd')
|
||||
|
||||
proto:
|
||||
protoc --go_out=plugins=grpc:. *.proto
|
||||
|
||||
$(SERVICES): proto
|
||||
$(SERVICES):
|
||||
$(call compile_service,$(@))
|
||||
|
||||
$(DOCKERS):
|
||||
@@ -35,12 +44,24 @@ dockers: $(DOCKERS)
|
||||
docker build --tag=mainflux/dashflux -f dashflux/docker/Dockerfile dashflux
|
||||
docker build --tag=mainflux/mqtt -f mqtt/Dockerfile .
|
||||
|
||||
latest: dockers
|
||||
$(DOCKERS_DEV):
|
||||
$(call make_docker_dev,$(@))
|
||||
|
||||
dockers_dev: $(DOCKERS_DEV)
|
||||
|
||||
mqtt:
|
||||
cd mqtt && npm install
|
||||
|
||||
define docker_push
|
||||
for svc in $(SERVICES); do \
|
||||
docker push mainflux/$$svc; \
|
||||
docker push mainflux/$$svc:$(1); \
|
||||
done
|
||||
docker push mainflux/dashflux
|
||||
docker push mainflux/mqtt
|
||||
docker push mainflux/dashflux:$(1)
|
||||
docker push mainflux/mqtt:$(1)
|
||||
endef
|
||||
|
||||
latest: dockers
|
||||
$(call docker_push,latest)
|
||||
|
||||
release:
|
||||
$(eval version = $(shell git describe --abbrev=0 --tags))
|
||||
@@ -48,9 +69,13 @@ release:
|
||||
$(MAKE) dockers
|
||||
for svc in $(SERVICES); do \
|
||||
docker tag mainflux/$$svc mainflux/$$svc:$(version); \
|
||||
docker push mainflux/$$svc:$(version); \
|
||||
done
|
||||
docker tag mainflux/dashflux mainflux/dashflux:$(version)
|
||||
docker push mainflux/dashflux:$(version)
|
||||
docker tag mainflux/mqtt mainflux/mqtt:$(version)
|
||||
docker push mainflux/mqtt:$(version)
|
||||
$(call docker_push,$(version))
|
||||
|
||||
rundev:
|
||||
cd scripts && ./run.sh
|
||||
|
||||
run:
|
||||
docker-compose -f docker/docker-compose.yml up
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package mainflux
|
||||
|
||||
// Response contains HTTP response specific methods.
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# Mainflux CLI
|
||||
## Build
|
||||
From the project root:
|
||||
```
|
||||
make cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
### Service
|
||||
#### Get the service verison
|
||||
```
|
||||
mainflux-cli version
|
||||
```
|
||||
|
||||
### User management
|
||||
#### Create User
|
||||
```
|
||||
mainflux-cli users create john.doe@email.com password
|
||||
```
|
||||
|
||||
#### Login User
|
||||
```
|
||||
mainflux-cli users token john.doe@email.com password
|
||||
```
|
||||
|
||||
### System Provisioning
|
||||
#### Provision Device
|
||||
```
|
||||
mainflux-cli things create '{"type":"device", "name":"nyDevice"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Provision Application
|
||||
```
|
||||
mainflux-cli things create '{"type":"app", "name":"nyDevice"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Retrieve All Things
|
||||
```
|
||||
mainflux-cli things get all --offset=1 --limit=5 <user_auth_token>
|
||||
```
|
||||
|
||||
#### Retrieve Thing By ID
|
||||
```
|
||||
mainflux-cli things get <thing_id> --offset=1 --limit=5 <user_auth_token>
|
||||
```
|
||||
|
||||
#### Remove Thing
|
||||
```
|
||||
mainflux-cli things delete <thing_id> <user_auth_token>
|
||||
```
|
||||
|
||||
#### Provision Channel
|
||||
```
|
||||
mainflux-cli channels create '{"name":"nyChannel"}' <user_auth_token>
|
||||
```
|
||||
|
||||
#### Retrieve All Channels
|
||||
```
|
||||
mainflux-cli channels get all --offset=1 --limit=5 <user_auth_token>
|
||||
```
|
||||
|
||||
#### Retrievie Channel By ID
|
||||
```
|
||||
mainflux-cli channels get <channel_id> --offset=1 --limit=5 <user_auth_token>
|
||||
```
|
||||
|
||||
#### Remove Channel
|
||||
```
|
||||
mainflux-cli channels delete <channel_id> <user_auth_token>
|
||||
```
|
||||
|
||||
### Access control
|
||||
#### Connect Thing to a Channel
|
||||
```
|
||||
mainflux-cli things connect <thing_id> <channel_id> <user_auth_token>
|
||||
```
|
||||
|
||||
#### Disconnect Things from a Channel
|
||||
```
|
||||
mainflux-cli things disconnect <thing_id> <channel_id> <user_auth_token>
|
||||
```
|
||||
|
||||
### Messaging
|
||||
#### Send a message over HTTP
|
||||
```
|
||||
mainflux-cli msg send <channel_id> '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]' <thing_auth_token>
|
||||
```
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mfxsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdChannels = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create <JSON_channel> <user_auth_token>",
|
||||
Long: `Creates new channel and generates it's UUID`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var channel mfxsdk.Channel
|
||||
if err := json.Unmarshal([]byte(args[0]), &channel); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := sdk.CreateChannel(channel, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(id)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "get",
|
||||
Short: "get all/<channel_id> <user_auth_token>",
|
||||
Long: `Gets list of all channels or gets channel by id`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "all" {
|
||||
l, err := sdk.Channels(args[1], uint64(Offset), uint64(Limit))
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(l)
|
||||
return
|
||||
}
|
||||
|
||||
c, err := sdk.Channel(args[0], args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(c)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "update",
|
||||
Short: "update <JSON_string> <user_auth_token>",
|
||||
Long: `Updates channel record`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var channel mfxsdk.Channel
|
||||
if err := json.Unmarshal([]byte(args[0]), &channel); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.UpdateChannel(channel, args[1]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "delete <channel_id> <user_auth_token>",
|
||||
Long: `Delete channel by ID`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DeleteChannel(args[0], args[1]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewChannelsCmd returns channels command.
|
||||
func NewChannelsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "channels",
|
||||
Short: "Manipulation with channels",
|
||||
Long: `Manipulation with channels: create, delete or update channels`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage(cmd.Short)
|
||||
},
|
||||
}
|
||||
|
||||
for i := range cmdChannels {
|
||||
cmd.AddCommand(&cmdChannels[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
const contentTypeSenml = "application/senml+json"
|
||||
|
||||
var cmdMessages = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "send",
|
||||
Short: "send <channel_id> <JSON_string> <thing_token>",
|
||||
Long: `Sends message on the channel`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.SendMessage(args[0], args[1], args[2]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewMessagesCmd returns messages command.
|
||||
func NewMessagesCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "msg",
|
||||
Short: "Send or retrieve messages",
|
||||
Long: `Send or retrieve messages: control message flow on the channel`,
|
||||
}
|
||||
|
||||
for i := range cmdMessages {
|
||||
cmd.AddCommand(&cmdMessages[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import mfxsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
|
||||
// Keep SDK handle in global var
|
||||
var sdk mfxsdk.SDK
|
||||
|
||||
// SetSDK sets mainflux SDK instance.
|
||||
func SetSDK(s mfxsdk.SDK) {
|
||||
sdk = s
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mfxsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const thingsEP = "things"
|
||||
|
||||
var cmdThings = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create <JSON_thing> <user_auth_token>",
|
||||
Long: `Create new thing, generate his UUID and store it`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var thing mfxsdk.Thing
|
||||
if err := json.Unmarshal([]byte(args[0]), &thing); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := sdk.CreateThing(thing, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(id)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "get",
|
||||
Short: "get all/<thing_id> <user_auth_token>",
|
||||
Long: `Get all things or thing by id`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == "all" {
|
||||
l, err := sdk.Things(args[1], uint64(Offset), uint64(Limit))
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
flush(l)
|
||||
return
|
||||
}
|
||||
|
||||
t, err := sdk.Thing(args[0], args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(t)
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "delete <thing_id> <user_auth_token>",
|
||||
Long: `Removes thing from database`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DeleteThing(args[0], args[1]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "update",
|
||||
Short: "update <JSON_string> <user_auth_token>",
|
||||
Long: `Update thing record`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
var thing mfxsdk.Thing
|
||||
if err := json.Unmarshal([]byte(args[0]), &thing); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.UpdateThing(thing, args[1]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "connect",
|
||||
Short: "connect <thing_id> <channel_id> <user_auth_token>",
|
||||
Long: `Connect thing to the channel`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.ConnectThing(args[0], args[1], args[2]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "disconnect",
|
||||
Short: "disconnect <thing_id> <channel_id> <user_auth_token>",
|
||||
Long: `Disconnect thing to the channel`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
if err := sdk.DisconnectThing(args[0], args[1], args[2]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewThingsCmd returns things command.
|
||||
func NewThingsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "things",
|
||||
Short: "things <options>",
|
||||
Long: `Things handling: create, delete or update things`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage(cmd.Short)
|
||||
},
|
||||
}
|
||||
|
||||
for i := range cmdThings {
|
||||
cmd.AddCommand(&cmdThings[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
mfxsdk "github.com/mainflux/mainflux/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cmdUsers = []cobra.Command{
|
||||
cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create <username> <password>",
|
||||
Long: `Creates new user`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
user := mfxsdk.User{
|
||||
Email: args[0],
|
||||
Password: args[1],
|
||||
}
|
||||
if err := sdk.CreateUser(user); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
cobra.Command{
|
||||
Use: "token",
|
||||
Short: "token <username> <password>",
|
||||
Long: `Creates new token`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Short)
|
||||
return
|
||||
}
|
||||
|
||||
user := mfxsdk.User{
|
||||
Email: args[0],
|
||||
Password: args[1],
|
||||
}
|
||||
token, err := sdk.CreateToken(user)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(token)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewUsersCmd returns users command.
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "users",
|
||||
Short: "users create/token <email> <password>",
|
||||
Long: `Manages users in the system (create account or token)`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
logUsage(cmd.Short)
|
||||
},
|
||||
}
|
||||
|
||||
for i := range cmdUsers {
|
||||
cmd.AddCommand(&cmdUsers[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
// Limit query parameter
|
||||
Limit uint = 10
|
||||
// Offset query parameter
|
||||
Offset uint
|
||||
)
|
||||
|
||||
func flush(i interface{}) {
|
||||
fmt.Printf("%s", color.BlueString(spew.Sdump(i)))
|
||||
}
|
||||
|
||||
func logUsage(u string) {
|
||||
fmt.Printf(color.YellowString("Usage: %s\n"), u)
|
||||
}
|
||||
|
||||
func logError(err error) {
|
||||
fmt.Printf("%s\n", color.RedString(err.Error()))
|
||||
}
|
||||
|
||||
func logOK() {
|
||||
fmt.Printf("%s\n", color.GreenString("OK"))
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package cli
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// NewVersionCmd returns version command.
|
||||
func NewVersionCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Get version of Mainflux Things Service",
|
||||
Long: `Mainflux server health check`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
v, err := sdk.Version()
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
flush(v)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/readers"
|
||||
"github.com/mainflux/mainflux/readers/api"
|
||||
"github.com/mainflux/mainflux/readers/cassandra"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
sep = ","
|
||||
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defCluster = "127.0.0.1"
|
||||
defKeyspace = "mainflux"
|
||||
defThingsURL = "localhost:8181"
|
||||
|
||||
envLogLevel = "MF_CASSANDRA_READER_LOG_LEVEL"
|
||||
envPort = "MF_CASSANDRA_READER_PORT"
|
||||
envCluster = "MF_CASSANDRA_READER_DB_CLUSTER"
|
||||
envKeyspace = "MF_CASSANDRA_READER_DB_KEYSPACE"
|
||||
envThingsURL = "MF_THINGS_URL"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
logLevel string
|
||||
port string
|
||||
cluster string
|
||||
keyspace string
|
||||
thingsURL string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
session := connectToCassandra(cfg.cluster, cfg.keyspace, logger)
|
||||
defer session.Close()
|
||||
|
||||
conn := connectToThings(cfg.thingsURL, logger)
|
||||
defer conn.Close()
|
||||
|
||||
tc := thingsapi.NewClient(conn)
|
||||
repo := newService(session, logger)
|
||||
|
||||
errs := make(chan error, 2)
|
||||
|
||||
go startHTTPServer(repo, tc, cfg.port, errs, logger)
|
||||
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("Cassandra reader service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
logLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
port: mainflux.Env(envPort, defPort),
|
||||
cluster: mainflux.Env(envCluster, defCluster),
|
||||
keyspace: mainflux.Env(envKeyspace, defKeyspace),
|
||||
thingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
}
|
||||
}
|
||||
|
||||
func connectToCassandra(cluster, keyspace string, logger logger.Logger) *gocql.Session {
|
||||
session, err := cassandra.Connect(strings.Split(cluster, sep), keyspace)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to Cassandra cluster: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func connectToThings(url string, logger logger.Logger) *grpc.ClientConn {
|
||||
conn, err := grpc.Dial(url, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to things service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func newService(session *gocql.Session, logger logger.Logger) readers.MessageRepository {
|
||||
repo := cassandra.New(session)
|
||||
repo = api.LoggingMiddleware(repo, logger)
|
||||
repo = api.MetricsMiddleware(
|
||||
repo,
|
||||
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "cassandra",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"}),
|
||||
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "cassandra",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"}),
|
||||
)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, port string, errs chan error, logger logger.Logger) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Cassandra reader service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, "cassandra-reader"))
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/cassandra"
|
||||
"github.com/nats-io/go-nats"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
queue = "cassandra-writer"
|
||||
sep = ","
|
||||
|
||||
defNatsURL = nats.DefaultURL
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defCluster = "127.0.0.1"
|
||||
defKeyspace = "mainflux"
|
||||
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envLogLevel = "MF_CASSANDRA_WRITER_LOG_LEVEL"
|
||||
envPort = "MF_CASSANDRA_WRITER_PORT"
|
||||
envCluster = "MF_CASSANDRA_WRITER_DB_CLUSTER"
|
||||
envKeyspace = "MF_CASSANDRA_WRITER_DB_KEYSPACE"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
natsURL string
|
||||
logLevel string
|
||||
port string
|
||||
cluster string
|
||||
keyspace string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
nc := connectToNATS(cfg.natsURL, logger)
|
||||
defer nc.Close()
|
||||
|
||||
session := connectToCassandra(cfg.cluster, cfg.keyspace, logger)
|
||||
defer session.Close()
|
||||
|
||||
repo := newService(session, logger)
|
||||
if err := writers.Start(nc, repo, queue, logger); err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create Cassandra writer: %s", err))
|
||||
}
|
||||
|
||||
errs := make(chan error, 2)
|
||||
|
||||
go startHTTPServer(cfg.port, errs, logger)
|
||||
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("Cassandra writer service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
natsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
logLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
port: mainflux.Env(envPort, defPort),
|
||||
cluster: mainflux.Env(envCluster, defCluster),
|
||||
keyspace: mainflux.Env(envKeyspace, defKeyspace),
|
||||
}
|
||||
}
|
||||
|
||||
func connectToNATS(url string, logger logger.Logger) *nats.Conn {
|
||||
nc, err := nats.Connect(url)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return nc
|
||||
}
|
||||
|
||||
func connectToCassandra(cluster, keyspace string, logger logger.Logger) *gocql.Session {
|
||||
session, err := cassandra.Connect(strings.Split(cluster, sep), keyspace)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to Cassandra cluster: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func newService(session *gocql.Session, logger logger.Logger) writers.MessageRepository {
|
||||
repo := cassandra.New(session)
|
||||
repo = writers.LoggingMiddleware(repo, logger)
|
||||
repo = writers.MetricsMiddleware(
|
||||
repo,
|
||||
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "cassandra",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"}),
|
||||
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "cassandra",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"}),
|
||||
)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func startHTTPServer(port string, errs chan error, logger logger.Logger) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Cassandra writer service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, cassandra.MakeHandler())
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/mainflux/mainflux/cli"
|
||||
"github.com/mainflux/mainflux/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func main() {
|
||||
msgContentType := string(sdk.CTJSONSenML)
|
||||
sdkConf := sdk.Config{
|
||||
BaseURL: "http://localhost",
|
||||
UsersPrefix: "",
|
||||
ThingsPrefix: "",
|
||||
HTTPAdapterPrefix: "http",
|
||||
MsgContentType: sdk.ContentType(msgContentType),
|
||||
TLSVerification: false,
|
||||
}
|
||||
|
||||
// Root
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "mainflux-cli",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
sdkConf.MsgContentType = sdk.ContentType(msgContentType)
|
||||
s := sdk.NewSDK(sdkConf)
|
||||
cli.SetSDK(s)
|
||||
},
|
||||
}
|
||||
|
||||
// API commands
|
||||
versionCmd := cli.NewVersionCmd()
|
||||
usersCmd := cli.NewUsersCmd()
|
||||
thingsCmd := cli.NewThingsCmd()
|
||||
channelsCmd := cli.NewChannelsCmd()
|
||||
messagesCmd := cli.NewMessagesCmd()
|
||||
|
||||
// Root Commands
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
rootCmd.AddCommand(usersCmd)
|
||||
rootCmd.AddCommand(thingsCmd)
|
||||
rootCmd.AddCommand(channelsCmd)
|
||||
rootCmd.AddCommand(messagesCmd)
|
||||
|
||||
// Root Flags
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&sdkConf.BaseURL,
|
||||
"mainflux-url",
|
||||
"m",
|
||||
sdkConf.BaseURL,
|
||||
"Mainflux host URL",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&sdkConf.UsersPrefix,
|
||||
"users-prefix",
|
||||
"u",
|
||||
sdkConf.UsersPrefix,
|
||||
"Mainflux users service prefix",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&sdkConf.ThingsPrefix,
|
||||
"things-prefix",
|
||||
"t",
|
||||
sdkConf.ThingsPrefix,
|
||||
"Mainflux things service prefix",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&sdkConf.HTTPAdapterPrefix,
|
||||
"http-prefix",
|
||||
"a",
|
||||
sdkConf.HTTPAdapterPrefix,
|
||||
"Mainflux http adapter prefix",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(
|
||||
&msgContentType,
|
||||
"content-type",
|
||||
"c",
|
||||
msgContentType,
|
||||
"Mainflux message content type",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().BoolVarP(
|
||||
&sdkConf.TLSVerification,
|
||||
"insecure",
|
||||
"i",
|
||||
sdkConf.TLSVerification,
|
||||
"Do not check for TLS cert",
|
||||
)
|
||||
|
||||
// Client and Channels Flags
|
||||
rootCmd.PersistentFlags().UintVarP(
|
||||
&cli.Limit,
|
||||
"limit",
|
||||
"l",
|
||||
100,
|
||||
"limit query parameter",
|
||||
)
|
||||
|
||||
rootCmd.PersistentFlags().UintVarP(
|
||||
&cli.Offset,
|
||||
"offset",
|
||||
"o",
|
||||
0,
|
||||
"offset query parameter",
|
||||
)
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
+29
-8
@@ -1,7 +1,15 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -12,7 +20,7 @@ import (
|
||||
adapter "github.com/mainflux/mainflux/http"
|
||||
"github.com/mainflux/mainflux/http/api"
|
||||
"github.com/mainflux/mainflux/http/nats"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
@@ -21,9 +29,11 @@ import (
|
||||
|
||||
const (
|
||||
defPort string = "8180"
|
||||
defLogLevel string = "error"
|
||||
defNatsURL string = broker.DefaultURL
|
||||
defThingsURL string = "localhost:8181"
|
||||
envPort string = "MF_HTTP_ADAPTER_PORT"
|
||||
envLogLevel string = "MF_HTTP_ADAPTER_LOG_LEVEL"
|
||||
envNatsURL string = "MF_NATS_URL"
|
||||
envThingsURL string = "MF_THINGS_URL"
|
||||
)
|
||||
@@ -31,17 +41,18 @@ const (
|
||||
type config struct {
|
||||
ThingsURL string
|
||||
NatsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{
|
||||
ThingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
}
|
||||
|
||||
logger := log.New(os.Stdout)
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
nc, err := broker.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
@@ -52,7 +63,7 @@ func main() {
|
||||
|
||||
conn, err := grpc.Dial(cfg.ThingsURL, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to users service: %s", err))
|
||||
logger.Error(fmt.Sprintf("Failed to connect to things service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer conn.Close()
|
||||
@@ -95,3 +106,13 @@ func main() {
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("HTTP adapter terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
ThingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
influxdata "github.com/influxdata/influxdb/client/v2"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/readers"
|
||||
"github.com/mainflux/mainflux/readers/api"
|
||||
"github.com/mainflux/mainflux/readers/influxdb"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
defThingsURL = "localhost:8181"
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "8086"
|
||||
defDBUser = "mainflux"
|
||||
defDBPass = "mainflux"
|
||||
|
||||
envThingsURL = "MF_THINGS_URL"
|
||||
envLogLevel = "MF_INFLUX_READER_LOG_LEVEL"
|
||||
envPort = "MF_INFLUX_READER_PORT"
|
||||
envDBName = "MF_INFLUX_READER_DB_NAME"
|
||||
envDBHost = "MF_INFLUX_READER_DB_HOST"
|
||||
envDBPort = "MF_INFLUX_READER_DB_PORT"
|
||||
envDBUser = "MF_INFLUX_READER_DB_USER"
|
||||
envDBPass = "MF_INFLUX_READER_DB_PASS"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
ThingsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
DBName string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPass string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, clientCfg := loadConfigs()
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
conn := connectToThings(cfg.ThingsURL, logger)
|
||||
defer conn.Close()
|
||||
|
||||
tc := thingsapi.NewClient(conn)
|
||||
|
||||
client, err := influxdata.NewHTTPClient(clientCfg)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB client: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
repo, err := influxdb.New(client, cfg.DBName)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
errs := make(chan error, 2)
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
go startHTTPServer(repo, tc, cfg.Port, logger, errs)
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("InfluxDB writer service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfigs() (config, influxdata.HTTPConfig) {
|
||||
cfg := config{
|
||||
ThingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
DBPass: mainflux.Env(envDBPass, defDBPass),
|
||||
}
|
||||
|
||||
clientCfg := influxdata.HTTPConfig{
|
||||
Addr: fmt.Sprintf("http://%s:%s", cfg.DBHost, cfg.DBPort),
|
||||
Username: cfg.DBUser,
|
||||
Password: cfg.DBPass,
|
||||
}
|
||||
|
||||
return cfg, clientCfg
|
||||
}
|
||||
|
||||
func connectToThings(url string, logger logger.Logger) *grpc.ClientConn {
|
||||
conn, err := grpc.Dial(url, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to things service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func newService(client influxdata.Client, logger logger.Logger) readers.MessageRepository {
|
||||
repo, _ := influxdb.New(client, "mainflux")
|
||||
repo = api.LoggingMiddleware(repo, logger)
|
||||
repo = api.MetricsMiddleware(
|
||||
repo,
|
||||
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"}),
|
||||
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"}),
|
||||
)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("InfluxDB reader service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, "influxdb-reader"))
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
influxdata "github.com/influxdata/influxdb/client/v2"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/influxdb"
|
||||
"github.com/nats-io/go-nats"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
queue = "influxdb-writer"
|
||||
|
||||
defNatsURL = nats.DefaultURL
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defBatchSize = "5000"
|
||||
defBatchTimeout = "5"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "8086"
|
||||
defDBUser = "mainflux"
|
||||
defDBPass = "mainflux"
|
||||
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envLogLevel = "MF_INFLUX_WRITER_LOG_LEVEL"
|
||||
envPort = "MF_INFLUX_WRITER_PORT"
|
||||
envBatchSize = "MF_INFLUX_WRITER_BATCH_SIZE"
|
||||
envBatchTimeout = "MF_INFLUX_WRITER_BATCH_TIMEOUT"
|
||||
envDBName = "MF_INFLUX_WRITER_DB_NAME"
|
||||
envDBHost = "MF_INFLUX_WRITER_DB_HOST"
|
||||
envDBPort = "MF_INFLUX_WRITER_DB_PORT"
|
||||
envDBUser = "MF_INFLUX_WRITER_DB_USER"
|
||||
envDBPass = "MF_INFLUX_WRITER_DB_PASS"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
NatsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
BatchSize string
|
||||
BatchTimeout string
|
||||
DBName string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPass string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, clientCfg := loadConfigs()
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
nc, err := nats.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
client, err := influxdata.NewHTTPClient(clientCfg)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB client: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
batchTimeout, err := strconv.Atoi(cfg.BatchTimeout)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Invalid value for batch timeout: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
batchSize, err := strconv.Atoi(cfg.BatchSize)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Invalid value of batch size: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
timeout := time.Duration(batchTimeout) * time.Second
|
||||
repo, err := influxdb.New(client, cfg.DBName, batchSize, timeout)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
counter, latency := makeMetrics()
|
||||
repo = writers.LoggingMiddleware(repo, logger)
|
||||
repo = writers.MetricsMiddleware(repo, counter, latency)
|
||||
if err := writers.Start(nc, repo, queue, logger); err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to start message writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
errs := make(chan error, 2)
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
go startHTTPService(cfg.Port, logger, errs)
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("InfluxDB writer service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfigs() (config, influxdata.HTTPConfig) {
|
||||
cfg := config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
BatchSize: mainflux.Env(envBatchSize, defBatchSize),
|
||||
BatchTimeout: mainflux.Env(envBatchTimeout, defBatchTimeout),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
DBPass: mainflux.Env(envDBPass, defDBPass),
|
||||
}
|
||||
|
||||
clientCfg := influxdata.HTTPConfig{
|
||||
Addr: fmt.Sprintf("http://%s:%s", cfg.DBHost, cfg.DBPort),
|
||||
Username: cfg.DBUser,
|
||||
Password: cfg.DBPass,
|
||||
}
|
||||
|
||||
return cfg, clientCfg
|
||||
}
|
||||
|
||||
func makeMetrics() (*kitprometheus.Counter, *kitprometheus.Summary) {
|
||||
counter := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_count",
|
||||
Help: "Number of database inserts.",
|
||||
}, []string{"method"})
|
||||
|
||||
latency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of inserts in microseconds.",
|
||||
}, []string{"method"})
|
||||
|
||||
return counter, latency
|
||||
}
|
||||
|
||||
func startHTTPService(port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("InfluxDB writer service started, exposed port %s", p))
|
||||
errs <- http.ListenAndServe(p, influxdb.MakeHandler())
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
influxdata "github.com/influxdata/influxdb/client/v2"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/influxdb"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
name = "influxdb-writer"
|
||||
senML = "out.senml"
|
||||
prefix = "http://"
|
||||
defNatsURL = nats.DefaultURL
|
||||
defPort = "8180"
|
||||
defPointName = "messages"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "8086"
|
||||
defDBUser = "mainflux"
|
||||
defDBPass = "mainflux"
|
||||
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envPort = "MF_INFLUX_WRITER_PORT"
|
||||
envDBName = "MF_INFLUX_WRITER_DB_NAME"
|
||||
envDBHost = "MF_INFLUX_WRITER_DB_HOST"
|
||||
envDBPort = "MF_INFLUX_WRITER_DB_PORT"
|
||||
envDBUser = "MF_INFLUX_WRITER_DB_USER"
|
||||
envDBPass = "MF_INFLUX_WRITER_DB_PASS"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
NatsURL string
|
||||
Port string
|
||||
DBName string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPass string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, clientCfg := loadConfigs()
|
||||
logger := log.New(os.Stdout)
|
||||
|
||||
nc, err := nats.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
client, err := influxdata.NewHTTPClient(clientCfg)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB client: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
repo, err := influxdb.New(client, cfg.DBName)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create InfluxDB writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
counter, latency := makeMetrics()
|
||||
repo = writers.LoggingMiddleware(repo, logger)
|
||||
repo = writers.MetricsMiddleware(repo, counter, latency)
|
||||
if err := writers.Start(name, nc, logger, repo); err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to start message writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
errs := make(chan error, 2)
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
go startHTTPService(cfg.Port, logger, errs)
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("InfluxDB writer service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfigs() (config, influxdata.HTTPConfig) {
|
||||
cfg := config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
DBPass: mainflux.Env(envDBPass, defDBPass),
|
||||
}
|
||||
|
||||
clientCfg := influxdata.HTTPConfig{
|
||||
Addr: fmt.Sprintf("%s%s:%s", prefix, cfg.DBHost, cfg.DBPort),
|
||||
Username: cfg.DBUser,
|
||||
Password: cfg.DBPass,
|
||||
}
|
||||
|
||||
return cfg, clientCfg
|
||||
}
|
||||
|
||||
func makeMetrics() (*kitprometheus.Counter, *kitprometheus.Summary) {
|
||||
counter := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_count",
|
||||
Help: "Number of database inserts.",
|
||||
}, []string{"method"})
|
||||
|
||||
latency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "influxdb",
|
||||
Subsystem: "message_writer",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of inserts in microseconds.",
|
||||
}, []string{"method"})
|
||||
|
||||
return counter, latency
|
||||
}
|
||||
|
||||
func startHTTPService(port string, logger log.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Influxdb writer service started, exposed port %s", p))
|
||||
errs <- http.ListenAndServe(p, influxdb.MakeHandler())
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/readers"
|
||||
"github.com/mainflux/mainflux/readers/api"
|
||||
"github.com/mainflux/mainflux/readers/mongodb"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
"github.com/mongodb/mongo-go-driver/mongo"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
defThingsURL = "localhost:8181"
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "27017"
|
||||
|
||||
envThingsURL = "MF_THINGS_URL"
|
||||
envLogLevel = "MF_MONGO_READER_LOG_LEVEL"
|
||||
envPort = "MF_MONGO_READER_PORT"
|
||||
envDBName = "MF_MONGO_READER_DB_NAME"
|
||||
envDBHost = "MF_MONGO_READER_DB_HOST"
|
||||
envDBPort = "MF_MONGO_READER_DB_PORT"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
thingsURL string
|
||||
logLevel string
|
||||
port string
|
||||
dbName string
|
||||
dbHost string
|
||||
dbPort string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfigs()
|
||||
logger, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
conn := connectToThings(cfg.thingsURL, logger)
|
||||
defer conn.Close()
|
||||
|
||||
tc := thingsapi.NewClient(conn)
|
||||
|
||||
db := connectToMongoDB(cfg.dbHost, cfg.dbPort, cfg.dbName, logger)
|
||||
|
||||
repo := newService(db, logger)
|
||||
|
||||
errs := make(chan error, 2)
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
go startHTTPServer(repo, tc, cfg.port, logger, errs)
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("MongoDB reader service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfigs() config {
|
||||
return config{
|
||||
thingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
logLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
port: mainflux.Env(envPort, defPort),
|
||||
dbName: mainflux.Env(envDBName, defDBName),
|
||||
dbHost: mainflux.Env(envDBHost, defDBHost),
|
||||
dbPort: mainflux.Env(envDBPort, defDBPort),
|
||||
}
|
||||
}
|
||||
|
||||
func connectToMongoDB(host, port, name string, logger logger.Logger) *mongo.Database {
|
||||
client, err := mongo.Connect(context.Background(), fmt.Sprintf("mongodb://%s:%s", host, port), nil)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to database: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return client.Database(name)
|
||||
}
|
||||
|
||||
func connectToThings(url string, logger logger.Logger) *grpc.ClientConn {
|
||||
conn, err := grpc.Dial(url, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to things service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func newService(db *mongo.Database, logger logger.Logger) readers.MessageRepository {
|
||||
repo := mongodb.New(db)
|
||||
repo = api.LoggingMiddleware(repo, logger)
|
||||
repo = api.MetricsMiddleware(
|
||||
repo,
|
||||
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "mongodb",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"}),
|
||||
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "mongodb",
|
||||
Subsystem: "message_reader",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"}),
|
||||
)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Mongo reader service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, "cassandra-reader"))
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -10,41 +18,47 @@ import (
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
mongodb "github.com/mainflux/mainflux/writers/mongodb"
|
||||
"github.com/mainflux/mainflux/writers/mongodb"
|
||||
"github.com/mongodb/mongo-go-driver/mongo"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
"github.com/nats-io/go-nats"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
name = "mongodb-writer"
|
||||
defNatsURL = nats.DefaultURL
|
||||
defPort = "8180"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "27017"
|
||||
queue = "mongodb-writer"
|
||||
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envPort = "MF_MONGO_WRITER_PORT"
|
||||
envDBName = "MF_MONGO_WRITER_DB_NAME"
|
||||
envDBHost = "MF_MONGO_WRITER_DB_HOST"
|
||||
envDBPort = "MF_MONGO_WRITER_DB_PORT"
|
||||
defNatsURL = nats.DefaultURL
|
||||
defLogLevel = "error"
|
||||
defPort = "8180"
|
||||
defDBName = "mainflux"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "27017"
|
||||
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envLogLevel = "MF_MONGO_WRITER_LOG_LEVEL"
|
||||
envPort = "MF_MONGO_WRITER_PORT"
|
||||
envDBName = "MF_MONGO_WRITER_DB_NAME"
|
||||
envDBHost = "MF_MONGO_WRITER_DB_HOST"
|
||||
envDBPort = "MF_MONGO_WRITER_DB_PORT"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
NatsURL string
|
||||
Port string
|
||||
DBName string
|
||||
DBHost string
|
||||
DBPort string
|
||||
NatsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
DBName string
|
||||
DBHost string
|
||||
DBPort string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfigs()
|
||||
logger := log.New(os.Stdout)
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
nc, err := nats.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
@@ -59,16 +73,12 @@ func main() {
|
||||
}
|
||||
|
||||
db := client.Database(cfg.DBName)
|
||||
repo, err := mongodb.New(db)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to create MongoDB writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
repo := mongodb.New(db)
|
||||
|
||||
counter, latency := makeMetrics()
|
||||
repo = writers.LoggingMiddleware(repo, logger)
|
||||
repo = writers.MetricsMiddleware(repo, counter, latency)
|
||||
if err := writers.Start(name, nc, logger, repo); err != nil {
|
||||
if err := writers.Start(nc, repo, queue, logger); err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to start message writer: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -88,11 +98,12 @@ func main() {
|
||||
|
||||
func loadConfigs() config {
|
||||
return config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +125,7 @@ func makeMetrics() (*kitprometheus.Counter, *kitprometheus.Summary) {
|
||||
return counter, latency
|
||||
}
|
||||
|
||||
func startHTTPService(port string, logger log.Logger, errs chan error) {
|
||||
func startHTTPService(port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Mongodb writer service started, exposed port %s", p))
|
||||
errs <- http.ListenAndServe(p, mongodb.MakeHandler())
|
||||
+55
-31
@@ -1,54 +1,84 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/normalizer"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
"github.com/mainflux/mainflux/normalizer/api"
|
||||
"github.com/mainflux/mainflux/normalizer/nats"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
defNatsURL string = nats.DefaultURL
|
||||
defPort string = "8180"
|
||||
envNatsURL string = "MF_NATS_URL"
|
||||
envPort string = "MF_NORMALIZER_PORT"
|
||||
defNatsURL string = broker.DefaultURL
|
||||
defLogLevel string = "error"
|
||||
defPort string = "8180"
|
||||
envNatsURL string = "MF_NATS_URL"
|
||||
envLogLevel string = "MF_NORMALIZER_LOG_LEVEL"
|
||||
envPort string = "MF_NORMALIZER_PORT"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
NatsURL string
|
||||
Port string
|
||||
NatsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
logger := log.New(os.Stdout)
|
||||
|
||||
nc, err := nats.Connect(cfg.NatsURL)
|
||||
nc, err := broker.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
svc := normalizer.New()
|
||||
svc = api.LoggingMiddleware(svc, logger)
|
||||
svc = api.MetricsMiddleware(
|
||||
svc,
|
||||
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "normalizer",
|
||||
Subsystem: "api",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"}),
|
||||
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "normalizer",
|
||||
Subsystem: "api",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"}),
|
||||
)
|
||||
|
||||
errs := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
p := fmt.Sprintf(":%s", cfg.Port)
|
||||
logger.Info(fmt.Sprintf("Normalizer service started, exposed port %s", cfg.Port))
|
||||
errs <- http.ListenAndServe(p, normalizer.MakeHandler())
|
||||
errs <- http.ListenAndServe(p, api.MakeHandler())
|
||||
}()
|
||||
|
||||
go func() {
|
||||
@@ -57,22 +87,16 @@ func main() {
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
counter := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: "normalizer",
|
||||
Subsystem: "api",
|
||||
Name: "request_count",
|
||||
Help: "Number of requests received.",
|
||||
}, []string{"method"})
|
||||
|
||||
latency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
|
||||
Namespace: "normalizer",
|
||||
Subsystem: "api",
|
||||
Name: "request_latency_microseconds",
|
||||
Help: "Total duration of requests in microseconds.",
|
||||
}, []string{"method"})
|
||||
|
||||
normalizer.Subscribe(nc, logger, counter, latency)
|
||||
nats.Subscribe(svc, nc, logger)
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("Normalizer service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
}
|
||||
}
|
||||
|
||||
+90
-42
@@ -1,22 +1,33 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/things"
|
||||
"github.com/mainflux/mainflux/things/api"
|
||||
grpcapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
httpapi "github.com/mainflux/mainflux/things/api/http"
|
||||
"github.com/mainflux/mainflux/things/postgres"
|
||||
rediscache "github.com/mainflux/mainflux/things/redis"
|
||||
"github.com/mainflux/mainflux/things/uuid"
|
||||
usersapi "github.com/mainflux/mainflux/users/api/grpc"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
@@ -24,39 +35,55 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "5432"
|
||||
defDBUser = "mainflux"
|
||||
defDBPass = "mainflux"
|
||||
defDBName = "things"
|
||||
defHTTPPort = "8180"
|
||||
defGRPCPort = "8181"
|
||||
defUsersURL = "localhost:8181"
|
||||
envDBHost = "MF_THINGS_DB_HOST"
|
||||
envDBPort = "MF_THINGS_DB_PORT"
|
||||
envDBUser = "MF_THINGS_DB_USER"
|
||||
envDBPass = "MF_THINGS_DB_PASS"
|
||||
envDBName = "MF_THINGS_DB"
|
||||
envHTTPPort = "MF_THINGS_HTTP_PORT"
|
||||
envGRPCPort = "MF_THINGS_GRPC_PORT"
|
||||
envUsersURL = "MF_USERS_URL"
|
||||
defLogLevel = "error"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "5432"
|
||||
defDBUser = "mainflux"
|
||||
defDBPass = "mainflux"
|
||||
defDBName = "things"
|
||||
defCacheURL = "localhost:6379"
|
||||
defCachePass = ""
|
||||
defCacheDB = "0"
|
||||
defHTTPPort = "8180"
|
||||
defGRPCPort = "8181"
|
||||
defUsersURL = "localhost:8181"
|
||||
envLogLevel = "MF_THINGS_LOG_LEVEL"
|
||||
envDBHost = "MF_THINGS_DB_HOST"
|
||||
envDBPort = "MF_THINGS_DB_PORT"
|
||||
envDBUser = "MF_THINGS_DB_USER"
|
||||
envDBPass = "MF_THINGS_DB_PASS"
|
||||
envDBName = "MF_THINGS_DB"
|
||||
envCacheURL = "MF_THINGS_CACHE_URL"
|
||||
envCachePass = "MF_THINGS_CACHE_PASS"
|
||||
envCacheDB = "MF_THINGS_CACHE_DB"
|
||||
envHTTPPort = "MF_THINGS_HTTP_PORT"
|
||||
envGRPCPort = "MF_THINGS_GRPC_PORT"
|
||||
envUsersURL = "MF_USERS_URL"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPass string
|
||||
DBName string
|
||||
HTTPPort string
|
||||
GRPCPort string
|
||||
UsersURL string
|
||||
LogLevel string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPass string
|
||||
DBName string
|
||||
CacheURL string
|
||||
CachePass string
|
||||
CacheDB string
|
||||
HTTPPort string
|
||||
GRPCPort string
|
||||
UsersURL string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
|
||||
logger := log.New(os.Stdout)
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
cache := connectToCache(cfg.CacheURL, cfg.CachePass, cfg.CacheDB, logger)
|
||||
|
||||
db := connectToDB(cfg, logger)
|
||||
defer db.Close()
|
||||
@@ -64,7 +91,7 @@ func main() {
|
||||
conn := connectToUsersService(cfg.UsersURL, logger)
|
||||
defer conn.Close()
|
||||
|
||||
svc := newService(conn, db, logger)
|
||||
svc := newService(conn, db, cache, logger)
|
||||
errs := make(chan error, 2)
|
||||
|
||||
go startHTTPServer(svc, cfg.HTTPPort, logger, errs)
|
||||
@@ -76,24 +103,43 @@ func main() {
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
err := <-errs
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("Things service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
DBPass: mainflux.Env(envDBPass, defDBPass),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
HTTPPort: mainflux.Env(envHTTPPort, defHTTPPort),
|
||||
GRPCPort: mainflux.Env(envGRPCPort, defGRPCPort),
|
||||
UsersURL: mainflux.Env(envUsersURL, defUsersURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
DBPass: mainflux.Env(envDBPass, defDBPass),
|
||||
DBName: mainflux.Env(envDBName, defDBName),
|
||||
CacheURL: mainflux.Env(envCacheURL, defCacheURL),
|
||||
CachePass: mainflux.Env(envCachePass, defCachePass),
|
||||
CacheDB: mainflux.Env(envCacheDB, defCacheDB),
|
||||
HTTPPort: mainflux.Env(envHTTPPort, defHTTPPort),
|
||||
GRPCPort: mainflux.Env(envGRPCPort, defGRPCPort),
|
||||
UsersURL: mainflux.Env(envUsersURL, defUsersURL),
|
||||
}
|
||||
}
|
||||
|
||||
func connectToDB(cfg config, logger log.Logger) *sql.DB {
|
||||
func connectToCache(cacheURL, cachePass string, cacheDB string, logger logger.Logger) *redis.Client {
|
||||
|
||||
db, err := strconv.Atoi(cacheDB)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to cache: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return redis.NewClient(&redis.Options{
|
||||
Addr: cacheURL,
|
||||
Password: cachePass,
|
||||
DB: db,
|
||||
})
|
||||
}
|
||||
|
||||
func connectToDB(cfg config, logger logger.Logger) *sql.DB {
|
||||
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to postgres: %s", err))
|
||||
@@ -102,7 +148,7 @@ func connectToDB(cfg config, logger log.Logger) *sql.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
func connectToUsersService(usersAddr string, logger log.Logger) *grpc.ClientConn {
|
||||
func connectToUsersService(usersAddr string, logger logger.Logger) *grpc.ClientConn {
|
||||
conn, err := grpc.Dial(usersAddr, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to users service: %s", err))
|
||||
@@ -111,13 +157,15 @@ func connectToUsersService(usersAddr string, logger log.Logger) *grpc.ClientConn
|
||||
return conn
|
||||
}
|
||||
|
||||
func newService(conn *grpc.ClientConn, db *sql.DB, logger log.Logger) things.Service {
|
||||
func newService(conn *grpc.ClientConn, db *sql.DB, client *redis.Client, logger logger.Logger) things.Service {
|
||||
users := usersapi.NewClient(conn)
|
||||
thingsRepo := postgres.NewThingRepository(db, logger)
|
||||
channelsRepo := postgres.NewChannelRepository(db, logger)
|
||||
chanCache := rediscache.NewChannelCache(client)
|
||||
thingCache := rediscache.NewThingCache(client)
|
||||
idp := uuid.New()
|
||||
|
||||
svc := things.New(users, thingsRepo, channelsRepo, idp)
|
||||
svc := things.New(users, thingsRepo, channelsRepo, chanCache, thingCache, idp)
|
||||
svc = api.LoggingMiddleware(svc, logger)
|
||||
svc = api.MetricsMiddleware(
|
||||
svc,
|
||||
@@ -137,13 +185,13 @@ func newService(conn *grpc.ClientConn, db *sql.DB, logger log.Logger) things.Ser
|
||||
return svc
|
||||
}
|
||||
|
||||
func startHTTPServer(svc things.Service, port string, logger log.Logger, errs chan error) {
|
||||
func startHTTPServer(svc things.Service, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Things service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, httpapi.MakeHandler(svc))
|
||||
}
|
||||
|
||||
func startGRPCServer(svc things.Service, port string, logger log.Logger, errs chan error) {
|
||||
func startGRPCServer(svc things.Service, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
listener, err := net.Listen("tcp", p)
|
||||
if err != nil {
|
||||
|
||||
+22
-8
@@ -1,8 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -11,7 +19,7 @@ import (
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/users"
|
||||
"github.com/mainflux/mainflux/users/api"
|
||||
grpcapi "github.com/mainflux/mainflux/users/api/grpc"
|
||||
@@ -24,6 +32,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defLogLevel = "error"
|
||||
defDBHost = "localhost"
|
||||
defDBPort = "5432"
|
||||
defDBUser = "mainflux"
|
||||
@@ -32,6 +41,7 @@ const (
|
||||
defHTTPPort = "8180"
|
||||
defGRPCPort = "8181"
|
||||
defSecret = "users"
|
||||
envLogLevel = "MF_USERS_LOG_LEVEL"
|
||||
envDBHost = "MF_USERS_DB_HOST"
|
||||
envDBPort = "MF_USERS_DB_PORT"
|
||||
envDBUser = "MF_USERS_DB_USER"
|
||||
@@ -43,6 +53,7 @@ const (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
LogLevel string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
@@ -56,8 +67,10 @@ type config struct {
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
|
||||
logger := log.New(os.Stdout)
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
db := connectToDB(cfg, logger)
|
||||
defer db.Close()
|
||||
|
||||
@@ -73,12 +86,13 @@ func main() {
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
err := <-errs
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("Users service terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
DBHost: mainflux.Env(envDBHost, defDBHost),
|
||||
DBPort: mainflux.Env(envDBPort, defDBPort),
|
||||
DBUser: mainflux.Env(envDBUser, defDBUser),
|
||||
@@ -90,7 +104,7 @@ func loadConfig() config {
|
||||
}
|
||||
}
|
||||
|
||||
func connectToDB(cfg config, logger log.Logger) *sql.DB {
|
||||
func connectToDB(cfg config, logger logger.Logger) *sql.DB {
|
||||
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to postgres: %s", err))
|
||||
@@ -99,7 +113,7 @@ func connectToDB(cfg config, logger log.Logger) *sql.DB {
|
||||
return db
|
||||
}
|
||||
|
||||
func newService(db *sql.DB, secret string, logger log.Logger) users.Service {
|
||||
func newService(db *sql.DB, secret string, logger logger.Logger) users.Service {
|
||||
repo := postgres.New(db)
|
||||
hasher := bcrypt.New()
|
||||
idp := jwt.New(secret)
|
||||
@@ -124,13 +138,13 @@ func newService(db *sql.DB, secret string, logger log.Logger) users.Service {
|
||||
return svc
|
||||
}
|
||||
|
||||
func startHTTPServer(svc users.Service, port string, logger log.Logger, errs chan error) {
|
||||
func startHTTPServer(svc users.Service, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
logger.Info(fmt.Sprintf("Users HTTP service started, exposed port %s", port))
|
||||
errs <- http.ListenAndServe(p, httpapi.MakeHandler(svc, logger))
|
||||
}
|
||||
|
||||
func startGRPCServer(svc users.Service, port string, logger log.Logger, errs chan error) {
|
||||
func startGRPCServer(svc users.Service, port string, logger logger.Logger, errs chan error) {
|
||||
p := fmt.Sprintf(":%s", port)
|
||||
listener, err := net.Listen("tcp", p)
|
||||
if err != nil {
|
||||
|
||||
+25
-8
@@ -1,7 +1,15 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -9,7 +17,7 @@ import (
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/grpc"
|
||||
adapter "github.com/mainflux/mainflux/ws"
|
||||
"github.com/mainflux/mainflux/ws/api"
|
||||
@@ -21,9 +29,11 @@ import (
|
||||
|
||||
const (
|
||||
defPort = "8180"
|
||||
defLogLevel = "error"
|
||||
defNatsURL = broker.DefaultURL
|
||||
defThingsURL = "localhost:8181"
|
||||
envPort = "MF_WS_ADAPTER_PORT"
|
||||
envLogLevel = "MF_WS_ADAPTER_LOG_LEVEL"
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
envThingsURL = "MF_THINGS_URL"
|
||||
)
|
||||
@@ -31,18 +41,17 @@ const (
|
||||
type config struct {
|
||||
ThingsURL string
|
||||
NatsURL string
|
||||
LogLevel string
|
||||
Port string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{
|
||||
ThingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
logger := log.New(os.Stdout)
|
||||
|
||||
nc, err := broker.Connect(cfg.NatsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
@@ -94,3 +103,11 @@ func main() {
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("WebSocket adapter terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
return config{
|
||||
NatsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
LogLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
Port: mainflux.Env(envPort, defPort),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
"favicon.png"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Route, RouterModule } from '@angular/router';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<div *mobxAutorun>
|
||||
<div class="loading" *ngIf="uiStore.loading" fxLayoutAlign="center center">
|
||||
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
.loading {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { reaction } from 'mobx';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import './rxjs-extensions.ts';
|
||||
import 'hammerjs';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<div class="container" style="height: 80vh" fxLayoutAlign="center center">
|
||||
<form fxLayout="column" [formGroup]="loginForm" (ngSubmit)="login()" fxFlex="30%" fxFlex.sm="70%" fxFlex.xs="90%">
|
||||
<mat-card>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
::ng-deep mat-card-content.loginCard {
|
||||
height: 200px;
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<div class="container" style="height: 80vh" fxLayoutAlign="center center">
|
||||
<form fxLayout="column" [formGroup]="signupForm" (ngSubmit)="signup()" fxFlex="30%" fxFlex.sm="70%" fxFlex.xs="90%">
|
||||
<mat-card>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
::ng-deep mat-card-content.loginCard {
|
||||
height: 200px;
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<form [formGroup]="addChannelForm" (ngSubmit)="onAddChannel()">
|
||||
<h1 *ngIf="!editMode" mat-dialog-title>Add channel</h1>
|
||||
<h1 *ngIf="editMode" mat-dialog-title>Edit channel</h1>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<div class="channelsContainer" fxLayout="row" fxLayoutWrap>
|
||||
<ng-container [ngSwitch]="channelsStore.channels?.length > 0">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
.addButton {
|
||||
position: fixed;
|
||||
bottom: 12px;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
+7
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<h1 mat-dialog-title>{{data.question}}</h1>
|
||||
<div mat-dialog-actions fxLayoutAlign="end end">
|
||||
<button mat-button mat-dialog-close>Cancel</button>
|
||||
|
||||
+7
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material';
|
||||
|
||||
+7
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material';
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<textarea formControlName="payload" matInput placeholder="Payload" matTextareaAutosize matAutosizeMinRows="2"
|
||||
<textarea formControlName="metadata" matInput placeholder="Metadata" matTextareaAutosize matAutosizeMinRows="2"
|
||||
matAutosizeMaxRows="5"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@ export class ThingDialogComponent implements OnInit {
|
||||
id: null,
|
||||
type: ['', [Validators.required]],
|
||||
name: ['', [Validators.required, Validators.minLength(5)]],
|
||||
payload: ['']
|
||||
metadata: ['']
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<!--
|
||||
Copyright (c) 2018
|
||||
Mainflux
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<div class="thingsContainer" fxLayout="row" fxLayoutWrap>
|
||||
<ng-container [ngSwitch]="thingsStore.things?.length > 0">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
@@ -17,9 +24,9 @@
|
||||
<mat-header-cell fxFlex="10%" *matHeaderCellDef mat-sort-header>Type</mat-header-cell>
|
||||
<mat-cell fxFlex="10%" *matCellDef="let row"> {{row.type}}</mat-cell>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="payload">
|
||||
<mat-header-cell fxFlex="35%" *matHeaderCellDef mat-sort-header>Payload</mat-header-cell>
|
||||
<mat-cell fxFlex="35%" *matCellDef="let row"> {{row.payload | json}}</mat-cell>
|
||||
<ng-container matColumnDef="metadata">
|
||||
<mat-header-cell fxFlex="35%" *matHeaderCellDef mat-sort-header>Metadata</mat-header-cell>
|
||||
<mat-cell fxFlex="35%" *matCellDef="let row"> {{row.metadata | json}}</mat-cell>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container matColumnDef="actions">
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
.addButton {
|
||||
position: fixed;
|
||||
bottom: 12px;
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { toJS } from 'mobx';
|
||||
@@ -16,7 +23,7 @@ import { ChannelsStore } from '../../core/store/channels.store';
|
||||
})
|
||||
export class ThingsComponent implements OnInit {
|
||||
things: Observable<Thing[]>;
|
||||
displayedColumns = ['id', 'name', 'type', 'payload', 'actions'];
|
||||
displayedColumns = ['id', 'name', 'type', 'metadata', 'actions'];
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import {
|
||||
MatButtonModule,
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import '../../../rxjs-extensions';
|
||||
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClient, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface Thing {
|
||||
id?: '';
|
||||
type: string;
|
||||
name: string;
|
||||
payload: string;
|
||||
metadata: string;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('ThingsStore', () => {
|
||||
const newThing: Thing = {
|
||||
name: 'new thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.addThing(newThing);
|
||||
@@ -89,7 +89,7 @@ describe('ThingsStore', () => {
|
||||
const newThing: Thing = {
|
||||
name: 'new thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.addThing(newThing);
|
||||
@@ -104,7 +104,7 @@ describe('ThingsStore', () => {
|
||||
const newThing: Thing = {
|
||||
name: 'new thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.addThing(newThing);
|
||||
@@ -120,7 +120,7 @@ describe('ThingsStore', () => {
|
||||
const newThing: Thing = {
|
||||
name: 'new thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.addThing(newThing);
|
||||
@@ -136,7 +136,7 @@ describe('ThingsStore', () => {
|
||||
const editedThing: Thing = {
|
||||
name: 'edited thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.editThing(editedThing);
|
||||
@@ -151,7 +151,7 @@ describe('ThingsStore', () => {
|
||||
const editedThing: Thing = {
|
||||
name: 'edited thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.editThing(editedThing);
|
||||
@@ -167,7 +167,7 @@ describe('ThingsStore', () => {
|
||||
const editedThing: Thing = {
|
||||
name: 'edited thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.editThing(editedThing);
|
||||
@@ -182,7 +182,7 @@ describe('ThingsStore', () => {
|
||||
const editedThing: Thing = {
|
||||
name: 'edited thing',
|
||||
type: 'app',
|
||||
payload: '',
|
||||
metadata: '',
|
||||
};
|
||||
|
||||
thingsStore.editThing(editedThing);
|
||||
@@ -198,7 +198,7 @@ describe('ThingsStore', () => {
|
||||
const thingToBeDeleted: Thing = {
|
||||
name: 'thingToBeDeleted',
|
||||
type: 'app',
|
||||
payload: ''
|
||||
metadata: ''
|
||||
};
|
||||
|
||||
thingsStore.deleteThing(thingToBeDeleted);
|
||||
@@ -213,7 +213,7 @@ describe('ThingsStore', () => {
|
||||
const thingToBeDeleted: Thing = {
|
||||
name: 'thingToBeDeleted',
|
||||
type: 'app',
|
||||
payload: ''
|
||||
metadata: ''
|
||||
};
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ describe('ThingsStore', () => {
|
||||
const thingToBeDeleted: Thing = {
|
||||
name: 'thingToBeDeleted',
|
||||
type: 'app',
|
||||
payload: ''
|
||||
metadata: ''
|
||||
};
|
||||
|
||||
thingsStore.deleteThing(thingToBeDeleted);
|
||||
@@ -245,7 +245,7 @@ describe('ThingsStore', () => {
|
||||
const thingToBeDeleted: Thing = {
|
||||
name: 'thingToBeDeleted',
|
||||
type: 'app',
|
||||
payload: ''
|
||||
metadata: ''
|
||||
};
|
||||
|
||||
thingsStore.deleteThing(thingToBeDeleted);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import 'rxjs/add/observable/combineLatest';
|
||||
import 'rxjs/add/observable/interval';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -6,7 +6,7 @@
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.png">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2018
|
||||
* Mainflux
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package mainflux acts as an umbrella package containing multiple different
|
||||
// microservices and defines all shared domain concepts.
|
||||
package mainflux
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM scratch
|
||||
ARG SVC_NAME
|
||||
COPY mainflux-$SVC_NAME /exe
|
||||
ENTRYPOINT ["/exe"]
|
||||
@@ -0,0 +1,28 @@
|
||||
###
|
||||
# This docker-compose file contains optional Cassandra and cassandra-reader. Since these are optional, this file is
|
||||
# dependent of docker-compose file from <project_root>/docker. In order to run
|
||||
# these optional service, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/cassandra-reader/docker-compose.yml up
|
||||
# from project root.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
cassandra-reader:
|
||||
image: mainflux/cassandra-reader:latest
|
||||
container_name: mainflux-cassandra-reader
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_THINGS_URL: things:8183
|
||||
MF_CASSANDRA_READER_PORT: 8903
|
||||
MF_CASSANDRA_READER_DB_CLUSTER: mainflux-cassandra
|
||||
MF_CASSANDRA_READER_DB_KEYSPACE: mainflux
|
||||
ports:
|
||||
- 8903:8903
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
@@ -0,0 +1,39 @@
|
||||
###
|
||||
# This docker-compose file contains optional Cassandra and cassandra-writer. Since these are optional, this file is
|
||||
# dependent of docker-compose file from <project_root>/docker. In order to run
|
||||
# these optional service, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/cassandra-writer/docker-compose.yml up
|
||||
# from project root.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
cassandra:
|
||||
image: cassandra:3.11.2
|
||||
container_name: mainflux-cassandra
|
||||
restart: on-failure
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
|
||||
cassandra-writer:
|
||||
image: mainflux/cassandra-writer:latest
|
||||
container_name: mainflux-cassandra-writer
|
||||
depends_on:
|
||||
- cassandra
|
||||
expose:
|
||||
- 8902
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_NATS_URL: nats://nats:4222
|
||||
MF_CASSANDRA_WRITER_PORT: 8902
|
||||
MF_CASSANDRA_WRITER_DB_CLUSTER: mainflux-cassandra
|
||||
MF_CASSANDRA_WRITER_DB_KEYSPACE: mainflux
|
||||
ports:
|
||||
- 8902:8902
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
docker-compose -f docker/addons/cassandra-writer/docker-compose.yml up -d
|
||||
sleep 20
|
||||
docker exec mainflux-cassandra cqlsh -e "CREATE KEYSPACE IF NOT EXISTS mainflux WITH replication = {'class':'SimpleStrategy','replication_factor':'1'};"
|
||||
@@ -0,0 +1,30 @@
|
||||
###
|
||||
# This docker-compose file contains optional InfluxDB-reader service for the Mainflux
|
||||
# platform. Since this service is optional, this file is dependent on the docker-compose.yml
|
||||
# file from <project_root>/docker/. In order to run InfluxDB-reader service, core services,
|
||||
# as well as the network from the core composition, should be already running.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
influxdb-reader:
|
||||
image: mainflux/influxdb-reader:latest
|
||||
container_name: mainflux-influxdb-reader
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_THINGS_URL: things:8183
|
||||
MF_INFLUX_READER_PORT: 8905
|
||||
MF_INFLUX_READER_DB_NAME: mainflux
|
||||
MF_INFLUX_READER_DB_HOST: mainflux-influxdb
|
||||
MF_INFLUX_READER_DB_PORT: 8086
|
||||
MF_INFLUX_READER_DB_USER: mainflux
|
||||
MF_INFLUX_READER_DB_PASS: mainflux
|
||||
ports:
|
||||
- 8905:8905
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
+17
-7
@@ -1,13 +1,16 @@
|
||||
###
|
||||
# This docker-compose file contains optional InfluxDB, InfluxDB-writer and Grafana services
|
||||
# for Mainflux platform. Since these are optional, this file is dependent of docker-compose file
|
||||
# from <project_root>/docker. In order to run these optional service, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/influxdb/docker-compose.yml up
|
||||
# from project root.
|
||||
# for the Mainflux platform. Since this services are optional, this file is dependent on the
|
||||
# docker-compose.yml file from <project_root>/docker/. In order to run these services,
|
||||
# core services, as well as the network from the core composition, should be already running.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
|
||||
influxdb:
|
||||
@@ -18,26 +21,31 @@ services:
|
||||
INFLUXDB_DB: mainflux
|
||||
INFLUXDB_ADMIN_USER: mainflux
|
||||
INFLUXDB_ADMIN_PASSWORD: mainflux
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
|
||||
influxdb-writer:
|
||||
image: mainflux/influxdb:latest
|
||||
image: mainflux/influxdb-writer:latest
|
||||
container_name: mainflux-influxdb-writer
|
||||
depends_on:
|
||||
- influxdb
|
||||
- nats
|
||||
expose:
|
||||
- 8900
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_NATS_URL: nats://nats:4222
|
||||
MF_INFLUX_WRITER_PORT: 8900
|
||||
MF_INFLUX_WRITER_BATCH_SIZE: 5000
|
||||
MF_INFLUX_WRITER_BATCH_TIMEOUT: 5
|
||||
MF_INFLUX_WRITER_DB_NAME: mainflux
|
||||
MF_INFLUX_WRITER_DB_HOST: influxdb
|
||||
MF_INFLUX_WRITER_DB_HOST: mainflux-influxdb
|
||||
MF_INFLUX_WRITER_DB_PORT: 8086
|
||||
MF_INFLUX_WRITER_DB_USER: mainflux
|
||||
MF_INFLUX_WRITER_DB_PASS: mainflux
|
||||
ports:
|
||||
- 8900:8900
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:5.1.3
|
||||
@@ -47,3 +55,5 @@ services:
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 3001:3000
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
@@ -0,0 +1,29 @@
|
||||
###
|
||||
# This docker-compose file contains optional MongoDB-reader service
|
||||
# for Mainflux platform. Since these are optional, this file is dependent of docker-compose file
|
||||
# from <project_root>/docker. In order to run these optional service, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/mongodb-reader/docker-compose.yml up
|
||||
# from project root. MongoDB service is defined in docker/addons/mongodb-writer/docker-compose.yml.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
mongodb-reader:
|
||||
image: mainflux/mongodb-reader:latest
|
||||
container_name: mainflux-mongodb-reader
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_THINGS_URL: things:8183
|
||||
MF_MONGO_READER_PORT: 8904
|
||||
MF_MONGO_READER_DB_NAME: mainflux
|
||||
MF_MONGO_READER_DB_HOST: mongodb
|
||||
MF_MONGO_READER_DB_PORT: 27017
|
||||
ports:
|
||||
- 8904:8904
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
+11
-7
@@ -2,15 +2,18 @@
|
||||
# This docker-compose file contains optional MongoDB and MongoDB-writer services
|
||||
# for Mainflux platform. Since these are optional, this file is dependent of docker-compose file
|
||||
# from <project_root>/docker. In order to run these optional service, execute command:
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/mongodb/docker-compose.yml up
|
||||
# docker-compose -f docker/docker-compose.yml -f docker/addons/mongodb-writer/docker-compose.yml up
|
||||
# from project root. MongoDB default port (27017) is exposed, so you can use various tools for database
|
||||
# inspection and data visualization.
|
||||
###
|
||||
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
networks:
|
||||
docker_mainflux-base-net:
|
||||
external: true
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
image: mongo:3.6-jessie
|
||||
container_name: mainflux-mongodb
|
||||
@@ -21,15 +24,14 @@ services:
|
||||
MONGO_INITDB_DATABASE: mainflux
|
||||
ports:
|
||||
- 27017:27017
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
|
||||
mongo-writer:
|
||||
image: mainflux/mongodb:latest
|
||||
mongodb-writer:
|
||||
image: mainflux/mongodb-writer:latest
|
||||
container_name: mainflux-mongodb-writer
|
||||
depends_on:
|
||||
- mongodb
|
||||
- nats
|
||||
expose:
|
||||
- 8901
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_NATS_URL: nats://nats:4222
|
||||
@@ -39,3 +41,5 @@ services:
|
||||
MF_MONGO_WRITER_DB_PORT: 27017
|
||||
ports:
|
||||
- 8901:8901
|
||||
networks:
|
||||
- docker_mainflux-base-net
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
mainflux-base-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:1.13-alpine
|
||||
@@ -22,11 +26,15 @@ services:
|
||||
- 80:80
|
||||
- 443:443
|
||||
- 8883:8883
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
nats:
|
||||
image: nats:1.0.2
|
||||
image: nats:1.3.0
|
||||
container_name: mainflux-nats
|
||||
restart: on-failure
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
users-db:
|
||||
image: postgres:10.2-alpine
|
||||
@@ -36,6 +44,8 @@ services:
|
||||
POSTGRES_USER: mainflux
|
||||
POSTGRES_PASSWORD: mainflux
|
||||
POSTGRES_DB: users
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
users:
|
||||
image: mainflux/users:latest
|
||||
@@ -57,6 +67,8 @@ services:
|
||||
MF_USERS_SECRET: secret
|
||||
ports:
|
||||
- 8180:8180
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
things-db:
|
||||
image: postgres:10.2-alpine
|
||||
@@ -66,6 +78,15 @@ services:
|
||||
POSTGRES_USER: mainflux
|
||||
POSTGRES_PASSWORD: mainflux
|
||||
POSTGRES_DB: things
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
things-cache:
|
||||
image: redis:4.0.9-alpine
|
||||
container_name: mainflux-things-cache
|
||||
restart: on-failure
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
things:
|
||||
image: mainflux/things:latest
|
||||
@@ -83,22 +104,29 @@ services:
|
||||
MF_THINGS_DB_USER: mainflux
|
||||
MF_THINGS_DB_PASS: mainflux
|
||||
MF_THINGS_DB: things
|
||||
MF_THINGS_CACHE_URL: things-cache:6379
|
||||
MF_THINGS_HTTP_PORT: 8182
|
||||
MF_THINGS_GRPC_PORT: 8183
|
||||
MF_USERS_URL: users:8181
|
||||
MF_THINGS_SECRET: secret
|
||||
ports:
|
||||
- 8182:8182
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
normalizer:
|
||||
image: mainflux/normalizer:latest
|
||||
container_name: mainflux-normalizer
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- nats
|
||||
expose:
|
||||
- 8184
|
||||
environment:
|
||||
MF_NATS_URL: nats://nats:4222
|
||||
MF_NORMALIZER_PORT: 8184
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
dashflux:
|
||||
image: mainflux/dashflux:latest
|
||||
@@ -106,12 +134,15 @@ services:
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
ws-adapter:
|
||||
image: mainflux/ws:latest
|
||||
container_name: mainflux-ws
|
||||
depends_on:
|
||||
- things
|
||||
- nats
|
||||
expose:
|
||||
- 8186
|
||||
restart: on-failure
|
||||
@@ -121,12 +152,15 @@ services:
|
||||
MF_THINGS_URL: things:8183
|
||||
ports:
|
||||
- 8186:8186
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
http-adapter:
|
||||
image: mainflux/http:latest
|
||||
container_name: mainflux-http
|
||||
depends_on:
|
||||
- things
|
||||
- nats
|
||||
restart: on-failure
|
||||
expose:
|
||||
- 8185
|
||||
@@ -136,18 +170,32 @@ services:
|
||||
MF_THINGS_URL: things:8183
|
||||
ports:
|
||||
- 8185:8185
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
redis:
|
||||
image: redis:4.0.9-alpine
|
||||
container_name: mainflux-redis
|
||||
restart: on-failure
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
mqtt-adapter:
|
||||
image: mainflux/mqtt:latest
|
||||
container_name: mainflux-mqtt
|
||||
depends_on:
|
||||
- things
|
||||
- nats
|
||||
- redis
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_MQTT_ADAPTER_PORT: 1883
|
||||
MF_MQTT_WS_PORT: 8880
|
||||
MF_MQTT_REDIS_HOST: redis
|
||||
MF_NATS_URL: nats://nats:4222
|
||||
MF_THINGS_URL: things:8183
|
||||
ports:
|
||||
- 1883:1883
|
||||
- 8880:8880
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
+1
-9
@@ -58,18 +58,10 @@ http {
|
||||
# Virtual Host Configs
|
||||
##
|
||||
|
||||
# HTTP
|
||||
# HTTPS
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name localhost;
|
||||
access_log off;
|
||||
error_log off;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS
|
||||
server {
|
||||
# SSL configuration
|
||||
#
|
||||
listen 443 ssl http2 default_server;
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
## Getting Mainflux
|
||||
|
||||
Mainflux can be fetched from the official [Mainflux GitHub repository](https://github.com/Mainflux/mainflux):
|
||||
|
||||
```
|
||||
go get github.com/mainflux/mainflux
|
||||
cd $GOPATH/src/github.com/mainflux/mainflux
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
### Prerequisites
|
||||
Make sure that you have [Protocol Buffers](https://developers.google.com/protocol-buffers/) compiler (`protoc`) installed.
|
||||
|
||||
[Go Protobuf](https://github.com/golang/protobuf) installation instructions are [here](https://github.com/golang/protobuf#installation).
|
||||
Go Protobuf uses C bindings, so you will need to install [C++ protobuf](https://github.com/google/protobuf) as a prerequisite.
|
||||
|
||||
### Build All Services
|
||||
|
||||
Use `GNU Make` tool to build all Mainflux services:
|
||||
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
Build artefacts will be put in the `build` directory.
|
||||
|
||||
> N.B. All Mainflux services are built as a statically linked binaries. This way they can be portable (transferred to any platform just by placing them there and running them) as they contain all needed libraries and do not relay on shared system libraries. This helps creating [FROM scratch](https://hub.docker.com/_/scratch/) dockers.
|
||||
|
||||
### Build Individual Microservice
|
||||
Individual microservices can be built with:
|
||||
|
||||
```
|
||||
make <microservice_name>
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
make http
|
||||
```
|
||||
|
||||
will build the HTTP Adapter microservice.
|
||||
|
||||
### Building Dockers
|
||||
|
||||
Dockers can be built with:
|
||||
|
||||
```
|
||||
make dockers
|
||||
```
|
||||
|
||||
or individually with:
|
||||
|
||||
```
|
||||
make docker_<microservice_name>
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
make docker_http
|
||||
```
|
||||
|
||||
> N.B. Mainflux creates `FROM scratch` docker containers which are compact and small in size.
|
||||
|
||||
> N.B. The `things-db` and `users-db` containers are built from a vanilla PostgreSQL docker image downloaded from docker hub which does not persist the data when these containers are rebuilt. Thus, __rebuilding of all docker containers with `make dockers` or rebuilding the `things-db` and `users-db` containers separately with `make docker_things-db` and `make docker_users-db` respectively, will cause data loss. All your users, things, channels and connections between them will be lost!__ As we use this setup only for development, we don't guarantee any permanent data persistence. If you need to retain the data between the container rebuilds you can attach volume to the `things-db` and `users-db` containers. Check the official docs on how to use volumes [here](https://docs.docker.com/storage/volumes/) and [here](https://docs.docker.com/compose/compose-file/#volumes).
|
||||
|
||||
#### Building Docker images for development
|
||||
|
||||
In order to speed up build process, you can use commands such as:
|
||||
|
||||
```bash
|
||||
make dockers_dev
|
||||
```
|
||||
|
||||
or individually with
|
||||
|
||||
```bash
|
||||
make docker_dev_<microservice_name>
|
||||
```
|
||||
|
||||
Commands `make dockers` and `make dockers_dev` are similar. The main difference is that building images in the development mode is done on the local machine, rather than an intermediate image, which makes building images much faster. Before running this command, corresponding binary needs to be built in order to make changes visible. This can be done using `make` or `make <service_name>` command. Commands `make dockers_dev` and `make docker_dev_<service_name>` should be used only for development to speed up the process of image building. **For deployment images, commands from section above should be used.**
|
||||
|
||||
### MQTT Microservice
|
||||
The MQTT Microservice in Mainflux is special, as it is currently the only microservice written in NodeJS. It is not compiled, but node modules need to be downloaded in order to start the service:
|
||||
|
||||
```
|
||||
cd mqtt
|
||||
npm install
|
||||
```
|
||||
|
||||
Note that there is a shorthand for doing these commands with `make` tool:
|
||||
|
||||
```
|
||||
make mqtt
|
||||
```
|
||||
|
||||
After that, the MQTT Adapter can be started from top directory (as it needs to find `*.proto` files) with:
|
||||
```
|
||||
node mqtt/mqtt.js
|
||||
```
|
||||
|
||||
### Protobuf
|
||||
Aforementioned `make` (which is an alias for `make all` target) is calling `protoc` command prior to compiling individual microservices.
|
||||
|
||||
To do this by hand, execute:
|
||||
|
||||
```
|
||||
protoc --go_out=plugins=grpc:. *.proto
|
||||
```
|
||||
|
||||
A shorthand to do this via `make` tool is:
|
||||
|
||||
```
|
||||
make proto
|
||||
```
|
||||
|
||||
> N.B. This must be done once at the beginning in order to generate protobuf Go structures needed for the build.
|
||||
|
||||
### Cross-compiling for ARM
|
||||
Mainflux can be compiled for ARM platform and run on Raspberry Pi or other similar IoT gateways, by following the instructions [here](https://dave.cheney.net/2015/08/22/cross-compilation-with-go-1-5) or [here](https://www.alexruf.net/golang/arm/raspberrypi/2016/01/16/cross-compile-with-go-1-5-for-raspberry-pi.html) as well as information
|
||||
found [here](https://github.com/golang/go/wiki/GoArm). The environment variables `GOARCH=arm` and `GOARM=7` must be set for the compilation.
|
||||
|
||||
Cross-compilation for ARM with Mainflux make:
|
||||
|
||||
```
|
||||
GOOS=linux GOARCH=arm GOARM=7 make
|
||||
```
|
||||
|
||||
## Running tests
|
||||
To run all of the tests you can execute:
|
||||
```
|
||||
make test
|
||||
```
|
||||
Dockertest is used for the tests, so to run them, you will need the Docker daemon/service running.
|
||||
|
||||
## Installing
|
||||
Installing Go binaries is simple: just move them from `build` to `$GOBIN` (do not fortget to add `$GOBIN` to your `$PATH`).
|
||||
|
||||
You can execute:
|
||||
|
||||
```
|
||||
make install
|
||||
```
|
||||
|
||||
which will do this copying of the binaries.
|
||||
|
||||
> N.B. Only Go binaries will be installed this way. The MQTT adapter is a NodeJS script and will stay in the `mqtt` dir.
|
||||
|
||||
## Deployment
|
||||
|
||||
### Prerequisites
|
||||
Mainflux depends on several infrastructural services, notably [NATS](https://www.nats.io/) broker and [PostgreSQL](https://www.postgresql.org/) database.
|
||||
|
||||
#### NATS
|
||||
Mainflux uses NATS as it's central message bus. For development purposes (when not run via Docker), it expects that NATS is installed on the local system.
|
||||
|
||||
To do this execute:
|
||||
|
||||
```
|
||||
go get github.com/nats-io/gnatsd
|
||||
```
|
||||
|
||||
This will install `gnatsd` binary that can be simply run by executing:
|
||||
|
||||
```
|
||||
gnatsd
|
||||
```
|
||||
|
||||
#### PostgreSQL
|
||||
Mainflux uses PostgreSQL to store metadata (`users`, `things` and `channels` entities alongside with authorization tokens).
|
||||
It expects that PostgreSQL DB is installed, set up and running on the local system.
|
||||
|
||||
Information how to set-up (prepare) PostgreSQL database can be found [here](https://support.rackspace.com/how-to/postgresql-creating-and-dropping-roles/),
|
||||
and it is done by executing following commands:
|
||||
|
||||
```
|
||||
# Create `users` and `things` databases
|
||||
sudo -u postgres createdb users
|
||||
sudo -u postgres createdb things
|
||||
|
||||
# Set-up Postgres roles
|
||||
sudo su - postgres
|
||||
psql -U postgres
|
||||
postgres=# CREATE ROLE mainflux WITH LOGIN ENCRYPTED PASSWORD 'mainflux';
|
||||
postgres=# ALTER USER mainflux WITH LOGIN ENCRYPTED PASSWORD 'mainflux';
|
||||
```
|
||||
|
||||
### Mainflux Services
|
||||
Running of the Mainflux microservices can be tricky, as there is a lot of them and each demand configuration in the form of environment variables.
|
||||
|
||||
The whole system (set of microservices) can be run with one command:
|
||||
|
||||
```
|
||||
make run
|
||||
```
|
||||
|
||||
which will properly configure and run all microservices.
|
||||
|
||||
Please assure that MQTT microservice has `node_modules` installed, as explained in _MQTT Microservice_ chapter.
|
||||
|
||||
> N.B. `make run` actually calls helper script `scripts/run.sh`, so you can inspect this script for the details.
|
||||
+159
-2
@@ -118,7 +118,7 @@ Content-Length: 1105
|
||||
"id": "cb63f852-2d48-44f0-a0cf-e450496c6c92",
|
||||
"type": "app",
|
||||
"name": "myapp",
|
||||
"key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MjMzNTYzOTcsImlzcyI6Im1haW5mbHV4Iiwic3ViIjoiY2I2M2Y4NTItMmQ0OC00NGYwLWEwY2YtZTQ1MDQ5NmM2YzkyIn0.FE6DWB3yJmBb8uojpQJaKUEbD0Elrjx0HhJA28bVzkU"
|
||||
"key": "cbf02d60-72f2-4180-9f82-2c957db929d1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -282,6 +282,32 @@ If you are not able to send custom headers in your handshake request, send it as
|
||||
query parameter `authorization`. Then your path should look like this
|
||||
`/channels/<channel_id>/messages?authorization=<thing_auth_key>`.
|
||||
|
||||
If you are using the docker environment prepend the url with `ws`. So for example
|
||||
`/ws/channels/<channel_id>/messages?authorization=<thing_auth_key>`
|
||||
|
||||
#### Basic nodejs example
|
||||
|
||||
```javascript
|
||||
const WebSocket = require('ws');
|
||||
|
||||
// do not verify self-signed certificates if you are using one
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
|
||||
// cbf02d60-72f2-4180-9f82-2c957db929d1 is an example of a thing_auth_key
|
||||
const ws = new WebSocket('wss://localhost/ws/channels/1/messages?authorization=cbf02d60-72f2-4180-9f82-2c957db929d1')
|
||||
|
||||
ws.on('open', () => {
|
||||
ws.send('something')
|
||||
})
|
||||
|
||||
ws.on('message', (data) => {
|
||||
console.log(data)
|
||||
})
|
||||
ws.on('error', (e) => {
|
||||
console.log(e)
|
||||
})
|
||||
```
|
||||
|
||||
### MQTT
|
||||
|
||||
To send and receive messages over MQTT you could use [Mosquitto tools](https://mosquitto.org),
|
||||
@@ -290,7 +316,7 @@ or [Paho](https://www.eclipse.org/paho/) if you want to use MQTT over WebSocket.
|
||||
To publish message over channel, thing should call following command:
|
||||
|
||||
```
|
||||
mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost -m [{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]
|
||||
mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost -m '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
|
||||
```
|
||||
|
||||
To subscribe to channel, thing should call following command:
|
||||
@@ -301,3 +327,134 @@ mosquitto_sub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h
|
||||
|
||||
If you are using TLS to secure MQTT connection, add `--cafile docker/ssl/certs/ca.crt`
|
||||
to every command.
|
||||
|
||||
## Add-ons
|
||||
|
||||
The `<project_root>/docker` folder contains an `addons` directory. This directory is used for various services that are not core to the Mainflux platform but could be used for providing additional features.
|
||||
|
||||
In order to run these services, core services, as well as the network from the core composition, should be already running.
|
||||
|
||||
### Writers
|
||||
|
||||
Writers provide an implementation of various `message writers`. Message writers are services that consume normalized (in `SenML` format) Mainflux messages and store them in specific data store.
|
||||
|
||||
#### InfluxDB, InfluxDB-writer and Grafana
|
||||
|
||||
From the project root execute the following command:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/addons/influxdb-writer/docker-compose.yml up -d
|
||||
```
|
||||
This will install and start:
|
||||
|
||||
- [InfluxDB](https://docs.influxdata.com/influxdb) - time series database
|
||||
- InfluxDB writer - message repository implementation for InfluxDB
|
||||
- [Grafana](https://grafana.com) - tool for database exploration and data visualization and analytics
|
||||
|
||||
Those new services will take some additional ports:
|
||||
|
||||
- 8086 by InfluxDB
|
||||
- 8900 by InfluxDB writer service
|
||||
- 3001 by Grafana
|
||||
|
||||
To access Grafana, navigate to `http://localhost:3001` and login with: `admin`, password: `admin`
|
||||
|
||||
#### Cassandra and Cassandra-writer
|
||||
|
||||
```bash
|
||||
./docker/addons/cassandra-writer/init.sh
|
||||
```
|
||||
_Please note that Cassandra may not be suitable for your testing enviroment because it has high system requirements._
|
||||
|
||||
#### MongoDB and MongoDB-writer
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/addons/mongodb-writer/docker-compose.yml up -d
|
||||
```
|
||||
MongoDB default port (27017) is exposed, so you can use various tools for database inspection and data visualization.
|
||||
|
||||
### Readers
|
||||
|
||||
Readers provide an implementation of various `message readers`.
|
||||
Message readers are services that consume normalized (in `SenML` format) Mainflux messages from data storage and opens HTTP API for message consumption.
|
||||
Installing corresponding writer before reader is implied.
|
||||
|
||||
|
||||
#### InfluxDB-reader
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/addons/influxdb-reader/docker-compose.yml up -d
|
||||
```
|
||||
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8905
|
||||
|
||||
|
||||
To read sent messages on channel with id `channel_id` you should send `GET` request to `/channels/<channel_id>/messages` with thing access token in `Authorization` header. That thing must be connected to channel with `channel_id`
|
||||
|
||||
```
|
||||
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8905/channels/<channel_id>/messages
|
||||
```
|
||||
|
||||
Response should look like this:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Tue, 18 Sep 2018 18:56:19 GMT
|
||||
Content-Length: 228
|
||||
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"Channel": 1,
|
||||
"Publisher": 2,
|
||||
"Protocol": "mqtt",
|
||||
"Name": "name:voltage",
|
||||
"Unit": "V",
|
||||
"Value": 5.6,
|
||||
"Time": 48.56
|
||||
},
|
||||
{
|
||||
"Channel": 1,
|
||||
"Publisher": 2,
|
||||
"Protocol": "mqtt",
|
||||
"Name": "name:temperature",
|
||||
"Unit": "C",
|
||||
"Value": 24.3,
|
||||
"Time": 48.56
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Note that you will receive only those messages that were sent by authorization token's owner.
|
||||
You can specify `offset` and `limit` parameters in order to fetch specific group of messages. In that case, your request should look like:
|
||||
|
||||
```
|
||||
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8905/channels/<channel_id>/messages?offset=0&limit=5
|
||||
```
|
||||
If you don't provide them, default values will be used instead: 0 for `offset`, and 10 for `limit`.
|
||||
|
||||
#### Cassandra-reader
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/addons/cassandra-reader/docker-compose.yml up -d
|
||||
```
|
||||
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8903
|
||||
|
||||
Aside from port, reading request is same as for other readers:
|
||||
|
||||
```
|
||||
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8903/channels/<channel_id>/messages
|
||||
```
|
||||
|
||||
#### MongoDB-reader
|
||||
|
||||
```bash
|
||||
docker-compose -f docker/addons/mongodb-reader/docker-compose.yml up -d
|
||||
```
|
||||
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8904
|
||||
|
||||
Aside from port, reading request is same as for other readers:
|
||||
|
||||
```
|
||||
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8904/channels/<channel_id>/messages
|
||||
```
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package mainflux
|
||||
|
||||
import "os"
|
||||
|
||||
+8
-6
@@ -8,11 +8,12 @@ The service is configured using the environment variables presented in the
|
||||
following table. Note that any unset variables will be replaced with their
|
||||
default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------------------|---------------------|-----------------------|
|
||||
| MF_HTTP_ADAPTER_PORT | Service HTTP port | 8180 |
|
||||
| MF_NATS_URL | NATS instance URL | nats://localhost:4222 |
|
||||
| MF_THINGS_URL | Things service URL | localhost:8181 |
|
||||
| Variable | Description | Default |
|
||||
|-----------------------------|--------------------------------|-----------------------|
|
||||
| MF_HTTP_ADAPTER_LOG_LEVEL | Log level for the HTTP Adapter | error |
|
||||
| MF_HTTP_ADAPTER_PORT | Service HTTP port | 8180 |
|
||||
| MF_NATS_URL | NATS instance URL | nats://localhost:4222 |
|
||||
| MF_THINGS_URL | Things service URL | localhost:8181 |
|
||||
|
||||
## Deployment
|
||||
|
||||
@@ -30,6 +31,7 @@ services:
|
||||
environment:
|
||||
MF_THINGS_URL: [Things service URL]
|
||||
MF_NATS_URL: [NATS instance URL]
|
||||
MF_HTTP_ADAPTER_LOG_LEVEL: [HTTP Adapter Log Level]
|
||||
MF_HTTP_ADAPTER_PORT: [Service HTTP port]
|
||||
```
|
||||
|
||||
@@ -48,7 +50,7 @@ make http
|
||||
make install
|
||||
|
||||
# set the environment variables and run the service
|
||||
MF_THINGS_URL=[Things service URL] MF_NATS_URL=[NATS instance URL] MF_HTTP_ADAPTER_PORT=[Service HTTP port] $GOBIN/mainflux-http
|
||||
MF_THINGS_URL=[Things service URL] MF_NATS_URL=[NATS instance URL] MF_HTTP_ADAPTER_LOG_LEVEL=[HTTP Adapter Log Level] MF_HTTP_ADAPTER_PORT=[Service HTTP port] $GOBIN/mainflux-http
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package http contains the domain concept definitions needed to support
|
||||
// Mainflux http adapter service functionality.
|
||||
package http
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package api contains API-related concerns: endpoint definitions, middlewares
|
||||
// and all resource representations.
|
||||
package api
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package api_test
|
||||
|
||||
import (
|
||||
@@ -5,6 +12,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -49,59 +57,74 @@ func (tr testRequest) make() (*http.Response, error) {
|
||||
}
|
||||
|
||||
func TestPublish(t *testing.T) {
|
||||
id := uint64(1)
|
||||
chanID := "1"
|
||||
invalidID := "wrong"
|
||||
contentType := "application/senml+json"
|
||||
token := "auth_token"
|
||||
invalidToken := "invalid_token"
|
||||
msg := `[{"n":"current","t":-1,"v":1.6}]`
|
||||
|
||||
id, _ := strconv.ParseUint(chanID, 10, 64)
|
||||
thingsClient := mocks.NewThingsClient(map[string]uint64{token: id})
|
||||
pub := newService()
|
||||
ts := newHTTPServer(pub, thingsClient)
|
||||
defer ts.Close()
|
||||
|
||||
cases := map[string]struct {
|
||||
chanID uint64
|
||||
chanID string
|
||||
msg string
|
||||
contentType string
|
||||
auth string
|
||||
status int
|
||||
}{
|
||||
"publish message": {
|
||||
chanID: id,
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusAccepted,
|
||||
},
|
||||
"publish message without authorization token": {
|
||||
chanID: id,
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
contentType: contentType,
|
||||
auth: "",
|
||||
status: http.StatusForbidden,
|
||||
},
|
||||
"publish message with invalid authorization token": {
|
||||
chanID: id,
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
contentType: contentType,
|
||||
auth: invalidToken,
|
||||
status: http.StatusForbidden,
|
||||
},
|
||||
"publish message without content type": {
|
||||
chanID: id,
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
contentType: "",
|
||||
auth: token,
|
||||
status: http.StatusAccepted,
|
||||
},
|
||||
"publish message to wrong channel": {
|
||||
chanID: invalidID,
|
||||
msg: msg,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusNotFound,
|
||||
},
|
||||
"publish message unable to authorize": {
|
||||
chanID: chanID,
|
||||
msg: msg,
|
||||
contentType: contentType,
|
||||
auth: mocks.ServiceErrToken,
|
||||
status: http.StatusServiceUnavailable,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodPost,
|
||||
url: fmt.Sprintf("%s/channels/%d/messages", ts.URL, tc.chanID),
|
||||
url: fmt.Sprintf("%s/channels/%s/messages", ts.URL, tc.chanID),
|
||||
contentType: tc.contentType,
|
||||
token: tc.auth,
|
||||
body: strings.NewReader(tc.msg),
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// +build !test
|
||||
|
||||
package api
|
||||
|
||||
+10
-4
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@@ -21,13 +28,12 @@ const protocol = "http"
|
||||
|
||||
var (
|
||||
errMalformedData = errors.New("malformed SenML data")
|
||||
errNotFound = errors.New("non-existent entity")
|
||||
auth mainflux.ThingsServiceClient
|
||||
)
|
||||
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc mainflux.MessagePublisher, cc mainflux.ThingsServiceClient) http.Handler {
|
||||
auth = cc
|
||||
func MakeHandler(svc mainflux.MessagePublisher, tc mainflux.ThingsServiceClient) http.Handler {
|
||||
auth = tc
|
||||
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(encodeError),
|
||||
@@ -118,7 +124,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
switch err {
|
||||
case errMalformedData:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case errNotFound:
|
||||
case things.ErrNotFound:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
case things.ErrUnauthorizedAccess:
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package mocks
|
||||
|
||||
import "github.com/mainflux/mainflux"
|
||||
|
||||
+21
-1
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
@@ -6,10 +13,15 @@ import (
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/things"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var _ mainflux.ThingsServiceClient = (*thingsClient)(nil)
|
||||
|
||||
// ServiceErrToken is used to simulate internal server error.
|
||||
const ServiceErrToken = "unavailable"
|
||||
|
||||
type thingsClient struct {
|
||||
things map[string]uint64
|
||||
}
|
||||
@@ -21,13 +33,21 @@ func NewThingsClient(data map[string]uint64) mainflux.ThingsServiceClient {
|
||||
|
||||
func (tc thingsClient) CanAccess(ctx context.Context, req *mainflux.AccessReq, opts ...grpc.CallOption) (*mainflux.ThingID, error) {
|
||||
key := req.GetToken()
|
||||
|
||||
// Since there is no appropriate way to simulate internal server error,
|
||||
// we had to use this obscure approach. ErrorToken simulates gRPC
|
||||
// call which returns internal server error.
|
||||
if key == ServiceErrToken {
|
||||
return nil, status.Error(codes.Internal, "internal server error")
|
||||
}
|
||||
|
||||
if key == "" {
|
||||
return nil, things.ErrUnauthorizedAccess
|
||||
}
|
||||
|
||||
id, ok := tc.things[key]
|
||||
if !ok {
|
||||
return nil, things.ErrUnauthorizedAccess
|
||||
return nil, status.Error(codes.PermissionDenied, "invalid credentials provided")
|
||||
}
|
||||
|
||||
return &mainflux.ThingID{Value: id}, nil
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018
|
||||
// Mainflux
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package nats contains NATS message publisher implementation.
|
||||
package nats
|
||||
|
||||
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: internal.proto
|
||||
|
||||
package mainflux
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
import (
|
||||
context "golang.org/x/net/context"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type AccessReq struct {
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
ChanID uint64 `protobuf:"varint,2,opt,name=chanID,proto3" json:"chanID,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *AccessReq) Reset() { *m = AccessReq{} }
|
||||
func (m *AccessReq) String() string { return proto.CompactTextString(m) }
|
||||
func (*AccessReq) ProtoMessage() {}
|
||||
func (*AccessReq) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_internal_50ed0f35f4250621, []int{0}
|
||||
}
|
||||
func (m *AccessReq) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_AccessReq.Unmarshal(m, b)
|
||||
}
|
||||
func (m *AccessReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_AccessReq.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *AccessReq) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_AccessReq.Merge(dst, src)
|
||||
}
|
||||
func (m *AccessReq) XXX_Size() int {
|
||||
return xxx_messageInfo_AccessReq.Size(m)
|
||||
}
|
||||
func (m *AccessReq) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_AccessReq.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_AccessReq proto.InternalMessageInfo
|
||||
|
||||
func (m *AccessReq) GetToken() string {
|
||||
if m != nil {
|
||||
return m.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *AccessReq) GetChanID() uint64 {
|
||||
if m != nil {
|
||||
return m.ChanID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ThingID struct {
|
||||
Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ThingID) Reset() { *m = ThingID{} }
|
||||
func (m *ThingID) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThingID) ProtoMessage() {}
|
||||
func (*ThingID) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_internal_50ed0f35f4250621, []int{1}
|
||||
}
|
||||
func (m *ThingID) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ThingID.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ThingID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ThingID.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *ThingID) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ThingID.Merge(dst, src)
|
||||
}
|
||||
func (m *ThingID) XXX_Size() int {
|
||||
return xxx_messageInfo_ThingID.Size(m)
|
||||
}
|
||||
func (m *ThingID) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ThingID.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ThingID proto.InternalMessageInfo
|
||||
|
||||
func (m *ThingID) GetValue() uint64 {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Token) Reset() { *m = Token{} }
|
||||
func (m *Token) String() string { return proto.CompactTextString(m) }
|
||||
func (*Token) ProtoMessage() {}
|
||||
func (*Token) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_internal_50ed0f35f4250621, []int{2}
|
||||
}
|
||||
func (m *Token) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Token.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Token.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *Token) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Token.Merge(dst, src)
|
||||
}
|
||||
func (m *Token) XXX_Size() int {
|
||||
return xxx_messageInfo_Token.Size(m)
|
||||
}
|
||||
func (m *Token) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Token.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Token proto.InternalMessageInfo
|
||||
|
||||
func (m *Token) GetValue() string {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UserID struct {
|
||||
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *UserID) Reset() { *m = UserID{} }
|
||||
func (m *UserID) String() string { return proto.CompactTextString(m) }
|
||||
func (*UserID) ProtoMessage() {}
|
||||
func (*UserID) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_internal_50ed0f35f4250621, []int{3}
|
||||
}
|
||||
func (m *UserID) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UserID.Unmarshal(m, b)
|
||||
}
|
||||
func (m *UserID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_UserID.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (dst *UserID) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_UserID.Merge(dst, src)
|
||||
}
|
||||
func (m *UserID) XXX_Size() int {
|
||||
return xxx_messageInfo_UserID.Size(m)
|
||||
}
|
||||
func (m *UserID) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_UserID.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_UserID proto.InternalMessageInfo
|
||||
|
||||
func (m *UserID) GetValue() string {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*AccessReq)(nil), "mainflux.AccessReq")
|
||||
proto.RegisterType((*ThingID)(nil), "mainflux.ThingID")
|
||||
proto.RegisterType((*Token)(nil), "mainflux.Token")
|
||||
proto.RegisterType((*UserID)(nil), "mainflux.UserID")
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// ThingsServiceClient is the client API for ThingsService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type ThingsServiceClient interface {
|
||||
CanAccess(ctx context.Context, in *AccessReq, opts ...grpc.CallOption) (*ThingID, error)
|
||||
Identify(ctx context.Context, in *Token, opts ...grpc.CallOption) (*ThingID, error)
|
||||
}
|
||||
|
||||
type thingsServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewThingsServiceClient(cc *grpc.ClientConn) ThingsServiceClient {
|
||||
return &thingsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *thingsServiceClient) CanAccess(ctx context.Context, in *AccessReq, opts ...grpc.CallOption) (*ThingID, error) {
|
||||
out := new(ThingID)
|
||||
err := c.cc.Invoke(ctx, "/mainflux.ThingsService/CanAccess", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *thingsServiceClient) Identify(ctx context.Context, in *Token, opts ...grpc.CallOption) (*ThingID, error) {
|
||||
out := new(ThingID)
|
||||
err := c.cc.Invoke(ctx, "/mainflux.ThingsService/Identify", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ThingsServiceServer is the server API for ThingsService service.
|
||||
type ThingsServiceServer interface {
|
||||
CanAccess(context.Context, *AccessReq) (*ThingID, error)
|
||||
Identify(context.Context, *Token) (*ThingID, error)
|
||||
}
|
||||
|
||||
func RegisterThingsServiceServer(s *grpc.Server, srv ThingsServiceServer) {
|
||||
s.RegisterService(&_ThingsService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _ThingsService_CanAccess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AccessReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ThingsServiceServer).CanAccess(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/mainflux.ThingsService/CanAccess",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ThingsServiceServer).CanAccess(ctx, req.(*AccessReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ThingsService_Identify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Token)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ThingsServiceServer).Identify(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/mainflux.ThingsService/Identify",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ThingsServiceServer).Identify(ctx, req.(*Token))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _ThingsService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "mainflux.ThingsService",
|
||||
HandlerType: (*ThingsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "CanAccess",
|
||||
Handler: _ThingsService_CanAccess_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Identify",
|
||||
Handler: _ThingsService_Identify_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "internal.proto",
|
||||
}
|
||||
|
||||
// UsersServiceClient is the client API for UsersService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type UsersServiceClient interface {
|
||||
Identify(ctx context.Context, in *Token, opts ...grpc.CallOption) (*UserID, error)
|
||||
}
|
||||
|
||||
type usersServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewUsersServiceClient(cc *grpc.ClientConn) UsersServiceClient {
|
||||
return &usersServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *usersServiceClient) Identify(ctx context.Context, in *Token, opts ...grpc.CallOption) (*UserID, error) {
|
||||
out := new(UserID)
|
||||
err := c.cc.Invoke(ctx, "/mainflux.UsersService/Identify", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UsersServiceServer is the server API for UsersService service.
|
||||
type UsersServiceServer interface {
|
||||
Identify(context.Context, *Token) (*UserID, error)
|
||||
}
|
||||
|
||||
func RegisterUsersServiceServer(s *grpc.Server, srv UsersServiceServer) {
|
||||
s.RegisterService(&_UsersService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _UsersService_Identify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Token)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UsersServiceServer).Identify(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/mainflux.UsersService/Identify",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UsersServiceServer).Identify(ctx, req.(*Token))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _UsersService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "mainflux.UsersService",
|
||||
HandlerType: (*UsersServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Identify",
|
||||
Handler: _UsersService_Identify_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "internal.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("internal.proto", fileDescriptor_internal_50ed0f35f4250621) }
|
||||
|
||||
var fileDescriptor_internal_50ed0f35f4250621 = []byte{
|
||||
// 231 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcb, 0xcc, 0x2b, 0x49,
|
||||
0x2d, 0xca, 0x4b, 0xcc, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0xc8, 0x4d, 0xcc, 0xcc,
|
||||
0x4b, 0xcb, 0x29, 0xad, 0x50, 0xb2, 0xe4, 0xe2, 0x74, 0x4c, 0x4e, 0x4e, 0x2d, 0x2e, 0x0e, 0x4a,
|
||||
0x2d, 0x14, 0x12, 0xe1, 0x62, 0x2d, 0xc9, 0xcf, 0x4e, 0xcd, 0x93, 0x60, 0x54, 0x60, 0xd4, 0xe0,
|
||||
0x0c, 0x82, 0x70, 0x84, 0xc4, 0xb8, 0xd8, 0x92, 0x33, 0x12, 0xf3, 0x3c, 0x5d, 0x24, 0x98, 0x14,
|
||||
0x18, 0x35, 0x58, 0x82, 0xa0, 0x3c, 0x25, 0x79, 0x2e, 0xf6, 0x90, 0x8c, 0xcc, 0xbc, 0x74, 0x4f,
|
||||
0x17, 0x90, 0xc6, 0xb2, 0xc4, 0x9c, 0xd2, 0x54, 0xb0, 0x46, 0x96, 0x20, 0x08, 0x47, 0x49, 0x96,
|
||||
0x8b, 0x35, 0x04, 0x6c, 0x02, 0x8a, 0x34, 0x27, 0x4c, 0x5a, 0x8e, 0x8b, 0x2d, 0xb4, 0x38, 0xb5,
|
||||
0x08, 0x5d, 0x3b, 0x4c, 0xde, 0xa8, 0x82, 0x8b, 0x17, 0x6c, 0x7e, 0x71, 0x70, 0x6a, 0x51, 0x59,
|
||||
0x66, 0x72, 0xaa, 0x90, 0x29, 0x17, 0xa7, 0x73, 0x62, 0x1e, 0xc4, 0xb9, 0x42, 0xc2, 0x7a, 0x30,
|
||||
0x3f, 0xe8, 0xc1, 0x3d, 0x20, 0x25, 0x88, 0x10, 0x84, 0x3a, 0x4d, 0x89, 0x41, 0xc8, 0x80, 0x8b,
|
||||
0xc3, 0x33, 0x25, 0x35, 0xaf, 0x24, 0x33, 0xad, 0x52, 0x88, 0x1f, 0x49, 0x01, 0xc8, 0x69, 0x58,
|
||||
0x75, 0x18, 0xd9, 0x73, 0xf1, 0x80, 0x5c, 0x06, 0xb7, 0x58, 0x1f, 0x9f, 0x09, 0x02, 0x08, 0x01,
|
||||
0x88, 0x77, 0x94, 0x18, 0x92, 0xd8, 0xc0, 0xc1, 0x6c, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x2f,
|
||||
0xbc, 0xec, 0x14, 0x78, 0x01, 0x00, 0x00,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user