initial commit
diff --git a/README b/README
new file mode 100644
index 0000000..fdcdaaa
--- /dev/null
+++ b/README
@@ -0,0 +1,53 @@
+Mirko, the HSWAW microservice helper library
+============================================
+
+Wanna write a Go microservice for HSWAW? Can't be arsed to copy paste code? This is the library for you!
+
+Usage (dev)
+-----------
+
+ package main
+
+ import (
+ "code.hackerspace.pl/q3k/mirko"
+ )
+
+ func main() {
+ m := mirko.New()
+
+ // setup/checks before TCP ports are opened...
+ // ...
+
+ if err := m.Listen(); err != nil {
+ glog.Exitf("Listen(): %v", err)
+ }
+
+ // register your gRPC and http handlers...
+ // (relfection and basic debug http is automatically registered)
+ // pb.RegisterFooServer(m.GRPC(), s)
+ // m.HTTPMux().HandleFunc("/debug/foo", fooHandler)
+
+ if err := m.Serve(); err != nil {
+ glog.Exitf("Serve(): %v", err)
+ }
+
+ // start any other background processing...
+
+ select {}
+ }
+
+Usage (running)
+---------------
+
+The following flags are automatically registered:
+
+ - `-listen_address` (default: `127.0.0.1:42000`): where to listen for gRPC requests
+ - `-debug_address` (default: `127.0.0.1:42001`): where to listen for debug HTTP requests
+
+Since this library also includes [hspki](https://code.hackerspace.pl/q3k/hspki), you also get all the typical `-hspki_{...}` flags included.
+
+The following debug HTTP handlers are installed:
+
+ - `/debug/status`: show the [statusz](https://github.com/q3k/statusz) page
+ - `/debug/requests`: show the [net/trace](https://godoc.org/golang.org/x/net/trace) page (including gRPC traces)
+
diff --git a/mirko.go b/mirko.go
new file mode 100644
index 0000000..3acf9b1
--- /dev/null
+++ b/mirko.go
@@ -0,0 +1,121 @@
+package mirko
+
+import (
+ "flag"
+ "fmt"
+ "net"
+ "net/http"
+ "time"
+
+ "code.hackerspace.pl/q3k/hspki"
+ "github.com/golang/glog"
+ "github.com/q3k/statusz"
+ "golang.org/x/net/trace"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/reflection"
+)
+
+var (
+ flagListenAddress string
+ flagDebugAddress string
+)
+
+func init() {
+ flag.StringVar(&flagListenAddress, "listen_address", "127.0.0.1:42000", "gRPC listen address")
+ flag.StringVar(&flagDebugAddress, "debug_address", "127.0.0.1:42001", "HTTP debug/status listen address")
+}
+
+type Mirko struct {
+ grpcListen net.Listener
+ grpcServer *grpc.Server
+ httpListen net.Listener
+ httpServer *http.Server
+ httpMux *http.ServeMux
+}
+
+func New() *Mirko {
+ return &Mirko{}
+}
+
+func (m *Mirko) Listen() error {
+ grpc.EnableTracing = true
+ grpcLis, err := net.Listen("tcp", flagListenAddress)
+ if err != nil {
+ return fmt.Errorf("net.Listen: %v", err)
+ }
+ m.grpcListen = grpcLis
+ m.grpcServer = grpc.NewServer(hspki.WithServerHSPKI()...)
+ reflection.Register(m.grpcServer)
+
+ httpLis, err := net.Listen("tcp", flagDebugAddress)
+ if err != nil {
+ return fmt.Errorf("net.Listen: %v", err)
+ }
+
+ m.httpMux = http.NewServeMux()
+ // Canonical URLs
+ m.httpMux.HandleFunc("/debug/status", statusz.StatusHandler)
+ m.httpMux.HandleFunc("/debug/requests", trace.Traces)
+
+ // -z legacy URLs
+ m.httpMux.HandleFunc("/statusz", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/debug/status", http.StatusSeeOther)
+ })
+ m.httpMux.HandleFunc("/rpcz", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/debug/requests", http.StatusSeeOther)
+ })
+ m.httpMux.HandleFunc("/requestz", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/debug/requests", http.StatusSeeOther)
+ })
+
+ // root redirect
+ m.httpMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/debug/status", http.StatusSeeOther)
+ })
+
+ m.httpListen = httpLis
+ m.httpServer = &http.Server{
+ Addr: flagDebugAddress,
+ Handler: m.httpMux,
+ }
+
+ return nil
+}
+
+func (m *Mirko) GRPC() *grpc.Server {
+ if m.grpcServer == nil {
+ panic("GRPC() called before Listen()")
+ }
+ return m.grpcServer
+}
+
+func (m *Mirko) HTTPMux() *http.ServeMux {
+ if m.httpMux == nil {
+ panic("HTTPMux() called before Listen()")
+ }
+ return m.httpMux
+}
+
+func (m *Mirko) Serve() error {
+ errs := make(chan error, 1)
+ go func() {
+ if err := m.grpcServer.Serve(m.grpcListen); err != nil {
+ errs <- err
+ }
+ }()
+ go func() {
+ if err := m.httpServer.Serve(m.httpListen); err != nil {
+ errs <- err
+ }
+ }()
+
+ ticker := time.NewTicker(1 * time.Second)
+ select {
+ case <-ticker.C:
+ glog.Infof("gRPC listening on %s", flagListenAddress)
+ glog.Infof("HTTP listening on %s", flagDebugAddress)
+ return nil
+ case err := <-errs:
+ return err
+ }
+}