Compare commits

..

28 Commits

Author SHA1 Message Date
Sava 0fd0e6a13f Initial user, device, channel provisioning script used to speed up testing on a fresh Mainflux installation. Accepts email, password, device name, channel name as arguments. (#369)
Signed-off-by: Sava Radoš <sava.rados@mainflux.com>
2018-08-27 20:51:17 +02:00
Jovan Kostovski 8a86593dc3 NOISSUE - Makefile test target, CREATE TABLE and dev guide enhancements (#359)
* Fixes #337

Signed-off-by: Jovan Kostovski <chombium@gmail.com>

* added create table if not exists

Signed-off-by: Jovan Kostovski <chombium@gmail.com>

* added test target in sync with Semaphore CI

Signed-off-by: Jovan Kostovski <chombium@gmail.com>

* added warning about the possible data loss

Signed-off-by: Jovan Kostovski <chombium@gmail.com>
2018-08-27 12:17:41 +02:00
Ivan Milošević effade00aa MF-325 - Add SPDX license and copyright headers (#362)
* MF-325 - Add SPDX license and copyright headers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* MF-325 - Add SPDX license and copyright headers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* MF-325 - Add SPDX license and copyright headers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* MF-325 - Add SPDX license and copyright headers

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* MF-325 - Change mainflux version from 0.4.0 to 0.5.0

Signed-off-by: Ivan Milošević <iva@blokovi.com>
2018-08-26 13:15:48 +02:00
Sava 8edf6907bc Change project retrieval procedure from git clone to go get (#366)
Signed-off-by: Sava Radoš <sava.rados@mainflux.com>
2018-08-25 14:39:30 +02:00
Dušan Borovčanin 507bd2ee84 MF-311 - Implement basic InfluxDB reader (#365)
* Add InfluxDB reader

Summary:
- Add basic reader features
- Update Makefile

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Raise test coverage

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update README.md and docker composition

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Fix docker-compose.yml

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Remove exposed ports

Ports are already exposed by mapping, so no need to explicity expose them.

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-08-25 12:48:03 +02:00
Sava 86f0d8e0d6 MF-363 - Add compiled .proto files (#364)
* Add compiled .proto files

Signed-off-by: Sava Radoš <sava.rados@mainflux.com>

* Remove proto as prerequisite for build services target

Signed-off-by: Sava Radoš <sava.rados@mainflux.com>
2018-08-24 15:33:40 +02:00
Aleksandar Novaković 6461761985 Add logging middleware to normalizer service (#360)
Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-08-21 10:15:50 +02:00
Paul RATHGEB ec03d877f0 Declare docker_mainflux-base-net as external and add it to all services (#361)
Signed-off-by: Paul RATHGEB <paul.rathgeb@skynet.be>
2018-08-20 22:00:45 +02:00
Ivan Milošević 4e137a3214 MF-343 - Thing Model: rename the Payload Field to Metadata (#358)
* Rename Payload field to Metadata

Rename Payload field of Thing to Metadata.

Signed-off-by: Ivan Milošević <iva@blokovi.com>

* Revert JSON payload rename in docs

Signed-off-by: Ivan Milošević <iva@blokovi.com>
2018-08-17 16:20:35 +02:00
Drasko DRASKOVIC af281da430 NOISSUE - Add insecure param to cli (#356)
Signed-off-by: drasko <drasko.draskovic@gmail.com>
2018-08-17 04:58:09 +02:00
Drasko DRASKOVIC 1683d17830 Add some make command info (#353)
Signed-off-by: drasko <drasko.draskovic@gmail.com>
2018-08-16 21:51:49 +02:00
Drasko DRASKOVIC 7e83b2d612 NOISSUE - Add system run script (#350)
* NOISSUE - Add system run script

Signed-off-by: drasko <drasko.draskovic@gmail.com>

* Add MQTT

Signed-off-by: drasko <drasko.draskovic@gmail.com>

* Add MQTT module install to Makefile. Fix warnings.

Signed-off-by: drasko <drasko.draskovic@gmail.com>
2018-08-16 19:52:43 +02:00
Drasko DRASKOVIC 312d30fd69 NOISSUE - Add Development Guide doc (#351)
* NOISSUE - Add Development Guide doc

Signed-off-by: drasko <drasko.draskovic@gmail.com>

* Add MQTT info

Signed-off-by: drasko <drasko.draskovic@gmail.com>

* Fix typos

Signed-off-by: drasko <drasko.draskovic@gmail.com>
2018-08-16 19:44:11 +02:00
Drasko DRASKOVIC 2c988c19b0 NOISSUE - Rename bashflux to cli and fix cert path (#349)
* NOISSUE - rename bashflux to cli and fix cert path

Signed-off-by: drasko <drasko.draskovic@gmail.com>

* Fix pkg name

Signed-off-by: drasko <drasko.draskovic@gmail.com>
2018-08-16 13:41:27 +02:00
Paul RATHGEB 455fedf075 Fix the influxdb hostname. Fix #346 (#348)
Signed-off-by: Paul RATHGEB <paul.rathgeb@skynet.be>
2018-08-16 04:06:25 +02:00
Aleksandar Novaković 58cdf2cddc MF-312 - Implement basic MongoDB reader (#344)
* Add mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add tests for mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add documentation for mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Fix test function name

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Update comment in docker-compose for mongodb-reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-08-08 13:38:34 +02:00
Aleksandar Novaković 6d48446c16 MF-313 - Implement basic Cassandra reader (#331)
* Fix logger message in http service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Inline query and error handling in cassandra writer

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Fix comments and import statement in writer interface

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add reader common interface and shared HTTP API

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add Cassandra reader implementation

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add tests for cassandra reader

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add swagger doc and readme for readers

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Update make file

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add docker-compose configuration for cassandra reader

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add readme file to cassandra reader

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-08-06 17:06:55 +02:00
Ivan Milošević 29d146636a Change favicon on Dashflux (#341)
Signed-off-by: Ivan Milosevic <iva@blokovi.com>
2018-08-01 23:11:40 +02:00
Marco Ferragina f3f14e803d Improved getting started docs (#339)
* Improved getting started docs

Better explaination of how to send messages to a channel using websockets.
Added a basic nodejs example

Signed-off-by: Marco Ferragina <marco.ferragina@gmail.com>

* Added leading slash

Signed-off-by: Marco Ferragina <marco.ferragina@gmail.com>

* added some comments to example code in docs

Signed-off-by: Marco Ferragina <marco.ferragina@gmail.com>
2018-07-25 11:12:31 +02:00
Manuel Imperiale b090aa3e02 MF-216 - Integrate Bashflux into monorepo (#308)
* MF-216 - Integrate Bashflux into monorepo

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename clients -> things

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix FormatResLog

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Initialize Channels commands in channels.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Mv bashflux to cmd/ repertory

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Mv API commands files to bashflux repertory

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Initialize Users commands in users.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Initialize Version command in version.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Initialize Messages command in messages.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm bashflux .gitignore and mv commands to root .gitignore

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename API commands vars

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix certificates paths

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm test logs

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Remove get channels cmd without arguments

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix connect and disconnect commands

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix messages endpoint

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm useless comments and dead code

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use contentTypeSenml var

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename cmdCobra -> cmd

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm else statments

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename SetServerAddr function vars

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename conf parameters

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename main with proper name

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix Update channel comment

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix README

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm .DS_Store from .gitignore

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename hhtp_client.go -> http.go

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm DeleteAllChannels and DeleteAllThings funcs

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix BF users usage log

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Improve bashflux logs

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Share types in funcs

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Typo fix

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix BF version cmd

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Set certs paths via env variables

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix package

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rm not direct dependencies from Gopkg.toml

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix README

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Add def prefix to certificates paths

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* User thiings service for version cmd

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename GetReqResp -> SendRequest

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix version help

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Return directly the pointer in NewVersionCmd

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Define endpoints names as consts and be consistent with naming

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use Spintf for string concatenation

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* typo fix

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix README

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix version endpoint

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix serverAddr

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
2018-07-11 13:53:37 +02:00
Dušan Borovčanin 0b954847fd MF-334 - Correct normalizer k8 port (#335)
* Fix k8s normalizer deployment port

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Remove targert port

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-07-02 14:53:16 +02:00
Dušan Borovčanin 44f5a7241f NOISSUE - Expose SenML subject from Normalizer service (#330)
* Expose SenML subject from Normalizer service

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Export shared NATS subjects

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-06-19 00:37:04 +02:00
Dušan Borovčanin b694f08ea2 Inteface implementation files match interface name (#329)
Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-06-18 10:51:30 +02:00
Dušan Borovčanin f1537528f9 NOISSUE - Raise test coverage (#324)
* Update WS tests

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Use require in all writer tests

Refactor code.

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Ignore Mainflux generated pb.go files

Ignore *.pb.go files generated by Mainflux, but don't ignore vendored generated code.

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Return an exported ErrNotFound instead of the unexported one

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update mocks to match the actual behaviour

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Update mocks error message

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Add auth service unavailable error test

Since this error is caused by gRPC server returning codes.Internal,
this behaviour is simulated using specific token. When that token is
passed as an auth header, the mock gRPC client returns aforementioned error.

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Use require package for postgres tests

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Remove redundant error checks in tests

Refactor tests.

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Rename error flag token

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-06-16 02:30:46 +02:00
Aleksandar Novaković 344eed7976 NOISSUE - Add exported metrics visualization for grafana (#326)
* Add exported metrics visualization in grafana

Add graphics for request count and request latency for users, things,
http adapter and ws adapter services.

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Rename grafana export file

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Move metrics configuration to metrics dir

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-06-15 17:08:49 +02:00
Aleksandar Novaković d8357b500c MF-328 - Add message persistence support for MQTT (#327)
* Add redis for message persistence

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add redis to docker composition

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Fix mqtt publish command in documentation

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Update documentation with new environment variables

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-06-15 07:27:23 -07:00
Dušan Borovčanin 993398b8ab NOISSUE - Update Kubernetes setup (#322)
* Add InfluxDB writer services setup to k8s

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>

* Remove commented NginX config

Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
2018-06-15 13:04:52 +02:00
Aleksandar Novaković 426f59d392 MF-235 - Add support for storing messages in Cassandra (#321)
* Add Cassandra writer implementation

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add cassandra service with version and metrics endpoints

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add test for cassandra writer

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Exclude api.go files from code coverage

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add readme file for cassandra writer

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add docker compose configuration for cassandra writer

Add README file. Add docker compose configuration.

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add gocql as project dependency

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Fix init script for cassandra in docker-compose

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add testifies require subpackage

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-06-08 14:25:55 +02:00
597 changed files with 59773 additions and 2482 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
build
*.pb.go
site/
Generated
+110 -7
View File
@@ -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 = [
@@ -108,6 +120,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 +149,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 +203,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 +229,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 +422,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 +553,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 +568,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "6010ae4c4f91c30b3a63789cc280466ce56d50f387c1e4d11c49df1302f083da"
inputs-digest = "e3b07d2098253644fc2f77fede1f00fcc077a20e4f46c59466ffd61c4998bb00"
solver-name = "gps-cdcl"
solver-version = 1
+16
View File
@@ -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 -4
View File
@@ -1,5 +1,5 @@
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))
CGO_ENABLED ?= 0
GOOS ?= linux
@@ -12,20 +12,24 @@ define make_docker
docker build --build-arg SVC_NAME=$(subst docker_,,$(1)) --tag=mainflux/$(subst docker_,,$(1)) -f docker/Dockerfile .
endef
all: $(SERVICES)
all: $(SERVICES) mqtt
.PHONY: all $(SERVICES) dockers latest release
.PHONY: all $(SERVICES) dockers 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,6 +39,9 @@ dockers: $(DOCKERS)
docker build --tag=mainflux/dashflux -f dashflux/docker/Dockerfile dashflux
docker build --tag=mainflux/mqtt -f mqtt/Dockerfile .
mqtt:
cd mqtt && npm install
latest: dockers
for svc in $(SERVICES); do \
docker push mainflux/$$svc; \
@@ -54,3 +61,6 @@ release:
docker push mainflux/dashflux:$(version)
docker tag mainflux/mqtt mainflux/mqtt:$(version)
docker push mainflux/mqtt:$(version)
run:
cd scripts && ./run.sh
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package mainflux
// Response contains HTTP response specific methods.
+87
View File
@@ -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>
```
+127
View File
@@ -0,0 +1,127 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/spf13/cobra"
)
const channelsEP = "channels"
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
}
CreateChannel(args[0], args[1])
},
},
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" {
GetChannels(args[1])
return
}
GetChannel(args[0], args[1])
},
},
cobra.Command{
Use: "update",
Short: "update <channel_id> <JSON_string> <user_auth_token>",
Long: `Updates channel record`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
LogUsage(cmd.Short)
return
}
UpdateChannel(args[0], args[1], args[2])
},
},
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
}
DeleteChannel(args[0], args[1])
},
},
}
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
}
// CreateChannel - creates new channel and generates UUID
func CreateChannel(data, token string) {
url := fmt.Sprintf("%s/%s", serverAddr, channelsEP)
req, err := http.NewRequest("POST", url, strings.NewReader(data))
SendRequest(req, token, err)
}
// GetChannels - gets all channels
func GetChannels(token string) {
url := fmt.Sprintf("%s/%s?offset=%s&limit=%s",
serverAddr, channelsEP, strconv.Itoa(Offset), strconv.Itoa(Limit))
req, err := http.NewRequest("GET", url, nil)
SendRequest(req, token, err)
}
// GetChannel - gets channel by ID
func GetChannel(id, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, channelsEP, id)
req, err := http.NewRequest("GET", url, nil)
SendRequest(req, token, err)
}
// UpdateChannel - update a channel
func UpdateChannel(id, data, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, channelsEP, id)
req, err := http.NewRequest("PUT", url, strings.NewReader(data))
SendRequest(req, token, err)
}
// DeleteChannel - removes channel
func DeleteChannel(id, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, channelsEP, id)
req, err := http.NewRequest("DELETE", url, nil)
SendRequest(req, token, err)
}
+76
View File
@@ -0,0 +1,76 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"github.com/mainflux/mainflux"
)
const (
defCertsPath = "/src/github.com/mainflux/mainflux/docker/ssl/certs/"
envCertFile = "MF_CERT_FILE"
envKeyFile = "MF_KEY_FILE"
envCaFile = "MF_CA_FILE"
)
var (
httpClient = &http.Client{}
serverAddr = fmt.Sprintf("https://%s", "localhost")
defCertFile = fmt.Sprintf("%s%s%s", os.Getenv("GOPATH"), defCertsPath, "mainflux-server.crt")
defKeyFile = fmt.Sprintf("%s%s%s", os.Getenv("GOPATH"), defCertsPath, "mainflux-server.key")
defCaFile = fmt.Sprintf("%s%s%s", os.Getenv("GOPATH"), defCertsPath, "ca.crt")
)
// SetServerAddr - set addr using host and port
func SetServerAddr(proto string, host string, port int) {
serverAddr = fmt.Sprintf("%s://%s", proto, host)
if port != 0 {
serverAddr = fmt.Sprintf("%s:%s", serverAddr, strconv.Itoa(port))
}
}
func SetCerts() {
// Set certificates paths
certFile := mainflux.Env(envCertFile, defCertFile)
keyFile := mainflux.Env(envKeyFile, defKeyFile)
caFile := mainflux.Env(envCaFile, defCaFile)
// Load client cert
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatal(err)
}
// Load CA cert
caCert, err := ioutil.ReadFile(caFile)
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
httpClient = &http.Client{Transport: transport}
}
+59
View File
@@ -0,0 +1,59 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"net/http"
"strings"
"github.com/spf13/cobra"
)
const contentTypeSenml = "application/senml+json"
var cmdMessages = []cobra.Command{
cobra.Command{
Use: "send",
Short: "send <channel_id> <JSON_string> <client_token>",
Long: `Sends message on the channel`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
LogUsage(cmd.Short)
return
}
SendMsg(args[0], args[1], args[2])
},
},
}
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
}
// SendMsg - publishes SenML message on the channel
func SendMsg(id, msg, token string) {
url := serverAddr + "/http/channels/" + id + "/messages"
req, err := http.NewRequest("POST", url, strings.NewReader(msg))
LogError(err)
req.Header.Set("Authorization", token)
req.Header.Add("Content-Type", contentTypeSenml)
resp, err := httpClient.Do(req)
FormatResLog(resp, err)
}
+167
View File
@@ -0,0 +1,167 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"fmt"
"net/http"
"strconv"
"strings"
"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
}
CreateThing(args[0], args[1])
},
},
cobra.Command{
Use: "get",
Short: "get all/<thing_id> <user_auth_token>",
Long: `Get all thingss or thing by id`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
LogUsage(cmd.Short)
return
}
if args[0] == "all" {
GetThings(args[1])
return
}
GetThing(args[0], args[1])
},
},
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
}
DeleteThing(args[0], args[1])
},
},
cobra.Command{
Use: "update",
Short: "update <thing_id> <JSON_string> <user_auth_token>",
Long: `Update thing record`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 3 {
LogUsage(cmd.Short)
return
}
UpdateThing(args[0], args[1], args[2])
},
},
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
}
ConnectThing(args[0], args[1], args[2])
},
},
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
}
DisconnectThing(args[0], args[1], args[2])
},
},
}
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
}
// CreateThing - creates new thing and generates thing UUID
func CreateThing(data, token string) {
url := fmt.Sprintf("%s/%s", serverAddr, thingsEP)
req, err := http.NewRequest("POST", url, strings.NewReader(data))
SendRequest(req, token, err)
}
// GetThings - gets all things
func GetThings(token string) {
url := fmt.Sprintf("%s/%s?offset=%s&limit=%s",
serverAddr, thingsEP, strconv.Itoa(Offset), strconv.Itoa(Limit))
req, err := http.NewRequest("GET", url, nil)
SendRequest(req, token, err)
}
// GetThing - gets thing by ID
func GetThing(id, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, thingsEP, id)
req, err := http.NewRequest("GET", url, nil)
SendRequest(req, token, err)
}
// UpdateThing - updates thing by ID
func UpdateThing(id, data, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, thingsEP, id)
req, err := http.NewRequest("PUT", url, strings.NewReader(data))
SendRequest(req, token, err)
}
// DeleteThing - removes thing
func DeleteThing(id, token string) {
url := fmt.Sprintf("%s/%s/%s", serverAddr, thingsEP, id)
req, err := http.NewRequest("DELETE", url, nil)
SendRequest(req, token, err)
}
// ConnectThing - connect thing to a channel
func ConnectThing(cliId, chanId, token string) {
url := fmt.Sprintf("%s/%s/%s/%s/%s", serverAddr, channelsEP,
chanId, thingsEP, cliId)
req, err := http.NewRequest("PUT", url, nil)
SendRequest(req, token, err)
}
// DisconnectThing - connect thing to a channel
func DisconnectThing(cliId, chanId, token string) {
url := fmt.Sprintf("%s/%s/%s/%s/%s", serverAddr, channelsEP,
chanId, thingsEP, cliId)
req, err := http.NewRequest("DELETE", url, nil)
SendRequest(req, token, err)
}
+75
View File
@@ -0,0 +1,75 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"fmt"
"strings"
"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
}
CreateUser(args[0], args[1])
},
},
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
}
CreateToken(args[0], args[1])
},
},
}
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
}
// CreateUser - create user
func CreateUser(user, pwd string) {
msg := fmt.Sprintf(`{"email": "%s", "password": "%s"}`, user, pwd)
url := fmt.Sprintf("%s/users", serverAddr)
resp, err := httpClient.Post(url, contentType, strings.NewReader(msg))
FormatResLog(resp, err)
}
// CreateToken - create user token
func CreateToken(user, pwd string) {
msg := fmt.Sprintf(`{"email": "%s", "password": "%s"}`, user, pwd)
url := fmt.Sprintf("%s/tokens", serverAddr)
resp, err := httpClient.Post(url, contentType, strings.NewReader(msg))
FormatResLog(resp, err)
}
+75
View File
@@ -0,0 +1,75 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"fmt"
"io/ioutil"
"net/http"
"github.com/fatih/color"
"github.com/hokaccha/go-prettyjson"
)
const contentType = "application/json"
var Limit = 10
var Offset = 0
func SendRequest(req *http.Request, token string, e error) {
req.Header.Set("Authorization", token)
req.Header.Add("Content-Type", contentType)
if e != nil {
LogError(e)
return
}
resp, err := httpClient.Do(req)
FormatResLog(resp, err)
}
// FormatResLog - format http response
func FormatResLog(resp *http.Response, err error) {
if err != nil {
LogError(err)
return
}
defer resp.Body.Close()
fmt.Printf(color.CyanString("%s %s\nContent-Length: %v\n\n"),
resp.Proto, resp.Status, resp.ContentLength)
if len(resp.Header.Get("Location")) != 0 {
fmt.Printf(color.BlueString("Resource location: %s\n\n"),
resp.Header.Get("Location"))
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
LogError(err)
return
}
if len(body) != 0 {
pj, err := prettyjson.Format([]byte(body))
if err != nil {
fmt.Printf("%s\n\n", color.BlueString(string(body)))
return
}
fmt.Printf("%s\n\n", string(pj))
}
}
func LogUsage(u string) {
fmt.Printf(color.YellowString("Usage: %s\n\n"), u)
}
func LogError(err error) {
fmt.Printf("%s\n\n", color.RedString(err.Error()))
}
+31
View File
@@ -0,0 +1,31 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package cli
import (
"fmt"
"github.com/spf13/cobra"
)
func NewVersionCmd() *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Get version of Mainflux Things Service",
Long: `Mainflux server health checkt.`,
Run: func(cmd *cobra.Command, args []string) {
Version()
},
}
}
// Version - server health check
func Version() {
url := fmt.Sprintf("%s/version", serverAddr)
FormatResLog(httpClient.Get(url))
}
+134
View File
@@ -0,0 +1,134 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/gocql/gocql"
"github.com/mainflux/mainflux"
log "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 = ","
defPort = "8180"
defCluster = "127.0.0.1"
defKeyspace = "mainflux"
defThingsURL = "localhost:8181"
envPort = "MF_CASSANDRA_READER_PORT"
envCluster = "MF_CASSANDRA_READER_DB_CLUSTER"
envKeyspace = "MF_CASSANDRA_READER_DB_KEYSPACE"
envThingsURL = "MF_THINGS_URL"
)
type config struct {
port string
cluster string
keyspace string
thingsURL string
}
func main() {
cfg := loadConfig()
logger := log.New(os.Stdout)
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{
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 log.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 log.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 log.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 log.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"))
}
+134
View File
@@ -0,0 +1,134 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/gocql/gocql"
"github.com/mainflux/mainflux"
log "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/writers"
"github.com/mainflux/mainflux/writers/cassandra"
nats "github.com/nats-io/go-nats"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
const (
sep = ","
defNatsURL = nats.DefaultURL
defPort = "8180"
defCluster = "127.0.0.1"
defKeyspace = "mainflux"
envNatsURL = "MF_NATS_URL"
envPort = "MF_CASSANDRA_WRITER_PORT"
envCluster = "MF_CASSANDRA_WRITER_DB_CLUSTER"
envKeyspace = "MF_CASSANDRA_WRITER_DB_KEYSPACE"
)
type config struct {
natsURL string
port string
cluster string
keyspace string
}
func main() {
cfg := loadConfig()
logger := log.New(os.Stdout)
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, logger, repo); 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),
port: mainflux.Env(envPort, defPort),
cluster: mainflux.Env(envCluster, defCluster),
keyspace: mainflux.Env(envKeyspace, defKeyspace),
}
}
func connectToNATS(url string, logger log.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 log.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 log.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 log.Logger) {
p := fmt.Sprintf(":%s", port)
logger.Info(fmt.Sprintf("Cassandra writer service started, exposed port %s", port))
errs <- http.ListenAndServe(p, cassandra.MakeHandler())
}
+77
View File
@@ -0,0 +1,77 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"log"
"github.com/mainflux/mainflux/cli"
"github.com/spf13/cobra"
)
func main() {
conf := struct {
host string
port int
insecure bool
}{
"localhost",
0,
false,
}
// Root
var rootCmd = &cobra.Command{
Use: "mainflux-cli",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
var proto string
if conf.insecure {
proto = "http"
} else {
proto = "https"
cli.SetCerts()
}
cli.SetServerAddr(proto, conf.host, conf.port)
},
}
// 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(
&conf.host, "host", "m", conf.host, "HTTP Host address")
rootCmd.PersistentFlags().IntVarP(
&conf.port, "port", "p", conf.port, "HTTP Host Port")
rootCmd.PersistentFlags().BoolVarP(
&conf.insecure, "insecure", "i", false, "do not use TLS")
// Client and Channels Flags
rootCmd.PersistentFlags().IntVarP(
&cli.Limit, "limit", "l", 100, "limit query parameter")
rootCmd.PersistentFlags().IntVarP(
&cli.Offset, "offset", "o", 0, "offset query parameter")
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
}
+8 -1
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
@@ -52,7 +59,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()
+141
View File
@@ -0,0 +1,141 @@
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/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"
defPort = "8180"
defDBName = "mainflux"
defDBHost = "localhost"
defDBPort = "8086"
defDBUser = "mainflux"
defDBPass = "mainflux"
envThingsURL = "MF_THINGS_URL"
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
Port string
DBName string
DBHost string
DBPort string
DBUser string
DBPass string
}
func main() {
cfg, clientCfg := loadConfigs()
logger := log.New(os.Stdout)
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),
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 log.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 log.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 log.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"))
}
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
@@ -18,9 +25,6 @@ import (
)
const (
name = "influxdb-writer"
senML = "out.senml"
prefix = "http://"
defNatsURL = nats.DefaultURL
defPort = "8180"
defPointName = "messages"
@@ -76,7 +80,7 @@ func main() {
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, logger, repo); err != nil {
logger.Error(fmt.Sprintf("Failed to start message writer: %s", err))
os.Exit(1)
}
@@ -106,7 +110,7 @@ func loadConfigs() (config, influxdata.HTTPConfig) {
}
clientCfg := influxdata.HTTPConfig{
Addr: fmt.Sprintf("%s%s:%s", prefix, cfg.DBHost, cfg.DBPort),
Addr: fmt.Sprintf("http://%s:%s", cfg.DBHost, cfg.DBPort),
Username: cfg.DBUser,
Password: cfg.DBPass,
}
+134
View File
@@ -0,0 +1,134 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/mainflux/mainflux"
log "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"
defPort = "8180"
defDBName = "mainflux"
defDBHost = "localhost"
defDBPort = "27017"
envThingsURL = "MF_THINGS_URL"
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
port string
dbName string
dbHost string
dbPort string
}
func main() {
cfg := loadConfigs()
logger := log.New(os.Stdout)
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),
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 log.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 log.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 log.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 log.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,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
@@ -19,7 +26,6 @@ import (
)
const (
name = "mongodb-writer"
defNatsURL = nats.DefaultURL
defPort = "8180"
defDBName = "mainflux"
@@ -59,16 +65,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, logger, repo); err != nil {
logger.Error(fmt.Sprintf("Failed to start message writer: %s", err))
os.Exit(1)
}
+32 -19
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
@@ -10,14 +17,16 @@ import (
"github.com/mainflux/mainflux"
log "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
defNatsURL string = broker.DefaultURL
defPort string = "8180"
envNatsURL string = "MF_NATS_URL"
envPort string = "MF_NORMALIZER_PORT"
@@ -36,19 +45,37 @@ func main() {
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,21 +84,7 @@ 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))
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
+1 -1
View File
@@ -9,7 +9,7 @@
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
"favicon.png"
],
"index": "index.html",
"main": "main.ts",
+7
View File
@@ -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';
+7
View File
@@ -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>
+7
View File
@@ -1,3 +1,10 @@
/*
* Copyright (c) 2018
* Mainflux
*
* SPDX-License-Identifier: Apache-2.0
*/
.loading {
position: absolute;
width: 100%;
+7
View File
@@ -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';
+7
View File
@@ -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';
+7
View File
@@ -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';
@@ -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>
@@ -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';
@@ -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';
+1 -1
View File
@@ -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);
+7
View File
@@ -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

+1 -1
View File
@@ -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>
+7
View File
@@ -1 +1,8 @@
/*
* Copyright (c) 2018
* Mainflux
*
* SPDX-License-Identifier: Apache-2.0
*/
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
+7
View File
@@ -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,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
+3
View File
@@ -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
@@ -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,13 +21,14 @@ 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
@@ -32,12 +36,14 @@ services:
MF_NATS_URL: nats://nats:4222
MF_INFLUX_WRITER_PORT: 8900
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 +53,5 @@ services:
restart: on-failure
ports:
- 3001:3000
networks:
- docker_mainflux-base-net
@@ -0,0 +1,31 @@
###
# 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
expose:
- 8901
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
@@ -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
+41 -1
View File
@@ -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.1.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,8 @@ services:
POSTGRES_USER: mainflux
POSTGRES_PASSWORD: mainflux
POSTGRES_DB: things
networks:
- mainflux-base-net
things:
image: mainflux/things:latest
@@ -89,16 +103,22 @@ services:
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 +126,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 +144,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 +162,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
+191
View File
@@ -0,0 +1,191 @@
## Getting Mainflux
Mainflux can be fetched from 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 (transfered to any platform just by placing them there and running them) as they contain all needed libraries and do not relay on system shared libs. This helps creating [FROM scratch](https://hub.docker.com/_/scratch/) dockers.
### Build Individual Microservice
Individual microservices can be built with command:
```
make <microservice_name>
```
For example:
```
make http
```
will build 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 as 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).
### MQTT Microservice
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 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 one time in 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.
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), 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 test you can execute:
```
make test
```
Dockertest is used for the test, so to run the tests you will need the Docker deamon/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 copy of binaries.
> N.B. Only Go binaries will be installed this way. MQTT adapter is NodeJS script and will stay in `mqtt` dir.
## Deployment
### Prerequisites
Mainflux depends on several infrastructureal 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/go-nats
```
This will install `gnatsd` binary that can be simply run by invoking
```
gnatsd
```
#### PostgreSQL
Mainflux uses PostgreSQL to store metadata (`users`, `things` and `channels` entities alongside with authorization tokens).
It expects that PostgreSQL DB is installed, setu-up and running on the local system.
Inflormation 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 config in the form of environment variables.
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.
+28 -2
View File
@@ -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:
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package mainflux
import "os"
+7
View File
@@ -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
+7
View File
@@ -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
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package api
import (
+31 -8
View File
@@ -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),
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
// +build !test
package api
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
// +build !test
package api
+10 -4
View File
@@ -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)
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
package mocks
import "github.com/mainflux/mainflux"
+21 -1
View File
@@ -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
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
// Package nats contains NATS message publisher implementation.
package nats
+381
View File
@@ -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,
}
+7
View File
@@ -1,3 +1,10 @@
//
// Copyright (c) 2018
// Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//
syntax = "proto3";
package mainflux;
+32
View File
@@ -0,0 +1,32 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mainflux-grafana
labels:
component: mainflux-grafana
spec:
replicas: 1
template:
metadata:
labels:
component: mainflux-grafana
spec:
containers:
- name: mainflux-grafana
image: grafana/grafana:5.1.3
imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: mainflux-grafana
labels:
component: mainflux-grafana
spec:
selector:
component: mainflux-grafana
ports:
- port: 3001
targetPort: 3000
type: LoadBalancer
+64
View File
@@ -0,0 +1,64 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: mainflux-influxdb-data-disk
labels:
name: mainflux-influxdb-data-disk
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /tmp/data/influxdb-0
persistentVolumeReclaimPolicy: Recycle
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: mainflux-influxdb-data-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: mainflux-influxdb
labels:
name: mainflux-influxdb
spec:
containers:
- name: mainflux-influxdb
image: influxdb:1.5.2-alpine
env:
- name: INFLUXDB_DB
value: "mainflux"
- name: INFLUXDB_ADMIN_USER
value: "mainflux"
- name: INFLUXDB_ADMIN_PASSWORD
value: "mainflux"
ports:
- containerPort: 8086
volumeMounts:
- mountPath: /var/lib/influxdb
name: mainflux-influxdb-data
volumes:
- name: mainflux-influxdb-data
persistentVolumeClaim:
claimName: mainflux-influxdb-data-claim
---
apiVersion: v1
kind: Service
metadata:
name: mainflux-influxdb
labels:
name: mainflux-influxdb
spec:
ports:
- port: 8086
selector:
name: mainflux-influxdb
+47
View File
@@ -0,0 +1,47 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: influxdb-writer
labels:
component: influxdb-writer
spec:
replicas: 1
template:
metadata:
labels:
component: influxdb-writer
spec:
containers:
- name: mainflux-influxdb
image: mainflux/influxdb:latest
imagePullPolicy: Always
ports:
- containerPort: 8900
env:
- name: MF_NATS_URL
value: "nats://nats:4222"
- name: MF_INFLUX_WRITER_PORT
value: "8900"
- name: MF_INFLUX_WRITER_DB_NAME
value: "mainflux"
- name: MF_INFLUX_WRITER_DB_HOST
value: "mainflux-influxdb"
- name: MF_INFLUX_WRITER_DB_PORT
value: "8086"
- name: MF_INFLUX_WRITER_DB_USER
value: "mainflux"
- name: MF_INFLUX_WRITER_DB_PASS
value: "mainflux"
---
apiVersion: v1
kind: Service
metadata:
name: influxdb-writer
labels:
component: influxdb-writer
spec:
selector:
component: influxdb-writer
ports:
- port: 8900
type: LoadBalancer
+6 -7
View File
@@ -1,5 +1,5 @@
apiVersion: apps/v1beta1
kind: Deployment
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: normalizer
labels:
@@ -21,16 +21,15 @@ spec:
- name: MF_NORMALIZER_PORT
value: "8184"
---
apiVersion: v1
kind: Service
apiVersion: v1
kind: Service
metadata:
name: normalizer
labels:
component: normalizer
component: normalizer
spec:
selector:
component: normalizer
ports:
- port: 8183
targetPort: 8183
- port: 8184
clusterIP: None
+1 -1
View File
@@ -32,7 +32,7 @@ spec:
spec:
containers:
- name: nats
image: nats:1.0.4
image: nats:1.1.0
args: [ "--config", "/etc/nats/nats.conf"]
volumeMounts:
- name: config-volume

Some files were not shown because too many files have changed in this diff Show More