Skip to content

Commit

Permalink
Complete initial implementation of persistent WebSocket for both cont…
Browse files Browse the repository at this point in the history
…ainer and response realtime data.
  • Loading branch information
nathan-osman committed May 7, 2022
1 parent f9b8b8f commit 04b56ce
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 153 deletions.
18 changes: 12 additions & 6 deletions dockmon/dockmon.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dockmon

import (
"context"
"net/http"
"time"

"github.com/docker/docker/api/types"
Expand All @@ -25,6 +24,8 @@ const (
Die = "die"

containerStoppedMessage = "The container serving this application is not currently running."

messageTypeContainer = "container"
)

var evtOptions = types.EventsOptions{
Expand Down Expand Up @@ -56,10 +57,6 @@ type Dockmon struct {
closedChan chan bool
}

func (d *Dockmon) loggerCallback(resp *http.Response) {
d.logger.LogResponse(resp)
}

func (d *Dockmon) newContainerFromClient(ctx context.Context, client *client.Client, id string) (*container.Container, error) {
containerJSON, err := client.ContainerInspect(ctx, id)
if err != nil {
Expand All @@ -76,15 +73,24 @@ func (d *Dockmon) newContainerFromClient(ctx context.Context, client *client.Cli
if !containerJSON.State.Running {
c.Disable(containerStoppedMessage)
}
c.Proxy.SetCallback(d.loggerCallback)
c.Proxy.SetCallback(d.responseCallback)
return c, nil
}

type messageContainer struct {
Action string `json:"action"`
Container *container.Container `json:"container"`
}

func (d *Dockmon) sendEvent(action string, c *container.Container) {
d.eventChan <- &Event{
Action: action,
Container: c,
}
d.logger.Log(messageTypeContainer, &messageContainer{
Action: action,
Container: c,
})
}

func (d *Dockmon) add(ctx context.Context, id string) {
Expand Down
55 changes: 55 additions & 0 deletions dockmon/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package dockmon

import (
"mime"
"net"
"net/http"
)

const messageTypeResponse = "response"

type messageResponse struct {
RemoteAddr string `json:"remote_addr"`
CountryCode string `json:"country_code"`
CountryName string `json:"country_name"`
Method string `json:"method"`
Host string `json:"host"`
Path string `json:"path"`
StatusCode int `json:"status_code"`
Status string `json:"status"`
ContentLength string `json:"content_length"`
ContentType string `json:"content_type"`
}

func (d *Dockmon) responseCallback(resp *http.Response) {
host, _, err := net.SplitHostPort(resp.Request.RemoteAddr)
if err != nil {
host = resp.Request.RemoteAddr
}
var (
countryCode string
countryName string
)
r, err := d.logger.Geolocate(host)
if err == nil {
countryCode = r.CountryCode
countryName = r.CountryName
}
contentType := resp.Header.Get("Content-Type")
mediatype, _, err := mime.ParseMediaType(contentType)
if err != nil {
mediatype = contentType
}
d.logger.Log(messageTypeResponse, &messageResponse{
RemoteAddr: host,
CountryCode: countryCode,
CountryName: countryName,
Method: resp.Request.Method,
Host: resp.Request.Host,
Path: resp.Request.URL.Path,
StatusCode: resp.StatusCode,
Status: resp.Status,
ContentLength: resp.Header.Get("Content-Length"),
ContentType: mediatype,
})
}
4 changes: 0 additions & 4 deletions logger/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ package logger

// Config provides the configuration for the logger.
type Config struct {
// Debug indicates whether debugging is enabled or not.
Debug bool
// GeolocationDBType indicates the type of geolocation database.
GeolocationDBType string
// GeolocationDBPath provides the path to the geolocation database.
GeolocationDBPath string
// Status indicates whether the status website is enabled or not.
Status bool
}
55 changes: 0 additions & 55 deletions logger/container.go

This file was deleted.

34 changes: 25 additions & 9 deletions logger/logger.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package logger

import (
"errors"
"net/http"

"github.com/nathan-osman/geolocator"
"github.com/nathan-osman/geolocator/ip2location"
"github.com/nathan-osman/go-herald"
)

var (
errNoGeolocator = errors.New("no geolocation database provided")
)

// Logger acts as a centralized component for ingesting data from the other
// components and processing it.
type Logger struct {
Expand All @@ -29,12 +34,9 @@ func New(cfg *Config) (*Logger, error) {
if err != nil {
return nil, err
}
var h *herald.Herald
if cfg.Status {
h = herald.New()
h.SetCheckOrigin(func(r *http.Request) bool { return true })
h.Start()
}
h := herald.New()
h.SetCheckOrigin(func(r *http.Request) bool { return true })
h.Start()
return &Logger{
geolocator: p,
herald: h,
Expand All @@ -47,11 +49,25 @@ func (l *Logger) AddClient(w http.ResponseWriter, r *http.Request) error {
return err
}

func (l *Logger) Geolocate(host string) (*geolocator.Response, error) {
if l.geolocator != nil {
return l.geolocator.Geolocate(host)
}
return nil, errNoGeolocator
}

func (l *Logger) Log(action string, data interface{}) {
m, err := herald.NewMessage(action, data)
if err != nil {
// TODO: something other than panic here
panic(err)
}
l.herald.Send(m, nil)
}

// Close shuts down the logger.
func (l *Logger) Close() {
if l.herald != nil {
l.herald.Close()
}
l.herald.Close()
if l.geolocator != nil {
l.geolocator.Close()
}
Expand Down
67 changes: 0 additions & 67 deletions logger/response.go

This file was deleted.

2 changes: 0 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,8 @@ func main() {

// Create the logger
l, err := logger.New(&logger.Config{
Debug: c.Bool("debug"),
GeolocationDBType: c.String("geolocation-db-type"),
GeolocationDBPath: c.String("geolocation-db-path"),
Status: statusDomain != "",
})
if err != nil {
return err
Expand Down
Loading

0 comments on commit 04b56ce

Please sign in to comment.