<commit_before>package main

import (
	"github.com/gin-gonic/gin"
	"github.com/go-gorp/gorp"
	"github.com/loopfz/scecret/db/testdb"
	"github.com/loopfz/scecret/utils/tonic"
)

var db *gorp.DbMap

func main() {

	tdb, err := testdb.InitTestDB(false)
	if err != nil {
		panic(err)
	}

	db = tdb

	router := gin.Default()

	// Auth
	router.POST("/register", tonic.Handler(RegisterUser, 201))
	router.POST("/auth", tonic.Handler(Auth, 200))
	router.GET("/me", tonic.Handler(GetMe, 200))

	// Scenarios
	router.POST("/scenario", tonic.Handler(NewScenario, 201))
	router.GET("/scenario", tonic.Handler(ListScenarios, 200))
	router.GET("/scenario/:scenario", tonic.Handler(GetScenario, 200))
	router.PUT("/scenario/:scenario", tonic.Handler(UpdateScenario, 200))
	router.DELETE("/scenario/:scenario", tonic.Handler(DeleteScenario, 204))
	router.GET("/scenario/:scenario/graph", tonic.Handler(GetGraph, 200))

	// Locations
	router.POST("/scenario/:scenario/location", tonic.Handler(NewLocation, 201))
	router.GET("/scenario/:scenario/location", tonic.Handler(ListLocations, 200))
	router.GET("/scenario/:scenario/location/:location", tonic.Handler(GetLocation, 200))
	router.PUT("/scenario/:scenario/location/:location", tonic.Handler(UpdateLocation, 200))
	router.DELETE("/scenario/:scenario/location/:location", tonic.Handler(DeleteLocation, 204))

	// Location cards
	router.POST("/scenario/:scenario/location/:location/card", tonic.Handler(NewLocationCard, 201))
	router.GET("/scenario/:scenario/location/:location/card", tonic.Handler(ListLocationCards, 200))
	router.GET("/scenario/:scenario/location/:location/card/:card", tonic.Handler(GetLocationCard, 200))
	router.PUT("/scenario/:scenario/location/:location/card/:location_card", tonic.Handler(UpdateLocationCard, 200))
	router.DELETE("/scenario/:scenario/location/:location/card/:location_card", tonic.Handler(DeleteLocationCard, 204))

	// Location links
	router.POST("/scenario/:scenario/locationlink", tonic.Handler(NewLocationLink, 201))
	router.GET("/scenario/:scenario/locationlink", tonic.Handler(ListLocationLinks, 200))
	router.GET("/scenario/:scenario/locationlink/:locationlink", tonic.Handler(GetLocationLink, 200))
	router.DELETE("/scenario/:scenario/locationlink/:locationlink", tonic.Handler(DeleteLocationLink, 204))

	// Element links
	router.POST("/scenario/:scenario/elementlink", tonic.Handler(NewElementLink, 201))
	router.GET("/scenario/:scenario/elementlink", tonic.Handler(ListElementLinks, 200))
	router.GET("/scenario/:scenario/elementlink/:elementlink", tonic.Handler(GetElementLink, 200))
	router.DELETE("/scenario/:scenario/elementlink/:elementlink", tonic.Handler(DeleteElementLink, 204))

	// State tokens
	router.GET("/scenario/:scenario/statetoken", tonic.Handler(ListStateTokens, 200))
	router.GET("/scenario/:scenario/statetoken/:statetoken", tonic.Handler(GetStateToken, 200))

	// State token links
	router.POST("/scenario/:scenario/statetokenlink", tonic.Handler(NewStateTokenLink, 201))
	router.GET("/scenario/:scenario/statetokenlink", tonic.Handler(ListStateTokenLinks, 200))
	router.GET("/scenario/:scenario/statetokenlink/:statetokenlink", tonic.Handler(GetStateTokenLink, 200))
	router.DELETE("/scenario/:scenario/statetokenlink/:statetokenlink", tonic.Handler(DeleteStateTokenLink, 204))

	// Stats
	router.POST("/scenario/:scenario/stat", tonic.Handler(NewStat, 201))
	router.GET("/scenario/:scenario/stat", tonic.Handler(ListStats, 200))
	router.GET("/scenario/:scenario/stat/:stat", tonic.Handler(GetStat, 200))
	router.PUT("/scenario/:scenario/stat/:stat", tonic.Handler(UpdateStat, 200))
	router.DELETE("/scenario/:scenario/stat/:stat", tonic.Handler(DeleteStat, 204))

	// Skill tests
	router.POST("/scenario/:scenario/skilltest", tonic.Handler(CreateSkillTest, 201))
	router.GET("/scenario/:scenario/skilltest", tonic.Handler(ListSkillTests, 200))
	router.GET("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(GetSkillTest, 200))
	router.PUT("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(UpdateSkillTest, 200))
	router.DELETE("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(DeleteSkillTest, 204))

	// Icons
	router.POST("/scenario/:scenario/icon", tonic.Handler(NewIcon, 201))
	router.GET("/scenario/:scenario/icon", tonic.Handler(ListIcons, 200))
	router.GET("/scenario/:scenario/icon/:icon", tonic.Handler(GetIcon, 200))
	router.PUT("/scenario/:scenario/icon/:icon", tonic.Handler(UpdateIcon, 200))
	router.DELETE("/scenario/:scenario/icon/:icon", tonic.Handler(DeleteIcon, 204))

	// Elements
	router.POST("/scenario/:scenario/element", tonic.Handler(NewElement, 201))
	router.GET("/scenario/:scenario/element", tonic.Handler(ListElements, 200))
	router.GET("/scenario/:scenario/element/:element", tonic.Handler(GetElement, 200))
	router.PUT("/scenario/:scenario/element/:element", tonic.Handler(UpdateElement, 200))
	router.DELETE("/scenario/:scenario/element/:element", tonic.Handler(DeleteElement, 204))

	router.GET("/scenario/:scenario/card", tonic.Handler(ListCards, 200))
	router.GET("/scenario/:scenario/card/:card", tonic.Handler(GetCard, 200))
	router.PUT("/scenario/:scenario/card/:card", tonic.Handler(UpdateCard, 200))

	router.POST("/scenario/:scenario/card/:card/icon", tonic.Handler(NewCardIcon, 201))
	router.GET("/scenario/:scenario/card/:card/icon", tonic.Handler(ListCardIcons, 200))
	router.GET("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(GetCardIcon, 200))
	router.PUT("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(UpdateCardIcon, 200))
	router.DELETE("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(DeleteCardIcon, 204))

	// TODO POST /sandbox

	router.Run(":8080")
}
<commit_msg>Added comments on api handler def<commit_after>package main

import (
	"github.com/gin-gonic/gin"
	"github.com/go-gorp/gorp"
	"github.com/loopfz/scecret/db/testdb"
	"github.com/loopfz/scecret/utils/tonic"
)

var db *gorp.DbMap

func main() {

	tdb, err := testdb.InitTestDB(false)
	if err != nil {
		panic(err)
	}

	db = tdb

	router := gin.Default()

	// Auth
	router.POST("/register", tonic.Handler(RegisterUser, 201))
	router.POST("/auth", tonic.Handler(Auth, 200))
	router.GET("/me", tonic.Handler(GetMe, 200))

	// Scenarios
	router.POST("/scenario", tonic.Handler(NewScenario, 201))
	router.GET("/scenario", tonic.Handler(ListScenarios, 200))
	router.GET("/scenario/:scenario", tonic.Handler(GetScenario, 200))
	router.PUT("/scenario/:scenario", tonic.Handler(UpdateScenario, 200))
	router.DELETE("/scenario/:scenario", tonic.Handler(DeleteScenario, 204))
	router.GET("/scenario/:scenario/graph", tonic.Handler(GetGraph, 200))

	// Locations
	router.POST("/scenario/:scenario/location", tonic.Handler(NewLocation, 201))
	router.GET("/scenario/:scenario/location", tonic.Handler(ListLocations, 200))
	router.GET("/scenario/:scenario/location/:location", tonic.Handler(GetLocation, 200))
	router.PUT("/scenario/:scenario/location/:location", tonic.Handler(UpdateLocation, 200))
	router.DELETE("/scenario/:scenario/location/:location", tonic.Handler(DeleteLocation, 204))

	// Location cards
	router.POST("/scenario/:scenario/location/:location/card", tonic.Handler(NewLocationCard, 201))
	router.GET("/scenario/:scenario/location/:location/card", tonic.Handler(ListLocationCards, 200))
	router.GET("/scenario/:scenario/location/:location/card/:card", tonic.Handler(GetLocationCard, 200))
	router.PUT("/scenario/:scenario/location/:location/card/:location_card", tonic.Handler(UpdateLocationCard, 200))
	router.DELETE("/scenario/:scenario/location/:location/card/:location_card", tonic.Handler(DeleteLocationCard, 204))

	// Location links
	router.POST("/scenario/:scenario/locationlink", tonic.Handler(NewLocationLink, 201))
	router.GET("/scenario/:scenario/locationlink", tonic.Handler(ListLocationLinks, 200))
	router.GET("/scenario/:scenario/locationlink/:locationlink", tonic.Handler(GetLocationLink, 200))
	router.DELETE("/scenario/:scenario/locationlink/:locationlink", tonic.Handler(DeleteLocationLink, 204))

	// Element links
	router.POST("/scenario/:scenario/elementlink", tonic.Handler(NewElementLink, 201))
	router.GET("/scenario/:scenario/elementlink", tonic.Handler(ListElementLinks, 200))
	router.GET("/scenario/:scenario/elementlink/:elementlink", tonic.Handler(GetElementLink, 200))
	router.DELETE("/scenario/:scenario/elementlink/:elementlink", tonic.Handler(DeleteElementLink, 204))

	// State tokens
	router.GET("/scenario/:scenario/statetoken", tonic.Handler(ListStateTokens, 200))
	router.GET("/scenario/:scenario/statetoken/:statetoken", tonic.Handler(GetStateToken, 200))

	// State token links
	router.POST("/scenario/:scenario/statetokenlink", tonic.Handler(NewStateTokenLink, 201))
	router.GET("/scenario/:scenario/statetokenlink", tonic.Handler(ListStateTokenLinks, 200))
	router.GET("/scenario/:scenario/statetokenlink/:statetokenlink", tonic.Handler(GetStateTokenLink, 200))
	router.DELETE("/scenario/:scenario/statetokenlink/:statetokenlink", tonic.Handler(DeleteStateTokenLink, 204))

	// Stats
	router.POST("/scenario/:scenario/stat", tonic.Handler(NewStat, 201))
	router.GET("/scenario/:scenario/stat", tonic.Handler(ListStats, 200))
	router.GET("/scenario/:scenario/stat/:stat", tonic.Handler(GetStat, 200))
	router.PUT("/scenario/:scenario/stat/:stat", tonic.Handler(UpdateStat, 200))
	router.DELETE("/scenario/:scenario/stat/:stat", tonic.Handler(DeleteStat, 204))

	// Skill tests
	router.POST("/scenario/:scenario/skilltest", tonic.Handler(CreateSkillTest, 201))
	router.GET("/scenario/:scenario/skilltest", tonic.Handler(ListSkillTests, 200))
	router.GET("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(GetSkillTest, 200))
	router.PUT("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(UpdateSkillTest, 200))
	router.DELETE("/scenario/:scenario/skilltest/:skilltest", tonic.Handler(DeleteSkillTest, 204))

	// Icons
	router.POST("/scenario/:scenario/icon", tonic.Handler(NewIcon, 201))
	router.GET("/scenario/:scenario/icon", tonic.Handler(ListIcons, 200))
	router.GET("/scenario/:scenario/icon/:icon", tonic.Handler(GetIcon, 200))
	router.PUT("/scenario/:scenario/icon/:icon", tonic.Handler(UpdateIcon, 200))
	router.DELETE("/scenario/:scenario/icon/:icon", tonic.Handler(DeleteIcon, 204))

	// Elements
	router.POST("/scenario/:scenario/element", tonic.Handler(NewElement, 201))
	router.GET("/scenario/:scenario/element", tonic.Handler(ListElements, 200))
	router.GET("/scenario/:scenario/element/:element", tonic.Handler(GetElement, 200))
	router.PUT("/scenario/:scenario/element/:element", tonic.Handler(UpdateElement, 200))
	router.DELETE("/scenario/:scenario/element/:element", tonic.Handler(DeleteElement, 204))

	// Cards
	router.GET("/scenario/:scenario/card", tonic.Handler(ListCards, 200))
	router.GET("/scenario/:scenario/card/:card", tonic.Handler(GetCard, 200))
	router.PUT("/scenario/:scenario/card/:card", tonic.Handler(UpdateCard, 200))

	// Card icons
	router.POST("/scenario/:scenario/card/:card/icon", tonic.Handler(NewCardIcon, 201))
	router.GET("/scenario/:scenario/card/:card/icon", tonic.Handler(ListCardIcons, 200))
	router.GET("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(GetCardIcon, 200))
	router.PUT("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(UpdateCardIcon, 200))
	router.DELETE("/scenario/:scenario/card/:card/icon/:icon", tonic.Handler(DeleteCardIcon, 204))

	// TODO POST /sandbox

	router.Run(":8080")
}
<|endoftext|>


<commit_before>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
)

/*
{
  "monitors": [
    {
      "id": "2cSZzK3XfmG",
      "type": "connectivity",
      "isMute": false,
      "scopes": [],
      "excludeScopes": []
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "host",
      "isMute": false,
      "name": "disk.aa-00.writes.delta",
      "duration": 3,
      "metric": "disk.aa-00.writes.delta",
      "operator": ">",
      "warning": 20000.0,
      "critical": 400000.0,
      "scopes": [
        "SomeService"
      ],
      "excludeScopes": [
        "SomeService: db-slave-backup"
      ],
      "notificationInterval": 60
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "service",
      "isMute": false,
      "name": "SomeService - custom.access_num.4xx_count",
      "service": "SomeService",
      "duration": 1,
      "metric": "custom.access_num.4xx_count",
      "operator": ">",
      "warning": 50.0,
      "critical": 100.0
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "external",
      "isMute": false,
      "name": "example.com",
      "url": "http://www.example.com",
      "service": "SomeService",
      "maxCheckAttempts": 1,
      "responseTimeCritical": 10000,
      "responseTimeWarning": 5000,
      "responseTimeDuration": 5,
      "certificationExpirationCritical": 15,
      "certificationExpirationWarning": 30,
      "containsString": "Example"
    }
  ]
}
*/

// Monitor information
type Monitor struct {
	ID                              string   `json:"id,omitempty"`
	Name                            string   `json:"name,omitempty"`
	Type                            string   `json:"type,omitempty"`
	IsMute                          bool     `json:"isMute,omitempty"`
	Metric                          string   `json:"metric,omitempty"`
	Operator                        string   `json:"operator,omitempty"`
	Warning                         float64  `json:"warning,omitempty"`
	Critical                        float64  `json:"critical,omitempty"`
	Duration                        uint64   `json:"duration,omitempty"`
	URL                             string   `json:"url,omitempty"`
	Scopes                          []string `json:"scopes,omitempty"`
	Service                         string   `json:"service,omitempty"`
	MaxCheckAttempts                float64  `json:"maxCheckAttempts,omitempty"`
	NotificationInterval            uint64   `json:"notificationInterval,omitempty"`
	ExcludeScopes                   []string `json:"excludeScopes,omitempty"`
	ResponseTimeCritical            float64  `json:"responseTimeCritical,omitempty"`
	ResponseTimeWarning             float64  `json:"responseTimeWarning,omitempty"`
	ResponseTimeDuration            float64  `json:"responseTimeDuration,omitempty"`
	CertificationExpirationCritical uint64   `json:"certificationExpirationCritical,omitempty"`
	CertificationExpirationWarning  uint64   `json:"certificationExpirationWarning,omitempty"`
	ContainsString                  string   `json:"containsString,omitempty"`
	Expression                      string   `json:"expression,omitempty"`
}

// FindMonitors find monitors
func (c *Client) FindMonitors() ([]*Monitor, error) {
	req, err := http.NewRequest("GET", c.urlFor("/api/v0/monitors").String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Monitors []*(Monitor) `json:"monitors"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return data.Monitors, err
}

// CreateMonitor creating monitor
func (c *Client) CreateMonitor(param *Monitor) (*Monitor, error) {
	resp, err := c.PostJSON("/api/v0/monitors", param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// UpdateMonitor update monitor
func (c *Client) UpdateMonitor(monitorID string, param *Monitor) (*Monitor, error) {
	resp, err := c.PutJSON(fmt.Sprintf("/api/v0/monitors/%s", monitorID), param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// DeleteMonitor update monitor
func (c *Client) DeleteMonitor(monitorID string) (*Monitor, error) {
	req, err := http.NewRequest(
		"DELETE",
		c.urlFor(fmt.Sprintf("/api/v0/monitors/%s", monitorID)).String(),
		nil,
	)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}
<commit_msg>Define each monitor type<commit_after>package mackerel

import (
	"encoding/json"
	"fmt"
	"net/http"
)

/*
{
  "monitors": [
    {
      "id": "2cSZzK3XfmG",
      "type": "connectivity",
      "isMute": false,
      "scopes": [],
      "excludeScopes": []
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "host",
      "isMute": false,
      "name": "disk.aa-00.writes.delta",
      "duration": 3,
      "metric": "disk.aa-00.writes.delta",
      "operator": ">",
      "warning": 20000.0,
      "critical": 400000.0,
      "scopes": [
        "SomeService"
      ],
      "excludeScopes": [
        "SomeService: db-slave-backup"
      ],
      "notificationInterval": 60
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "service",
      "isMute": false,
      "name": "SomeService - custom.access_num.4xx_count",
      "service": "SomeService",
      "duration": 1,
      "metric": "custom.access_num.4xx_count",
      "operator": ">",
      "warning": 50.0,
      "critical": 100.0
    },
    {
      "id"  : "2cSZzK3XfmG",
      "type": "external",
      "isMute": false,
      "name": "example.com",
      "url": "http://www.example.com",
      "service": "SomeService",
      "maxCheckAttempts": 1,
      "responseTimeCritical": 10000,
      "responseTimeWarning": 5000,
      "responseTimeDuration": 5,
      "certificationExpirationCritical": 15,
      "certificationExpirationWarning": 30,
      "containsString": "Example"
    }
  ]
}
*/

// MonitorI represents interface to which each monitor type must confirm to.
type MonitorI interface {
	// MonitorType() must return monitor type.
	MonitorType() string
}

const (
	monitorTypeConnectivity  = "connectivity"
	monitorTypeHostMeric     = "host"
	monitorTypeServiceMetric = "service"
	monitorTypeExternalHTTP  = "external"
	monitorTypeExpression    = "expression"
)

// Ensure each monitor type conforms to the Monitor interface.
var (
	_ MonitorI = (*MonitorConnectivity)(nil)
	_ MonitorI = (*MonitorHostMetric)(nil)
	_ MonitorI = (*MonitorServiceMetric)(nil)
	_ MonitorI = (*MonitorExternalHTTP)(nil)
	_ MonitorI = (*MonitorExpression)(nil)
)

type MonitorConnectivity struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	Scopes        []string `json:"scopes,omitempty"`
	ExcludeScopes []string `json:"excludeScopes,omitempty"`
}

func (m *MonitorConnectivity) MonitorType() string {
	return monitorTypeConnectivity
}

type MonitorHostMetric struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	Metric   string  `json:"metric,omitempty"`
	Operator string  `json:"operator,omitempty"`
	Warning  float64 `json:"warning,omitempty"`
	Critical float64 `json:"critical,omitempty"`
	Duration uint64  `json:"duration,omitempty"`

	Scopes        []string `json:"scopes,omitempty"`
	ExcludeScopes []string `json:"excludeScopes,omitempty"`
}

func (m *MonitorHostMetric) MonitorType() string {
	return monitorTypeHostMeric
}

type MonitorServiceMetric struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	Service  string  `json:"service,omitempty"`
	Metric   string  `json:"metric,omitempty"`
	Operator string  `json:"operator,omitempty"`
	Warning  float64 `json:"warning,omitempty"`
	Critical float64 `json:"critical,omitempty"`
	Duration uint64  `json:"duration,omitempty"`
}

func (m *MonitorServiceMetric) MonitorType() string {
	return monitorTypeServiceMetric
}

type MonitorExternalHTTP struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	URL                             string  `json:"url,omitempty"`
	MaxCheckAttempts                float64 `json:"maxCheckAttempts,omitempty"`
	Service                         string  `json:"service,omitempty"`
	ResponseTimeCritical            float64 `json:"responseTimeCritical,omitempty"`
	ResponseTimeWarning             float64 `json:"responseTimeWarning,omitempty"`
	ResponseTimeDuration            float64 `json:"responseTimeDuration,omitempty"`
	ContainsString                  string  `json:"containsString,omitempty"`
	CertificationExpirationCritical uint64  `json:"certificationExpirationCritical,omitempty"`
	CertificationExpirationWarning  uint64  `json:"certificationExpirationWarning,omitempty"`
}

func (m *MonitorExternalHTTP) MonitorType() string {
	return monitorTypeExternalHTTP
}

type MonitorExpression struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	Expression string  `json:"expression,omitempty"`
	Operator   string  `json:"operator,omitempty"`
	Warning    float64 `json:"warning,omitempty"`
	Critical   float64 `json:"critical,omitempty"`
}

func (m *MonitorExpression) MonitorType() string {
	return monitorTypeExpression
}

// Monitor information
type Monitor struct {
	ID                              string   `json:"id,omitempty"`
	Name                            string   `json:"name,omitempty"`
	Type                            string   `json:"type,omitempty"`
	IsMute                          bool     `json:"isMute,omitempty"`
	Metric                          string   `json:"metric,omitempty"`
	Operator                        string   `json:"operator,omitempty"`
	Warning                         float64  `json:"warning,omitempty"`
	Critical                        float64  `json:"critical,omitempty"`
	Duration                        uint64   `json:"duration,omitempty"`
	URL                             string   `json:"url,omitempty"`
	Scopes                          []string `json:"scopes,omitempty"`
	Service                         string   `json:"service,omitempty"`
	MaxCheckAttempts                float64  `json:"maxCheckAttempts,omitempty"`
	NotificationInterval            uint64   `json:"notificationInterval,omitempty"`
	ExcludeScopes                   []string `json:"excludeScopes,omitempty"`
	ResponseTimeCritical            float64  `json:"responseTimeCritical,omitempty"`
	ResponseTimeWarning             float64  `json:"responseTimeWarning,omitempty"`
	ResponseTimeDuration            float64  `json:"responseTimeDuration,omitempty"`
	CertificationExpirationCritical uint64   `json:"certificationExpirationCritical,omitempty"`
	CertificationExpirationWarning  uint64   `json:"certificationExpirationWarning,omitempty"`
	ContainsString                  string   `json:"containsString,omitempty"`
	Expression                      string   `json:"expression,omitempty"`
}

// FindMonitors find monitors
func (c *Client) FindMonitors() ([]*Monitor, error) {
	req, err := http.NewRequest("GET", c.urlFor("/api/v0/monitors").String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Monitors []*(Monitor) `json:"monitors"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return data.Monitors, err
}

// CreateMonitor creating monitor
func (c *Client) CreateMonitor(param *Monitor) (*Monitor, error) {
	resp, err := c.PostJSON("/api/v0/monitors", param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// UpdateMonitor update monitor
func (c *Client) UpdateMonitor(monitorID string, param *Monitor) (*Monitor, error) {
	resp, err := c.PutJSON(fmt.Sprintf("/api/v0/monitors/%s", monitorID), param)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

// DeleteMonitor update monitor
func (c *Client) DeleteMonitor(monitorID string) (*Monitor, error) {
	req, err := http.NewRequest(
		"DELETE",
		c.urlFor(fmt.Sprintf("/api/v0/monitors/%s", monitorID)).String(),
		nil,
	)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data Monitor
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Comcast Cable Communications Management, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// End Copyright

package money

import (
	"bytes"
	"net/http"
)

//Header keys
const (
	MoneyHeader      = "X-Money-Trace"
	MoneySpansHeader = "X-Money-Spans"

	//money-trace context keys
	tIDKey = "trace-id"
	pIDKey = "parent-id"
	sIDKey = "span-id"
)

//MainSpan is a handy way to decorate your handler with money capabilities
//TODO: need to explain about how to use the money trace context values in in the request context
//TODO: disclaimer that this decorator changes the behavior of the responseWriter by allowing multiply
//body and code writes
func MainSpan(appName string) func(http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {

				rw := &rwInterceptor{ResponseWriter: w, Code: http.StatusOK, Body: new(bytes.Buffer)}
				defer rw.Flush()

				if r.Header.Get(MoneyHeader) != "" {
					var (
						tc  *TraceContext
						err error
					)

					if tc, err = decodeTraceContext(r.Header.Get(MoneyHeader)); err == nil {
						r = r.WithContext(traceCxt(tc))

						var done = Start(rw.Header())

						//finish this main handler span
						defer done(&SpanReport{
							Name:    "HTTPHandler",
							AppName: appName,
							Code:    rw.Code,
							Success: rw.Code < 400,
							TC:      tc,
						})
					}
				}

				h.ServeHTTP(rw, r)
			})
	}
}

//rwInterceptor allows temporary buffering of
//body and code for an original responseWriter
type rwInterceptor struct {
	http.ResponseWriter
	Code int
	Body *bytes.Buffer
}

//Write simply saves the last array of bytes written. Such data
//is then written to the original responseWriter once Flush() is called
func (rw *rwInterceptor) Write(b []byte) (int, error) {
	rw.Body.Reset() //starting fresh
	return rw.Body.Write(b)
}

//WriteHeader saves the last code written to the it. Such code
//is then written to the original responseWriter once Flush() is called
func (rw *rwInterceptor) WriteHeader(code int) {
	rw.Code = code
}

//Flush transfers the temporary buffer data into the original responseWriter
func (rw *rwInterceptor) Flush() (int, error) {
	rw.ResponseWriter.WriteHeader(rw.Code)
	return rw.ResponseWriter.Write(rw.Body.Bytes())
}
<commit_msg>update main span decorator comment<commit_after>// Copyright 2016 Comcast Cable Communications Management, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// End Copyright

package money

import (
	"bytes"
	"net/http"
)

//Header keys
const (
	MoneyHeader      = "X-Money-Trace"
	MoneySpansHeader = "X-Money-Spans"

	//money-trace context keys
	tIDKey = "trace-id"
	pIDKey = "parent-id"
	sIDKey = "span-id"
)

//MainSpan is the way to decorate your handler with money capabilities
//It also places money trace context information in the incoming request's contexts
//This is done so you can pass such trace context information to subsequent systems using money as well.
//Important: this decorator changes the behavior of the incoming responseWriter into the handler
//by allowing multiple body and code writes and keeping only the last writes. This allows the decorator
//to send back money span headers
func MainSpan(appName string) func(http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {

				rw := &rwInterceptor{ResponseWriter: w, Code: http.StatusOK, Body: new(bytes.Buffer)}
				defer rw.Flush()

				if r.Header.Get(MoneyHeader) != "" {
					var (
						tc  *TraceContext
						err error
					)

					if tc, err = decodeTraceContext(r.Header.Get(MoneyHeader)); err == nil {
						r = r.WithContext(traceCxt(tc))

						var done = Start(rw.Header())

						//finish this main handler span
						defer done(&SpanReport{
							Name:    "HTTPHandler",
							AppName: appName,
							Code:    rw.Code,
							Success: rw.Code < 400,
							TC:      tc,
						})
					}
				}

				h.ServeHTTP(rw, r)
			})
	}
}

//rwInterceptor allows temporary buffering of
//body and code for an original responseWriter
type rwInterceptor struct {
	http.ResponseWriter
	Code int
	Body *bytes.Buffer
}

//Write simply saves the last array of bytes written. Such data
//is then written to the original responseWriter once Flush() is called
func (rw *rwInterceptor) Write(b []byte) (int, error) {
	rw.Body.Reset() //starting fresh
	return rw.Body.Write(b)
}

//WriteHeader saves the last code written to the it. Such code
//is then written to the original responseWriter once Flush() is called
func (rw *rwInterceptor) WriteHeader(code int) {
	rw.Code = code
}

//Flush transfers the temporary buffer data into the original responseWriter
func (rw *rwInterceptor) Flush() (int, error) {
	rw.ResponseWriter.WriteHeader(rw.Code)
	return rw.ResponseWriter.Write(rw.Body.Bytes())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"net/http"
	"time"
)

// TLS represents the cert and key files for TLS connections
type TLS struct {
	Cert string
	Key  string
}

// LogHandler logs the request/response to the given io.Writer in Common Log Format
type LogHandler struct {
	writer  io.Writer
	handler http.Handler
}

func NewLogHandler(writer io.Writer, handler http.Handler) http.Handler {
	return &LogHandler{
		writer:  writer,
		handler: handler,
	}
}

// ServeHTTP Logs the request and calls the handler
func (lh *LogHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	startTime := time.Now()

	loggedWriter := &responseLogger{w: w}
	lh.handler.ServeHTTP(loggedWriter, req)

	username := "-"
	if req.URL.User != nil {
		name := req.URL.User.Username()
		if name != "" {
			username = name
		}
	}

	fmt.Fprintf(lh.writer, "%s %s - [%s] \"%s %s %s\" %d %d\n",
		req.RemoteAddr,
		username,
		startTime.Format("02/Jan/2006:15:04:05 -0700"),
		req.Method,
		req.RequestURI,
		req.Proto,
		loggedWriter.status,
		loggedWriter.size)
}

type responseLogger struct {
	w      http.ResponseWriter
	status int
	size   int
}

func (rl *responseLogger) Header() http.Header {
	return rl.w.Header()
}

func (rl *responseLogger) Write(b []byte) (int, error) {
	if rl.status == 0 {
		// The status will be StatusOk if WriteHeader has not been called
		rl.status = http.StatusOK
	}

	size, err := rl.w.Write(b)
	rl.size += size
	return size, err
}

func (rl *responseLogger) WriteHeader(s int) {
	rl.w.WriteHeader(s)
	rl.status = s
}
<commit_msg>Just a few changes to the log handler, mostly cosmetic<commit_after>package main

import (
	"fmt"
	"io"
	"net/http"
	"time"
)

// TLS represents the cert and key files for TLS connections
type TLS struct {
	Cert string
	Key  string
}

// LogHandler logs the request/response to the given io.Writer in Common Log Format
type LogHandler struct {
	writer  io.Writer
	handler http.Handler
}

func NewLogHandler(writer io.Writer, handler http.Handler) http.Handler {
	return &LogHandler{
		writer:  writer,
		handler: handler,
	}
}

// ServeHTTP Logs the request and calls the handler
func (lh *LogHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	accessTime := time.Now()

	loggedWriter := &responseLogger{responseWriter: rw}
	lh.handler.ServeHTTP(loggedWriter, req)

	// Get username field if given
	username := "-"
	if req.URL.User != nil {
		name := req.URL.User.Username()
		if name != "" {
			username = name
		}
	}

	fmt.Fprintf(lh.writer, "%s %s - [%s] \"%s %s %s\" %d %d\n",
		req.RemoteAddr,
		username,
		accessTime.Format("02/Jan/2006:15:04:05 -0700"),
		req.Method,
		req.RequestURI,
		req.Proto,
		loggedWriter.status,
		loggedWriter.length)
}

// responseLogger implements http.ResponseWriter, keeps log of status code and content length
type responseLogger struct {
	responseWriter http.ResponseWriter
	status         int
	length         int
}

func (rl *responseLogger) Header() http.Header {
	return rl.responseWriter.Header()
}

// Write calls the responseWriters write, and keeps track of the content length
func (rl *responseLogger) Write(b []byte) (int, error) {
	if rl.status == 0 {
		// The status will be StatusOk if WriteHeader has not been called
		rl.status = http.StatusOK
	}

	size, err := rl.responseWriter.Write(b)
	rl.length += size
	return size, err
}

// WriteHeader sets the status code, and writes the header to the set reponseWriter
func (rl *responseLogger) WriteHeader(status int) {
	rl.responseWriter.WriteHeader(status)
	rl.status = status
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/litl/galaxy/log"
)

var (
	httpRouter *HostRouter
)

type RequestLogger struct{}

// This works along with the ServiceRegistry, and the individual Services to
// route http requests based on the Host header. The Resgistry hold the mapping
// of VHost names to individual services, and each service has it's own
// ReeverseProxy to fulfill the request.
// HostRouter contains the ReverseProxy http Listener, and has an http.Handler
// to service the requets.
type HostRouter struct {
	sync.Mutex
	// the http frontend
	server *http.Server

	// track our listener so we can kill the server
	listener net.Listener
}

func NewHostRouter() *HostRouter {
	return &HostRouter{}
}

func (r *HostRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var err error
	host := req.Host
	if strings.Contains(host, ":") {
		host, _, err = net.SplitHostPort(req.Host)
		if err != nil {
			log.Warnf("%s", err)
		}
	}

	svc := Registry.GetVHostService(host)

	if svc != nil && svc.httpProxy != nil {
		// The vhost has a service registered, give it to the proxy
		svc.ServeHTTP(w, req)
		return
	}

	r.adminHandler(w, req)
}

func (r *HostRouter) adminHandler(w http.ResponseWriter, req *http.Request) {
	r.Lock()
	defer r.Unlock()

	if Registry.VHostsLen() == 0 {
		http.Error(w, "no backends available", http.StatusServiceUnavailable)
		return
	}

	// TODO: better status lines
	stats := Registry.Stats()
	for _, svc := range stats {
		if len(svc.VirtualHosts) == 0 {
			continue
		}
		fmt.Fprintf(w, "%v\n", svc.VirtualHosts)
		for _, b := range svc.Backends {
			js, _ := json.Marshal(b)
			fmt.Fprintf(w, "\t%s\n", string(js))
		}
	}

	fmt.Fprintf(w, "\n")
	return
}

// TODO: collect more stats?

// Start the HTTP Router frontend.
// Takes a channel to notify when the listener is started
// to safely synchronize tests.
func (r *HostRouter) Start(ready chan bool) {
	//FIXME: poor locking strategy
	r.Lock()

	log.Printf("HTTP server listening at %s", listenAddr)

	// Proxy acts as http handler:
	r.server = &http.Server{
		Addr:           listenAddr,
		Handler:        r,
		ReadTimeout:    60 * time.Second,
		WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	var err error
	r.listener, err = net.Listen("tcp", listenAddr)
	if err != nil {
		log.Errorf("%s", err)
		r.Unlock()
		return
	}

	r.Unlock()
	if ready != nil {
		close(ready)
	}

	// This will log a closed connection error every time we Stop
	// but that's mostly a testing issue.
	log.Errorf("%s", r.server.Serve(r.listener))
}

func (r *HostRouter) Stop() {
	r.listener.Close()
}

func startHTTPServer() {
	//FIXME: this global wg?
	defer wg.Done()
	httpRouter = NewHostRouter()
	httpRouter.Start(nil)
}

func sslRedirect(pr *ProxyRequest) bool {
	pr.Request.Header.Set("X-Request-Id", genId())

	if sslOnly && pr.Request.Header.Get("X-Forwarded-Proto") != "https" {
		//TODO: verify RequestURI
		redirLoc := "https://" + pr.Request.Host + pr.Request.RequestURI
		http.Redirect(pr.ResponseWriter, pr.Request, redirLoc, http.StatusMovedPermanently)
		return false
	}

	return true
}

type ErrorPage struct {
	// The Mutex protects access to the body slice.
	// Everything else should be static once the ErrorPage is created.
	sync.Mutex

	Location    string
	StatusCodes []int

	// body contains the cached error page
	body []byte
}

func (e *ErrorPage) Body() []byte {
	e.Lock()
	defer e.Unlock()
	return e.body
}

func (e *ErrorPage) SetBody(b []byte) {
	e.Lock()
	defer e.Unlock()
	e.body = b
}

// ErrorResponse provides a ReverProxy callback to process a response and
// insert custom error pages for a virtual host.
type ErrorResponse struct {
	sync.Mutex

	// map them by status for responses
	pages map[int]*ErrorPage

	// keep this handy to refresh the pages
	client *http.Client
}

func NewErrorResponse(pages map[string][]int) *ErrorResponse {
	errors := &ErrorResponse{
		pages: make(map[int]*ErrorPage),
	}

	// aggressively timeout connections
	errors.client = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 2 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 2 * time.Second,
		},
		Timeout: 5 * time.Second,
	}

	if pages != nil {
		errors.Update(pages)
	}
	return errors
}

// Get the error page body
// We permanently cache error pages once we've seen them
func (e *ErrorResponse) Get(code int) []byte {
	e.Lock()
	page, ok := e.pages[code]
	e.Unlock()

	if !ok {
		// this is a code we don't handle
		return nil
	}

	body := page.Body()
	if body != nil {
		return body
	}

	// we haven't successfully fetched this error
	e.fetch(page)
	return page.Body()
}

func (e *ErrorResponse) fetch(page *ErrorPage) {
	log.Debugf("Fetching error page from %s", page.Location)
	resp, err := e.client.Get(page.Location)
	if err != nil {
		log.Warnf("Could not fetch %s: %s", page.Location, err.Error())
		return
	}
	defer resp.Body.Close()

	// If the StatusCode matches any of our registered codes, it's OK
	for _, code := range page.StatusCodes {
		if resp.StatusCode == code {
			break
		}
	}

	if resp.StatusCode != http.StatusOK {
		log.Warnf("Server returned %d when fetching %s", resp.StatusCode, page.Location)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Warnf("Error reading response from %s: %s", page.Location, err.Error())
		return
	}

	if len(body) > 0 {
		page.SetBody(body)
		return
	}
	log.Warnf("Empty response from %s", page.Location)
}

// This replaces all existing ErrorPages
func (e *ErrorResponse) Update(pages map[string][]int) {
	e.Lock()
	defer e.Unlock()

	e.pages = make(map[int]*ErrorPage)

	for loc, codes := range pages {
		page := &ErrorPage{
			StatusCodes: codes,
			Location:    loc,
		}

		for _, code := range codes {
			e.pages[code] = page
		}
		go e.fetch(page)
	}
}

func (e *ErrorResponse) CheckResponse(pr *ProxyRequest) bool {

	errPage := e.Get(pr.Response.StatusCode)
	if errPage != nil {
		pr.ResponseWriter.WriteHeader(pr.Response.StatusCode)
		pr.ResponseWriter.Write(errPage)
		return false
	}

	return true
}

func logProxyRequest(pr *ProxyRequest) bool {
	// TODO: we may to be able to switch this off
	if pr == nil {
		return true
	}

	var id, method, clientIP, url, backend, agent string

	duration := pr.FinishTime.Sub(pr.StartTime)

	if pr.Request != nil {
		id = pr.Request.Header.Get("X-Request-Id")
		method = pr.Request.Method
		clientIP = pr.Request.RemoteAddr
		url = pr.Request.Host + pr.Request.RequestURI
		agent = pr.Request.UserAgent()
	}

	if pr.Response != nil && pr.Response.Request != nil && pr.Response.Request.URL != nil {
		backend = pr.Response.Request.URL.Host
	}

	err := fmt.Sprintf("%v", pr.ProxyError)

	fmtStr := "id=%s method=%s clientIp=%s url=%s backend=%s duration=%s agent=%s, err=%s"

	log.Printf(fmtStr, id, method, clientIP, url, backend, duration, agent, err)
	return true
}
<commit_msg>Lost the OK assignment<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/litl/galaxy/log"
)

var (
	httpRouter *HostRouter
)

type RequestLogger struct{}

// This works along with the ServiceRegistry, and the individual Services to
// route http requests based on the Host header. The Resgistry hold the mapping
// of VHost names to individual services, and each service has it's own
// ReeverseProxy to fulfill the request.
// HostRouter contains the ReverseProxy http Listener, and has an http.Handler
// to service the requets.
type HostRouter struct {
	sync.Mutex
	// the http frontend
	server *http.Server

	// track our listener so we can kill the server
	listener net.Listener
}

func NewHostRouter() *HostRouter {
	return &HostRouter{}
}

func (r *HostRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var err error
	host := req.Host
	if strings.Contains(host, ":") {
		host, _, err = net.SplitHostPort(req.Host)
		if err != nil {
			log.Warnf("%s", err)
		}
	}

	svc := Registry.GetVHostService(host)

	if svc != nil && svc.httpProxy != nil {
		// The vhost has a service registered, give it to the proxy
		svc.ServeHTTP(w, req)
		return
	}

	r.adminHandler(w, req)
}

func (r *HostRouter) adminHandler(w http.ResponseWriter, req *http.Request) {
	r.Lock()
	defer r.Unlock()

	if Registry.VHostsLen() == 0 {
		http.Error(w, "no backends available", http.StatusServiceUnavailable)
		return
	}

	// TODO: better status lines
	stats := Registry.Stats()
	for _, svc := range stats {
		if len(svc.VirtualHosts) == 0 {
			continue
		}
		fmt.Fprintf(w, "%v\n", svc.VirtualHosts)
		for _, b := range svc.Backends {
			js, _ := json.Marshal(b)
			fmt.Fprintf(w, "\t%s\n", string(js))
		}
	}

	fmt.Fprintf(w, "\n")
	return
}

// TODO: collect more stats?

// Start the HTTP Router frontend.
// Takes a channel to notify when the listener is started
// to safely synchronize tests.
func (r *HostRouter) Start(ready chan bool) {
	//FIXME: poor locking strategy
	r.Lock()

	log.Printf("HTTP server listening at %s", listenAddr)

	// Proxy acts as http handler:
	r.server = &http.Server{
		Addr:           listenAddr,
		Handler:        r,
		ReadTimeout:    60 * time.Second,
		WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	var err error
	r.listener, err = net.Listen("tcp", listenAddr)
	if err != nil {
		log.Errorf("%s", err)
		r.Unlock()
		return
	}

	r.Unlock()
	if ready != nil {
		close(ready)
	}

	// This will log a closed connection error every time we Stop
	// but that's mostly a testing issue.
	log.Errorf("%s", r.server.Serve(r.listener))
}

func (r *HostRouter) Stop() {
	r.listener.Close()
}

func startHTTPServer() {
	//FIXME: this global wg?
	defer wg.Done()
	httpRouter = NewHostRouter()
	httpRouter.Start(nil)
}

func sslRedirect(pr *ProxyRequest) bool {
	pr.Request.Header.Set("X-Request-Id", genId())

	if sslOnly && pr.Request.Header.Get("X-Forwarded-Proto") != "https" {
		//TODO: verify RequestURI
		redirLoc := "https://" + pr.Request.Host + pr.Request.RequestURI
		http.Redirect(pr.ResponseWriter, pr.Request, redirLoc, http.StatusMovedPermanently)
		return false
	}

	return true
}

type ErrorPage struct {
	// The Mutex protects access to the body slice.
	// Everything else should be static once the ErrorPage is created.
	sync.Mutex

	Location    string
	StatusCodes []int

	// body contains the cached error page
	body []byte
}

func (e *ErrorPage) Body() []byte {
	e.Lock()
	defer e.Unlock()
	return e.body
}

func (e *ErrorPage) SetBody(b []byte) {
	e.Lock()
	defer e.Unlock()
	e.body = b
}

// ErrorResponse provides a ReverProxy callback to process a response and
// insert custom error pages for a virtual host.
type ErrorResponse struct {
	sync.Mutex

	// map them by status for responses
	pages map[int]*ErrorPage

	// keep this handy to refresh the pages
	client *http.Client
}

func NewErrorResponse(pages map[string][]int) *ErrorResponse {
	errors := &ErrorResponse{
		pages: make(map[int]*ErrorPage),
	}

	// aggressively timeout connections
	errors.client = &http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 2 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 2 * time.Second,
		},
		Timeout: 5 * time.Second,
	}

	if pages != nil {
		errors.Update(pages)
	}
	return errors
}

// Get the error page body
// We permanently cache error pages once we've seen them
func (e *ErrorResponse) Get(code int) []byte {
	e.Lock()
	page, ok := e.pages[code]
	e.Unlock()

	if !ok {
		// this is a code we don't handle
		return nil
	}

	body := page.Body()
	if body != nil {
		return body
	}

	// we haven't successfully fetched this error
	e.fetch(page)
	return page.Body()
}

func (e *ErrorResponse) fetch(page *ErrorPage) {
	log.Debugf("Fetching error page from %s", page.Location)
	resp, err := e.client.Get(page.Location)
	if err != nil {
		log.Warnf("Could not fetch %s: %s", page.Location, err.Error())
		return
	}
	defer resp.Body.Close()

	// If the StatusCode matches any of our registered codes, it's OK
	for _, code := range page.StatusCodes {
		if resp.StatusCode == code {
			resp.StatusCode = http.StatusOK
			break
		}
	}

	if resp.StatusCode != http.StatusOK {
		log.Warnf("Server returned %d when fetching %s", resp.StatusCode, page.Location)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Warnf("Error reading response from %s: %s", page.Location, err.Error())
		return
	}

	if len(body) > 0 {
		page.SetBody(body)
		return
	}
	log.Warnf("Empty response from %s", page.Location)
}

// This replaces all existing ErrorPages
func (e *ErrorResponse) Update(pages map[string][]int) {
	e.Lock()
	defer e.Unlock()

	e.pages = make(map[int]*ErrorPage)

	for loc, codes := range pages {
		page := &ErrorPage{
			StatusCodes: codes,
			Location:    loc,
		}

		for _, code := range codes {
			e.pages[code] = page
		}
		go e.fetch(page)
	}
}

func (e *ErrorResponse) CheckResponse(pr *ProxyRequest) bool {

	errPage := e.Get(pr.Response.StatusCode)
	if errPage != nil {
		pr.ResponseWriter.WriteHeader(pr.Response.StatusCode)
		pr.ResponseWriter.Write(errPage)
		return false
	}

	return true
}

func logProxyRequest(pr *ProxyRequest) bool {
	// TODO: we may to be able to switch this off
	if pr == nil {
		return true
	}

	var id, method, clientIP, url, backend, agent string

	duration := pr.FinishTime.Sub(pr.StartTime)

	if pr.Request != nil {
		id = pr.Request.Header.Get("X-Request-Id")
		method = pr.Request.Method
		clientIP = pr.Request.RemoteAddr
		url = pr.Request.Host + pr.Request.RequestURI
		agent = pr.Request.UserAgent()
	}

	if pr.Response != nil && pr.Response.Request != nil && pr.Response.Request.URL != nil {
		backend = pr.Response.Request.URL.Host
	}

	err := fmt.Sprintf("%v", pr.ProxyError)

	fmtStr := "id=%s method=%s clientIp=%s url=%s backend=%s duration=%s agent=%s, err=%s"

	log.Printf(fmtStr, id, method, clientIP, url, backend, duration, agent, err)
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"errors"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discover/discover"
)

type HTTPFrontend struct {
	Addr      string
	TLSAddr   string
	TLSConfig *tls.Config

	mtx      sync.RWMutex
	domains  map[string]*httpServer
	services map[string]*httpServer

	etcdPrefix string

	etcd     *etcd.Client
	discover *discover.Client
}

func NewHTTPFrontend(addr string) (*HTTPFrontend, error) {
	f := &HTTPFrontend{
		Addr:       addr,
		etcd:       etcd.NewClient(nil),
		etcdPrefix: "/strowger/http/",
		domains:    make(map[string]*httpServer),
		services:   make(map[string]*httpServer),
	}
	var err error
	f.discover, err = discover.NewClient()
	return f, err
}

func (s *HTTPFrontend) AddHTTPDomain(domain string, service string, certs [][]byte, key []byte) error {
	return s.addDomain(domain, service, true)
}

func (s *HTTPFrontend) addDomain(domain string, service string, persist bool) error {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	if server, ok := s.domains[domain]; ok {
		if server.name != service {
			return errors.New("domain exists with different service")
		}
		return nil
	}

	server := s.services[service]
	if server == nil {
		server = &httpServer{name: service, services: s.discover.Services(service)}
	}
	if persist {
		_, ok, err := s.etcd.TestAndSet(s.etcdPrefix+domain+"/service", "", service, 0)
		if err != nil {
			return err
		}
		if !ok {
			return errors.New("domain already exists in etcd")
		}
	}
	// TODO: set cert/key data if provided

	server.refs++
	s.domains[domain] = server
	s.services[service] = server
	// TODO: TLS config

	log.Println("Add service", service, "to domain", domain)

	return nil
}

func (s *HTTPFrontend) RemoveHTTPDomain(domain string) {
	s.mtx.Lock()
	defer s.mtx.Unlock()
	server := s.domains[domain]
	if server == nil {
		return
	}
	delete(s.domains, domain)
	server.refs++
	if server.refs <= 0 {
		// TODO: close service set stream
		delete(s.services, server.name)
	}
	// TODO: persist
}

func (s *HTTPFrontend) syncDatabase() {
	data, err := s.etcd.Get(s.etcdPrefix)
	if e, ok := err.(etcd.EtcdError); ok && e.ErrorCode == 100 {
		// key not found, ignore
		err = nil
	}
	if err != nil {
		log.Fatal(err)
		return
	}
	for _, res := range data {
		if !res.Dir {
			continue
		}
		domain := path.Base(res.Key)
		serviceRes, err := s.etcd.Get(res.Key + "/service")
		if err != nil {
			log.Fatal(err)
		}
		if len(serviceRes) != 1 {
			continue
		}
		service := serviceRes[0].Value
		if err := s.addDomain(domain, service, false); err != nil {
			log.Fatal(err)
		}
	}
	var since uint64
	if len(data) > 0 {
		since = data[len(data)-1].Index
	}

	stream := make(chan *etcd.Response)
	stop := make(chan bool)
	// TODO: store stop
	go s.etcd.Watch(s.etcdPrefix, since, stream, stop)
	for res := range stream {
		if !res.Dir && res.NewKey && path.Base(res.Key) == "service" {
			domain := path.Base(path.Dir(res.Key))
			if err := s.addDomain(domain, res.Value, false); err != nil {
				// TODO: log error
			}
		}
		// TODO: handle delete
	}
	log.Println("done watching etcd")
}

func (s *HTTPFrontend) serve() {
	l, err := net.Listen("tcp", s.Addr)
	if err != nil {
		// TODO: log error
		return
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			// TODO: log error
			break
		}
		go s.handle(conn)
	}
}

func (s *HTTPFrontend) serveTLS() {
	l, err := net.Listen("tcp", s.TLSAddr)
	if err != nil {
		// TODO: log error
		return
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			// TODO: log error
			break
		}
		go s.handle(conn)
	}
}

func (s *HTTPFrontend) handle(conn net.Conn) {
	defer conn.Close()
	sc := httputil.NewServerConn(conn, nil)
	req, err := sc.Read()
	if err != nil {
		if err != httputil.ErrPersistEOF {
			// TODO: log error
		}
		return
	}

	s.mtx.RLock()
	// TODO: handle wildcard domains
	backend := s.domains[req.Host]
	s.mtx.RUnlock()
	log.Println(req, backend)
	if backend == nil {
		// TODO: return 404
		return
	}
	_, tls := conn.(*tls.Conn)
	backend.handle(req, sc, tls)
}

type httpServer struct {
	name     string
	services *discover.ServiceSet
	refs     int
}

func (s *httpServer) getBackend() *httputil.ClientConn {
	for _, addr := range shuffle(s.services.OnlineAddrs()) {
		// TODO: set connection timeout
		backend, err := net.Dial("tcp", addr)
		if err != nil {
			// TODO: log error
			// TODO: limit number of backends tried
			// TODO: temporarily quarantine failing backends
			log.Println("backend error", err)
			continue
		}
		return httputil.NewClientConn(backend, nil)
	}
	// TODO: log no backends found error
	return nil
}

func (s *httpServer) handle(req *http.Request, sc *httputil.ServerConn, tls bool) {
	req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10))
	backend := s.getBackend()
	if backend == nil {
		// TODO: Return 503
		log.Println("no backend found")
		return
	}
	defer backend.Close()

	for {
		if req.Method != "GET" && req.Method != "POST" && req.Method != "HEAD" &&
			req.Method != "OPTIONS" && req.Method != "PUT" && req.Method != "DELETE" && req.Method != "TRACE" {
			// TODO: return 405
		}

		req.Proto = "HTTP/1.1"
		req.ProtoMajor = 1
		req.ProtoMinor = 1
		delete(req.Header, "Te")
		delete(req.Header, "Transfer-Encoding")

		if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
			// If we aren't the first proxy retain prior
			// X-Forwarded-For information as a comma+space
			// separated list and fold multiple headers into one.
			if prior, ok := req.Header["X-Forwarded-For"]; ok {
				clientIP = strings.Join(prior, ", ") + ", " + clientIP
			}
			req.Header.Set("X-Forwarded-For", clientIP)
		}
		if tls {
			req.Header.Set("X-Forwarded-Proto", "https")
		} else {
			req.Header.Set("X-Forwarded-Proto", "http")
		}
		// TODO: Set X-Forwarded-Port

		if err := backend.Write(req); err != nil {
			log.Println("server write err:", err)
			return
		}
		res, err := backend.Read(req)
		if res != nil {
			if err := sc.Write(req, res); err != nil {
				if err != io.EOF && err != httputil.ErrPersistEOF {
					log.Println("client write err:", err)
					// TODO: log error
				}
				return
			}
		}
		if err != nil {
			if err != io.EOF && err != httputil.ErrPersistEOF {
				log.Println("server read err:", err)
				// TODO: log error
				// TODO: Return 502
			}
			return
		}

		// TODO: Proxy HTTP CONNECT? (example: Go RPC over HTTP)
		if res.StatusCode == http.StatusSwitchingProtocols {
			serverW, serverR := backend.Hijack()
			clientW, clientR := sc.Hijack()
			defer serverW.Close()
			done := make(chan struct{})
			go func() {
				serverR.WriteTo(clientW)
				close(done)
			}()
			clientR.WriteTo(serverW)
			<-done
			return
		}

		// TODO: http pipelining
		req, err = sc.Read()
		if err != nil {
			if err != io.EOF && err != httputil.ErrPersistEOF {
				log.Println("client read err:", err)
			}
			return
		}
		req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10))
	}
}

func shuffle(s []string) []string {
	for i := len(s) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		s[i], s[j] = s[j], s[i]
	}
	return s
}

func init() {
	rand.Seed(time.Now().UnixNano())
}
<commit_msg>Update discover API usage<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discover/discover"
)

type HTTPFrontend struct {
	Addr      string
	TLSAddr   string
	TLSConfig *tls.Config

	mtx      sync.RWMutex
	domains  map[string]*httpServer
	services map[string]*httpServer

	etcdPrefix string

	etcd     *etcd.Client
	discover *discover.Client
}

func NewHTTPFrontend(addr string) (*HTTPFrontend, error) {
	f := &HTTPFrontend{
		Addr:       addr,
		etcd:       etcd.NewClient(nil),
		etcdPrefix: "/strowger/http/",
		domains:    make(map[string]*httpServer),
		services:   make(map[string]*httpServer),
	}
	var err error
	f.discover, err = discover.NewClient()
	return f, err
}

func (s *HTTPFrontend) AddHTTPDomain(domain string, service string, certs [][]byte, key []byte) error {
	return s.addDomain(domain, service, true)
}

func (s *HTTPFrontend) addDomain(domain string, service string, persist bool) error {
	s.mtx.Lock()
	defer s.mtx.Unlock()

	if server, ok := s.domains[domain]; ok {
		if server.name != service {
			return errors.New("domain exists with different service")
		}
		return nil
	}

	server := s.services[service]
	if server == nil {
		services, err := s.discover.Services(service)
		if err != nil {
			return err
		}
		server = &httpServer{name: service, services: services}
	}
	if persist {
		_, ok, err := s.etcd.TestAndSet(s.etcdPrefix+domain+"/service", "", service, 0)
		if err != nil {
			return err
		}
		if !ok {
			return errors.New("domain already exists in etcd")
		}
	}
	// TODO: set cert/key data if provided

	server.refs++
	s.domains[domain] = server
	s.services[service] = server
	// TODO: TLS config

	log.Println("Add service", service, "to domain", domain)

	return nil
}

func (s *HTTPFrontend) RemoveHTTPDomain(domain string) {
	s.mtx.Lock()
	defer s.mtx.Unlock()
	server := s.domains[domain]
	if server == nil {
		return
	}
	delete(s.domains, domain)
	server.refs++
	if server.refs <= 0 {
		// TODO: close service set stream
		delete(s.services, server.name)
	}
	// TODO: persist
}

func (s *HTTPFrontend) syncDatabase() {
	data, err := s.etcd.Get(s.etcdPrefix)
	if e, ok := err.(etcd.EtcdError); ok && e.ErrorCode == 100 {
		// key not found, ignore
		err = nil
	}
	if err != nil {
		log.Fatal(err)
		return
	}
	for _, res := range data {
		if !res.Dir {
			continue
		}
		domain := path.Base(res.Key)
		serviceRes, err := s.etcd.Get(res.Key + "/service")
		if err != nil {
			log.Fatal(err)
		}
		if len(serviceRes) != 1 {
			continue
		}
		service := serviceRes[0].Value
		if err := s.addDomain(domain, service, false); err != nil {
			log.Fatal(err)
		}
	}
	var since uint64
	if len(data) > 0 {
		since = data[len(data)-1].Index
	}

	stream := make(chan *etcd.Response)
	stop := make(chan bool)
	// TODO: store stop
	go s.etcd.Watch(s.etcdPrefix, since, stream, stop)
	for res := range stream {
		if !res.Dir && res.NewKey && path.Base(res.Key) == "service" {
			domain := path.Base(path.Dir(res.Key))
			if err := s.addDomain(domain, res.Value, false); err != nil {
				// TODO: log error
			}
		}
		// TODO: handle delete
	}
	log.Println("done watching etcd")
}

func (s *HTTPFrontend) serve() {
	l, err := net.Listen("tcp", s.Addr)
	if err != nil {
		// TODO: log error
		return
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			// TODO: log error
			break
		}
		go s.handle(conn)
	}
}

func (s *HTTPFrontend) serveTLS() {
	l, err := net.Listen("tcp", s.TLSAddr)
	if err != nil {
		// TODO: log error
		return
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			// TODO: log error
			break
		}
		go s.handle(conn)
	}
}

func (s *HTTPFrontend) handle(conn net.Conn) {
	defer conn.Close()
	sc := httputil.NewServerConn(conn, nil)
	req, err := sc.Read()
	if err != nil {
		if err != httputil.ErrPersistEOF {
			// TODO: log error
		}
		return
	}

	s.mtx.RLock()
	// TODO: handle wildcard domains
	backend := s.domains[req.Host]
	s.mtx.RUnlock()
	log.Println(req, backend)
	if backend == nil {
		// TODO: return 404
		return
	}
	_, tls := conn.(*tls.Conn)
	backend.handle(req, sc, tls)
}

type httpServer struct {
	name     string
	services *discover.ServiceSet
	refs     int
}

func (s *httpServer) getBackend() *httputil.ClientConn {
	for _, addr := range shuffle(s.services.OnlineAddrs()) {
		// TODO: set connection timeout
		backend, err := net.Dial("tcp", addr)
		if err != nil {
			// TODO: log error
			// TODO: limit number of backends tried
			// TODO: temporarily quarantine failing backends
			log.Println("backend error", err)
			continue
		}
		return httputil.NewClientConn(backend, nil)
	}
	// TODO: log no backends found error
	return nil
}

func (s *httpServer) handle(req *http.Request, sc *httputil.ServerConn, tls bool) {
	req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10))
	backend := s.getBackend()
	if backend == nil {
		// TODO: Return 503
		log.Println("no backend found")
		return
	}
	defer backend.Close()

	for {
		if req.Method != "GET" && req.Method != "POST" && req.Method != "HEAD" &&
			req.Method != "OPTIONS" && req.Method != "PUT" && req.Method != "DELETE" && req.Method != "TRACE" {
			// TODO: return 405
		}

		req.Proto = "HTTP/1.1"
		req.ProtoMajor = 1
		req.ProtoMinor = 1
		delete(req.Header, "Te")
		delete(req.Header, "Transfer-Encoding")

		if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
			// If we aren't the first proxy retain prior
			// X-Forwarded-For information as a comma+space
			// separated list and fold multiple headers into one.
			if prior, ok := req.Header["X-Forwarded-For"]; ok {
				clientIP = strings.Join(prior, ", ") + ", " + clientIP
			}
			req.Header.Set("X-Forwarded-For", clientIP)
		}
		if tls {
			req.Header.Set("X-Forwarded-Proto", "https")
		} else {
			req.Header.Set("X-Forwarded-Proto", "http")
		}
		// TODO: Set X-Forwarded-Port

		if err := backend.Write(req); err != nil {
			log.Println("server write err:", err)
			return
		}
		res, err := backend.Read(req)
		if res != nil {
			if err := sc.Write(req, res); err != nil {
				if err != io.EOF && err != httputil.ErrPersistEOF {
					log.Println("client write err:", err)
					// TODO: log error
				}
				return
			}
		}
		if err != nil {
			if err != io.EOF && err != httputil.ErrPersistEOF {
				log.Println("server read err:", err)
				// TODO: log error
				// TODO: Return 502
			}
			return
		}

		// TODO: Proxy HTTP CONNECT? (example: Go RPC over HTTP)
		if res.StatusCode == http.StatusSwitchingProtocols {
			serverW, serverR := backend.Hijack()
			clientW, clientR := sc.Hijack()
			defer serverW.Close()
			done := make(chan struct{})
			go func() {
				serverR.WriteTo(clientW)
				close(done)
			}()
			clientR.WriteTo(serverW)
			<-done
			return
		}

		// TODO: http pipelining
		req, err = sc.Read()
		if err != nil {
			if err != io.EOF && err != httputil.ErrPersistEOF {
				log.Println("client read err:", err)
			}
			return
		}
		req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10))
	}
}

func shuffle(s []string) []string {
	for i := len(s) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		s[i], s[j] = s[j], s[i]
	}
	return s
}

func init() {
	rand.Seed(time.Now().UnixNano())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"sync"
)

var (
	addr         = flag.String("addr", "localhost:7702", "The address on which netprint listens.")
	tcp          = flag.Bool("tcp", false, "Accept raw TCP requests instead of HTTP.")
	udp          = flag.Bool("udp", false, "Accept raw UDP packets instead of HTTP.")
	responseCode = flag.Int("response-code", http.StatusOK, "Response code for HTTP requests.")
	responseText = flag.String("response-text", "", "Response body for HTTP requests.")
	mode         = modeHTTP
	mut          sync.Mutex
)

func fatal(args ...interface{}) {
	fmt.Println(args...)
	os.Exit(1)
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf(format, args...)
	os.Exit(1)
}

func init() {
	flag.Parse()
	if *tcp {
		if *udp {
			fatal("Cannot specify both -tcp and -udp.")
		}
		mode = modeTCP
	}
	if *udp {
		mode = modeUDP
	}

	setFlags := map[string]bool{}
	flag.Visit(func(f *flag.Flag) { setFlags[f.Name] = true })

	for _, f := range []string{"response-code", "response-text"} {
		if setFlags[f] && mode != modeHTTP {
			fatalf("Cannot specify -%s except in HTTP mode.", f)
		}
	}
	if setFlags["response-code"] && (*responseCode < 100 || *responseCode >= 600) {
		fatal("Invalid HTTP response code:", *responseCode)
	}
}

type modeType int

const (
	modeHTTP modeType = iota
	modeTCP
	modeUDP
)

// copyRecordNewline is like io.Copy, but says whether the copied data ended in a newline.
func copyRecordNewline(dst io.Writer, src io.Reader) (written int64, err error, endingNewline bool) {
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = io.ErrShortWrite
				break
			}
			endingNewline = buf[nr-1] == '\n'
		}
		if er == io.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err, endingNewline
}

func handleHTTP(w http.ResponseWriter, r *http.Request) {
	// It's pretty dumb to synchronize all the HTTP handlers when net/http is doing such a good job of
	// multiplexing requests onto goroutines for me, but this approach is simpler than constructing a
	// non-concurrent HTTP server.
	mut.Lock()
	defer mut.Unlock()

	fmt.Printf(">>>>> Request: %s\n", r.URL)
	written, err, endingNewline := copyRecordNewline(os.Stdout, r.Body)
	if err != nil {
		return
	}
	if written == 0 {
		fmt.Println("(Empty body.)")
	} else if !endingNewline {
		fmt.Println()
	}

	w.WriteHeader(*responseCode)
	w.Write([]byte(*responseText))
}

func runHTTP() error {
	mux := http.NewServeMux()
	mux.HandleFunc("/", handleHTTP)
	fmt.Println("Now accepting HTTP requests on", *addr)
	return http.ListenAndServe(*addr, mux)
}

func handleTCP(conn net.Conn) {
	fmt.Printf(">>>>> %s connected.\n", conn.RemoteAddr())
	written, err, endingNewline := copyRecordNewline(os.Stdout, conn)
	if err != nil {
		return
	}
	if written == 0 {
		fmt.Println("(No data transmitted.)")
	} else if !endingNewline {
		fmt.Println()
	}
	fmt.Printf(">>>>> %s disconnected.\n", conn.RemoteAddr())
}

func runTCP() error {
	l, err := net.Listen("tcp", *addr)
	if err != nil {
		return err
	}
	fmt.Println("Now accepting raw TCP requests on", *addr)
	for {
		conn, err := l.Accept()
		if err != nil {
			return err
		}
		handleTCP(conn)
	}
}

func handleUDP(conn *net.UDPConn) {
	buf := make([]byte, 10 * 1024) // 10KB buffer to handle pretty damn big UDP packets
	for {
		n, addr, err := conn.ReadFromUDP(buf)
		if err != nil {
			return
		}
		fmt.Printf(">>>>> Received a packet from %s\n", addr)
		if n == 0 {
			fmt.Println("(No data transmitted.)")
		} else {
			os.Stdout.Write(buf[:n])
			if buf[n-1] != '\n' {
				fmt.Println()
			}
		}
	}
}

func runUDP() error {
	u, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		return err
	}
	conn, err := net.ListenUDP("udp", u)
	if err != nil {
		return err
	}
	fmt.Println("Now accepting raw UDP requests on", *addr)
	handleUDP(conn)
	return nil
}

func main() {
	switch mode {
	case modeHTTP:
		fatal(runHTTP())
	case modeTCP:
		fatal(runTCP())
	case modeUDP:
		fatal(runUDP())
	}
}
<commit_msg>Don't use sync.Mutex as a value receiver<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"sync"
)

var (
	addr         = flag.String("addr", "localhost:7702", "The address on which netprint listens.")
	tcp          = flag.Bool("tcp", false, "Accept raw TCP requests instead of HTTP.")
	udp          = flag.Bool("udp", false, "Accept raw UDP packets instead of HTTP.")
	responseCode = flag.Int("response-code", http.StatusOK, "Response code for HTTP requests.")
	responseText = flag.String("response-text", "", "Response body for HTTP requests.")
	mode         = modeHTTP
	mut          = &sync.Mutex{}
)

func fatal(args ...interface{}) {
	fmt.Println(args...)
	os.Exit(1)
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf(format, args...)
	os.Exit(1)
}

func init() {
	flag.Parse()
	if *tcp {
		if *udp {
			fatal("Cannot specify both -tcp and -udp.")
		}
		mode = modeTCP
	}
	if *udp {
		mode = modeUDP
	}

	setFlags := map[string]bool{}
	flag.Visit(func(f *flag.Flag) { setFlags[f.Name] = true })

	for _, f := range []string{"response-code", "response-text"} {
		if setFlags[f] && mode != modeHTTP {
			fatalf("Cannot specify -%s except in HTTP mode.", f)
		}
	}
	if setFlags["response-code"] && (*responseCode < 100 || *responseCode >= 600) {
		fatal("Invalid HTTP response code:", *responseCode)
	}
}

type modeType int

const (
	modeHTTP modeType = iota
	modeTCP
	modeUDP
)

// copyRecordNewline is like io.Copy, but says whether the copied data ended in a newline.
func copyRecordNewline(dst io.Writer, src io.Reader) (written int64, err error, endingNewline bool) {
	buf := make([]byte, 32*1024)
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			nw, ew := dst.Write(buf[:nr])
			if nw > 0 {
				written += int64(nw)
			}
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = io.ErrShortWrite
				break
			}
			endingNewline = buf[nr-1] == '\n'
		}
		if er == io.EOF {
			break
		}
		if er != nil {
			err = er
			break
		}
	}
	return written, err, endingNewline
}

func handleHTTP(w http.ResponseWriter, r *http.Request) {
	// It's pretty dumb to synchronize all the HTTP handlers when net/http is doing such a good job of
	// multiplexing requests onto goroutines for me, but this approach is simpler than constructing a
	// non-concurrent HTTP server.
	mut.Lock()
	defer mut.Unlock()

	fmt.Printf(">>>>> Request: %s\n", r.URL)
	written, err, endingNewline := copyRecordNewline(os.Stdout, r.Body)
	if err != nil {
		return
	}
	if written == 0 {
		fmt.Println("(Empty body.)")
	} else if !endingNewline {
		fmt.Println()
	}

	w.WriteHeader(*responseCode)
	w.Write([]byte(*responseText))
}

func runHTTP() error {
	mux := http.NewServeMux()
	mux.HandleFunc("/", handleHTTP)
	fmt.Println("Now accepting HTTP requests on", *addr)
	return http.ListenAndServe(*addr, mux)
}

func handleTCP(conn net.Conn) {
	fmt.Printf(">>>>> %s connected.\n", conn.RemoteAddr())
	written, err, endingNewline := copyRecordNewline(os.Stdout, conn)
	if err != nil {
		return
	}
	if written == 0 {
		fmt.Println("(No data transmitted.)")
	} else if !endingNewline {
		fmt.Println()
	}
	fmt.Printf(">>>>> %s disconnected.\n", conn.RemoteAddr())
}

func runTCP() error {
	l, err := net.Listen("tcp", *addr)
	if err != nil {
		return err
	}
	fmt.Println("Now accepting raw TCP requests on", *addr)
	for {
		conn, err := l.Accept()
		if err != nil {
			return err
		}
		handleTCP(conn)
	}
}

func handleUDP(conn *net.UDPConn) {
	buf := make([]byte, 10*1024) // 10KB buffer to handle pretty damn big UDP packets
	for {
		n, addr, err := conn.ReadFromUDP(buf)
		if err != nil {
			return
		}
		fmt.Printf(">>>>> Received a packet from %s\n", addr)
		if n == 0 {
			fmt.Println("(No data transmitted.)")
		} else {
			os.Stdout.Write(buf[:n])
			if buf[n-1] != '\n' {
				fmt.Println()
			}
		}
	}
}

func runUDP() error {
	u, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		return err
	}
	conn, err := net.ListenUDP("udp", u)
	if err != nil {
		return err
	}
	fmt.Println("Now accepting raw UDP requests on", *addr)
	handleUDP(conn)
	return nil
}

func main() {
	switch mode {
	case modeHTTP:
		fatal(runHTTP())
	case modeTCP:
		fatal(runTCP())
	case modeUDP:
		fatal(runUDP())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/daneharrigan/hipchat"
)

func main() {
	user := "11111_22222"
	pass := "secret"
	resource := "bot"
	roomJid := "11111_room_name@conf.hipchat.com"
	fullName := "Some Bot"
	mentionName := "SomeBot"

	client, err := hipchat.NewClient(user, pass, resource)
	if err != nil {
		fmt.Printf("client error: %s\n", err)
		return
	}

	client.Status("chat")
	client.Join(roomJid, fullName)

  go client.KeepAlive()

	go func() {
		for {
			select {
			case message := <-client.Messages():
				if strings.HasPrefix(message.Body, "@"+mentionName) {
					client.Say(roomJid, fullName, "Hello")
				}
			}
		}
	}()
	select {}
}
<commit_msg>fixes spacing<commit_after>package main

import (
    "fmt"
    "strings"

    "github.com/daneharrigan/hipchat"
)

func main() {
    user := "11111_22222"
    pass := "secret"
    resource := "bot"
    roomJid := "11111_room_name@conf.hipchat.com"
    fullName := "Some Bot"
    mentionName := "SomeBot"

    client, err := hipchat.NewClient(user, pass, resource)
    if err != nil {
        fmt.Printf("client error: %s\n", err)
        return
    }

    client.Status("chat")
    client.Join(roomJid, fullName)

    go client.KeepAlive()

    go func() {
        for {
            select {
            case message := <-client.Messages():
                if strings.HasPrefix(message.Body, "@"+mentionName) {
                    client.Say(roomJid, fullName, "Hello")
                }
            }
        }
    }()
    select {}
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"net/http"

	"github.com/sirupsen/logrus"
)

const URLRouteGetInfo = "/"

const MethodGetInfo = http.MethodGet

type getInfoHandler struct {
	logger logrus.FieldLogger
	info   string
}

type ErrGetInfoHandler string

func (e ErrGetInfoHandler) Error() string {
	return "get info handler error: " + string(e)
}

func NewGetInfoHandler(logger logrus.FieldLogger, version, build string) http.Handler {
	return &getInfoHandler{
		logger: logger,
		info:   fmt.Sprintf("Wellcome to Snake-Server!\nVersion: %s (build %s)\n", version, build),
	}
}

func (h *getInfoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	if _, err := fmt.Fprint(w, h.info); err != nil {
		h.logger.Error(ErrGetInfoHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
}
<commit_msg>Small fix getInfoHandler: write 200 status code<commit_after>package handlers

import (
	"fmt"
	"net/http"

	"github.com/sirupsen/logrus"
)

const URLRouteGetInfo = "/"

const MethodGetInfo = http.MethodGet

type getInfoHandler struct {
	logger logrus.FieldLogger
	info   string
}

type ErrGetInfoHandler string

func (e ErrGetInfoHandler) Error() string {
	return "get info handler error: " + string(e)
}

func NewGetInfoHandler(logger logrus.FieldLogger, version, build string) http.Handler {
	return &getInfoHandler{
		logger: logger,
		info:   fmt.Sprintf("Wellcome to Snake-Server!\nVersion: %s (build %s)\n", version, build),
	}
}

func (h *getInfoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	if _, err := fmt.Fprint(w, h.info); err != nil {
		h.logger.Error(ErrGetInfoHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
)

const (
	_ = iota
	REQ_NEIGHBOR
	REQ_NEIGHBORS
	REQ_ADJ_RIB_IN
	REQ_ADJ_RIB_OUT
	REQ_ADJ_RIB_LOCAL
	REQ_ADJ_RIB_LOCAL_BEST
)
const (
	BASE_VERSION       = "/v1"
	NEIGHBOR           = "/bgp/neighbor"
	NEIGHBORS          = "/bgp/neighbors"
	ADJ_RIB_IN         = "/bgp/adj-rib-in"
	ADJ_RIB_OUT        = "/bgp/adj-rib-out"
	ADJ_RIB_LOCAL      = "/bgp/adj-rib-local"
	ADJ_RIB_LOCAL_BEST = "/bgp/adj-rib-local/best"

	PARAM_REMOTE_PEER_ADDR = "remotePeerAddr"
)

const REST_PORT = 8080

const (
	_ = iota
	JSON_FORMATTED
	JSON_UN_FORMATTED
)

var JsonFormat int = JSON_FORMATTED

// trigger struct for exchanging information in the rest and peer.
// rest and peer operated at different thread.

type RestRequest struct {
	RequestType int
	RemoteAddr  string
	ResponseCh  chan RestResponse
	Err         error
}

func NewRestRequest(reqType int, remoteAddr string) *RestRequest {
	r := &RestRequest{
		RequestType: reqType,
		RemoteAddr:  remoteAddr,
		ResponseCh:  make(chan RestResponse),
	}
	return r
}

type RestResponse interface {
	Err() error
}

type RestResponseDefault struct {
	ResponseErr error
}

func (r *RestResponseDefault) Err() error {
	return r.ResponseErr
}

// Response struct for Neighbor
type RestResponseNeighbor struct {
	RestResponseDefault
	RemoteAddr    string
	RemoteAs      uint32
	NeighborState uint32
	UpdateCount   int
}

// Response struct for Rib
type RestResponseRib struct {
	RestResponseDefault
	RemoteAddr string
	RemoteAs   uint32
	RibInfo    []string
}

type RestServer struct {
	port        int
	bgpServerCh chan *RestRequest
}

func NewRestServer(port int, bgpServerCh chan *RestRequest) *RestServer {
	rs := &RestServer{
		port:        port,
		bgpServerCh: bgpServerCh}
	return rs
}

// Main thread of rest service.
// URL than can receive.
//   get state of neighbor.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/neighbor/<remote address of target neighbor>
//   get state of neighbors.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/neighbors
//   get adj-rib-in of each neighbor.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-in/<remote address of target neighbor>
//   get adj-rib-out of each neighbor.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-out/<remote address of target neighbor>
//   get adj-rib-local of each neighbor.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/<remote address of target neighbor>
//   get only best path of adj-rib-local  of each neighbor.
//     -- curt -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/best/<remote address of target neighbor>
func (rs *RestServer) Serve() {
	neighbor := BASE_VERSION + NEIGHBOR
	// neighbors := BASE_VERSION + NEIGHBORS
	// adjRibIn := BASE_VERSION + ADJ_RIB_IN
	// adjRibOut := BASE_VERSION + ADJ_RIB_OUT
	// adjRibLocal := BASE_VERSION + ADJ_RIB_LOCAL
	// adjRibLocalBest := BASE_VERSION + ADJ_RIB_LOCAL_BEST

	r := mux.NewRouter()
	// set URLs
	r.HandleFunc(neighbor+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.Neighbor).Methods("GET")
	// r.HandleFunc(neighbors, rs.Neighbors).Methods("GET")
	// r.HandleFunc(adjRibIn+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibIn).Methods("GET")
	// r.HandleFunc(adjRibOut+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibOut).Methods("GET")
	// r.HandleFunc(adjRibLocal+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocal).Methods("GET")
	// r.HandleFunc(adjRibLocalBest+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocalBest).Methods("GET")

	// Handler when not found url
	r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
	http.Handle("/", r)

	http.ListenAndServe(":"+strconv.Itoa(rs.port), nil)

}

// Http request of curl, return the json format infomation of neibor state.
func (rs *RestServer) Neighbor(w http.ResponseWriter, r *http.Request) {
	//	remotePeerAddr := mux.Vars(r)[PARAM_REMOTE_PEER_ADDR]

	params := mux.Vars(r)
	remoteAddr, found := params[PARAM_REMOTE_PEER_ADDR]
	if !found {
		errStr := "neighbor address is not specified"
		log.Debug(errStr)
		http.Error(w, errStr, http.StatusInternalServerError)
	}

	log.Debugf("Look up neighbor with the remote address : %v", remoteAddr)

	//Send channel of request parameter.
	req := NewRestRequest(REQ_NEIGHBOR, remoteAddr)
	rs.bgpServerCh <- req

	//Wait response
	resInf := <-req.ResponseCh
	if e := resInf.Err(); e != nil {
		log.Debug(e.Error())
		http.Error(w, e.Error(), http.StatusInternalServerError)
		return
	}

	res := resInf.(*RestResponseNeighbor)

	var jns []byte
	var err error
	switch JsonFormat {
	case JSON_FORMATTED:
		jns, err = json.MarshalIndent(res, "", "  ") // formatted json
	case JSON_UN_FORMATTED:
		jns, err = json.Marshal(res) // Unformatted json
	}
	if err != nil {
		errStr := fmt.Sprintf("Failed to perth json of neighbor state", remoteAddr)
		log.Error(errStr)
		http.Error(w, errStr, http.StatusInternalServerError)
		return
	}
	w.Write(jns)
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
<commit_msg>api: fix Neighbor() error handling<commit_after>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
)

const (
	_ = iota
	REQ_NEIGHBOR
	REQ_NEIGHBORS
	REQ_ADJ_RIB_IN
	REQ_ADJ_RIB_OUT
	REQ_ADJ_RIB_LOCAL
	REQ_ADJ_RIB_LOCAL_BEST
)
const (
	BASE_VERSION       = "/v1"
	NEIGHBOR           = "/bgp/neighbor"
	NEIGHBORS          = "/bgp/neighbors"
	ADJ_RIB_IN         = "/bgp/adj-rib-in"
	ADJ_RIB_OUT        = "/bgp/adj-rib-out"
	ADJ_RIB_LOCAL      = "/bgp/adj-rib-local"
	ADJ_RIB_LOCAL_BEST = "/bgp/adj-rib-local/best"

	PARAM_REMOTE_PEER_ADDR = "remotePeerAddr"
)

const REST_PORT = 8080

const (
	_ = iota
	JSON_FORMATTED
	JSON_UN_FORMATTED
)

var JsonFormat int = JSON_FORMATTED

// trigger struct for exchanging information in the rest and peer.
// rest and peer operated at different thread.

type RestRequest struct {
	RequestType int
	RemoteAddr  string
	ResponseCh  chan RestResponse
	Err         error
}

func NewRestRequest(reqType int, remoteAddr string) *RestRequest {
	r := &RestRequest{
		RequestType: reqType,
		RemoteAddr:  remoteAddr,
		ResponseCh:  make(chan RestResponse),
	}
	return r
}

type RestResponse interface {
	Err() error
}

type RestResponseDefault struct {
	ResponseErr error
}

func (r *RestResponseDefault) Err() error {
	return r.ResponseErr
}

// Response struct for Neighbor
type RestResponseNeighbor struct {
	RestResponseDefault
	RemoteAddr    string
	RemoteAs      uint32
	NeighborState uint32
	UpdateCount   int
}

// Response struct for Rib
type RestResponseRib struct {
	RestResponseDefault
	RemoteAddr string
	RemoteAs   uint32
	RibInfo    []string
}

type RestServer struct {
	port        int
	bgpServerCh chan *RestRequest
}

func NewRestServer(port int, bgpServerCh chan *RestRequest) *RestServer {
	rs := &RestServer{
		port:        port,
		bgpServerCh: bgpServerCh}
	return rs
}

// Main thread of rest service.
// URL than can receive.
//   get state of neighbor.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/neighbor/<remote address of target neighbor>
//   get state of neighbors.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/neighbors
//   get adj-rib-in of each neighbor.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-in/<remote address of target neighbor>
//   get adj-rib-out of each neighbor.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-out/<remote address of target neighbor>
//   get adj-rib-local of each neighbor.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/<remote address of target neighbor>
//   get only best path of adj-rib-local  of each neighbor.
//     -- curl -i -X GET http://<ownIP>:3000/v1/bgp/adj-rib-local/best/<remote address of target neighbor>
func (rs *RestServer) Serve() {
	neighbor := BASE_VERSION + NEIGHBOR
	// neighbors := BASE_VERSION + NEIGHBORS
	// adjRibIn := BASE_VERSION + ADJ_RIB_IN
	// adjRibOut := BASE_VERSION + ADJ_RIB_OUT
	// adjRibLocal := BASE_VERSION + ADJ_RIB_LOCAL
	// adjRibLocalBest := BASE_VERSION + ADJ_RIB_LOCAL_BEST

	r := mux.NewRouter()
	// set URLs
	r.HandleFunc(neighbor+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.Neighbor).Methods("GET")
	// r.HandleFunc(neighbors, rs.Neighbors).Methods("GET")
	// r.HandleFunc(adjRibIn+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibIn).Methods("GET")
	// r.HandleFunc(adjRibOut+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibOut).Methods("GET")
	// r.HandleFunc(adjRibLocal+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocal).Methods("GET")
	// r.HandleFunc(adjRibLocalBest+"/{"+PARAM_REMOTE_PEER_ADDR+"}", rs.AdjRibLocalBest).Methods("GET")

	// Handler when not found url
	r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
	http.Handle("/", r)

	http.ListenAndServe(":"+strconv.Itoa(rs.port), nil)

}

// Http request of curl, return the json format infomation of neibor state.
func (rs *RestServer) Neighbor(w http.ResponseWriter, r *http.Request) {
	//	remotePeerAddr := mux.Vars(r)[PARAM_REMOTE_PEER_ADDR]

	params := mux.Vars(r)
	remoteAddr, found := params[PARAM_REMOTE_PEER_ADDR]
	if !found {
		errStr := "neighbor address is not specified"
		log.Debug(errStr)
		http.Error(w, errStr, http.StatusInternalServerError)
		return
	}

	log.Debugf("Look up neighbor with the remote address : %v", remoteAddr)

	//Send channel of request parameter.
	req := NewRestRequest(REQ_NEIGHBOR, remoteAddr)
	rs.bgpServerCh <- req

	//Wait response
	resInf := <-req.ResponseCh
	if e := resInf.Err(); e != nil {
		log.Debug(e.Error())
		http.Error(w, e.Error(), http.StatusInternalServerError)
		return
	}

	res := resInf.(*RestResponseNeighbor)

	var jns []byte
	var err error
	switch JsonFormat {
	case JSON_FORMATTED:
		jns, err = json.MarshalIndent(res, "", "  ") // formatted json
	case JSON_UN_FORMATTED:
		jns, err = json.Marshal(res) // Unformatted json
	}
	if err != nil {
		errStr := fmt.Sprintf("Failed to perth json of neighbor state", remoteAddr)
		log.Error(errStr)
		http.Error(w, errStr, http.StatusInternalServerError)
		return
	}
	w.Write(jns)
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
<|endoftext|>


<commit_before>package api

import (
	"context"
	stdlog "log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/db"
	"github.com/mundipagg/boleto-api/log"
	"github.com/mundipagg/boleto-api/queue"
)

//InstallRestAPI "instala" e sobe o servico de rest
func InstallRestAPI() {

	l := log.CreateLog()
	l.Operation = "InstallAPI"

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Recovery())
	useNewRelic(router)

	if config.Get().DevMode && !config.Get().MockMode {
		router.Use(gin.Logger())
	}

	Base(router)
	V1(router)
	V2(router)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)

	server := &http.Server{
		Addr:    config.Get().APIPort,
		Handler: router,
	}

	go func() {
		err := server.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			interrupt <- syscall.SIGTERM
			l.Error(err, "Got an error when trying serve.ListAndServe()")
			stdlog.Println("err: ", err)
		}
	}()

	<-interrupt
	stdlog.Println("shutdown server")

	// Close DB Connection
	err := db.CloseConnection()
	if err != nil {
		l.ErrorWithBasic("error closing Mongodb connection", "Error", err)
	} else {
		l.InfoWithBasic("mongodb connection successfully closed", "Information", nil)
	}

	// Close RabbitMQ Connection
	err = queue.CloseConnection()
	if err != nil {
		l.ErrorWithBasic("error closing rabbitmq connection", "Error", err)
	} else {
		l.InfoWithBasic("rabbitmq connection successfully closed", "Information", nil)
	}

	// Server Shutdown
	err = server.Shutdown(context.Background())
	if err != nil {
		l.ErrorWithBasic("shutdown server with error", "Error", err)
	}

	l.InfoWithBasic("shutdown completed", "Information", nil)
	stdlog.Println("shutdown completed")
	time.Sleep(10 * time.Second)
}
<commit_msg>:recycle: remove closeconnections e sleep<commit_after>package api

import (
	"context"
	stdlog "log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/gin-gonic/gin"
	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/log"
)

//InstallRestAPI "instala" e sobe o servico de rest
func InstallRestAPI() {

	l := log.CreateLog()
	l.Operation = "InstallAPI"

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Recovery())
	useNewRelic(router)

	if config.Get().DevMode && !config.Get().MockMode {
		router.Use(gin.Logger())
	}

	Base(router)
	V1(router)
	V2(router)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)

	server := &http.Server{
		Addr:    config.Get().APIPort,
		Handler: router,
	}

	go func() {
		err := server.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			interrupt <- syscall.SIGTERM
			l.ErrorWithBasic("got an error when trying serve.ListAndServe()", "Error", err)
			stdlog.Println("err: ", err)
		}
	}()

	<-interrupt
	stdlog.Println("start shutdown server...")

	// // Close DB Connection
	// err := db.CloseConnection()
	// if err != nil {
	// 	l.ErrorWithBasic("error closing Mongodb connection", "Error", err)
	// } else {
	// 	l.InfoWithBasic("mongodb connection successfully closed", "Information", nil)
	// }

	// // Close RabbitMQ Connection
	// err = queue.CloseConnection()
	// if err != nil {
	// 	l.ErrorWithBasic("error closing rabbitmq connection", "Error", err)
	// } else {
	// 	l.InfoWithBasic("rabbitmq connection successfully closed", "Information", nil)
	// }

	// Server Shutdown
	err := server.Shutdown(context.Background())
	if err != nil {
		l.ErrorWithBasic("shutdown server with error", "Error", err)
	}

	l.InfoWithBasic("shutdown completed", "Information", nil)
	stdlog.Println("shutdown completed")
	// time.Sleep(10 * time.Second)
}
<|endoftext|>


<commit_before>package apns

import (
	"bytes"
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"io"
	"io/ioutil"
	"math/big"
	"time"
)

// https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

type jwtHeader struct {
	Alg string `json:"alg"`
	Kid string `json:"kid"`
}

type jwtClaim struct {
	Iss string `json:"iss"`
	Iat int64  `json:"iat"`
}

type ecdsaSignature struct {
	R, S *big.Int
}

func CreateJWT(keyFile string, kid string, teamID string, now time.Time) (string, error) {

	var b bytes.Buffer

	header := jwtHeader{
		Alg: "ES256",
		Kid: kid,
	}
	headerJSON, err := json.Marshal(&header)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, headerJSON); err != nil {
		return "", err
	}
	b.WriteString(".")

	claim := jwtClaim{
		Iss: teamID,
		Iat: now.Unix(),
	}
	claimJSON, err := json.Marshal(&claim)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, claimJSON); err != nil {
		return "", err
	}

	sig, err := createSignature(b.Bytes(), keyFile)
	if err != nil {
		return "", err
	}
	b.WriteString(".")

	if err := writeAsBase64(&b, sig); err != nil {
		return "", err
	}

	return b.String(), nil
}

func writeAsBase64(w io.Writer, byt []byte) error {
	enc := base64.NewEncoder(base64.RawURLEncoding, w)
	if _, err := enc.Write(byt); err != nil {
		return err
	}
	return enc.Close()
}

func createSignature(payload []byte, keyFile string) ([]byte, error) {
	h := crypto.SHA256.New()
	if _, err := h.Write(payload); err != nil {
		return nil, err
	}
	msg := h.Sum(nil)

	data, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(data)
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	r, s, err := ecdsa.Sign(rand.Reader, key.(*ecdsa.PrivateKey), msg)
	if err != nil {
		return nil, err
	}

	sig, err := asn1.Marshal(ecdsaSignature{r, s})
	if err != nil {
		return nil, err
	}

	return sig, nil
}
<commit_msg>always close base64 encoder<commit_after>package apns

import (
	"bytes"
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/x509"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"io"
	"io/ioutil"
	"math/big"
	"time"
)

// https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

type jwtHeader struct {
	Alg string `json:"alg"`
	Kid string `json:"kid"`
}

type jwtClaim struct {
	Iss string `json:"iss"`
	Iat int64  `json:"iat"`
}

type ecdsaSignature struct {
	R, S *big.Int
}

func CreateJWT(keyFile string, kid string, teamID string, now time.Time) (string, error) {

	var b bytes.Buffer

	header := jwtHeader{
		Alg: "ES256",
		Kid: kid,
	}
	headerJSON, err := json.Marshal(&header)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, headerJSON); err != nil {
		return "", err
	}
	b.WriteString(".")

	claim := jwtClaim{
		Iss: teamID,
		Iat: now.Unix(),
	}
	claimJSON, err := json.Marshal(&claim)
	if err != nil {
		return "", err
	}
	if err := writeAsBase64(&b, claimJSON); err != nil {
		return "", err
	}

	sig, err := createSignature(b.Bytes(), keyFile)
	if err != nil {
		return "", err
	}
	b.WriteString(".")

	if err := writeAsBase64(&b, sig); err != nil {
		return "", err
	}

	return b.String(), nil
}

func writeAsBase64(w io.Writer, byt []byte) error {
	enc := base64.NewEncoder(base64.RawURLEncoding, w)
	defer enc.Close()

	if _, err := enc.Write(byt); err != nil {
		return err
	}
	return nil
}

func createSignature(payload []byte, keyFile string) ([]byte, error) {
	h := crypto.SHA256.New()
	if _, err := h.Write(payload); err != nil {
		return nil, err
	}
	msg := h.Sum(nil)

	data, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}
	block, _ := pem.Decode(data)
	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	r, s, err := ecdsa.Sign(rand.Reader, key.(*ecdsa.PrivateKey), msg)
	if err != nil {
		return nil, err
	}

	sig, err := asn1.Marshal(ecdsaSignature{r, s})
	if err != nil {
		return nil, err
	}

	return sig, nil
}
<|endoftext|>