-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5cab161
Showing
7 changed files
with
594 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, build with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
.idea/ | ||
.vscode/ | ||
|
||
!/cmd/geottnd/geottnd | ||
!/cmd/ttncli/ttncli |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
MIT License | ||
|
||
Copyright (c) 2019 Fabrice Aneche | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
GeoTTN | ||
------ | ||
|
||
An application for The Things Network. | ||
|
||
This is a all in one server, that will store historical data of your devices and display them on a map. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"fmt" | ||
stdlog "log" | ||
"net" | ||
"net/http" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
|
||
ttnsdk "github.com/TheThingsNetwork/go-app-sdk" | ||
log "github.com/go-kit/kit/log" | ||
"github.com/go-kit/kit/log/level" | ||
"github.com/grpc-ecosystem/grpc-gateway/runtime" | ||
"github.com/namsral/flag" | ||
"github.com/prometheus/client_golang/prometheus/promhttp" | ||
"golang.org/x/sync/errgroup" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/health" | ||
healthpb "google.golang.org/grpc/health/grpc_health_v1" | ||
) | ||
|
||
const appName = "geottn" | ||
|
||
var ( | ||
version = "no version from LDFLAGS" | ||
|
||
appID = flag.String("appID", "akhtestapp", "The things network application ID") | ||
appAccessKey = flag.String("appAccessKey", "", "The things network access key") | ||
httpMetricsPort = flag.Int("httpMetricsPort", 8888, "http port") | ||
httpAPIPort = flag.Int("httpAPIPort", 9201, "http API port") | ||
healthPort = flag.Int("healthPort", 6666, "grpc health port") | ||
|
||
httpAPIServer *http.Server | ||
grpcHealthServer *grpc.Server | ||
httpMetricsServer *http.Server | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
logger := log.NewJSONLogger(log.NewSyncWriter(os.Stdout)) | ||
logger = log.With(logger, "caller", log.DefaultCaller, "ts", log.DefaultTimestampUTC) | ||
logger = log.With(logger, "app", appName) | ||
logger = level.NewFilter(logger, level.AllowAll()) | ||
|
||
stdlog.SetOutput(log.NewStdlibAdapter(logger)) | ||
|
||
level.Info(logger).Log("msg", "Starting app", "version", version) | ||
|
||
ctx := context.Background() | ||
ctx, cancel := context.WithCancel(ctx) | ||
|
||
// catch termination | ||
interrupt := make(chan os.Signal, 1) | ||
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) | ||
defer signal.Stop(interrupt) | ||
|
||
g, ctx := errgroup.WithContext(ctx) | ||
|
||
// gRPC Health Server | ||
healthServer := health.NewServer() | ||
g.Go(func() error { | ||
grpcHealthServer = grpc.NewServer() | ||
|
||
healthpb.RegisterHealthServer(grpcHealthServer, healthServer) | ||
|
||
haddr := fmt.Sprintf(":%d", *healthPort) | ||
hln, err := net.Listen("tcp", haddr) | ||
if err != nil { | ||
level.Error(logger).Log("msg", "gRPC Health server: failed to listen", "error", err) | ||
os.Exit(2) | ||
} | ||
level.Info(logger).Log("msg", fmt.Sprintf("gRPC health server serving at %s", haddr)) | ||
return grpcHealthServer.Serve(hln) | ||
}) | ||
|
||
// web server metrics | ||
g.Go(func() error { | ||
httpMetricsServer = &http.Server{ | ||
Addr: fmt.Sprintf(":%d", *httpMetricsPort), | ||
ReadTimeout: 10 * time.Second, | ||
WriteTimeout: 10 * time.Second, | ||
} | ||
level.Info(logger).Log("msg", fmt.Sprintf("HTTP Metrics server serving at :%d", *httpMetricsPort)) | ||
|
||
// Register Prometheus metrics handler. | ||
http.Handle("/metrics", promhttp.Handler()) | ||
|
||
if err := httpMetricsServer.ListenAndServe(); err != http.ErrServerClosed { | ||
return err | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
// web API server | ||
g.Go(func() error { | ||
mux := runtime.NewServeMux() | ||
|
||
httpAPIServer = &http.Server{ | ||
Addr: fmt.Sprintf(":%d", *httpAPIPort), | ||
ReadTimeout: 10 * time.Second, | ||
WriteTimeout: 10 * time.Second, | ||
Handler: mux, | ||
} | ||
level.Info(logger).Log("msg", fmt.Sprintf("HTTP API server serving at :%d", *httpAPIPort)) | ||
|
||
if err := httpAPIServer.ListenAndServe(); err != http.ErrServerClosed { | ||
return err | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
// TTN client subscriptions | ||
g.Go(func() error { | ||
logger := log.With(logger, "component", "ttnclient") | ||
config := ttnsdk.NewCommunityConfig(appName) | ||
config.ClientVersion = version | ||
|
||
// Create a new SDK client for the application | ||
client := config.NewClient(*appID, *appAccessKey) | ||
|
||
// Make sure the client is closed before the function returns | ||
// In your application, you should call this before the application shuts down | ||
defer client.Close() | ||
|
||
// Start Publish/Subscribe client (MQTT) | ||
pubsub, err := client.PubSub() | ||
if err != nil { | ||
level.Error(logger).Log("msg", "can't get pub/sub", "error", err) | ||
return err | ||
} | ||
|
||
// Make sure the pubsub client is closed before the function returns | ||
// In your application, you should call this before the application shuts down | ||
defer pubsub.Close() | ||
|
||
// Get a publish/subscribe client for all devices | ||
allDevicesPubSub := pubsub.AllDevices() | ||
|
||
// Make sure the pubsub client is closed before the function returns | ||
// In your application, you will probably call this before the application shuts down | ||
// This also stops existing subscriptions, in case you forgot to unsubscribe | ||
defer allDevicesPubSub.Close() | ||
|
||
// Subscribe to msgs | ||
msgs, err := allDevicesPubSub.SubscribeUplink() | ||
if err != nil { | ||
level.Error(logger).Log("msg", "can't subscribe to events", "error", err) | ||
return err | ||
} | ||
level.Info(logger).Log("msg", "subscribed to uplink messages") | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
// Unsubscribe from events | ||
level.Info(logger).Log("msg", "unsubscribing to uplink messages") | ||
|
||
if err = allDevicesPubSub.UnsubscribeEvents(); err != nil { | ||
level.Error(logger).Log("msg", "can't unsubscribe from events", "error", err) | ||
return err | ||
} | ||
return nil | ||
case msg := <-msgs: | ||
if msg == nil { | ||
break | ||
} | ||
hexPayload := hex.EncodeToString(msg.PayloadRaw) | ||
level.Info(logger).Log( | ||
"devID", msg.DevID, | ||
"msg", "received msg", | ||
"payload", hexPayload) | ||
|
||
} | ||
|
||
} | ||
|
||
return nil | ||
}) | ||
|
||
select { | ||
case <-interrupt: | ||
cancel() | ||
break | ||
case <-ctx.Done(): | ||
break | ||
} | ||
|
||
level.Warn(logger).Log("msg", "received shutdown signal") | ||
|
||
healthServer.SetServingStatus(fmt.Sprintf("grpc.health.v1.%s", appName), healthpb.HealthCheckResponse_NOT_SERVING) | ||
|
||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
defer shutdownCancel() | ||
|
||
if httpMetricsServer != nil { | ||
_ = httpMetricsServer.Shutdown(shutdownCtx) | ||
} | ||
|
||
if httpAPIServer != nil { | ||
_ = httpAPIServer.Shutdown(shutdownCtx) | ||
} | ||
|
||
if grpcHealthServer != nil { | ||
grpcHealthServer.GracefulStop() | ||
} | ||
|
||
err := g.Wait() | ||
if err != nil { | ||
level.Error(logger).Log("msg", "server returning an error", "error", err) | ||
os.Exit(2) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"flag" | ||
"log" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
|
||
ttnsdk "github.com/TheThingsNetwork/go-app-sdk" | ||
) | ||
|
||
const appName = "ttncli" | ||
|
||
var ( | ||
appID = flag.String("appID", "akhtestapp", "The things network application ID") | ||
appAccessKey = flag.String("appAccessKey", "", "The things network access key") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
ctx := context.Background() | ||
ctx, cancel := context.WithCancel(ctx) | ||
defer cancel() | ||
|
||
config := ttnsdk.NewCommunityConfig(appName) | ||
config.ClientVersion = "1.0" | ||
|
||
// Create a new SDK client for the application | ||
client := config.NewClient(*appID, *appAccessKey) | ||
|
||
// Make sure the client is closed before the function returns | ||
// In your application, you should call this before the application shuts down | ||
defer client.Close() | ||
|
||
// Start Publish/Subscribe client (MQTT) | ||
pubsub, err := client.PubSub() | ||
if err != nil { | ||
log.Fatal("can't get pub/sub", err) | ||
} | ||
|
||
// Get a publish/subscribe client for all devices | ||
allDevicesPubSub := pubsub.AllDevices() | ||
|
||
// Make sure the pubsub client is closed before the function returns | ||
// In your application, you will probably call this before the application shuts down | ||
// This also stops existing subscriptions, in case you forgot to unsubscribe | ||
defer allDevicesPubSub.Close() | ||
|
||
// Subscribe to events | ||
|
||
msgs, err := allDevicesPubSub.SubscribeUplink() | ||
if err != nil { | ||
log.Fatal("can't subscribe to events", err) | ||
} | ||
|
||
// catch termination | ||
interrupt := make(chan os.Signal, 1) | ||
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) | ||
defer signal.Stop(interrupt) | ||
|
||
go func() { | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
// Unsubscribe from events | ||
log.Println("unsubscribe from all devices") | ||
if err = allDevicesPubSub.UnsubscribeUplink(); err != nil { | ||
log.Fatal("can't unsubscribe from uplink msg", err) | ||
} | ||
return | ||
case msg := <-msgs: | ||
log.Println("msg", msg) | ||
|
||
if msg != nil && msg.PayloadRaw != nil { | ||
hexPayload := hex.EncodeToString(msg.PayloadRaw) | ||
log.Println("received msg", "data", hexPayload) | ||
} | ||
} | ||
} | ||
}() | ||
|
||
select { | ||
case <-interrupt: | ||
break | ||
case <-ctx.Done(): | ||
break | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module github.com/akhenakh/geottn | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/TheThingsNetwork/go-app-sdk v0.0.0-20190516120600-5d30ea62f538 | ||
github.com/go-kit/kit v0.9.0 | ||
github.com/grpc-ecosystem/grpc-gateway v1.9.0 | ||
github.com/namsral/flag v1.7.4-pre | ||
github.com/prometheus/client_golang v0.9.2 | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 | ||
google.golang.org/grpc v1.20.1 | ||
) |
Oops, something went wrong.