<commit_before>package udnssdk

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"
)

// SBTCService manages Probes
type SBTCService struct {
	client *Client
}

// ProbeInfoDTO wraps a probe response
type ProbeInfoDTO struct {
	ID         string           `json:"id"`
	PoolRecord string           `json:"poolRecord"`
	ProbeType  string           `json:"type"`
	Interval   string           `json:"interval"`
	Agents     []string         `json:"agents"`
	Threshold  int              `json:"threshold"`
	Details    *ProbeDetailsDTO `json:"details"`
}

// ProbeDetailsLimitDTO wraps a probe
type ProbeDetailsLimitDTO struct {
	Warning  int `json:"warning"`
	Critical int `json:"critical"`
	Fail     int `json:"fail"`
}

// ProbeDetailsDTO wraps the details of a probe
type ProbeDetailsDTO struct {
	data   []byte
	Detail interface{} `json:"detail,omitempty"`
	typ    string
}

// GetData returns the data because I'm working around something.
func (s *ProbeDetailsDTO) GetData() []byte {
	return s.data
}

// Populate does magical things with json unmarshalling to unroll the Probe into
// an appropriate datatype.  These are helper structures and functions for testing
// and direct API use.  In the Terraform implementation, we will use Terraforms own
// warped schema structure to handle the marshalling and unmarshalling.
func (s *ProbeDetailsDTO) Populate(typ string) (err error) {
	// TODO: actually document
	switch strings.ToUpper(typ) {
	case "HTTP":
		var pp HTTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "PING":
		var pp PingProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "FTP":
		var pp FTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "TCP":
		var pp TCPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "SMTP":
		var pp SMTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "SMTP_SEND":
		var pp SMTPSENDProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "DNS":
		var pp DNSProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	default:
		return fmt.Errorf("ERROR - ProbeDetailsDTO.Populate(\"%s\") - Fall through!\n", typ)
	}
}

// UnmarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) UnmarshalJSON(b []byte) (err error) {
	s.data = b
	return nil
}

// MarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) MarshalJSON() ([]byte, error) {
	var err error
	if s.Detail != nil {
		return json.Marshal(s.Detail)
	}
	if len(s.data) != 0 {
		return s.data, err
	}
	return json.Marshal(nil)
}

// GoString returns a string representation of the ProbeDetailsDTO internal data
func (s *ProbeDetailsDTO) GoString() string {
	return string(s.data)
}
func (s *ProbeDetailsDTO) String() string {
	return string(s.data)
}

// Transaction wraps a transaction response
type Transaction struct {
	Method          string                          `json:"method"`
	URL             string                          `json:"url"`
	TransmittedData string                          `json:"transmittedData,omitempty"`
	FollowRedirects bool                            `json:"followRedirects,omitempty"`
	Limits          map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// HTTPProbeDetailsDTO wraps HTTP probe details
type HTTPProbeDetailsDTO struct {
	Transactions []Transaction         `json:"transactions"`
	TotalLimits  *ProbeDetailsLimitDTO `json:"totalLimits,omitempty"`
}

// PingProbeDetailsDTO wraps Ping probe details
type PingProbeDetailsDTO struct {
	Packets    int                             `json:"packets,omitempty"`
	PacketSize int                             `json:"packetSize,omitempty"`
	Limits     map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// FTPProbeDetailsDTO wraps FTP probe details
type FTPProbeDetailsDTO struct {
	Port        int                             `json:"port,omitempty"`
	PassiveMode bool                            `json:"passiveMode,omitempty"`
	Username    string                          `json:"username,omitempty"`
	Password    string                          `json:"password,omitempty"`
	Path        string                          `json:"path"`
	Limits      map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// TCPProbeDetailsDTO wraps TCP probe details
type TCPProbeDetailsDTO struct {
	Port      int                             `json:"port,omitempty"`
	ControlIP string                          `json:"controlIP,omitempty"`
	Limits    map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// SMTPProbeDetailsDTO wraps SMTP probe details
type SMTPProbeDetailsDTO struct {
	Port   int                             `json:"port,omitempty"`
	Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// SMTPSENDProbeDetailsDTO wraps SMTP SEND probe details
type SMTPSENDProbeDetailsDTO struct {
	Port    int                             `json:"port,omitempty"`
	From    string                          `json:"from"`
	To      string                          `json:"to"`
	Message string                          `json:"message,omitempty"`
	Limits  map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// DNSProbeDetailsDTO wraps DNS probe details
type DNSProbeDetailsDTO struct {
	Port       int                             `json:"port,omitempty"`
	TCPOnly    bool                            `json:"tcpOnly,omitempty"`
	RecordType string                          `json:"type,omitempty"`
	OwnerName  string                          `json:"ownerName,omitempty"`
	Limits     map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// ProbeListDTO wraps a list of probes
type ProbeListDTO struct {
	Probes     []ProbeInfoDTO `json:"probes"`
	Queryinfo  QueryInfo      `json:"queryInfo"`
	Resultinfo ResultInfo     `json:"resultInfo"`
}

// ProbePath generates the URI path for a probe
func ProbePath(zone, typ, name, guid string) string {
	if guid == "" {
		r := RRSetKey{Zone: zone, Type: typ, Name: name}
		return r.ProbesURI()
	}
	p := ProbeKey{Zone: zone, Type: typ, Name: name, GUID: guid}
	return p.URI()
}

// AlertPath generates the URI path for an alert
func AlertPath(zone, typ, name string) string {
	r := RRSetKey{Zone: zone, Type: typ, Name: name}
	return r.AlertsURI()
}

func probeQueryPath(zone, typ, name, query string) string {
	r := RRSetKey{Zone: zone, Type: typ, Name: name}
	return r.ProbesQueryURI(query)
}

func probeAlertQueryPath(zone, typ, name string, offset int) string {
	r := RRSetKey{Name: name, Type: typ, Zone: zone}
	return r.AlertsQueryURI(offset)
}

// ListAllProbeAlerts returns all probe alerts with name, type & zone
func (s *SBTCService) ListAllProbeAlerts(name, typ, zone string) ([]ProbeAlertDataDTO, error) {
	r := RRSetKey{Name: name, Type: typ, Zone: zone}
	return s.Alerts().Select(r)
}

// ListProbeAlerts returns the probe alerts with name, type & zone, accepting an offset
func (s *SBTCService) ListProbeAlerts(name, typ, zone string, offset int) ([]ProbeAlertDataDTO, ResultInfo, *Response, error) {
	r := RRSetKey{Name: name, Type: typ, Zone: zone}
	return s.Alerts().SelectWithOffset(r, offset)
}

// GetProbe returns a probe with name, type, zone & guid
func (s *SBTCService) GetProbe(name, typ, zone, guid string) (ProbeInfoDTO, *Response, error) {
	p := ProbeKey{Name: name, Type: typ, Zone: zone, GUID: guid}
	return s.Probes().Find(p)
}

// CreateProbe creates a probe with name, type & zone using the ProbeInfoDTO dp
func (s *SBTCService) CreateProbe(name, typ, zone string, dp ProbeInfoDTO) (*Response, error) {
	r := RRSetKey{Name: name, Type: typ, Zone: zone}
	return s.Probes().Create(r, dp)
}

// UpdateProbe updates a probe given a name, type, zone & guid with the ProbeInfoDTO dp
func (s *SBTCService) UpdateProbe(name, typ, zone, guid string, dp ProbeInfoDTO) (*Response, error) {
	p := ProbeKey{Name: name, Type: typ, Zone: zone, GUID: guid}
	return s.Probes().Update(p, dp)
}

// ListProbes returns all probes by name, type & zone, with an optional query
func (s *SBTCService) ListProbes(query, name, typ, zone string) ([]ProbeInfoDTO, *Response, error) {
	r := RRSetKey{Zone: zone, Type: typ, Name: name}
	return s.Probes().Select(r, query)
}

// DeleteProbe deletes a probe by its name, type, zone & guid
func (s *SBTCService) DeleteProbe(name, typ, zone, guid string) (*Response, error) {
	p := ProbeKey{Name: name, Type: typ, Zone: zone, GUID: guid}
	return s.Probes().Delete(p)
}

// Create creates a probe with a RRSetKey using the ProbeInfoDTO dp
func (s *ProbesService) Create(r RRSetKey, dp ProbeInfoDTO) (*Response, error) {
	return s.client.post(r.ProbesURI(), dp, nil)
}

// Select returns all probes by a RRSetKey, with an optional query
func (s *ProbesService) Select(r RRSetKey, query string) ([]ProbeInfoDTO, *Response, error) {
	var pld ProbeListDTO

	// This API does not support pagination.
	uri := r.ProbesQueryURI(query)
	res, err := s.client.get(uri, &pld)

	ps := []ProbeInfoDTO{}
	if err == nil {
		for _, t := range pld.Probes {
			ps = append(ps, t)
		}
	}
	return ps, res, err
}

// ProbeKey collects the identifiers of a Probe
type ProbeKey struct {
	Zone string
	Type string
	Name string
	GUID string
}

// RRSetKey generates the RRSetKey for the ProbeKey
func (p *ProbeKey) RRSetKey() *RRSetKey {
	return &RRSetKey{
		Zone: p.Zone,
		Type: p.Type,
		Name: p.Name,
	}
}

// URI generates the URI for a probe
func (p *ProbeKey) URI() string {
	return fmt.Sprintf("%s/%s", p.RRSetKey().ProbesURI(), p.GUID)
}

// ProbesService manages Probes
type ProbesService struct {
	client *Client
}

// Probes allows access to the Probes API
func (s *SBTCService) Probes() *ProbesService {
	return &ProbesService{client: s.client}
}

// Find returns a probe from a ProbeKey
func (s *ProbesService) Find(p ProbeKey) (ProbeInfoDTO, *Response, error) {
	var t ProbeInfoDTO
	res, err := s.client.get(p.URI(), &t)
	return t, res, err
}

// Update updates a probe given a ProbeKey with the ProbeInfoDTO dp
func (s *ProbesService) Update(p ProbeKey, dp ProbeInfoDTO) (*Response, error) {
	return s.client.put(p.URI(), dp, nil)
}

// Delete deletes a probe by its ProbeKey
func (s *ProbesService) Delete(p ProbeKey) (*Response, error) {
	return s.client.delete(p.URI(), nil)
}

// AlertsService manages Alerts
type AlertsService struct {
	client *Client
}

// Alerts allows access to the Alerts API
func (s *SBTCService) Alerts() *AlertsService {
	return &AlertsService{client: s.client}
}

// ProbeAlertDataDTO wraps a probe alert response
type ProbeAlertDataDTO struct {
	PoolRecord      string    `json:"poolRecord"`
	ProbeType       string    `json:"probeType"`
	ProbeStatus     string    `json:"probeStatus"`
	AlertDate       time.Time `json:"alertDate"`
	FailoverOccured bool      `json:"failoverOccured"`
	OwnerName       string    `json:"ownerName"`
	Status          string    `json:"status"`
}

// ProbeAlertDataListDTO wraps the response for an index of probe alerts
type ProbeAlertDataListDTO struct {
	Alerts     []ProbeAlertDataDTO `json:"alerts"`
	Queryinfo  QueryInfo           `json:"queryInfo"`
	Resultinfo ResultInfo          `json:"resultInfo"`
}

// Select returns all probe alerts with a RRSetKey
func (s *AlertsService) Select(z RRSetKey) ([]ProbeAlertDataDTO, error) {
	// TODO: Sane Configuration for timeouts / retries
	maxerrs := 5
	waittime := 5 * time.Second

	// init accumulators
	as := []ProbeAlertDataDTO{}
	offset := 0
	errcnt := 0

	for {
		reqAlerts, ri, res, err := s.SelectWithOffset(z, offset)
		if err != nil {
			if res.StatusCode >= 500 {
				errcnt = errcnt + 1
				if errcnt < maxerrs {
					time.Sleep(waittime)
					continue
				}
			}
			return as, err
		}

		log.Printf("ResultInfo: %+v\n", ri)
		for _, a := range reqAlerts {
			as = append(as, a)
		}
		if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
			return as, nil
		}
		offset = ri.ReturnedCount + ri.Offset
		continue
	}
}

// SelectWithOffset returns the probe alerts with a RRSetKey, accepting an offset
func (s *AlertsService) SelectWithOffset(z RRSetKey, offset int) ([]ProbeAlertDataDTO, ResultInfo, *Response, error) {
	var ald ProbeAlertDataListDTO

	uri := z.AlertsQueryURI(offset)
	res, err := s.client.get(uri, &ald)

	as := []ProbeAlertDataDTO{}
	for _, a := range ald.Alerts {
		as = append(as, a)
	}
	return as, ald.Resultinfo, res, err
}
<commit_msg>probe.go: remove old interface<commit_after>package udnssdk

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"
)

// SBTCService manages Probes
type SBTCService struct {
	client *Client
}

// ProbeInfoDTO wraps a probe response
type ProbeInfoDTO struct {
	ID         string           `json:"id"`
	PoolRecord string           `json:"poolRecord"`
	ProbeType  string           `json:"type"`
	Interval   string           `json:"interval"`
	Agents     []string         `json:"agents"`
	Threshold  int              `json:"threshold"`
	Details    *ProbeDetailsDTO `json:"details"`
}

// ProbeDetailsLimitDTO wraps a probe
type ProbeDetailsLimitDTO struct {
	Warning  int `json:"warning"`
	Critical int `json:"critical"`
	Fail     int `json:"fail"`
}

// ProbeDetailsDTO wraps the details of a probe
type ProbeDetailsDTO struct {
	data   []byte
	Detail interface{} `json:"detail,omitempty"`
	typ    string
}

// GetData returns the data because I'm working around something.
func (s *ProbeDetailsDTO) GetData() []byte {
	return s.data
}

// Populate does magical things with json unmarshalling to unroll the Probe into
// an appropriate datatype.  These are helper structures and functions for testing
// and direct API use.  In the Terraform implementation, we will use Terraforms own
// warped schema structure to handle the marshalling and unmarshalling.
func (s *ProbeDetailsDTO) Populate(typ string) (err error) {
	// TODO: actually document
	switch strings.ToUpper(typ) {
	case "HTTP":
		var pp HTTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "PING":
		var pp PingProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "FTP":
		var pp FTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "TCP":
		var pp TCPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "SMTP":
		var pp SMTPProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "SMTP_SEND":
		var pp SMTPSENDProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	case "DNS":
		var pp DNSProbeDetailsDTO
		err = json.Unmarshal(s.data, &pp)
		s.typ = typ
		s.Detail = pp
		return err
	default:
		return fmt.Errorf("ERROR - ProbeDetailsDTO.Populate(\"%s\") - Fall through!\n", typ)
	}
}

// UnmarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) UnmarshalJSON(b []byte) (err error) {
	s.data = b
	return nil
}

// MarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) MarshalJSON() ([]byte, error) {
	var err error
	if s.Detail != nil {
		return json.Marshal(s.Detail)
	}
	if len(s.data) != 0 {
		return s.data, err
	}
	return json.Marshal(nil)
}

// GoString returns a string representation of the ProbeDetailsDTO internal data
func (s *ProbeDetailsDTO) GoString() string {
	return string(s.data)
}
func (s *ProbeDetailsDTO) String() string {
	return string(s.data)
}

// Transaction wraps a transaction response
type Transaction struct {
	Method          string                          `json:"method"`
	URL             string                          `json:"url"`
	TransmittedData string                          `json:"transmittedData,omitempty"`
	FollowRedirects bool                            `json:"followRedirects,omitempty"`
	Limits          map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// HTTPProbeDetailsDTO wraps HTTP probe details
type HTTPProbeDetailsDTO struct {
	Transactions []Transaction         `json:"transactions"`
	TotalLimits  *ProbeDetailsLimitDTO `json:"totalLimits,omitempty"`
}

// PingProbeDetailsDTO wraps Ping probe details
type PingProbeDetailsDTO struct {
	Packets    int                             `json:"packets,omitempty"`
	PacketSize int                             `json:"packetSize,omitempty"`
	Limits     map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// FTPProbeDetailsDTO wraps FTP probe details
type FTPProbeDetailsDTO struct {
	Port        int                             `json:"port,omitempty"`
	PassiveMode bool                            `json:"passiveMode,omitempty"`
	Username    string                          `json:"username,omitempty"`
	Password    string                          `json:"password,omitempty"`
	Path        string                          `json:"path"`
	Limits      map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// TCPProbeDetailsDTO wraps TCP probe details
type TCPProbeDetailsDTO struct {
	Port      int                             `json:"port,omitempty"`
	ControlIP string                          `json:"controlIP,omitempty"`
	Limits    map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// SMTPProbeDetailsDTO wraps SMTP probe details
type SMTPProbeDetailsDTO struct {
	Port   int                             `json:"port,omitempty"`
	Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// SMTPSENDProbeDetailsDTO wraps SMTP SEND probe details
type SMTPSENDProbeDetailsDTO struct {
	Port    int                             `json:"port,omitempty"`
	From    string                          `json:"from"`
	To      string                          `json:"to"`
	Message string                          `json:"message,omitempty"`
	Limits  map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// DNSProbeDetailsDTO wraps DNS probe details
type DNSProbeDetailsDTO struct {
	Port       int                             `json:"port,omitempty"`
	TCPOnly    bool                            `json:"tcpOnly,omitempty"`
	RecordType string                          `json:"type,omitempty"`
	OwnerName  string                          `json:"ownerName,omitempty"`
	Limits     map[string]ProbeDetailsLimitDTO `json:"limits"`
}

// ProbeListDTO wraps a list of probes
type ProbeListDTO struct {
	Probes     []ProbeInfoDTO `json:"probes"`
	Queryinfo  QueryInfo      `json:"queryInfo"`
	Resultinfo ResultInfo     `json:"resultInfo"`
}

// ProbeKey collects the identifiers of a Probe
type ProbeKey struct {
	Zone string
	Type string
	Name string
	GUID string
}

// RRSetKey generates the RRSetKey for the ProbeKey
func (p *ProbeKey) RRSetKey() *RRSetKey {
	return &RRSetKey{
		Zone: p.Zone,
		Type: p.Type,
		Name: p.Name,
	}
}

// URI generates the URI for a probe
func (p *ProbeKey) URI() string {
	return fmt.Sprintf("%s/%s", p.RRSetKey().ProbesURI(), p.GUID)
}

// ProbesService manages Probes
type ProbesService struct {
	client *Client
}

// Probes allows access to the Probes API
func (s *SBTCService) Probes() *ProbesService {
	return &ProbesService{client: s.client}
}

// Select returns all probes by a RRSetKey, with an optional query
func (s *ProbesService) Select(r RRSetKey, query string) ([]ProbeInfoDTO, *Response, error) {
	var pld ProbeListDTO

	// This API does not support pagination.
	uri := r.ProbesQueryURI(query)
	res, err := s.client.get(uri, &pld)

	ps := []ProbeInfoDTO{}
	if err == nil {
		for _, t := range pld.Probes {
			ps = append(ps, t)
		}
	}
	return ps, res, err
}

// Find returns a probe from a ProbeKey
func (s *ProbesService) Find(p ProbeKey) (ProbeInfoDTO, *Response, error) {
	var t ProbeInfoDTO
	res, err := s.client.get(p.URI(), &t)
	return t, res, err
}

// Create creates a probe with a RRSetKey using the ProbeInfoDTO dp
func (s *ProbesService) Create(r RRSetKey, dp ProbeInfoDTO) (*Response, error) {
	var ignored interface{}
	return s.client.post(r.ProbesURI(), dp, &ignored)
}

// Update updates a probe given a ProbeKey with the ProbeInfoDTO dp
func (s *ProbesService) Update(p ProbeKey, dp ProbeInfoDTO) (*Response, error) {
	return s.client.put(p.URI(), dp, nil)
}

// Delete deletes a probe by its ProbeKey
func (s *ProbesService) Delete(p ProbeKey) (*Response, error) {
	return s.client.delete(p.URI(), nil)
}

// AlertsService manages Alerts
type AlertsService struct {
	client *Client
}

// Alerts allows access to the Alerts API
func (s *SBTCService) Alerts() *AlertsService {
	return &AlertsService{client: s.client}
}

// ProbeAlertDataDTO wraps a probe alert response
type ProbeAlertDataDTO struct {
	PoolRecord      string    `json:"poolRecord"`
	ProbeType       string    `json:"probeType"`
	ProbeStatus     string    `json:"probeStatus"`
	AlertDate       time.Time `json:"alertDate"`
	FailoverOccured bool      `json:"failoverOccured"`
	OwnerName       string    `json:"ownerName"`
	Status          string    `json:"status"`
}

// ProbeAlertDataListDTO wraps the response for an index of probe alerts
type ProbeAlertDataListDTO struct {
	Alerts     []ProbeAlertDataDTO `json:"alerts"`
	Queryinfo  QueryInfo           `json:"queryInfo"`
	Resultinfo ResultInfo          `json:"resultInfo"`
}

// Select returns all probe alerts with a RRSetKey
func (s *AlertsService) Select(z RRSetKey) ([]ProbeAlertDataDTO, error) {
	// TODO: Sane Configuration for timeouts / retries
	maxerrs := 5
	waittime := 5 * time.Second

	// init accumulators
	as := []ProbeAlertDataDTO{}
	offset := 0
	errcnt := 0

	for {
		reqAlerts, ri, res, err := s.SelectWithOffset(z, offset)
		if err != nil {
			if res.StatusCode >= 500 {
				errcnt = errcnt + 1
				if errcnt < maxerrs {
					time.Sleep(waittime)
					continue
				}
			}
			return as, err
		}

		log.Printf("ResultInfo: %+v\n", ri)
		for _, a := range reqAlerts {
			as = append(as, a)
		}
		if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
			return as, nil
		}
		offset = ri.ReturnedCount + ri.Offset
		continue
	}
}

// SelectWithOffset returns the probe alerts with a RRSetKey, accepting an offset
func (s *AlertsService) SelectWithOffset(z RRSetKey, offset int) ([]ProbeAlertDataDTO, ResultInfo, *Response, error) {
	var ald ProbeAlertDataListDTO

	uri := z.AlertsQueryURI(offset)
	res, err := s.client.get(uri, &ald)

	as := []ProbeAlertDataDTO{}
	for _, a := range ald.Alerts {
		as = append(as, a)
	}
	return as, ald.Resultinfo, res, err
}
<|endoftext|>


<commit_before>// Copyright 2016 The Prometheus Authors
// 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 main

import (
	"fmt"
	"net/http"

	"github.com/prometheus/common/log"
	"github.com/sclevine/agouti"
)

const msInSecond = 1000

// from https://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface
type navigationTimings struct {
	ConnectEnd                 float64 `json:"connectEnd"`
	ConnectStart               float64 `json:"connectStart"`
	DomComplete                float64 `json:"domComplete"`
	DomContentLoadedEventEnd   float64 `json:"domContentLoadedEventEnd"`
	DomContentLoadedEventStart float64 `json:"domContentLoadedEventStart"`
	DomInteractive             float64 `json:"domInteractive"`
	DomLoading                 float64 `json:"domLoading"`
	DomainLookupEnd            float64 `json:"domainLookupEnd"`
	DomainLookupStart          float64 `json:"domainLookupStart"`
	FetchStart                 float64 `json:"fetchStart"`
	LoadEventEnd               float64 `json:"loadEventEnd"`
	LoadEventStart             float64 `json:"loadEventStart"`
	NavigationStart            float64 `json:"navigationStart"`
	RedirectEnd                float64 `json:"redirectEnd"`
	RedirectStart              float64 `json:"redirectStart"`
	RequestStart               float64 `json:"requestStart"`
	ResponseEnd                float64 `json:"responseEnd"`
	ResponseStart              float64 `json:"responseStart"`
	SecureConnectionStart      float64 `json:"secureConnectionStart"`
	UnloadEventEnd             float64 `json:"unloadEventEnd"`
	UnloadEventStart           float64 `json:"unloadEventStart"`
}

func probe(target string, w http.ResponseWriter) bool {
	// new page to ensure a clean session (no caching)
	options := []agouti.Option{
		agouti.Desired(agouti.NewCapabilities().Browser("chrome").With("javascriptEnabled")),
		agouti.Timeout(5),
	}
	page, err := driver.NewPage(options...)
	if err != nil {
		log.Error(err)
		return false
	}
	defer page.Destroy()

	err = page.Navigate(target)
	if err != nil {
		log.Error(err)
		return false
	}
	url, err := page.URL()
	if err != nil {
		log.Error(err)
		return false
	}
	if url != target {
		log.Errorf("got unexpected URL, ensure target accounts for any redirects; got %q, expected %q", url, target)
		return false
	}

	var timings *navigationTimings
	err = page.RunScript("return window.performance.timing;", nil, &timings)
	if err != nil {
		log.Error(err)
		return false
	}

	fmt.Fprintf(w, "navigation_timing_connect_end_seconds %f\n", timings.ConnectEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_connect_start_seconds %f\n", timings.ConnectStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_complete_seconds %f\n", timings.DomComplete/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_content_loaded_event_end_seconds %f\n", timings.DomContentLoadedEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_content_loaded_event_start_seconds %f\n", timings.DomContentLoadedEventStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_interactive_seconds %f\n", timings.DomInteractive/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_loading_seconds %f\n", timings.DomLoading/msInSecond)
	fmt.Fprintf(w, "navigation_timing_domain_lookup_end_seconds %f\n", timings.DomainLookupEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_domain_lookup_start_seconds %f\n", timings.DomainLookupStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_fetch_start_seconds %f\n", timings.FetchStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_load_event_end_seconds %f\n", timings.LoadEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_load_event_start_seconds %f\n", timings.LoadEventStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_redirect_end_seconds %f\n", timings.RedirectEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_redirect_start_seconds %f\n", timings.RedirectStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_request_start_seconds %f\n", timings.RequestStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_response_end_seconds %f\n", timings.ResponseEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_response_start_seconds %f\n", timings.ResponseStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_secure_connection_start_seconds %f\n", timings.SecureConnectionStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_start_seconds %f\n", timings.NavigationStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_unload_event_end_seconds %f\n", timings.UnloadEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_unload_event_start_seconds %f\n", timings.UnloadEventStart/msInSecond)

	logs, err := page.ReadAllLogs("browser")
	if err != nil {
		log.Error(err)
		return false
	}
	var warningCount, severeCount int
	for _, log := range logs {
		if log.Level == "WARNING" {
			warningCount++
		}
		if log.Level == "SEVERE" {
			severeCount++
		}
	}
	fmt.Fprintf(w, "browser_log_warning_count %d\n", warningCount)
	fmt.Fprintf(w, "browser_log_severe_count %d\n", severeCount)

	return true
}
<commit_msg>Remove JSON tags from navigationTimings struct<commit_after>// Copyright 2016 The Prometheus Authors
// 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 main

import (
	"fmt"
	"net/http"

	"github.com/prometheus/common/log"
	"github.com/sclevine/agouti"
)

const msInSecond = 1000

// from https://www.w3.org/TR/navigation-timing/#sec-navigation-timing-interface
type navigationTimings struct {
	ConnectEnd                 float64
	ConnectStart               float64
	DomComplete                float64
	DomContentLoadedEventEnd   float64
	DomContentLoadedEventStart float64
	DomInteractive             float64
	DomLoading                 float64
	DomainLookupEnd            float64
	DomainLookupStart          float64
	FetchStart                 float64
	LoadEventEnd               float64
	LoadEventStart             float64
	NavigationStart            float64
	RedirectEnd                float64
	RedirectStart              float64
	RequestStart               float64
	ResponseEnd                float64
	ResponseStart              float64
	SecureConnectionStart      float64
	UnloadEventEnd             float64
	UnloadEventStart           float64
}

func probe(target string, w http.ResponseWriter) bool {
	// new page to ensure a clean session (no caching)
	options := []agouti.Option{
		agouti.Desired(agouti.NewCapabilities().Browser("chrome").With("javascriptEnabled")),
		agouti.Timeout(5),
	}
	page, err := driver.NewPage(options...)
	if err != nil {
		log.Error(err)
		return false
	}
	defer page.Destroy()

	err = page.Navigate(target)
	if err != nil {
		log.Error(err)
		return false
	}
	url, err := page.URL()
	if err != nil {
		log.Error(err)
		return false
	}
	if url != target {
		log.Errorf("got unexpected URL, ensure target accounts for any redirects; got %q, expected %q", url, target)
		return false
	}

	var timings *navigationTimings
	err = page.RunScript("return window.performance.timing;", nil, &timings)
	if err != nil {
		log.Error(err)
		return false
	}

	fmt.Fprintf(w, "navigation_timing_connect_end_seconds %f\n", timings.ConnectEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_connect_start_seconds %f\n", timings.ConnectStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_complete_seconds %f\n", timings.DomComplete/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_content_loaded_event_end_seconds %f\n", timings.DomContentLoadedEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_content_loaded_event_start_seconds %f\n", timings.DomContentLoadedEventStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_interactive_seconds %f\n", timings.DomInteractive/msInSecond)
	fmt.Fprintf(w, "navigation_timing_dom_loading_seconds %f\n", timings.DomLoading/msInSecond)
	fmt.Fprintf(w, "navigation_timing_domain_lookup_end_seconds %f\n", timings.DomainLookupEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_domain_lookup_start_seconds %f\n", timings.DomainLookupStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_fetch_start_seconds %f\n", timings.FetchStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_load_event_end_seconds %f\n", timings.LoadEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_load_event_start_seconds %f\n", timings.LoadEventStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_redirect_end_seconds %f\n", timings.RedirectEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_redirect_start_seconds %f\n", timings.RedirectStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_request_start_seconds %f\n", timings.RequestStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_response_end_seconds %f\n", timings.ResponseEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_response_start_seconds %f\n", timings.ResponseStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_secure_connection_start_seconds %f\n", timings.SecureConnectionStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_start_seconds %f\n", timings.NavigationStart/msInSecond)
	fmt.Fprintf(w, "navigation_timing_unload_event_end_seconds %f\n", timings.UnloadEventEnd/msInSecond)
	fmt.Fprintf(w, "navigation_timing_unload_event_start_seconds %f\n", timings.UnloadEventStart/msInSecond)

	logs, err := page.ReadAllLogs("browser")
	if err != nil {
		log.Error(err)
		return false
	}
	var warningCount, severeCount int
	for _, log := range logs {
		if log.Level == "WARNING" {
			warningCount++
		}
		if log.Level == "SEVERE" {
			severeCount++
		}
	}
	fmt.Fprintf(w, "browser_log_warning_count %d\n", warningCount)
	fmt.Fprintf(w, "browser_log_severe_count %d\n", severeCount)

	return true
}
<|endoftext|>


<commit_before>// Copyright 2014, Hǎiliàng Wáng. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xsd

import (
	"fmt"
	"io"
	"reflect"
	"regexp"
	"strings"
)

func cleanDoc(s string) string {
	ss := strings.Split(s, "\n")
	for i := range ss {
		ss[i] = strings.TrimSpace(ss[i])
	}
	return strings.Join(ss, " ")
}

func (t ComplexType) GoName() string {
	return goType(t.Name)
}

func (a Attribute) GoName() string {
	return snakeToCamel(a.Name)
}

func (a Attribute) GoType(namespace string) string {
	if a.Type != "" {
		return goType(a.Type)
	}
	if goType(a.SimpleType.Restriction.Base) == "NMTOKEN" {
		return namespace + a.GoName()
	}
	return goType(a.SimpleType.Restriction.Base)
}

func (e Element) GoName() string {
	return snakeToCamel(e.Name)
}

func (e Element) GoType() string {
	return goType(e.Type)
}

func trimNamespace(s string) string {
	m := strings.Split(s, ":")
	if len(m) == 2 {
		return m[1]
	}
	return s
}

func snakeToCamel(s string) string {
	ss := strings.Split(s, "_")
	for i := range ss {
		ss[i] = strings.Title(ss[i])
	}
	return strings.Join(ss, "")
}

var lowerUpper = regexp.MustCompile(`([\P{Lu}])([\p{Lu}])`)

// convert name from camel case to snake case
func camelToSnake(s string) string {
	return strings.ToLower(lowerUpper.ReplaceAllString(s, `${1}_${2}`))
}

func omitType(s string) string {
	switch s {
	case "int", "string", "bool", "AnyURI":
		return s
	}
	return "*" + s
}

func goType(s string) string {
	s = trimNamespace(s)
	switch s {
	case "integer":
		return "int"
	case "boolean":
		return "bool"
	case "string":
		return "string"
	case "decimal":
		return "float32"
	}
	s = strings.TrimSuffix(s, "Type")
	s = strings.TrimSuffix(s, "type")
	return snakeToCamel(s)
}

func p(w io.Writer, v ...interface{}) {
	fmt.Fprint(w, v...)
	fmt.Fprintln(w)
}

type XMLNodeType int

const (
	XMLElement XMLNodeType = iota
	XMLAttr
	XMLCharData
	XMLInnerXML
	XMLComment
	XMLOmitted
)

type XMLTag struct {
	Type      XMLNodeType
	Name      string
	Omitempty bool
}

func ParseXMLTag(s string) XMLTag {
	values := strings.Split(reflect.StructTag(strings.Trim(s, "`")).Get("xml"), ",")
	t := XMLTag{Name: values[0]}
	for _, value := range values[1:] {
		switch value {
		case "-":
			t.Type = XMLOmitted
		case "attr":
			t.Type = XMLAttr
		case "chardata":
			t.Type = XMLCharData
		case "innerxml":
			t.Type = XMLInnerXML
		case "comment":
			t.Type = XMLComment
		case "omitempty":
			t.Omitempty = true
		}
	}
	return t
}

func (t XMLTag) String() string {
	var values []string
	values = append(values, t.Name)
	switch t.Type {
	case XMLOmitted:
		return `xml:"-"`
	case XMLAttr:
		values = append(values, "attr")
	case XMLCharData:
		values = append(values, "chardata")
	case XMLInnerXML:
		values = append(values, "innerxml")
	case XMLComment:
		values = append(values, "comment")
	}
	if t.Omitempty {
		values = append(values, "omitempty")
	}
	return fmt.Sprintf(`xml:"%s"`, strings.Join(values, ","))
}

type BSONNodeType int

const (
	BSONNormal BSONNodeType = iota
	BSONInline
	BSONOmitted
)

type BSONTag struct {
	Type      BSONNodeType
	Name      string
	Omitempty bool
}

func (t BSONTag) String() string {
	if t.Type == BSONOmitted {
		return `bson:"-"`
	}
	values := []string{t.Name}
	if t.Omitempty {
		values = append(values, "omitempty")
	}
	return fmt.Sprintf(`bson:"%s"`, strings.Join(values, ","))
}
<commit_msg>improve camel2snake.<commit_after>// Copyright 2014, Hǎiliàng Wáng. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xsd

import (
	"fmt"
	"io"
	"reflect"
	"regexp"
	"strings"
)

func cleanDoc(s string) string {
	ss := strings.Split(s, "\n")
	for i := range ss {
		ss[i] = strings.TrimSpace(ss[i])
	}
	return strings.Join(ss, " ")
}

func (t ComplexType) GoName() string {
	return goType(t.Name)
}

func (a Attribute) GoName() string {
	return snakeToCamel(a.Name)
}

func (a Attribute) GoType(namespace string) string {
	if a.Type != "" {
		return goType(a.Type)
	}
	if goType(a.SimpleType.Restriction.Base) == "NMTOKEN" {
		return namespace + a.GoName()
	}
	return goType(a.SimpleType.Restriction.Base)
}

func (e Element) GoName() string {
	return snakeToCamel(e.Name)
}

func (e Element) GoType() string {
	return goType(e.Type)
}

func trimNamespace(s string) string {
	m := strings.Split(s, ":")
	if len(m) == 2 {
		return m[1]
	}
	return s
}

func snakeToCamel(s string) string {
	ss := strings.Split(s, "_")
	for i := range ss {
		ss[i] = strings.Title(ss[i])
	}
	return strings.Join(ss, "")
}

var upperLower = regexp.MustCompile(`[\p{Lu}][\p{Ll}]`)

// convert name from camel case to snake case
func camelToSnake(s string) string {
	return strings.TrimPrefix(strings.ToLower(upperLower.ReplaceAllString(s, `_${0}`)), "_")
}

func omitType(s string) string {
	switch s {
	case "int", "string", "bool", "AnyURI":
		return s
	}
	return "*" + s
}

func goType(s string) string {
	s = trimNamespace(s)
	switch s {
	case "integer":
		return "int"
	case "boolean":
		return "bool"
	case "string":
		return "string"
	case "decimal":
		return "float32"
	}
	s = strings.TrimSuffix(s, "Type")
	s = strings.TrimSuffix(s, "type")
	return snakeToCamel(s)
}

func p(w io.Writer, v ...interface{}) {
	fmt.Fprint(w, v...)
	fmt.Fprintln(w)
}

type XMLNodeType int

const (
	XMLElement XMLNodeType = iota
	XMLAttr
	XMLCharData
	XMLInnerXML
	XMLComment
	XMLOmitted
)

type XMLTag struct {
	Type      XMLNodeType
	Name      string
	Omitempty bool
}

func ParseXMLTag(s string) XMLTag {
	values := strings.Split(reflect.StructTag(strings.Trim(s, "`")).Get("xml"), ",")
	t := XMLTag{Name: values[0]}
	for _, value := range values[1:] {
		switch value {
		case "-":
			t.Type = XMLOmitted
		case "attr":
			t.Type = XMLAttr
		case "chardata":
			t.Type = XMLCharData
		case "innerxml":
			t.Type = XMLInnerXML
		case "comment":
			t.Type = XMLComment
		case "omitempty":
			t.Omitempty = true
		}
	}
	return t
}

func (t XMLTag) String() string {
	var values []string
	values = append(values, t.Name)
	switch t.Type {
	case XMLOmitted:
		return `xml:"-"`
	case XMLAttr:
		values = append(values, "attr")
	case XMLCharData:
		values = append(values, "chardata")
	case XMLInnerXML:
		values = append(values, "innerxml")
	case XMLComment:
		values = append(values, "comment")
	}
	if t.Omitempty {
		values = append(values, "omitempty")
	}
	return fmt.Sprintf(`xml:"%s"`, strings.Join(values, ","))
}

type BSONNodeType int

const (
	BSONNormal BSONNodeType = iota
	BSONInline
	BSONOmitted
)

type BSONTag struct {
	Type      BSONNodeType
	Name      string
	Omitempty bool
}

func (t BSONTag) String() string {
	if t.Type == BSONOmitted {
		return `bson:"-"`
	}
	values := []string{t.Name}
	if t.Omitempty {
		values = append(values, "omitempty")
	}
	return fmt.Sprintf(`bson:"%s"`, strings.Join(values, ","))
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// gen runs go generate on Unicode- and CLDR-related package in the text
// repositories, taking into account dependencies and versions.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"unicode"

	"golang.org/x/text/internal/gen"
)

var (
	verbose     = flag.Bool("v", false, "verbose output")
	force       = flag.Bool("force", false, "ignore failing dependencies")
	excludeList = flag.String("exclude", "",
		"comma-separated list of packages to exclude")

	// The user can specify a selection of packages to build on the command line.
	args []string
)

func exclude(pkg string) bool {
	if len(args) > 0 {
		return !contains(args, pkg)
	}
	return contains(strings.Split(*excludeList, ","), pkg)
}

// TODO:
// - Better version handling.
// - Generate tables for the core unicode package?
// - Add generation for encodings. This requires some retooling here and there.
// - Running repo-wide "long" tests.

var vprintf = fmt.Printf

func main() {
	gen.Init()
	args = flag.Args()
	if !*verbose {
		// Set vprintf to a no-op.
		vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
	}

	// TODO: create temporary cache directory to load files and create and set
	// a "cache" option if the user did not specify the UNICODE_DIR environment
	// variable. This will prevent duplicate downloads and also will enable long
	// tests, which really need to be run after each generated package.

	if gen.UnicodeVersion() != unicode.Version {
		fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
			gen.UnicodeVersion,
			unicode.Version)
		// TODO: use collate to compare. Simple comparison will work, though,
		// until Unicode reaches version 10. To avoid circular dependencies, we
		// could use the NumericWeighter without using package collate using a
		// trivial Weighter implementation.
		if gen.UnicodeVersion() < unicode.Version && !*force {
			os.Exit(2)
		}
	}
	var (
		cldr     = generate("unicode/cldr")
		language = generate("language", cldr)
		internal = generate("internal", language)
		norm     = generate("unicode/norm")
		_        = generate("unicode/rangetable")
		_        = generate("unicode/bidi", norm)
		_        = generate("encoding/htmlindex", language)
		_        = generate("width")
		_        = generate("currency", cldr, language, internal)
		_        = generate("language/display", cldr, language)
		_        = generate("cases", norm, language)
		_        = generate("collate", norm, cldr, language)
		_        = generate("search", norm, cldr, language)
	)
	all.Wait()

	if hasErrors {
		fmt.Println("FAIL")
		os.Exit(1)
	}
	vprintf("SUCCESS\n")
}

var (
	all       sync.WaitGroup
	hasErrors bool
)

type dependency struct {
	sync.WaitGroup
	hasErrors bool
}

func generate(pkg string, deps ...*dependency) *dependency {
	var wg dependency
	if exclude(pkg) {
		return &wg
	}
	wg.Add(1)
	all.Add(1)
	go func() {
		defer wg.Done()
		defer all.Done()
		// Wait for dependencies to finish.
		for _, d := range deps {
			d.Wait()
			if d.hasErrors && !*force {
				fmt.Printf("--- ABORT: %s\n", pkg)
				wg.hasErrors = true
				return
			}
		}
		vprintf("=== GENERATE %s\n", pkg)
		args := []string{"generate"}
		if *verbose {
			args = append(args, "-v")
		}
		args = append(args, "./"+pkg)
		cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		w := &bytes.Buffer{}
		cmd.Stderr = w
		cmd.Stdout = w
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}

		vprintf("=== TEST %s\n", pkg)
		args[0] = "test"
		cmd = exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		wt := &bytes.Buffer{}
		cmd.Stderr = wt
		cmd.Stdout = wt
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(wt), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}
		vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
		fmt.Print(wt.String())
	}()
	return &wg
}

func contains(a []string, s string) bool {
	for _, e := range a {
		if s == e {
			return true
		}
	}
	return false
}

func indent(b *bytes.Buffer) string {
	return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
}
<commit_msg>: added new packages to gen tool<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

// gen runs go generate on Unicode- and CLDR-related package in the text
// repositories, taking into account dependencies and versions.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"unicode"

	"golang.org/x/text/internal/gen"
)

var (
	verbose     = flag.Bool("v", false, "verbose output")
	force       = flag.Bool("force", false, "ignore failing dependencies")
	excludeList = flag.String("exclude", "",
		"comma-separated list of packages to exclude")

	// The user can specify a selection of packages to build on the command line.
	args []string
)

func exclude(pkg string) bool {
	if len(args) > 0 {
		return !contains(args, pkg)
	}
	return contains(strings.Split(*excludeList, ","), pkg)
}

// TODO:
// - Better version handling.
// - Generate tables for the core unicode package?
// - Add generation for encodings. This requires some retooling here and there.
// - Running repo-wide "long" tests.

var vprintf = fmt.Printf

func main() {
	gen.Init()
	args = flag.Args()
	if !*verbose {
		// Set vprintf to a no-op.
		vprintf = func(string, ...interface{}) (int, error) { return 0, nil }
	}

	// TODO: create temporary cache directory to load files and create and set
	// a "cache" option if the user did not specify the UNICODE_DIR environment
	// variable. This will prevent duplicate downloads and also will enable long
	// tests, which really need to be run after each generated package.

	if gen.UnicodeVersion() != unicode.Version {
		fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n",
			gen.UnicodeVersion,
			unicode.Version)
		// TODO: use collate to compare. Simple comparison will work, though,
		// until Unicode reaches version 10. To avoid circular dependencies, we
		// could use the NumericWeighter without using package collate using a
		// trivial Weighter implementation.
		if gen.UnicodeVersion() < unicode.Version && !*force {
			os.Exit(2)
		}
	}
	var (
		cldr       = generate("unicode/cldr")
		language   = generate("language", cldr)
		internal   = generate("internal", language)
		norm       = generate("unicode/norm")
		rangetable = generate("unicode/rangetable")
		cases      = generate("cases", norm, language, rangetable)
		width      = generate("width")
		bidi       = generate("unicode/bidi", norm, rangetable)
		_          = generate("secure/precis", norm, rangetable, cases, width, bidi)
		_          = generate("encoding/htmlindex", language)
		_          = generate("currency", cldr, language, internal)
		_          = generate("internal/number", cldr, language, internal)
		_          = generate("language/display", cldr, language)
		_          = generate("collate", norm, cldr, language, rangetable)
		_          = generate("search", norm, cldr, language, rangetable)
	)
	all.Wait()

	if hasErrors {
		fmt.Println("FAIL")
		os.Exit(1)
	}
	vprintf("SUCCESS\n")
}

var (
	all       sync.WaitGroup
	hasErrors bool
)

type dependency struct {
	sync.WaitGroup
	hasErrors bool
}

func generate(pkg string, deps ...*dependency) *dependency {
	var wg dependency
	if exclude(pkg) {
		return &wg
	}
	wg.Add(1)
	all.Add(1)
	go func() {
		defer wg.Done()
		defer all.Done()
		// Wait for dependencies to finish.
		for _, d := range deps {
			d.Wait()
			if d.hasErrors && !*force {
				fmt.Printf("--- ABORT: %s\n", pkg)
				wg.hasErrors = true
				return
			}
		}
		vprintf("=== GENERATE %s\n", pkg)
		args := []string{"generate"}
		if *verbose {
			args = append(args, "-v")
		}
		args = append(args, "./"+pkg)
		cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		w := &bytes.Buffer{}
		cmd.Stderr = w
		cmd.Stdout = w
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}

		vprintf("=== TEST %s\n", pkg)
		args[0] = "test"
		cmd = exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
		wt := &bytes.Buffer{}
		cmd.Stderr = wt
		cmd.Stdout = wt
		if err := cmd.Run(); err != nil {
			fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(wt), err)
			hasErrors = true
			wg.hasErrors = true
			return
		}
		vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w))
		fmt.Print(wt.String())
	}()
	return &wg
}

func contains(a []string, s string) bool {
	for _, e := range a {
		if s == e {
			return true
		}
	}
	return false
}

func indent(b *bytes.Buffer) string {
	return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1)
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
)

var get = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get allentries|alltxs|chainhead|dblock|eblock|entry|firstentry|head|height"
	cmd.description = "Get data about Factom Chains, Entries, and Blocks"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		c := cli.New()
		c.Handle("allentries", getAllEntries)
		c.Handle("head", getHead)
		c.Handle("height", getHeight)
		c.Handle("dblock", getDBlock)
		c.Handle("chainhead", getChainHead)
		c.Handle("eblock", getEBlock)
		c.Handle("entry", getEntry)
		c.Handle("firstentry", getFirstEntry)
		c.HandleDefaultFunc(func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	help.Add("get", cmd)
	return cmd
}()

var getAllEntries = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get allentries [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get all of the Entries in a Chain"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		es, err := factom.GetAllChainEntries(chainid)
		if err != nil {
			for i, e := range es {
				fmt.Printf("Entry [%d] {\n%s}\n", i, e)
			}
			errorln(err)
			return
		}

		for i, e := range es {
			fmt.Printf("Entry [%d] {\n%s}\n", i, e)
		}
	}
	help.Add("get allentries", cmd)
	return cmd
}()

var getChainHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get chainhead [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get ebhead by chainid"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		head, err := factom.GetChainHead(chainid)
		if err != nil {
			errorln(err)
			return
		}
		eblock, err := factom.GetEBlock(head)
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println("EBlock:", head)
		fmt.Println(eblock)
	}
	help.Add("get chainhead", cmd)
	return cmd
}()

var getDBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get dblock KEYMR"
	cmd.description = "Get dblock contents by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		dblock, err := factom.GetDBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(dblock)
	}
	help.Add("get dblock", cmd)
	return cmd
}()

var getEBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get eblock KEYMR"
	cmd.description = "Get eblock by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		eblock, err := factom.GetEBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(eblock)
	}
	help.Add("get eblock", cmd)
	return cmd
}()

var getEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get entry HASH"
	cmd.description = "Get entry by hash"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		hash := args[0]
		entry, err := factom.GetEntry(hash)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get entry", cmd)
	return cmd
}()

var getFirstEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get firstentry [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get the first entry from a chain"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		entry, err := factom.GetFirstEntry(chainid)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get firstentry", cmd)
	return cmd
}()

var getHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head"
	cmd.description = "Get the latest completed directory block"
	cmd.execFunc = func(args []string) {
		head, err := factom.GetDBlockHead()
		if err != nil {
			errorln(err)
			return
		}
		dblock, err := factom.GetDBlock(head)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println("DBlock:", head)
		fmt.Println(dblock)
	}
	help.Add("get head", cmd)
	return cmd
}()

var getHeight = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get height"
	cmd.description = "Get the current directory block height"
	cmd.execFunc = func(args []string) {
		height, err := factom.GetDBlockHeight()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(height)
	}
	help.Add("get height", cmd)
	return cmd
}()

var properties = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli properties"
	cmd.description = "Get version information about facotmd and the factom wallet"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		f, a, w, err := factom.GetProperties()
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println("Factomd Version:", f)
		fmt.Println("API Version:", a)
		fmt.Println("Wallet Version:", w)
		fmt.Println("CLI Version:", Version)
	}
	help.Add("properties", cmd)
	return cmd
}()
<commit_msg>fixed help message<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
)

var get = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get allentries|chainhead|dblock|eblock|entry|firstentry|head|height"
	cmd.description = "Get data about Factom Chains, Entries, and Blocks"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		c := cli.New()
		c.Handle("allentries", getAllEntries)
		c.Handle("head", getHead)
		c.Handle("height", getHeight)
		c.Handle("dblock", getDBlock)
		c.Handle("chainhead", getChainHead)
		c.Handle("eblock", getEBlock)
		c.Handle("entry", getEntry)
		c.Handle("firstentry", getFirstEntry)
		c.HandleDefaultFunc(func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	help.Add("get", cmd)
	return cmd
}()

var getAllEntries = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get allentries [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get all of the Entries in a Chain"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		es, err := factom.GetAllChainEntries(chainid)
		if err != nil {
			for i, e := range es {
				fmt.Printf("Entry [%d] {\n%s}\n", i, e)
			}
			errorln(err)
			return
		}

		for i, e := range es {
			fmt.Printf("Entry [%d] {\n%s}\n", i, e)
		}
	}
	help.Add("get allentries", cmd)
	return cmd
}()

var getChainHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get chainhead [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get ebhead by chainid"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		head, err := factom.GetChainHead(chainid)
		if err != nil {
			errorln(err)
			return
		}
		eblock, err := factom.GetEBlock(head)
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println("EBlock:", head)
		fmt.Println(eblock)
	}
	help.Add("get chainhead", cmd)
	return cmd
}()

var getDBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get dblock KEYMR"
	cmd.description = "Get dblock contents by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		dblock, err := factom.GetDBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(dblock)
	}
	help.Add("get dblock", cmd)
	return cmd
}()

var getEBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get eblock KEYMR"
	cmd.description = "Get eblock by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		eblock, err := factom.GetEBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(eblock)
	}
	help.Add("get eblock", cmd)
	return cmd
}()

var getEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get entry HASH"
	cmd.description = "Get entry by hash"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		hash := args[0]
		entry, err := factom.GetEntry(hash)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get entry", cmd)
	return cmd
}()

var getFirstEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get firstentry [-n NAME1 -N HEXNAME2 ...] CHAINID"
	cmd.description = "Get the first entry from a chain"
	cmd.execFunc = func(args []string) {
		var (
			nAcii namesAscii
			nHex  namesHex
		)
		os.Args = args
		nameCollector = make([][]byte, 0)
		flag.Var(&nAcii, "n", "ascii name component")
		flag.Var(&nHex, "N", "hex binary name component")
		flag.Parse()
		args = flag.Args()

		var chainid string

		if len(args) < 1 && len(nameCollector) == 0 {
			fmt.Println(cmd.helpMsg)
			return
		}
		if len(nameCollector) != 0 {
			chainid = nametoid(nameCollector)
		} else {
			chainid = args[0]
		}

		entry, err := factom.GetFirstEntry(chainid)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get firstentry", cmd)
	return cmd
}()

var getHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head"
	cmd.description = "Get the latest completed directory block"
	cmd.execFunc = func(args []string) {
		head, err := factom.GetDBlockHead()
		if err != nil {
			errorln(err)
			return
		}
		dblock, err := factom.GetDBlock(head)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println("DBlock:", head)
		fmt.Println(dblock)
	}
	help.Add("get head", cmd)
	return cmd
}()

var getHeight = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get height"
	cmd.description = "Get the current directory block height"
	cmd.execFunc = func(args []string) {
		height, err := factom.GetDBlockHeight()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(height)
	}
	help.Add("get height", cmd)
	return cmd
}()

var properties = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli properties"
	cmd.description = "Get version information about facotmd and the factom wallet"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		f, a, w, err := factom.GetProperties()
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println("Factomd Version:", f)
		fmt.Println("API Version:", a)
		fmt.Println("Wallet Version:", w)
		fmt.Println("CLI Version:", Version)
	}
	help.Add("properties", cmd)
	return cmd
}()
<|endoftext|>


<commit_before>package proto

import (
	"fmt"
	"io"
	"net"
)

var (
	// ErrEOM end of message error
	ErrEOM = fmt.Errorf(
		"EOM",
	)
)

// Protocol is an interface to build the actual
// underlying message readers and writers. It is
// important to be able to swap out protocols
// with others
type Protocol interface {
	NewReader(io.Reader) io.Reader
	NewWriter(io.Writer) io.Writer
}

// Conn is a net.Conn but
// read and writing bytes goes
// through the protocol
type Conn struct {
	net.Conn
	W io.Writer
	R io.Reader
}

// Write write from the connection but only
// after going through the protocol
func (c *Conn) Write(b []byte) (int, error) {
	return c.W.Write(b)
}

// Read read from the connection but only
// after going through the protocol
func (c *Conn) Read(b []byte) (int, error) {
	return c.R.Read(b)
}

// MessageReader has the exact same interface as
// io.Reader but can also return a proto.EOM error
// which designates the end of a message but not the
// stream
type MessageReader interface {
	Read([]byte) (int, error)
}

// MessageWriter has the exat same interface as
// io.Writer. Writing the nil buffer or the empty
// buffer to a MessageWriter designates the end
// of a message and the start of a new one
type MessageWriter interface {
	Write([]byte) (int, error)
}

// WrapConn wraps a network connection around
// a protocol
func WrapConn(p Protocol, c net.Conn) net.Conn {
	C := Conn{
		Conn: c,
		W:    p.NewWriter(c),
		R:    p.NewReader(c),
	}

	return &C
}

// CopyMessages copy N messages from the reader
// to the writer, returns any errors.
// returns the number of messages written successful
// otherwise it will return a non-nil error and the
// number of bytes in the buffer
func CopyMessages(W io.Writer, R io.Reader, B []byte, N int) (int, error) {
	i := 0
	infinite := N < 0

	for i < N || infinite {
		n, err := R.Read(B)

		if err == ErrEOM {
			i++

			// Don't send an extra end of message markers
			if n != 0 {
				_, err := W.Write(B[:n])

				if err != nil {
					return n, err
				}
			}

			// End of message marker
			_, err := W.Write(nil)

			if err != nil {
				return n, err
			}

			continue
		}

		if err == io.EOF {
			return n, err
		}

		if err != nil {
			return n, err
		}

		_, err = W.Write(B[:n])

		if err != nil {
			return n, err
		}
	}

	return i, nil
}

// WriteMessage ...
func WriteMessage(W io.Writer, Bytes []byte) (int, error) {
	S := 0

	n, err := W.Write(Bytes)

	S += n

	if err != nil {
		return S, err
	}

	_, err = W.Write(nil)

	if err != nil {
		return S, err
	}

	return S, nil
}

// ReadMessage ...
func ReadMessage(R io.Reader) ([]byte, error) {
	var B []byte

	l := 16
	for {
		b := make([]byte, l)

		n, err := R.Read(b)

		if n == l {
			l *= 2
		}

		B = append(B, b[:n]...)

		if err == io.EOF {
			return B, nil
		}

		if err == ErrEOM {
			break
		}

		if err != nil {
			return B, err
		}
	}

	return B, nil
}

// Copy copy the bytes into a if a cannot
// hold b, grow a in order to contain it
func Copy(a, b []byte) []byte {
	La := len(a)
	Lb := len(b)

	if La < Lb {
		a = make([]byte, Lb)
	}

	n := copy(a, b)

	return a[:n]
}
<commit_msg>adding wrap helper<commit_after>package proto

import (
	"fmt"
	"io"
	"net"
)

var (
	// ErrEOM end of message error
	ErrEOM = fmt.Errorf(
		"EOM",
	)
)

// Protocol is an interface to build the actual
// underlying message readers and writers. It is
// important to be able to swap out protocols
// with others
type Protocol interface {
	NewReader(io.Reader) io.Reader
	NewWriter(io.Writer) io.Writer
}

// Conn is a net.Conn but
// read and writing bytes goes
// through the protocol
type Conn struct {
	net.Conn
	W io.Writer
	R io.Reader
}

// Write write from the connection but only
// after going through the protocol
func (c *Conn) Write(b []byte) (int, error) {
	return c.W.Write(b)
}

// Read read from the connection but only
// after going through the protocol
func (c *Conn) Read(b []byte) (int, error) {
	return c.R.Read(b)
}

// MessageReader has the exact same interface as
// io.Reader but can also return a proto.EOM error
// which designates the end of a message but not the
// stream
type MessageReader interface {
	Read([]byte) (int, error)
}

// MessageWriter has the exat same interface as
// io.Writer. Writing the nil buffer or the empty
// buffer to a MessageWriter designates the end
// of a message and the start of a new one
type MessageWriter interface {
	Write([]byte) (int, error)
}

// WrapConn wraps a network connection around
// a protocol
func WrapConn(p Protocol, c net.Conn) net.Conn {
	W, R := Wrap(p, c, c)

	C := Conn{
		Conn: c,
		W:    W,
		R:    R,
	}

	return &C
}

// Wrap wraps an io.Reader and io.Writer around
// a protocol
func Wrap(p Protocol, W io.Writer, R io.Reader) (io.Writer, io.Reader) {
	W = p.NewWriter(W)
	R = p.NewReader(R)

	return W, R
}

// CopyMessages copy N messages from the reader
// to the writer, returns any errors.
// returns the number of messages written successful
// otherwise it will return a non-nil error and the
// number of bytes in the buffer
func CopyMessages(W io.Writer, R io.Reader, B []byte, N int) (int, error) {
	i := 0
	infinite := N < 0

	for i < N || infinite {
		n, err := R.Read(B)

		if err == ErrEOM {
			i++

			// Don't send an extra end of message markers
			if n != 0 {
				_, err := W.Write(B[:n])

				if err != nil {
					return n, err
				}
			}

			// End of message marker
			_, err := W.Write(nil)

			if err != nil {
				return n, err
			}

			continue
		}

		if err == io.EOF {
			return n, err
		}

		if err != nil {
			return n, err
		}

		_, err = W.Write(B[:n])

		if err != nil {
			return n, err
		}
	}

	return i, nil
}

// WriteMessage ...
func WriteMessage(W io.Writer, Bytes []byte) (int, error) {
	S := 0

	n, err := W.Write(Bytes)

	S += n

	if err != nil {
		return S, err
	}

	_, err = W.Write(nil)

	if err != nil {
		return S, err
	}

	return S, nil
}

// ReadMessage ...
func ReadMessage(R io.Reader) ([]byte, error) {
	var B []byte

	l := 16
	for {
		b := make([]byte, l)

		n, err := R.Read(b)

		if n == l {
			l *= 2
		}

		B = append(B, b[:n]...)

		if err == io.EOF {
			return B, nil
		}

		if err == ErrEOM {
			break
		}

		if err != nil {
			return B, err
		}
	}

	return B, nil
}

// Copy copy the bytes into a if a cannot
// hold b, grow a in order to contain it
func Copy(a, b []byte) []byte {
	La := len(a)
	Lb := len(b)

	if La < Lb {
		a = make([]byte, Lb)
	}

	n := copy(a, b)

	return a[:n]
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google 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

https://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 main

import (
	"context"
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"time"

	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"golang.org/x/oauth2/google"
)

var projectID = ""

const (
	service        = "devops-demo"
	serviceVersion = "1.0.0"
	metricPrefix   = "devops-"
)

// A IndexVariables represents variables used in a template (index.html)
type IndexVariables struct {
	WebsiteTitle string
	RandomNumber string
}

func logRequest(r *http.Request, traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"UserAgent":                     r.UserAgent(),
		"RequestURL":                    r.Host,
		"RequestURI":                    r.RequestURI,
		"RequestMethod":                 r.Method,
		"Host":                          r.Host,
		"Proto":                         r.Proto,
		"ProtoMajor":                    r.ProtoMajor,
		"ProtoMinor":                    r.ProtoMinor,
		"RemoteAddr":                    r.RemoteAddr,
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func logMethod(traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func mainHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, span := trace.StartSpan(context.Background(), "/")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from mainHandler")

		iv := &IndexVariables{
			WebsiteTitle: "MainController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}

		renderTemplate(w, iv)
	})
}

func benchHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, span := trace.StartSpan(context.Background(), "/bench1")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from benchHandler")

		// Stress
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))

		iv := &IndexVariables{
			WebsiteTitle: "BenchController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}
		renderTemplate(w, iv)
	})
}

func addAttributesToSpan(span *trace.Span, r *http.Request) {
	span.AddAttributes(
		trace.StringAttribute("Method", r.Method),
		trace.StringAttribute("Host", r.Host),
		trace.StringAttribute("Proto", r.Proto),
		trace.Int64Attribute("ProtoMajor", int64(r.ProtoMajor)),
		trace.Int64Attribute("ProtoMinor", int64(r.ProtoMinor)),
		trace.Int64Attribute("ContentLength", int64(r.ContentLength)),
		trace.StringAttribute("RequestURI", r.RequestURI),
		trace.StringAttribute("RemoteAddr", r.RemoteAddr),
		trace.StringAttribute("UserAgent", r.UserAgent()),
		trace.StringAttribute("Referer", r.Referer()),
	)
}

func waitRandomMilliseconds(ctx context.Context) {
	_, span := trace.StartSpan(ctx, "waitRandomMilliseconds")
	defer span.End()
	time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
}

func fibonacci(ctx context.Context, loopNum int) {
	_, span := trace.StartSpan(ctx, "fibonacci")
	s := span.SpanContext()
	defer span.End()
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
	span.AddAttributes(trace.Int64Attribute("loopNum", int64(loopNum)))

	logMethod(s.TraceID.String(), s.SpanID.String(), fmt.Sprintf("Fibonacci calculation completed: %v loops", loopNum))
}

var templates = template.Must(template.ParseFiles("./template/index.html"))

func renderTemplate(w http.ResponseWriter, iv *IndexVariables) {
	err := templates.Execute(w, iv)
	if err != nil {
		log.Printf("Failed to render a template: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func initLogSettings() {
	log.SetFormatter(&log.JSONFormatter{
		FieldMap: log.FieldMap{
			log.FieldKeyTime:  "time",
			log.FieldKeyLevel: "severity",
			log.FieldKeyMsg:   "message",
		},
		TimestampFormat: time.RFC3339Nano,
	})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.InfoLevel)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initLogSettings()

	// Initialize the credential and projectID with Application Default Credentials (ADC)
	ctx := context.Background()
	cred, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		log.Fatal(err.Error())
	}
	projectID = cred.ProjectID
	log.Infof("Successfully retrieved GCP Project ID: %v", projectID)

	// Initialize Profiler
	if err := profiler.Start(profiler.Config{
		Service:        service,
		ServiceVersion: serviceVersion,
		ProjectID:      projectID,
	}); err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized profiler")

	// Initialize exporter
	exporter, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID:    projectID,
		MetricPrefix: metricPrefix,
	})
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized exporter")
	defer exporter.Flush()
	trace.RegisterExporter(exporter)
	trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})

	// Serve static files under /static/ directory
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	// Register handlers
	http.Handle("/", mainHandler())
	http.Handle("/bench1", benchHandler())

	log.Info("Start listening : 8080...")
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Add a line to use context variable<commit_after>/*
Copyright 2019 Google 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

https://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 main

import (
	"context"
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"time"

	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"golang.org/x/oauth2/google"
)

var projectID = ""

const (
	service        = "devops-demo"
	serviceVersion = "1.0.0"
	metricPrefix   = "devops-"
)

// A IndexVariables represents variables used in a template (index.html)
type IndexVariables struct {
	WebsiteTitle string
	RandomNumber string
}

func logRequest(r *http.Request, traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"UserAgent":                     r.UserAgent(),
		"RequestURL":                    r.Host,
		"RequestURI":                    r.RequestURI,
		"RequestMethod":                 r.Method,
		"Host":                          r.Host,
		"Proto":                         r.Proto,
		"ProtoMajor":                    r.ProtoMajor,
		"ProtoMinor":                    r.ProtoMinor,
		"RemoteAddr":                    r.RemoteAddr,
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func logMethod(traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func mainHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, span := trace.StartSpan(context.Background(), "/")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from mainHandler")

		iv := &IndexVariables{
			WebsiteTitle: "MainController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}

		renderTemplate(w, iv)
	})
}

func benchHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, span := trace.StartSpan(context.Background(), "/bench1")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from benchHandler")
		log.Printf("context: %v\n", ctx)

		// Stress
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))

		iv := &IndexVariables{
			WebsiteTitle: "BenchController",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}
		renderTemplate(w, iv)
	})
}

func addAttributesToSpan(span *trace.Span, r *http.Request) {
	span.AddAttributes(
		trace.StringAttribute("Method", r.Method),
		trace.StringAttribute("Host", r.Host),
		trace.StringAttribute("Proto", r.Proto),
		trace.Int64Attribute("ProtoMajor", int64(r.ProtoMajor)),
		trace.Int64Attribute("ProtoMinor", int64(r.ProtoMinor)),
		trace.Int64Attribute("ContentLength", int64(r.ContentLength)),
		trace.StringAttribute("RequestURI", r.RequestURI),
		trace.StringAttribute("RemoteAddr", r.RemoteAddr),
		trace.StringAttribute("UserAgent", r.UserAgent()),
		trace.StringAttribute("Referer", r.Referer()),
	)
}

func waitRandomMilliseconds(ctx context.Context) {
	_, span := trace.StartSpan(ctx, "waitRandomMilliseconds")
	defer span.End()
	time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
}

func fibonacci(ctx context.Context, loopNum int) {
	_, span := trace.StartSpan(ctx, "fibonacci")
	s := span.SpanContext()
	defer span.End()
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
	span.AddAttributes(trace.Int64Attribute("loopNum", int64(loopNum)))

	logMethod(s.TraceID.String(), s.SpanID.String(), fmt.Sprintf("Fibonacci calculation completed: %v loops", loopNum))
}

var templates = template.Must(template.ParseFiles("./template/index.html"))

func renderTemplate(w http.ResponseWriter, iv *IndexVariables) {
	err := templates.Execute(w, iv)
	if err != nil {
		log.Printf("Failed to render a template: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func initLogSettings() {
	log.SetFormatter(&log.JSONFormatter{
		FieldMap: log.FieldMap{
			log.FieldKeyTime:  "time",
			log.FieldKeyLevel: "severity",
			log.FieldKeyMsg:   "message",
		},
		TimestampFormat: time.RFC3339Nano,
	})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.InfoLevel)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initLogSettings()

	// Initialize the credential and projectID with Application Default Credentials (ADC)
	ctx := context.Background()
	cred, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		log.Fatal(err.Error())
	}
	projectID = cred.ProjectID
	log.Infof("Successfully retrieved GCP Project ID: %v", projectID)

	// Initialize Profiler
	if err := profiler.Start(profiler.Config{
		Service:        service,
		ServiceVersion: serviceVersion,
		ProjectID:      projectID,
	}); err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized profiler")

	// Initialize exporter
	exporter, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID:    projectID,
		MetricPrefix: metricPrefix,
	})
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized exporter")
	defer exporter.Flush()
	trace.RegisterExporter(exporter)
	trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})

	// Serve static files under /static/ directory
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	// Register handlers
	http.Handle("/", mainHandler())
	http.Handle("/bench1", benchHandler())

	log.Info("Start listening : 8080...")
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	_ "github.com/joho/godotenv/autoload"
	"github.com/MariaTerzieva/gotumblr"
	"os"
	"strconv"
)

const (
	tumblrURL  = "http://api.tumblr.com"
	blogName   = "devopsreactions.tumblr.com"
	blogTypes  = "text"
	postsLimit = 20
)

func main() {
	posts := getPosts()
	writePostsToCSV(posts)
}

func writePostsToCSV(posts []gotumblr.TextPost) {
	var row []string
	file, err := os.Create("data.csv")
	defer file.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	writer := csv.NewWriter(file)
	for _, post := range posts {
		row = []string{post.Title, post.Body, post.Post_url}
		writer.Write(row)
		if err := writer.Error(); err != nil {
			fmt.Println(err)
		}
	}
	writer.Flush()
}

func getPosts() []gotumblr.TextPost {
	var posts, newPosts []gotumblr.TextPost
	offset := 0
	client := getTumblrClient()
	for len(newPosts) == postsLimit || offset == 0 {
		options := getTumblrOptions(offset)
		postsResponse := client.Posts(blogName, blogTypes, options)
		newPosts = parsePosts(postsResponse)
		posts = append(posts, newPosts...)
		offset += postsLimit
	}
	return posts
}

func getTumblrClient() *gotumblr.TumblrRestClient {
	client := gotumblr.NewTumblrRestClient(
		os.Getenv("CONSUMER_KEY"),
		os.Getenv("CONSUMER_SECRET"),
		os.Getenv("TOKEN"),
		os.Getenv("TOKEN_SECRET"),
		"https://www.albertyw.com/",
		tumblrURL,
	)
	return client
}

func getTumblrOptions(offset int) map[string]string {
	options := map[string]string{}
	options["offset"] = strconv.Itoa(offset)
	options["limit"] = strconv.Itoa(postsLimit)
	return options
}

func parsePosts(postsResponse gotumblr.PostsResponse) []gotumblr.TextPost {
	var posts []gotumblr.TextPost
	var post gotumblr.TextPost
	for _, element := range postsResponse.Posts {
		err := json.Unmarshal(element, &post)
		if err != nil {
			fmt.Println(err)
		} else {
			posts = append(posts, post)
		}
	}
	return posts
}
<commit_msg>Add post id to csv<commit_after>package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	_ "github.com/joho/godotenv/autoload"
	"github.com/MariaTerzieva/gotumblr"
	"os"
	"strconv"
)

const (
	tumblrURL  = "http://api.tumblr.com"
	blogName   = "devopsreactions.tumblr.com"
	blogTypes  = "text"
	postsLimit = 20
)

func main() {
	posts := getPosts()
	writePostsToCSV(posts)
}

func writePostsToCSV(posts []gotumblr.TextPost) {
	var row []string
	file, err := os.Create("data.csv")
	defer file.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	writer := csv.NewWriter(file)
	for _, post := range posts {
		row = getRow(post)
		writer.Write(row)
		if err := writer.Error(); err != nil {
			fmt.Println(err)
		}
	}
	writer.Flush()
}

func getRow(post gotumblr.TextPost) (row []string) {
	row = []string{
		strconv.FormatInt(post.Id, 10),
		post.Title,
		post.Body,
		post.Post_url,
	}
	return row
}

func getPosts() []gotumblr.TextPost {
	var posts, newPosts []gotumblr.TextPost
	offset := 0
	client := getTumblrClient()
	for len(newPosts) == postsLimit || offset == 0 {
		options := getTumblrOptions(offset)
		postsResponse := client.Posts(blogName, blogTypes, options)
		newPosts = parsePosts(postsResponse)
		posts = append(posts, newPosts...)
		offset += postsLimit
	}
	return posts
}

func getTumblrClient() *gotumblr.TumblrRestClient {
	client := gotumblr.NewTumblrRestClient(
		os.Getenv("CONSUMER_KEY"),
		os.Getenv("CONSUMER_SECRET"),
		os.Getenv("TOKEN"),
		os.Getenv("TOKEN_SECRET"),
		"https://www.albertyw.com/",
		tumblrURL,
	)
	return client
}

func getTumblrOptions(offset int) map[string]string {
	options := map[string]string{}
	options["offset"] = strconv.Itoa(offset)
	options["limit"] = strconv.Itoa(postsLimit)
	return options
}

func parsePosts(postsResponse gotumblr.PostsResponse) []gotumblr.TextPost {
	var posts []gotumblr.TextPost
	var post gotumblr.TextPost
	for _, element := range postsResponse.Posts {
		err := json.Unmarshal(element, &post)
		if err != nil {
			fmt.Println(err)
		} else {
			posts = append(posts, post)
		}
	}
	return posts
}
<|endoftext|>


<commit_before>package goproxy

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"regexp"
	"strconv"
	"sync/atomic"

	"github.com/renzuinc/goproxy/http"
)

// The basic proxy type. Implements http.Handler.
type ProxyHttpServer struct {
	// session variable must be aligned in i386
	// see http://golang.org/src/pkg/sync/atomic/doc.go#L41
	sess int64
	// setting Verbose to true will log information on each request sent to the proxy
	Verbose         bool
	Logger          *log.Logger
	NonproxyHandler http.Handler
	reqHandlers     []ReqHandler
	respHandlers    []RespHandler
	httpsHandlers   []HttpsHandler
	Tr              *http.Transport
	// ConnectDial will be used to create TCP connections for CONNECT requests
	// if nil Tr.Dial will be used
	ConnectDial func(network string, addr string) (net.Conn, error)
}

var hasPort = regexp.MustCompile(`:\d+$`)

func copyHeaders(dst, src http.Header) {
	for k, _ := range dst {
		dst.Del(k)
	}
	for k, vs := range src {
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}

func isEof(r *bufio.Reader) bool {
	_, err := r.Peek(1)
	if err == io.EOF {
		return true
	}
	return false
}

func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req *http.Request, resp *http.Response) {
	req = r
	for _, h := range proxy.reqHandlers {
		req, resp = h.Handle(r, ctx)
		// non-nil resp means the handler decided to skip sending the request
		// and return canned response instead.
		if resp != nil {
			break
		}
	}
	return
}
func (proxy *ProxyHttpServer) filterResponse(respOrig *http.Response, ctx *ProxyCtx) (resp *http.Response) {
	resp = respOrig
	for _, h := range proxy.respHandlers {
		ctx.Resp = resp
		resp = h.Handle(resp, ctx)
	}
	return
}

func removeProxyHeaders(ctx *ProxyCtx, r *http.Request) {
	r.RequestURI = "" // this must be reset when serving a request with the client
	ctx.Logf("Sending request %v %v", r.Method, r.URL.String())
	// If no Accept-Encoding header exists, Transport will add the headers it can accept
	// and would wrap the response body with the relevant reader.
	r.Header.Del("Accept-Encoding")
	// curl can add that, see
	// http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
	r.Header.Del("Proxy-Connection")
	r.Header.Del("Proxy-Authenticate")
	r.Header.Del("Proxy-Authorization")
	// Connection, Authenticate and Authorization are single hop Header:
	// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
	// 14.10 Connection
	//   The Connection general-header field allows the sender to specify
	//   options that are desired for that particular connection and MUST NOT
	//   be communicated by proxies over further connections.
	r.Header.Del("Connection")
	r.Close = false
}

// Standard net/http function. Shouldn't be used directly, http.Serve will use it.
func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//r.Header["X-Forwarded-For"] = w.RemoteAddr()
	if r.Method == "CONNECT" {
		proxy.handleHttps(w, r)
	} else {
		ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy}

		var err error
		ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String())
		if !r.URL.IsAbs() {
			proxy.NonproxyHandler.ServeHTTP(w, r)
			return
		}
		r, resp := proxy.filterRequest(r, ctx)

		if resp == nil {
			removeProxyHeaders(ctx, r)
			fmt.Printf("Req %+v\n", r)
			resp, err = ctx.RoundTrip(r)
			if err != nil {
				ctx.Error = err
				resp = proxy.filterResponse(nil, ctx)
				if resp == nil {
					ctx.Logf("error read response %v %v:", r.URL.Host, err.Error())
					http.Error(w, err.Error(), 500)
					return
				}
			}
			ctx.Logf("Received response %v", resp.Status)
		}
		origBody := resp.Body
		resp = proxy.filterResponse(resp, ctx)

		ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode)
		// http.ResponseWriter will take care of filling the correct response length
		// Setting it now, might impose wrong value, contradicting the actual new
		// body the user returned.
		// We keep the original body to remove the header only if things changed.
		// This will prevent problems with HEAD requests where there's no body, yet,
		// the Content-Length header should be set.
		if origBody != resp.Body {

			// if response Body has a known length, we set that as the Content-Length
			bodyWithLength, ok := resp.Body.(KnownLengthReadCloser)
			if ok {
				resp.Header.Set("Content-Length", strconv.FormatInt(bodyWithLength.Length(), 10))
			} else {
				resp.Header.Del("Content-Length")
			}
		}
		copyHeaders(w.Header(), resp.Header)
		w.WriteHeader(resp.StatusCode)
		nr, err := io.Copy(w, resp.Body)
		if err := resp.Body.Close(); err != nil {
			ctx.Warnf("Can't close response body %v", err)
		}
		ctx.Logf("Copied %v bytes to client error=%v", nr, err)
	}
}

// New proxy server, logs to StdErr by default
func NewProxyHttpServer() *ProxyHttpServer {
	proxy := ProxyHttpServer{
		Logger:        log.New(os.Stderr, "", log.LstdFlags),
		reqHandlers:   []ReqHandler{},
		respHandlers:  []RespHandler{},
		httpsHandlers: []HttpsHandler{},
		NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500)
		}),
		Tr: &http.Transport{TLSClientConfig: tlsClientSkipVerify,
			Proxy: http.ProxyFromEnvironment},
	}
	proxy.ConnectDial = dialerFromEnv(&proxy)
	return &proxy
}
<commit_msg>Removed extra debug print<commit_after>package goproxy

import (
	"bufio"
	"io"
	"log"
	"net"
	"os"
	"regexp"
	"strconv"
	"sync/atomic"

	"github.com/renzuinc/goproxy/http"
)

// The basic proxy type. Implements http.Handler.
type ProxyHttpServer struct {
	// session variable must be aligned in i386
	// see http://golang.org/src/pkg/sync/atomic/doc.go#L41
	sess int64
	// setting Verbose to true will log information on each request sent to the proxy
	Verbose         bool
	Logger          *log.Logger
	NonproxyHandler http.Handler
	reqHandlers     []ReqHandler
	respHandlers    []RespHandler
	httpsHandlers   []HttpsHandler
	Tr              *http.Transport
	// ConnectDial will be used to create TCP connections for CONNECT requests
	// if nil Tr.Dial will be used
	ConnectDial func(network string, addr string) (net.Conn, error)
}

var hasPort = regexp.MustCompile(`:\d+$`)

func copyHeaders(dst, src http.Header) {
	for k, _ := range dst {
		dst.Del(k)
	}
	for k, vs := range src {
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}

func isEof(r *bufio.Reader) bool {
	_, err := r.Peek(1)
	if err == io.EOF {
		return true
	}
	return false
}

func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req *http.Request, resp *http.Response) {
	req = r
	for _, h := range proxy.reqHandlers {
		req, resp = h.Handle(r, ctx)
		// non-nil resp means the handler decided to skip sending the request
		// and return canned response instead.
		if resp != nil {
			break
		}
	}
	return
}
func (proxy *ProxyHttpServer) filterResponse(respOrig *http.Response, ctx *ProxyCtx) (resp *http.Response) {
	resp = respOrig
	for _, h := range proxy.respHandlers {
		ctx.Resp = resp
		resp = h.Handle(resp, ctx)
	}
	return
}

func removeProxyHeaders(ctx *ProxyCtx, r *http.Request) {
	r.RequestURI = "" // this must be reset when serving a request with the client
	ctx.Logf("Sending request %v %v", r.Method, r.URL.String())
	// If no Accept-Encoding header exists, Transport will add the headers it can accept
	// and would wrap the response body with the relevant reader.
	r.Header.Del("Accept-Encoding")
	// curl can add that, see
	// http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
	r.Header.Del("Proxy-Connection")
	r.Header.Del("Proxy-Authenticate")
	r.Header.Del("Proxy-Authorization")
	// Connection, Authenticate and Authorization are single hop Header:
	// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
	// 14.10 Connection
	//   The Connection general-header field allows the sender to specify
	//   options that are desired for that particular connection and MUST NOT
	//   be communicated by proxies over further connections.
	r.Header.Del("Connection")
	r.Close = false
}

// Standard net/http function. Shouldn't be used directly, http.Serve will use it.
func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//r.Header["X-Forwarded-For"] = w.RemoteAddr()
	if r.Method == "CONNECT" {
		proxy.handleHttps(w, r)
	} else {
		ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy}

		var err error
		ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String())
		if !r.URL.IsAbs() {
			proxy.NonproxyHandler.ServeHTTP(w, r)
			return
		}
		r, resp := proxy.filterRequest(r, ctx)

		if resp == nil {
			removeProxyHeaders(ctx, r)
			resp, err = ctx.RoundTrip(r)
			if err != nil {
				ctx.Error = err
				resp = proxy.filterResponse(nil, ctx)
				if resp == nil {
					ctx.Logf("error read response %v %v:", r.URL.Host, err.Error())
					http.Error(w, err.Error(), 500)
					return
				}
			}
			ctx.Logf("Received response %v", resp.Status)
		}
		origBody := resp.Body
		resp = proxy.filterResponse(resp, ctx)

		ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode)
		// http.ResponseWriter will take care of filling the correct response length
		// Setting it now, might impose wrong value, contradicting the actual new
		// body the user returned.
		// We keep the original body to remove the header only if things changed.
		// This will prevent problems with HEAD requests where there's no body, yet,
		// the Content-Length header should be set.
		if origBody != resp.Body {

			// if response Body has a known length, we set that as the Content-Length
			bodyWithLength, ok := resp.Body.(KnownLengthReadCloser)
			if ok {
				resp.Header.Set("Content-Length", strconv.FormatInt(bodyWithLength.Length(), 10))
			} else {
				resp.Header.Del("Content-Length")
			}
		}
		copyHeaders(w.Header(), resp.Header)
		w.WriteHeader(resp.StatusCode)
		nr, err := io.Copy(w, resp.Body)
		if err := resp.Body.Close(); err != nil {
			ctx.Warnf("Can't close response body %v", err)
		}
		ctx.Logf("Copied %v bytes to client error=%v", nr, err)
	}
}

// New proxy server, logs to StdErr by default
func NewProxyHttpServer() *ProxyHttpServer {
	proxy := ProxyHttpServer{
		Logger:        log.New(os.Stderr, "", log.LstdFlags),
		reqHandlers:   []ReqHandler{},
		respHandlers:  []RespHandler{},
		httpsHandlers: []HttpsHandler{},
		NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500)
		}),
		Tr: &http.Transport{TLSClientConfig: tlsClientSkipVerify,
			Proxy: http.ProxyFromEnvironment},
	}
	proxy.ConnectDial = dialerFromEnv(&proxy)
	return &proxy
}
<|endoftext|>