Skip to content

Commit 09e185e

Browse files
committed
Minimal service functionality
1 parent a73716b commit 09e185e

File tree

7 files changed

+210
-0
lines changed

7 files changed

+210
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@
1010

1111
# Output of the go coverage tool, specifically when used with LiteIDE
1212
*.out
13+
/homer
14+
15+
/glide.lock
16+
/vendor

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- repo: git://github.com/dnephin/pre-commit-golang
2+
sha: 471a7c123ea7a3b776ff018edf00066947873a94
3+
hooks:
4+
- id: go-fmt
5+
- id: go-vet
6+
- id: go-lint

glide.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package: github.com/skillcoder/homer
2+
import:
3+
- package: github.com/sirupsen/logrus
4+
version: ^1.0.6
5+
- package: github.com/eclipse/paho.mqtt.golang
6+
version: ^1.1.1
7+
- package: github.com/kshvakov/clickhouse
8+
version: ^1.3.4

handlers.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/skillcoder/homer/version"
7+
"github.com/takama/router"
8+
)
9+
10+
// home returns the path of current request
11+
func home(c *router.Control) {
12+
fmt.Fprintf(c.Writer, "Repo: %s, Commit: %s, Version: %s", version.REPO, version.COMMIT, version.RELEASE)
13+
}
14+
15+
// logger provides a log of requests
16+
func logger(c *router.Control) {
17+
remoteAddr := c.Request.Header.Get("X-Forwarded-For")
18+
if remoteAddr == "" {
19+
remoteAddr = c.Request.RemoteAddr
20+
}
21+
log.Infof("%s %s %s", remoteAddr, c.Request.Method, c.Request.URL.Path)
22+
}

main.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
"fmt"
6+
// "log"
7+
"os"
8+
// "time"
9+
"github.com/sirupsen/logrus"
10+
"github.com/takama/router"
11+
MQTT "github.com/eclipse/paho.mqtt.golang"
12+
// "github.com/skillcoder/homer/version"
13+
"github.com/skillcoder/homer/shutdown"
14+
)
15+
16+
var log = logrus.New()
17+
18+
//define a function for the default message handler
19+
var mqttMessageHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
20+
fmt.Printf("TOPIC: %s\n", msg.Topic())
21+
fmt.Printf("MSG: %s\n", msg.Payload())
22+
}
23+
24+
// Run server: go build; env SERVICE_PORT=8000 step-by-step
25+
// Try requests: curl http://127.0.0.1:8000/test
26+
func main() {
27+
http_listen := os.Getenv("SERVICE_LISTEN")
28+
if len(http_listen) == 0 {
29+
log.Fatal("Required env parameter SERVICE_LISTEN [ip:port] is not set")
30+
}
31+
32+
mqtt_server := os.Getenv("MQTT_SERVER")
33+
if len(mqtt_server) == 0 {
34+
log.Fatal("Required env parameter MQTT_SERVER [ip:port] is not set")
35+
}
36+
37+
//create a ClientOptions struct setting the broker address, clientid, turn
38+
//off trace output and set the default message handler
39+
opts := MQTT.NewClientOptions().AddBroker("tcp://"+mqtt_server)
40+
opts.SetClientID("go-homer-server")
41+
opts.SetDefaultPublishHandler(mqttMessageHandler)
42+
43+
//create and start a client using the above ClientOptions
44+
mqttClient := MQTT.NewClient(opts)
45+
if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
46+
panic(token.Error())
47+
}
48+
49+
//subscribe to the topic /go-mqtt/sample and request messages to be delivered
50+
//at a maximum qos of zero, wait for the receipt to confirm the subscription
51+
if token := mqttClient.Subscribe("/esp/init", 0, nil); token.Wait() && token.Error() != nil {
52+
fmt.Println(token.Error())
53+
os.Exit(1)
54+
}
55+
56+
//Publish 5 messages to /go-mqtt/sample at qos 1 and wait for the receipt
57+
//from the server after sending each message
58+
/*
59+
for i := 0; i < 5; i++ {
60+
text := fmt.Sprintf("this is msg #%d!", i)
61+
token := mqttClient.Publish("go-mqtt/sample", 0, false, text)
62+
token.Wait()
63+
}
64+
65+
time.Sleep(3 * time.Second)
66+
*/
67+
68+
//unsubscribe from /go-mqtt/sample
69+
/*
70+
if token := mqttClient.Unsubscribe("go-mqtt/sample"); token.Wait() && token.Error() != nil {
71+
fmt.Println(token.Error())
72+
os.Exit(1)
73+
}
74+
*/
75+
//mqttClient.Disconnect(250)
76+
77+
r := router.New()
78+
r.Logger = logger
79+
r.GET("/", home)
80+
81+
// Readiness and liveness probes for Kubernetes
82+
r.GET("/info", func(c *router.Control) {
83+
//common_handlers.Info(c, version.RELEASE, version.REPO, version.COMMIT)
84+
})
85+
r.GET("/healthz", func(c *router.Control) {
86+
c.Code(http.StatusOK).Body(http.StatusText(http.StatusOK))
87+
})
88+
89+
go r.Listen(http_listen)
90+
91+
logger := log.WithField("event", "shutdown")
92+
sdHandler := shutdown.NewHandler(logger)
93+
sdHandler.RegisterShutdown(sd)
94+
}
95+
96+
// sd does graceful dhutdown of the service
97+
func sd() (string, error) {
98+
// if service has to finish some tasks before shutting down, these tasks must be finished her
99+
return "Ok", nil
100+
}

shutdown/shutdown.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package shutdown
2+
3+
import (
4+
"os"
5+
"os/signal"
6+
"syscall"
7+
8+
"github.com/sirupsen/logrus"
9+
)
10+
11+
// Callback is a function to provide service shutdown.
12+
// This function should return status of shutdown and error in case of problems.
13+
type Callback func() (status string, err error)
14+
15+
// Handler handles shutting process
16+
type Handler struct {
17+
logger logrus.FieldLogger
18+
shutdownSignals []os.Signal
19+
}
20+
21+
// NewHandler creates an instance of Handler
22+
func NewHandler(logger logrus.FieldLogger) *Handler {
23+
return &Handler{
24+
logger: logger,
25+
shutdownSignals: []os.Signal{os.Interrupt, os.Kill, syscall.SIGTERM},
26+
}
27+
}
28+
29+
// RegisterShutdown set up a channel where we can send signal notifications and listen for the signal.
30+
// We must use a buffered channel, or risk missing the signal
31+
// if we're not ready to receive it when the signal is sent.
32+
// We strongly recommend to use this function once.
33+
// ToDo: how do we want to process case if user register few different shutdowns?
34+
func (h *Handler) RegisterShutdown(shutdown Callback) {
35+
interrupt := make(chan os.Signal, 1)
36+
signal.Notify(interrupt, h.shutdownSignals...)
37+
38+
killSignal := <-interrupt
39+
h.logger.Infof("Got signal: %+v", killSignal)
40+
41+
// ToDo: interrupt shutdown function if it takes too much time
42+
status, err := shutdown()
43+
if err != nil {
44+
h.logger.Fatalf("Error during shutdown: %s Status: %s\n", err.Error(), status)
45+
os.Exit(-1)
46+
}
47+
48+
if killSignal == os.Kill {
49+
h.logger.Infof("Service was killed with status: %s", status)
50+
} else {
51+
h.logger.Infof("Service was terminated by system signal with status: %s", status)
52+
}
53+
os.Exit(0)
54+
}
55+
56+
// AddShutdownSignal adds a user-defined signals to shutdown.
57+
// It might be helpful for testing.
58+
func (h *Handler) AddShutdownSignal(sig os.Signal) {
59+
h.shutdownSignals = append(h.shutdownSignals, sig)
60+
}

version/version.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package version
2+
3+
var (
4+
// RELEASE returns the release version
5+
RELEASE = "UNKNOWN"
6+
// REPO returns the git repository URL
7+
REPO = "UNKNOWN"
8+
// COMMIT returns the short sha from git
9+
COMMIT = "UNKNOWN"
10+
)

0 commit comments

Comments
 (0)