Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
akhenakh committed Nov 21, 2019
0 parents commit 5cab161
Show file tree
Hide file tree
Showing 7 changed files with 594 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
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
22 changes: 22 additions & 0 deletions LICENSE
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.
6 changes: 6 additions & 0 deletions README.md
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.
221 changes: 221 additions & 0 deletions cmd/geottnd/main.go
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)
}

}
93 changes: 93 additions & 0 deletions cmd/ttncli/main.go
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
}

}
13 changes: 13 additions & 0 deletions go.mod
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
)
Loading

0 comments on commit 5cab161

Please sign in to comment.