<commit_before>package metric

import (
	"strconv"
	"strings"
	"time"

	"github.com/concourse/concourse/atc/db/lock"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/concourse/atc/db"
)

var Databases []db.Conn
var DatabaseQueries = Meter(0)

var ContainersCreated = Meter(0)
var VolumesCreated = Meter(0)

var FailedContainers = Meter(0)
var FailedVolumes = Meter(0)

var ContainersDeleted = Meter(0)
var VolumesDeleted = Meter(0)

type SchedulingFullDuration struct {
	PipelineName string
	Duration     time.Duration
}

func (event SchedulingFullDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("full-scheduling-duration"),
		Event{
			Name:  "scheduling: full duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
			},
		},
	)
}

type SchedulingLoadVersionsDuration struct {
	PipelineName string
	Duration     time.Duration
}

func (event SchedulingLoadVersionsDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("loading-versions-duration"),
		Event{
			Name:  "scheduling: loading versions duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
			},
		},
	)
}

type SchedulingJobDuration struct {
	PipelineName string
	JobName      string
	Duration     time.Duration
}

func (event SchedulingJobDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("job-scheduling-duration"),
		Event{
			Name:  "scheduling: job duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
				"job":      event.JobName,
			},
		},
	)
}

type WorkerContainers struct {
	WorkerName string
	Platform   string
	Containers int
	TeamName   string
	Tags       []string
}

func (event WorkerContainers) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-containers"),
		Event{
			Name:  "worker containers",
			Value: event.Containers,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":    event.WorkerName,
				"platform":  event.Platform,
				"team_name": event.TeamName,
				"tags":      strings.Join(event.Tags[:], "/"),
			},
		},
	)
}

type WorkerVolumes struct {
	WorkerName string
	Platform   string
	Volumes    int
	TeamName   string
	Tags       []string
}

func (event WorkerVolumes) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-volumes"),
		Event{
			Name:  "worker volumes",
			Value: event.Volumes,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":    event.WorkerName,
				"platform":  event.Platform,
				"team_name": event.TeamName,
				"tags":      strings.Join(event.Tags[:], "/"),
			},
		},
	)
}

type WorkerTasks struct {
	WorkerName string
	Platform   string
	Tasks      int
}

func (event WorkerTasks) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-tasks"),
		Event{
			Name:  "worker tasks",
			Value: event.Tasks,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":   event.WorkerName,
				"platform": event.Platform,
			},
		},
	)
}

type VolumesToBeGarbageCollected struct {
	Volumes int
}

func (event VolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-orphaned-volumes-for-deletion"),
		Event{
			Name:       "orphaned volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatingContainersToBeGarbageCollected struct {
	Containers int
}

func (event CreatingContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-creating-containers-for-deletion"),
		Event{
			Name:       "creating containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatedContainersToBeGarbageCollected struct {
	Containers int
}

func (event CreatedContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-created-ccontainers-for-deletion"),
		Event{
			Name:       "created containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type DestroyingContainersToBeGarbageCollected struct {
	Containers int
}

func (event DestroyingContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-destroying-containers-for-deletion"),
		Event{
			Name:       "destroying containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type FailedContainersToBeGarbageCollected struct {
	Containers int
}

func (event FailedContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-failed-containers-for-deletion"),
		Event{
			Name:       "failed containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatedVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event CreatedVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-created-volumes-for-deletion"),
		Event{
			Name:       "created volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type DestroyingVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event DestroyingVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-destroying-volumes-for-deletion"),
		Event{
			Name:       "destroying volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type FailedVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event FailedVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-failed-volumes-for-deletion"),
		Event{
			Name:       "failed volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type GarbageCollectionContainerCollectorJobDropped struct {
	WorkerName string
}

func (event GarbageCollectionContainerCollectorJobDropped) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-container-collector-dropped"),
		Event{
			Name:  "GC container collector job dropped",
			Value: 1,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker": event.WorkerName,
			},
		},
	)
}

type BuildStarted struct {
	PipelineName string
	JobName      string
	BuildName    string
	BuildID      int
	TeamName     string
}

func (event BuildStarted) Emit(logger lager.Logger) {
	emit(
		logger.Session("build-started"),
		Event{
			Name:  "build started",
			Value: event.BuildID,
			State: EventStateOK,
			Attributes: map[string]string{
				"pipeline":   event.PipelineName,
				"job":        event.JobName,
				"build_name": event.BuildName,
				"build_id":   strconv.Itoa(event.BuildID),
				"team_name":  event.TeamName,
			},
		},
	)
}

type BuildFinished struct {
	PipelineName  string
	JobName       string
	BuildName     string
	BuildID       int
	BuildStatus   db.BuildStatus
	BuildDuration time.Duration
	TeamName      string
}

func (event BuildFinished) Emit(logger lager.Logger) {
	emit(
		logger.Session("build-finished"),
		Event{
			Name:  "build finished",
			Value: ms(event.BuildDuration),
			State: EventStateOK,
			Attributes: map[string]string{
				"pipeline":     event.PipelineName,
				"job":          event.JobName,
				"build_name":   event.BuildName,
				"build_id":     strconv.Itoa(event.BuildID),
				"build_status": string(event.BuildStatus),
				"team_name":    event.TeamName,
			},
		},
	)
}

func ms(duration time.Duration) float64 {
	return float64(duration) / 1000000
}

type ErrorLog struct {
	Message string
	Value   int
}

func (e ErrorLog) Emit(logger lager.Logger) {
	emit(
		logger.Session("error-log"),
		Event{
			Name:  "error log",
			Value: e.Value,
			State: EventStateWarning,
			Attributes: map[string]string{
				"message": e.Message,
			},
		},
	)
}

type HTTPResponseTime struct {
	Route      string
	Path       string
	Method     string
	StatusCode int
	Duration   time.Duration
}

func (event HTTPResponseTime) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > 100*time.Millisecond {
		state = EventStateWarning
	}

	if event.Duration > 1*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("http-response-time"),
		Event{
			Name:  "http response time",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"route":  event.Route,
				"path":   event.Path,
				"method": event.Method,
				"status": strconv.Itoa(event.StatusCode),
			},
		},
	)
}

type ResourceCheck struct {
	PipelineName string
	ResourceName string
	TeamName     string
	Success      bool
}

func (event ResourceCheck) Emit(logger lager.Logger) {
	state := EventStateOK
	if !event.Success {
		state = EventStateWarning
	}
	emit(
		logger.Session("resource-check"),
		Event{
			Name:  "resource checked",
			Value: 1,
			State: state,
			Attributes: map[string]string{
				"pipeline":  event.PipelineName,
				"resource":  event.ResourceName,
				"team_name": event.TeamName,
			},
		},
	)
}

type CheckFinished struct {
	ResourceConfigScopeID string
	CheckName             string
	Success               bool
}

func (event CheckFinished) Emit(logger lager.Logger) {
	state := EventStateOK
	if !event.Success {
		state = EventStateWarning
	}
	emit(
		logger.Session("check-finished"),
		Event{
			Name:  "check finished",
			Value: 1,
			State: state,
			Attributes: map[string]string{
				"scope_id":   event.ResourceConfigScopeID,
				"check_name": event.CheckName,
			},
		},
	)
}

var lockTypeNames = map[int]string{
	lock.LockTypeResourceConfigChecking: "ResourceConfigChecking",
	lock.LockTypeBuildTracking:          "BuildTracking",
	lock.LockTypePipelineScheduling:     "PipelineScheduling",
	lock.LockTypeBatch:                  "Batch",
	lock.LockTypeVolumeCreating:         "VolumeCreating",
	lock.LockTypeContainerCreating:      "ContainerCreating",
	lock.LockTypeDatabaseMigration:      "DatabaseMigration",
}

type LockAcquired struct {
	LockType string
}

func (event LockAcquired) Emit(logger lager.Logger) {
	emit(
		logger.Session("lock-acquired"),
		Event{
			Name:  "lock held",
			Value: 1,
			State: EventStateOK,
			Attributes: map[string]string{
				"type": event.LockType,
			},
		},
	)
}

type LockReleased struct {
	LockType string
}

func (event LockReleased) Emit(logger lager.Logger) {
	emit(
		logger.Session("lock-released"),
		Event{
			Name:  "lock held",
			Value: 0,
			State: EventStateOK,
			Attributes: map[string]string{
				"type": event.LockType,
			},
		},
	)
}

func LogLockAcquired(logger lager.Logger, lockID lock.LockID) {
	logger.Debug("acquired")

	if len(lockID) == 0 {
		return
	}

	if lockType, ok := lockTypeNames[lockID[0]]; ok {
		LockAcquired{LockType: lockType}.Emit(logger)
	}
}

func LogLockReleased(logger lager.Logger, lockID lock.LockID) {
	logger.Debug("released")

	if len(lockID) == 0 {
		return
	}

	if lockType, ok := lockTypeNames[lockID[0]]; ok {
		LockReleased{LockType: lockType}.Emit(logger)
	}
}

type WorkersState struct {
	WorkerStateByName map[string]db.WorkerState
}

func (event WorkersState) Emit(logger lager.Logger) {
	var (
		perStateCounter = map[db.WorkerState]int{}
		eventState      EventState
	)

	for _, workerState := range event.WorkerStateByName {
		_, exists := perStateCounter[workerState]
		if !exists {
			perStateCounter[workerState] = 1
			continue
		}

		perStateCounter[workerState] += 1
	}

	for state, count := range perStateCounter {
		if state == db.WorkerStateStalled && count > 0 {
			eventState = EventStateWarning
		} else {
			eventState = EventStateOK
		}

		emit(
			logger.Session("worker-state"),
			Event{
				Name:  "worker state",
				Value: count,
				State: eventState,
				Attributes: map[string]string{
					"state": string(state),
				},
			},
		)
	}
}
<commit_msg>Add forgotten metric for the active tasks locks and Resource Scanning.<commit_after>package metric

import (
	"strconv"
	"strings"
	"time"

	"github.com/concourse/concourse/atc/db/lock"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/concourse/atc/db"
)

var Databases []db.Conn
var DatabaseQueries = Meter(0)

var ContainersCreated = Meter(0)
var VolumesCreated = Meter(0)

var FailedContainers = Meter(0)
var FailedVolumes = Meter(0)

var ContainersDeleted = Meter(0)
var VolumesDeleted = Meter(0)

type SchedulingFullDuration struct {
	PipelineName string
	Duration     time.Duration
}

func (event SchedulingFullDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("full-scheduling-duration"),
		Event{
			Name:  "scheduling: full duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
			},
		},
	)
}

type SchedulingLoadVersionsDuration struct {
	PipelineName string
	Duration     time.Duration
}

func (event SchedulingLoadVersionsDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("loading-versions-duration"),
		Event{
			Name:  "scheduling: loading versions duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
			},
		},
	)
}

type SchedulingJobDuration struct {
	PipelineName string
	JobName      string
	Duration     time.Duration
}

func (event SchedulingJobDuration) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > time.Second {
		state = EventStateWarning
	}

	if event.Duration > 5*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("job-scheduling-duration"),
		Event{
			Name:  "scheduling: job duration (ms)",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"pipeline": event.PipelineName,
				"job":      event.JobName,
			},
		},
	)
}

type WorkerContainers struct {
	WorkerName string
	Platform   string
	Containers int
	TeamName   string
	Tags       []string
}

func (event WorkerContainers) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-containers"),
		Event{
			Name:  "worker containers",
			Value: event.Containers,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":    event.WorkerName,
				"platform":  event.Platform,
				"team_name": event.TeamName,
				"tags":      strings.Join(event.Tags[:], "/"),
			},
		},
	)
}

type WorkerVolumes struct {
	WorkerName string
	Platform   string
	Volumes    int
	TeamName   string
	Tags       []string
}

func (event WorkerVolumes) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-volumes"),
		Event{
			Name:  "worker volumes",
			Value: event.Volumes,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":    event.WorkerName,
				"platform":  event.Platform,
				"team_name": event.TeamName,
				"tags":      strings.Join(event.Tags[:], "/"),
			},
		},
	)
}

type WorkerTasks struct {
	WorkerName string
	Platform   string
	Tasks      int
}

func (event WorkerTasks) Emit(logger lager.Logger) {
	emit(
		logger.Session("worker-tasks"),
		Event{
			Name:  "worker tasks",
			Value: event.Tasks,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker":   event.WorkerName,
				"platform": event.Platform,
			},
		},
	)
}

type VolumesToBeGarbageCollected struct {
	Volumes int
}

func (event VolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-orphaned-volumes-for-deletion"),
		Event{
			Name:       "orphaned volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatingContainersToBeGarbageCollected struct {
	Containers int
}

func (event CreatingContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-creating-containers-for-deletion"),
		Event{
			Name:       "creating containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatedContainersToBeGarbageCollected struct {
	Containers int
}

func (event CreatedContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-created-ccontainers-for-deletion"),
		Event{
			Name:       "created containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type DestroyingContainersToBeGarbageCollected struct {
	Containers int
}

func (event DestroyingContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-destroying-containers-for-deletion"),
		Event{
			Name:       "destroying containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type FailedContainersToBeGarbageCollected struct {
	Containers int
}

func (event FailedContainersToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-failed-containers-for-deletion"),
		Event{
			Name:       "failed containers to be garbage collected",
			Value:      event.Containers,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type CreatedVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event CreatedVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-created-volumes-for-deletion"),
		Event{
			Name:       "created volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type DestroyingVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event DestroyingVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-destroying-volumes-for-deletion"),
		Event{
			Name:       "destroying volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type FailedVolumesToBeGarbageCollected struct {
	Volumes int
}

func (event FailedVolumesToBeGarbageCollected) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-found-failed-volumes-for-deletion"),
		Event{
			Name:       "failed volumes to be garbage collected",
			Value:      event.Volumes,
			State:      EventStateOK,
			Attributes: map[string]string{},
		},
	)
}

type GarbageCollectionContainerCollectorJobDropped struct {
	WorkerName string
}

func (event GarbageCollectionContainerCollectorJobDropped) Emit(logger lager.Logger) {
	emit(
		logger.Session("gc-container-collector-dropped"),
		Event{
			Name:  "GC container collector job dropped",
			Value: 1,
			State: EventStateOK,
			Attributes: map[string]string{
				"worker": event.WorkerName,
			},
		},
	)
}

type BuildStarted struct {
	PipelineName string
	JobName      string
	BuildName    string
	BuildID      int
	TeamName     string
}

func (event BuildStarted) Emit(logger lager.Logger) {
	emit(
		logger.Session("build-started"),
		Event{
			Name:  "build started",
			Value: event.BuildID,
			State: EventStateOK,
			Attributes: map[string]string{
				"pipeline":   event.PipelineName,
				"job":        event.JobName,
				"build_name": event.BuildName,
				"build_id":   strconv.Itoa(event.BuildID),
				"team_name":  event.TeamName,
			},
		},
	)
}

type BuildFinished struct {
	PipelineName  string
	JobName       string
	BuildName     string
	BuildID       int
	BuildStatus   db.BuildStatus
	BuildDuration time.Duration
	TeamName      string
}

func (event BuildFinished) Emit(logger lager.Logger) {
	emit(
		logger.Session("build-finished"),
		Event{
			Name:  "build finished",
			Value: ms(event.BuildDuration),
			State: EventStateOK,
			Attributes: map[string]string{
				"pipeline":     event.PipelineName,
				"job":          event.JobName,
				"build_name":   event.BuildName,
				"build_id":     strconv.Itoa(event.BuildID),
				"build_status": string(event.BuildStatus),
				"team_name":    event.TeamName,
			},
		},
	)
}

func ms(duration time.Duration) float64 {
	return float64(duration) / 1000000
}

type ErrorLog struct {
	Message string
	Value   int
}

func (e ErrorLog) Emit(logger lager.Logger) {
	emit(
		logger.Session("error-log"),
		Event{
			Name:  "error log",
			Value: e.Value,
			State: EventStateWarning,
			Attributes: map[string]string{
				"message": e.Message,
			},
		},
	)
}

type HTTPResponseTime struct {
	Route      string
	Path       string
	Method     string
	StatusCode int
	Duration   time.Duration
}

func (event HTTPResponseTime) Emit(logger lager.Logger) {
	state := EventStateOK

	if event.Duration > 100*time.Millisecond {
		state = EventStateWarning
	}

	if event.Duration > 1*time.Second {
		state = EventStateCritical
	}

	emit(
		logger.Session("http-response-time"),
		Event{
			Name:  "http response time",
			Value: ms(event.Duration),
			State: state,
			Attributes: map[string]string{
				"route":  event.Route,
				"path":   event.Path,
				"method": event.Method,
				"status": strconv.Itoa(event.StatusCode),
			},
		},
	)
}

type ResourceCheck struct {
	PipelineName string
	ResourceName string
	TeamName     string
	Success      bool
}

func (event ResourceCheck) Emit(logger lager.Logger) {
	state := EventStateOK
	if !event.Success {
		state = EventStateWarning
	}
	emit(
		logger.Session("resource-check"),
		Event{
			Name:  "resource checked",
			Value: 1,
			State: state,
			Attributes: map[string]string{
				"pipeline":  event.PipelineName,
				"resource":  event.ResourceName,
				"team_name": event.TeamName,
			},
		},
	)
}

type CheckFinished struct {
	ResourceConfigScopeID string
	CheckName             string
	Success               bool
}

func (event CheckFinished) Emit(logger lager.Logger) {
	state := EventStateOK
	if !event.Success {
		state = EventStateWarning
	}
	emit(
		logger.Session("check-finished"),
		Event{
			Name:  "check finished",
			Value: 1,
			State: state,
			Attributes: map[string]string{
				"scope_id":   event.ResourceConfigScopeID,
				"check_name": event.CheckName,
			},
		},
	)
}

var lockTypeNames = map[int]string{
	lock.LockTypeResourceConfigChecking: "ResourceConfigChecking",
	lock.LockTypeBuildTracking:          "BuildTracking",
	lock.LockTypePipelineScheduling:     "PipelineScheduling",
	lock.LockTypeBatch:                  "Batch",
	lock.LockTypeVolumeCreating:         "VolumeCreating",
	lock.LockTypeContainerCreating:      "ContainerCreating",
	lock.LockTypeDatabaseMigration:      "DatabaseMigration",
	lock.LockTypeActiveTasks:            "ActiveTasks",
	lock.LockTypeResourceScanning:       "ResourceScanning",
}

type LockAcquired struct {
	LockType string
}

func (event LockAcquired) Emit(logger lager.Logger) {
	emit(
		logger.Session("lock-acquired"),
		Event{
			Name:  "lock held",
			Value: 1,
			State: EventStateOK,
			Attributes: map[string]string{
				"type": event.LockType,
			},
		},
	)
}

type LockReleased struct {
	LockType string
}

func (event LockReleased) Emit(logger lager.Logger) {
	emit(
		logger.Session("lock-released"),
		Event{
			Name:  "lock held",
			Value: 0,
			State: EventStateOK,
			Attributes: map[string]string{
				"type": event.LockType,
			},
		},
	)
}

func LogLockAcquired(logger lager.Logger, lockID lock.LockID) {
	logger.Debug("acquired")

	if len(lockID) == 0 {
		return
	}

	if lockType, ok := lockTypeNames[lockID[0]]; ok {
		LockAcquired{LockType: lockType}.Emit(logger)
	}
}

func LogLockReleased(logger lager.Logger, lockID lock.LockID) {
	logger.Debug("released")

	if len(lockID) == 0 {
		return
	}

	if lockType, ok := lockTypeNames[lockID[0]]; ok {
		LockReleased{LockType: lockType}.Emit(logger)
	}
}

type WorkersState struct {
	WorkerStateByName map[string]db.WorkerState
}

func (event WorkersState) Emit(logger lager.Logger) {
	var (
		perStateCounter = map[db.WorkerState]int{}
		eventState      EventState
	)

	for _, workerState := range event.WorkerStateByName {
		_, exists := perStateCounter[workerState]
		if !exists {
			perStateCounter[workerState] = 1
			continue
		}

		perStateCounter[workerState] += 1
	}

	for state, count := range perStateCounter {
		if state == db.WorkerStateStalled && count > 0 {
			eventState = EventStateWarning
		} else {
			eventState = EventStateOK
		}

		emit(
			logger.Session("worker-state"),
			Event{
				Name:  "worker state",
				Value: count,
				State: eventState,
				Attributes: map[string]string{
					"state": string(state),
				},
			},
		)
	}
}
<|endoftext|>


<commit_before>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type exCommand struct {
	name string
	fn   func(*commandline, []string) continuity
}

// exComands represents a table of Ex commands and corresponding functions.
// The order is important. Preceding commands have higher precedence.
var exCommands = []exCommand{
	{"help", (*commandline).help},
	{"delete", (*commandline).delete},
	{"quit", (*commandline).quit},
	{"substitute", (*commandline).substitute},
}

type commandline struct {
	streamSet
	*editor

	basic *basic

	history [][]rune
	age     int
}

func newCommandline(s streamSet, e *editor) *commandline {
	return &commandline{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (e *commandline) Mode() mode {
	return modeCommandline
}

func (e *commandline) Position() int {
	return e.basic.pos + 1
}

func (e *commandline) Runes() []rune {
	return e.buf
}

func (e *commandline) Message() []rune {
	return append([]rune{':'}, e.basic.buf...)
}

func (e *commandline) Highlight() *screen.Hi {
	return nil
}

func (e *commandline) Run() (end continuity, next modeChanger, err error) {
	r, _, err := e.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
		end, err = e.execute()
		next = norm()

	case CharEscape, CharCtrlC:
		next = norm()

	case CharBackspace, CharCtrlH:
		if len(e.basic.buf) == 0 {
			next = norm()
			return
		}
		e.basic.delete(e.basic.pos-1, e.basic.pos)

	case CharCtrlB:
		e.basic.move(0)
	case CharCtrlE:
		e.basic.move(len(e.basic.buf))
	case CharCtrlN:
		e.historyForward()
	case CharCtrlP:
		e.historyBack()
	case CharCtrlU:
		e.basic.delete(0, e.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = e.basic.pos
		ed.buf = e.basic.buf
		pos := ed.pos
		ed.wordBackward()
		e.basic.delete(pos, ed.pos)
	default:
		e.basic.insert([]rune{r}, e.basic.pos)
	}
	return
}

func (e *commandline) execute() (end continuity, err error) {
	var candidate exCommand
	args := strings.Split(string(e.basic.buf), " ")
	s := args[0]
	if s == "" {
		return
	}
	args = args[1:]
	defer func() {
		e.history = append(e.history, e.basic.buf)
	}()
	for _, cmd := range exCommands {
		if !strings.HasPrefix(cmd.name, s) {
			continue
		}
		if cmd.name == s {
			end = cmd.fn(e, args)
			return
		}
		if candidate.name == "" {
			candidate = cmd
		}
	}
	if candidate.name != "" {
		end = candidate.fn(e, args)
		return
	}
	err = fmt.Errorf("not a command: %q", s)
	return
}

func (e *commandline) historyBack() {
	l := len(e.history)
	if l-e.age == 0 {
		return
	}
	e.age++
	e.basic.buf = e.history[l-e.age]
}

func (e *commandline) historyForward() {
	l := len(e.history)
	if e.age == 0 {
		return
	}
	e.age--
	e.basic.buf = e.history[l-e.age]
}

func (e *commandline) quit(args []string) continuity {
	return exit
}

func (e *commandline) delete(args []string) (_ continuity) {
	e.editor.delete(0, len(e.editor.buf))
	return
}

func (e *commandline) help(args []string) continuity {
	e.buf = []rune("help")
	e.pos = 4
	return execute
}

func (e *commandline) substitute(args []string) (_ continuity) {
	if len(args) != 2 {
		return
	}
	pat := args[0]
	s0 := args[1]
	s := strings.Replace(string(e.buf), pat, s0, -1)
	e.buf = []rune(s)
	return
}
<commit_msg>Add comment<commit_after>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type exCommand struct {
	name string
	fn   func(*commandline, []string) continuity
}

// exComands represents a table of Ex commands and corresponding functions.
// The order is important. Preceding commands have higher precedence.
var exCommands = []exCommand{
	{"help", (*commandline).help},
	{"delete", (*commandline).delete},
	{"quit", (*commandline).quit},
	{"substitute", (*commandline).substitute},
}

type commandline struct {
	streamSet
	*editor

	basic *basic

	// FIXME: currently live a moment.
	history [][]rune
	age     int
}

func newCommandline(s streamSet, e *editor) *commandline {
	return &commandline{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (e *commandline) Mode() mode {
	return modeCommandline
}

func (e *commandline) Position() int {
	return e.basic.pos + 1
}

func (e *commandline) Runes() []rune {
	return e.buf
}

func (e *commandline) Message() []rune {
	return append([]rune{':'}, e.basic.buf...)
}

func (e *commandline) Highlight() *screen.Hi {
	return nil
}

func (e *commandline) Run() (end continuity, next modeChanger, err error) {
	r, _, err := e.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
		end, err = e.execute()
		next = norm()

	case CharEscape, CharCtrlC:
		next = norm()

	case CharBackspace, CharCtrlH:
		if len(e.basic.buf) == 0 {
			next = norm()
			return
		}
		e.basic.delete(e.basic.pos-1, e.basic.pos)

	case CharCtrlB:
		e.basic.move(0)
	case CharCtrlE:
		e.basic.move(len(e.basic.buf))
	case CharCtrlN:
		e.historyForward()
	case CharCtrlP:
		e.historyBack()
	case CharCtrlU:
		e.basic.delete(0, e.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = e.basic.pos
		ed.buf = e.basic.buf
		pos := ed.pos
		ed.wordBackward()
		e.basic.delete(pos, ed.pos)
	default:
		e.basic.insert([]rune{r}, e.basic.pos)
	}
	return
}

func (e *commandline) execute() (end continuity, err error) {
	var candidate exCommand
	args := strings.Split(string(e.basic.buf), " ")
	s := args[0]
	if s == "" {
		return
	}
	args = args[1:]
	defer func() {
		e.history = append(e.history, e.basic.buf)
	}()
	for _, cmd := range exCommands {
		if !strings.HasPrefix(cmd.name, s) {
			continue
		}
		if cmd.name == s {
			end = cmd.fn(e, args)
			return
		}
		if candidate.name == "" {
			candidate = cmd
		}
	}
	if candidate.name != "" {
		end = candidate.fn(e, args)
		return
	}
	err = fmt.Errorf("not a command: %q", s)
	return
}

func (e *commandline) historyBack() {
	l := len(e.history)
	if l-e.age == 0 {
		return
	}
	e.age++
	e.basic.buf = e.history[l-e.age]
}

func (e *commandline) historyForward() {
	l := len(e.history)
	if e.age == 0 {
		return
	}
	e.age--
	e.basic.buf = e.history[l-e.age]
}

func (e *commandline) quit(args []string) continuity {
	return exit
}

func (e *commandline) delete(args []string) (_ continuity) {
	e.editor.delete(0, len(e.editor.buf))
	return
}

func (e *commandline) help(args []string) continuity {
	e.buf = []rune("help")
	e.pos = 4
	return execute
}

func (e *commandline) substitute(args []string) (_ continuity) {
	if len(args) != 2 {
		return
	}
	pat := args[0]
	s0 := args[1]
	s := strings.Replace(string(e.buf), pat, s0, -1)
	e.buf = []rune(s)
	return
}
<|endoftext|>


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

package saml

import (
	"fmt"

	"github.com/diego-araujo/go-saml"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/errors"
)

var (
	ErrRequestIdNotFound = &errors.ValidationError{Message: "Field attribute InResponseTo not found in saml response data"}
	ErrCheckSignature    = &errors.ValidationError{Message: "SAMLResponse signature validation"}
)

func getRequestIdFromResponse(r *saml.Response) (string, error) {
	var idRequest string
	if r.IsEncrypted() {
		idRequest = r.EncryptedAssertion.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.InResponseTo
	} else {
		idRequest = r.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.InResponseTo
	}
	if idRequest == "" {
		return "", ErrRequestIdNotFound
	}
	return idRequest, nil
}

func getUserIdentity(r *saml.Response) (string, error) {
	attrFriendlyNameIdentifier, err := config.GetString("auth:saml:idp-attribute-user-identity")
	if err != nil {
		return "", fmt.Errorf("error reading config auth:saml:idp-attribute-user-identity: %s ", err)
	}
	userIdentifier := r.GetAttribute(attrFriendlyNameIdentifier)
	if userIdentifier == "" {
		return "", fmt.Errorf("unable to parse identity provider data - not found  <Attribute FriendlyName=" + attrFriendlyNameIdentifier + "> ")
	}
	return userIdentifier, nil
}

func validateResponse(r *saml.Response, sp *saml.ServiceProviderSettings) error {
	if err := r.Validate(sp); err != nil {
		return err
	}
	if sp.IDPSignResponse {
		if err := r.ValidateResponseSignature(sp); err != nil {
			return err
		}
	}
	if err := r.ValidateExpiredConfirmation(sp); err != nil {
		return err
	}
	return nil
}
<commit_msg>auth/saml: update license year<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package saml

import (
	"fmt"

	"github.com/diego-araujo/go-saml"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/errors"
)

var (
	ErrRequestIdNotFound = &errors.ValidationError{Message: "Field attribute InResponseTo not found in saml response data"}
	ErrCheckSignature    = &errors.ValidationError{Message: "SAMLResponse signature validation"}
)

func getRequestIdFromResponse(r *saml.Response) (string, error) {
	var idRequest string
	if r.IsEncrypted() {
		idRequest = r.EncryptedAssertion.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.InResponseTo
	} else {
		idRequest = r.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.InResponseTo
	}
	if idRequest == "" {
		return "", ErrRequestIdNotFound
	}
	return idRequest, nil
}

func getUserIdentity(r *saml.Response) (string, error) {
	attrFriendlyNameIdentifier, err := config.GetString("auth:saml:idp-attribute-user-identity")
	if err != nil {
		return "", fmt.Errorf("error reading config auth:saml:idp-attribute-user-identity: %s ", err)
	}
	userIdentifier := r.GetAttribute(attrFriendlyNameIdentifier)
	if userIdentifier == "" {
		return "", fmt.Errorf("unable to parse identity provider data - not found  <Attribute FriendlyName=" + attrFriendlyNameIdentifier + "> ")
	}
	return userIdentifier, nil
}

func validateResponse(r *saml.Response, sp *saml.ServiceProviderSettings) error {
	if err := r.Validate(sp); err != nil {
		return err
	}
	if sp.IDPSignResponse {
		if err := r.ValidateResponseSignature(sp); err != nil {
			return err
		}
	}
	if err := r.ValidateExpiredConfirmation(sp); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package xparam

import "fmt"

//------------------------------------------------------------
// Xparam access for string
//------------------------------------------------------------

// Gets parameter as string.
func (xp XP) As_String(key string) (str string) {

	if val, ok := xp[key]; ok && val != nil {
		str = fmt.Sprint(val)
	}
	return
}

// Gets parameter as string pointer allowing for the nil option.
func (xp XP) As_StringNil(key string) (str *string) {

	if val, ok := xp[key]; ok && val != nil {
		s := fmt.Sprint(val)
		str = &s
	}
	return
}

// Sets parameter as string.
func (xp XP) To_String(to *map[string]string, key string) {
	if val, ok := xp[key]; ok && val != nil {
		str := fmt.Sprint(val)
		if str != "" {
			(*to)[key] = str
		}
	}
}
<commit_msg>strings auto trim space<commit_after>package xparam

import (
	"fmt"
	"strings"
)

//------------------------------------------------------------
// Xparam access for string
//------------------------------------------------------------

// Gets parameter as string.
func (xp XP) As_String(key string) (str string) {

	if val, ok := xp[key]; ok && val != nil {
		str = strings.TrimSpace(fmt.Sprint(val))
	}
	return
}

// Gets parameter as string pointer allowing for the nil option.
func (xp XP) As_StringNil(key string) (str *string) {

	if val, ok := xp[key]; ok && val != nil {
		s := strings.TrimSpace(fmt.Sprint(val))
		str = &s
	}
	return
}

// Sets parameter as string.
func (xp XP) To_String(to *map[string]string, key string) {
	if val, ok := xp[key]; ok && val != nil {
		str := strings.TrimSpace(fmt.Sprint(val))
		if str != "" {
			(*to)[key] = str
		}
	}
}
<|endoftext|>


<commit_before>// Package chrome provides Chrome-specific options for WebDriver.
package chrome

import (
	"bufio"
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/binary"
	"io"
	"os"

	"github.com/tebeka/selenium/internal/zip"
)

// CapabilitiesKey is the key in the top-level Capabilities map under which
// ChromeDriver expects the Chrome-specific options to be set.
const CapabilitiesKey = "chromeOptions"

// Capabilities defines the Chrome-specific desired capabilities when using
// ChromeDriver. An instance of this struct can be stored in the Capabilities
// map with a key of `chromeOptions`.  See
// https://sites.google.com/a/chromium.org/chromedriver/capabilities
type Capabilities struct {
	// Path is the file path to the Chrome binary to use.
	Path string `json:"binary,omitempty"`
	// Args are the command-line arguments to pass to the Chrome binary, in
	// addition to the ChromeDriver-supplied ones.
	Args []string `json:"args,omitempty"`
	// ExcludeSwitches are the command line flags that should be removed from
	// the ChromeDriver-supplied default flags. The strings included here should
	// not include a preceding '--'.
	ExcludeSwitches []string `json:"excludeSwitches,omitempty"`
	// Extensions are the list of extentions to install at startup. The
	// elements of this list should be the base-64, padded contents of a Chrome
	// extension file (.crx). Use the AddExtension method to add a local file.
	Extensions []string `json:"extensions,omitempty"`
	// LocalState are key/value pairs that are applied to the Local State file
	// in the user data folder.
	LocalState map[string]interface{} `json:"localState,omitempty"`
	// Prefs are the key/value pairs that are applied to the preferences of the
	// user profile in use.
	Prefs map[string]interface{} `json:"prefs,omitempty"`
	// Detatch, if true, will cause the browser to not be killed when
	// ChromeDriver quits if the session was not terminated.
	Detach *bool `json:"detach,omitempty"`
	// DebuggerAddr is the TCP/IP address of a Chrome debugger server to connect
	// to.
	DebuggerAddr string `json:"debuggerAddress,omitempty"`
	// MinidumpPath specifies the directory in which to store Chrome minidumps.
	// (This is only available on Linux).
	MinidumpPath string `json:"minidumpPath,omitempty"`
	// MobileEmulation provides options for mobile emulation.
	MobileEmulation *MobileEmulation `json:"mobileEmulation,omitempty"`
	// PerfLoggingPrefs specifies options for performance logging.
	PerfLoggingPrefs *PerfLoggingPreferences `json:"perfLoggingPrefs,omitempty"`
	// WindowTypes is a list of window types that will appear in the list of
	// window handles. For access to <webview> elements, include "webview" in
	// this list.
	WindowTypes []string `json:"windowTypes,omitempty"`
}

// TODO(minusnine): https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
// mentions "experimental options". Implement that.

// MobileEmulation provides options for mobile emulation. Only
// DeviceName or both of DeviceMetrics and UserAgent may be set at once.
type MobileEmulation struct {
	// DeviceName is the name of the device to emulate, e.g. "Google Nexus 5".
	// It should not be set if DeviceMetrics and UserAgent are set.
	DeviceName string `json:"deviceName,omitempty"`
	// DeviceMetrics provides specifications of an device to emulate. It should
	// not be set if DeviceName is set.
	DeviceMetrics *DeviceMetrics `json:"deviceMetrics,omitempty"`
	// UserAgent specifies the user agent string to send to the remote web
	// server.
	UserAgent string `json:"userAgent,omitempty"`
}

// DeviceMetrics specifies device attributes for emulation.
type DeviceMetrics struct {
	// Width is the width of the screen.
	Width uint `json:"width"`
	// Height is the height of the screen.
	Height uint `json:"height"`
	// PixelRatio is the pixel ratio of the screen.
	PixelRatio float64 `json:"pixelRatio"`
	// Touch indicates whether to emulate touch events. The default is true, if
	// unset.
	Touch *bool `json:"touch,omitempty"`
}

// PerfLoggingPreferences specifies configuration options for performance
// logging.
type PerfLoggingPreferences struct {
	// EnableNetwork specifies whether of not to collect events from the Network
	// domain. The default is true.
	EnableNetwork *bool `json:"enableNetwork,omitempty"`
	// EnablePage specifies whether or not to collect events from the Page
	// domain. The default is true.
	EnablePage *bool `json:"enablePage,omitempty"`
	// EnableTimeline specifies whether or not to collect events from the
	// Timeline domain. When tracing is enabled, Timeline domain is implicitly
	// disabled, unless enableTimeline is explicitly set to true.
	EnableTimeline *bool `json:"enableTimeline,omitempty"`
	// TracingCategories is a comma-separated string of Chrome tracing categories
	// for which trace events should be collected. An unspecified or empty string
	// disables tracing.
	TracingCategories string `json:"tracingCategories,omitempty"`
	// BufferUsageReportingIntervalMillis is the requested number of milliseconds
	// between DevTools trace buffer usage events. For example, if 1000, then
	// once per second, DevTools will report how full the trace buffer is. If a
	// report indicates the buffer usage is 100%, a warning will be issued.
	BufferUsageReportingIntervalMillis uint `json:"bufferUsageReportingInterval,omitempty"`
}

// AddExtension adds an extension for the browser to load at startup. The path
// parameter should be a path to an extension file (which typically has a
// `.crx` file extension. Note that the contents of the file will be loaded
// into memory, as required by the protocol.
func (c *Capabilities) AddExtension(path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return c.addExtension(f)
}

// addExtension reads a Chrome extension's data from r, base64-encodes it, and
// attaches it to the Capabilities instance.
func (c *Capabilities) addExtension(r io.Reader) error {
	var buf bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
	if _, err := io.Copy(encoder, bufio.NewReader(r)); err != nil {
		return err
	}
	encoder.Close()
	c.Extensions = append(c.Extensions, buf.String())
	return nil
}

// AddUnpackedExtension creates a packaged Chrome extension with the files
// below the provided directory path and causes the browser to load that
// extension at startup.
func (c *Capabilities) AddUnpackedExtension(basePath string) error {
	buf, _, err := NewExtension(basePath)
	if err != nil {
		return err
	}
	return c.addExtension(bytes.NewBuffer(buf))
}

// NewExtension creates the payload of a Chrome extension file which is signed
// using the returned private key.
func NewExtension(basePath string) ([]byte, *rsa.PrivateKey, error) {
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, nil, err
	}
	data, err := NewExtensionWithKey(basePath, key)
	if err != nil {
		return nil, nil, err
	}
	return data, key, nil
}

// NewExtensionWithKey creates the payload of a Chrome extension file which is
// signed by the provided private key.
func NewExtensionWithKey(basePath string, key *rsa.PrivateKey) ([]byte, error) {
	zip, err := zip.New(basePath)
	if err != nil {
		return nil, err
	}

	h := sha1.New()
	if _, err := io.Copy(h, bytes.NewReader(zip.Bytes())); err != nil {
		return nil, err
	}
	hashed := h.Sum(nil)

	signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA1, hashed[:])
	if err != nil {
		return nil, err
	}

	pubKey, err := x509.MarshalPKIXPublicKey(key.Public())
	if err != nil {
		return nil, err
	}

	// This format is documented at https://developer.chrome.com/extensions/crx .
	buf := new(bytes.Buffer)
	if _, err := buf.Write([]byte("Cr24")); err != nil { // Magic number.
		return nil, err
	}

	// Version.
	if err := binary.Write(buf, binary.LittleEndian, uint32(2)); err != nil {
		return nil, err
	}

	// Public key length.
	if err := binary.Write(buf, binary.LittleEndian, uint32(len(pubKey))); err != nil {
		return nil, err
	}
	// Signature length.
	if err := binary.Write(buf, binary.LittleEndian, uint32(len(signature))); err != nil {
		return nil, err
	}

	// Public key payload.
	if err := binary.Write(buf, binary.LittleEndian, pubKey); err != nil {
		return nil, err
	}

	// Signature payload.
	if err := binary.Write(buf, binary.LittleEndian, signature); err != nil {
		return nil, err
	}

	// Zipped extension directory payload.
	if err := binary.Write(buf, binary.LittleEndian, zip.Bytes()); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}
<commit_msg>Add android chrome functionality (#113)<commit_after>// Package chrome provides Chrome-specific options for WebDriver.
package chrome

import (
	"bufio"
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/binary"
	"io"
	"os"

	"github.com/tebeka/selenium/internal/zip"
)

// CapabilitiesKey is the key in the top-level Capabilities map under which
// ChromeDriver expects the Chrome-specific options to be set.
const CapabilitiesKey = "chromeOptions"

// Capabilities defines the Chrome-specific desired capabilities when using
// ChromeDriver. An instance of this struct can be stored in the Capabilities
// map with a key of `chromeOptions`.  See
// https://sites.google.com/a/chromium.org/chromedriver/capabilities
type Capabilities struct {
	// Path is the file path to the Chrome binary to use.
	Path string `json:"binary,omitempty"`
	// Args are the command-line arguments to pass to the Chrome binary, in
	// addition to the ChromeDriver-supplied ones.
	Args []string `json:"args,omitempty"`
	// ExcludeSwitches are the command line flags that should be removed from
	// the ChromeDriver-supplied default flags. The strings included here should
	// not include a preceding '--'.
	ExcludeSwitches []string `json:"excludeSwitches,omitempty"`
	// Extensions are the list of extentions to install at startup. The
	// elements of this list should be the base-64, padded contents of a Chrome
	// extension file (.crx). Use the AddExtension method to add a local file.
	Extensions []string `json:"extensions,omitempty"`
	// LocalState are key/value pairs that are applied to the Local State file
	// in the user data folder.
	LocalState map[string]interface{} `json:"localState,omitempty"`
	// Prefs are the key/value pairs that are applied to the preferences of the
	// user profile in use.
	Prefs map[string]interface{} `json:"prefs,omitempty"`
	// Detatch, if true, will cause the browser to not be killed when
	// ChromeDriver quits if the session was not terminated.
	Detach *bool `json:"detach,omitempty"`
	// DebuggerAddr is the TCP/IP address of a Chrome debugger server to connect
	// to.
	DebuggerAddr string `json:"debuggerAddress,omitempty"`
	// MinidumpPath specifies the directory in which to store Chrome minidumps.
	// (This is only available on Linux).
	MinidumpPath string `json:"minidumpPath,omitempty"`
	// MobileEmulation provides options for mobile emulation.
	MobileEmulation *MobileEmulation `json:"mobileEmulation,omitempty"`
	// PerfLoggingPrefs specifies options for performance logging.
	PerfLoggingPrefs *PerfLoggingPreferences `json:"perfLoggingPrefs,omitempty"`
	// WindowTypes is a list of window types that will appear in the list of
	// window handles. For access to <webview> elements, include "webview" in
	// this list.
	WindowTypes []string `json:"windowTypes,omitempty"`
	// Android Chrome WebDriver path "com.android.chrome"
	AndroidPackage string `json:"androidPackage,omitempty"`
}

// TODO(minusnine): https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
// mentions "experimental options". Implement that.

// MobileEmulation provides options for mobile emulation. Only
// DeviceName or both of DeviceMetrics and UserAgent may be set at once.
type MobileEmulation struct {
	// DeviceName is the name of the device to emulate, e.g. "Google Nexus 5".
	// It should not be set if DeviceMetrics and UserAgent are set.
	DeviceName string `json:"deviceName,omitempty"`
	// DeviceMetrics provides specifications of an device to emulate. It should
	// not be set if DeviceName is set.
	DeviceMetrics *DeviceMetrics `json:"deviceMetrics,omitempty"`
	// UserAgent specifies the user agent string to send to the remote web
	// server.
	UserAgent string `json:"userAgent,omitempty"`
}

// DeviceMetrics specifies device attributes for emulation.
type DeviceMetrics struct {
	// Width is the width of the screen.
	Width uint `json:"width"`
	// Height is the height of the screen.
	Height uint `json:"height"`
	// PixelRatio is the pixel ratio of the screen.
	PixelRatio float64 `json:"pixelRatio"`
	// Touch indicates whether to emulate touch events. The default is true, if
	// unset.
	Touch *bool `json:"touch,omitempty"`
}

// PerfLoggingPreferences specifies configuration options for performance
// logging.
type PerfLoggingPreferences struct {
	// EnableNetwork specifies whether of not to collect events from the Network
	// domain. The default is true.
	EnableNetwork *bool `json:"enableNetwork,omitempty"`
	// EnablePage specifies whether or not to collect events from the Page
	// domain. The default is true.
	EnablePage *bool `json:"enablePage,omitempty"`
	// EnableTimeline specifies whether or not to collect events from the
	// Timeline domain. When tracing is enabled, Timeline domain is implicitly
	// disabled, unless enableTimeline is explicitly set to true.
	EnableTimeline *bool `json:"enableTimeline,omitempty"`
	// TracingCategories is a comma-separated string of Chrome tracing categories
	// for which trace events should be collected. An unspecified or empty string
	// disables tracing.
	TracingCategories string `json:"tracingCategories,omitempty"`
	// BufferUsageReportingIntervalMillis is the requested number of milliseconds
	// between DevTools trace buffer usage events. For example, if 1000, then
	// once per second, DevTools will report how full the trace buffer is. If a
	// report indicates the buffer usage is 100%, a warning will be issued.
	BufferUsageReportingIntervalMillis uint `json:"bufferUsageReportingInterval,omitempty"`
}

// AddExtension adds an extension for the browser to load at startup. The path
// parameter should be a path to an extension file (which typically has a
// `.crx` file extension. Note that the contents of the file will be loaded
// into memory, as required by the protocol.
func (c *Capabilities) AddExtension(path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return c.addExtension(f)
}

// addExtension reads a Chrome extension's data from r, base64-encodes it, and
// attaches it to the Capabilities instance.
func (c *Capabilities) addExtension(r io.Reader) error {
	var buf bytes.Buffer
	encoder := base64.NewEncoder(base64.StdEncoding, &buf)
	if _, err := io.Copy(encoder, bufio.NewReader(r)); err != nil {
		return err
	}
	encoder.Close()
	c.Extensions = append(c.Extensions, buf.String())
	return nil
}

// AddUnpackedExtension creates a packaged Chrome extension with the files
// below the provided directory path and causes the browser to load that
// extension at startup.
func (c *Capabilities) AddUnpackedExtension(basePath string) error {
	buf, _, err := NewExtension(basePath)
	if err != nil {
		return err
	}
	return c.addExtension(bytes.NewBuffer(buf))
}

// NewExtension creates the payload of a Chrome extension file which is signed
// using the returned private key.
func NewExtension(basePath string) ([]byte, *rsa.PrivateKey, error) {
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, nil, err
	}
	data, err := NewExtensionWithKey(basePath, key)
	if err != nil {
		return nil, nil, err
	}
	return data, key, nil
}

// NewExtensionWithKey creates the payload of a Chrome extension file which is
// signed by the provided private key.
func NewExtensionWithKey(basePath string, key *rsa.PrivateKey) ([]byte, error) {
	zip, err := zip.New(basePath)
	if err != nil {
		return nil, err
	}

	h := sha1.New()
	if _, err := io.Copy(h, bytes.NewReader(zip.Bytes())); err != nil {
		return nil, err
	}
	hashed := h.Sum(nil)

	signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA1, hashed[:])
	if err != nil {
		return nil, err
	}

	pubKey, err := x509.MarshalPKIXPublicKey(key.Public())
	if err != nil {
		return nil, err
	}

	// This format is documented at https://developer.chrome.com/extensions/crx .
	buf := new(bytes.Buffer)
	if _, err := buf.Write([]byte("Cr24")); err != nil { // Magic number.
		return nil, err
	}

	// Version.
	if err := binary.Write(buf, binary.LittleEndian, uint32(2)); err != nil {
		return nil, err
	}

	// Public key length.
	if err := binary.Write(buf, binary.LittleEndian, uint32(len(pubKey))); err != nil {
		return nil, err
	}
	// Signature length.
	if err := binary.Write(buf, binary.LittleEndian, uint32(len(signature))); err != nil {
		return nil, err
	}

	// Public key payload.
	if err := binary.Write(buf, binary.LittleEndian, pubKey); err != nil {
		return nil, err
	}

	// Signature payload.
	if err := binary.Write(buf, binary.LittleEndian, signature); err != nil {
		return nil, err
	}

	// Zipped extension directory payload.
	if err := binary.Write(buf, binary.LittleEndian, zip.Bytes()); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"io"
	"os"
	"strings"
	"time"
	"xd/lib/sync"
	//t "xd/lib/translate"
)

var mtx sync.Mutex

type logLevel int

const (
	debug = logLevel(0)
	info  = logLevel(1)
	warn  = logLevel(2)
	err   = logLevel(3)
	fatal = logLevel(4)
)

func (l logLevel) Int() int {
	return int(l)
}

func (l logLevel) Name() string {

	switch l {
	case debug:
		return "DBG"
	case info:
		return "NFO"
	case warn:
		return "WRN"
	case err:
		return "ERR"
	case fatal:
		return "FTL"
	default:
		return "???"
	}

}

var level = info

// SetLevel sets global logger level
func SetLevel(l string) {
	l = strings.ToLower(l)
	if l == "debug" {
		level = debug
	} else {
		level = info
	}
}

var out io.Writer = os.Stdout

// SetOutput sets logging to output to a writer
func SetOutput(w io.Writer) {
	out = w
}

func accept(lvl logLevel) bool {
	return lvl.Int() >= level.Int()
}

func log(lvl logLevel, f string, args ...interface{}) {
	if accept(lvl) {
		m := fmt.Sprintf(f, args...)
		t := time.Now()
		mtx.Lock()
		fmt.Fprintf(out, "%s[%s] %s\t%s%s", lvl.Color(), lvl.Name(), t, m, colorReset)
		fmt.Fprintln(out)
		mtx.Unlock()
		if lvl == fatal {
			panic(m)
		}
	}
}

// Debug prints debug message
func Debug(msg string) {
	log(debug, msg)
}

// Debugf prints formatted debug message
func Debugf(f string, args ...interface{}) {
	log(debug, f, args...)
}

// Info prints info log message
func Info(msg string) {
	log(info, msg)
}

// Infof prints formatted info log message
func Infof(f string, args ...interface{}) {
	log(info, f, args...)
}

// Warn prints warn log message
func Warn(msg string) {
	log(warn, msg)
}

// Warnf prints formatted warn log message
func Warnf(f string, args ...interface{}) {
	log(warn, f, args...)
}

// Error prints error log message
func Error(msg string) {
	log(err, msg)
}

// Errorf prints formatted error log message
func Errorf(f string, args ...interface{}) {
	log(err, f, args...)
}

// Fatal print fatal error and panic
func Fatal(msg string) {
	log(fatal, msg)
}

// Fatalf print formatted fatal error and panic
func Fatalf(f string, args ...interface{}) {
	log(fatal, f, args...)
}
<commit_msg>log: parse all possible log strings from config<commit_after>package log

import (
	"fmt"
	"io"
	"os"
	"strings"
	"time"
	"xd/lib/sync"
	//t "xd/lib/translate"
)

var mtx sync.Mutex

type logLevel int

const (
	debug = logLevel(0)
	info  = logLevel(1)
	warn  = logLevel(2)
	err   = logLevel(3)
	fatal = logLevel(4)
)

func (l logLevel) Int() int {
	return int(l)
}

func (l logLevel) Name() string {

	switch l {
	case debug:
		return "DBG"
	case info:
		return "NFO"
	case warn:
		return "WRN"
	case err:
		return "ERR"
	case fatal:
		return "FTL"
	default:
		return "???"
	}

}

var level = info

// SetLevel sets global logger level
func SetLevel(l string) {
	l = strings.ToLower(l)
	if l == "debug" {
		level = debug
	} else if l == "info"{
		level = info
	} else if l == "warn"{
		level = warn
	} else if l == "err"{
		level = err
	} else if l == "fatal"{
		level = fatal
	} else {
		panic(fmt.Sprintf("invalid log level: '%s'", l))
	}
}

var out io.Writer = os.Stdout

// SetOutput sets logging to output to a writer
func SetOutput(w io.Writer) {
	out = w
}

func accept(lvl logLevel) bool {
	return lvl.Int() >= level.Int()
}

func log(lvl logLevel, f string, args ...interface{}) {
	if accept(lvl) {
		m := fmt.Sprintf(f, args...)
		t := time.Now()
		mtx.Lock()
		fmt.Fprintf(out, "%s[%s] %s\t%s%s", lvl.Color(), lvl.Name(), t, m, colorReset)
		fmt.Fprintln(out)
		mtx.Unlock()
		if lvl == fatal {
			panic(m)
		}
	}
}

// Debug prints debug message
func Debug(msg string) {
	log(debug, msg)
}

// Debugf prints formatted debug message
func Debugf(f string, args ...interface{}) {
	log(debug, f, args...)
}

// Info prints info log message
func Info(msg string) {
	log(info, msg)
}

// Infof prints formatted info log message
func Infof(f string, args ...interface{}) {
	log(info, f, args...)
}

// Warn prints warn log message
func Warn(msg string) {
	log(warn, msg)
}

// Warnf prints formatted warn log message
func Warnf(f string, args ...interface{}) {
	log(warn, f, args...)
}

// Error prints error log message
func Error(msg string) {
	log(err, msg)
}

// Errorf prints formatted error log message
func Errorf(f string, args ...interface{}) {
	log(err, f, args...)
}

// Fatal print fatal error and panic
func Fatal(msg string) {
	log(fatal, msg)
}

// Fatalf print formatted fatal error and panic
func Fatalf(f string, args ...interface{}) {
	log(fatal, f, args...)
}
<|endoftext|>


<commit_before>package irc

import (
	"fmt"
	"hash/fnv"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

const (
	timestampFormat = "15:04:05"
	alertSender     = "~!~"
	resetColors     = "\x1B[0m"
)

// TODO: Maybe use 256 color mode? \x1b[38;5;NUMBERm
var nickColors = []string{
	"\x1B[30m", "\x1B[30;1m", "\x1B[30;2m",
	"\x1B[31m", "\x1B[31;1m", "\x1B[31;2m",
	"\x1B[32m", "\x1B[32;1m", "\x1B[32;2m",
	"\x1B[33m", "\x1B[33;1m", "\x1B[33;2m",
	"\x1B[34m", "\x1B[34;1m", "\x1B[34;2m",
	"\x1B[35m", "\x1B[35;1m", "\x1B[35;2m",
	"\x1B[36m", "\x1B[36;1m", "\x1B[36;2m",
}

func colorizeNick(nick string) string {
	h := fnv.New32a()
	h.Write([]byte(nick))

	// Don't want negative indices, so do the mod on unsigned numbers.
	i := int(h.Sum32() % uint32(len(nickColors)))
	col := nickColors[i]

	return fmt.Sprintf("%s%15s%s", col, nick, resetColors)
}

func formatMessage(m *irc.Message) string {
	ts := time.Now().Format(timestampFormat)
	sender := alertSender
	line := fmt.Sprintf("%s %s", m.Command, m.Trailing())

	switch m.Command {
	case irc.PRIVMSG, irc.NOTICE:
		sender = colorizeNick(m.Prefix.Name)
		line = m.Trailing()

	case irc.RPL_TOPIC:
		sender = m.Prefix.Name
		line = fmt.Sprintf("%s: topic is \"%s\"", m.Params[1], m.Trailing())

	case irc.PING, irc.RPL_TOPICWHOTIME,
		irc.RPL_NAMREPLY, irc.RPL_ENDOFNAMES:
		// These are the skippable ones.
		return ""
	}

	return fmt.Sprintf("%s %s %s", ts, sender, line)

}
<commit_msg>Add formatting for JOIN/PART<commit_after>package irc

import (
	"fmt"
	"hash/fnv"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

const (
	timestampFormat = "15:04:05"
	alertSender     = "~!~"
	resetColors     = "\x1B[0m"
)

// TODO: Maybe use 256 color mode? \x1b[38;5;NUMBERm
var nickColors = []string{
	"\x1B[30m", "\x1B[30;1m", "\x1B[30;2m",
	"\x1B[31m", "\x1B[31;1m", "\x1B[31;2m",
	"\x1B[32m", "\x1B[32;1m", "\x1B[32;2m",
	"\x1B[33m", "\x1B[33;1m", "\x1B[33;2m",
	"\x1B[34m", "\x1B[34;1m", "\x1B[34;2m",
	"\x1B[35m", "\x1B[35;1m", "\x1B[35;2m",
	"\x1B[36m", "\x1B[36;1m", "\x1B[36;2m",
}

func colorizeNick(nick string) string {
	h := fnv.New32a()
	h.Write([]byte(nick))

	// Don't want negative indices, so do the mod on unsigned numbers.
	i := int(h.Sum32() % uint32(len(nickColors)))
	col := nickColors[i]

	return fmt.Sprintf("%s%15s%s", col, nick, resetColors)
}

func formatMessage(m *irc.Message) string {
	ts := time.Now().Format(timestampFormat)
	sender := alertSender
	line := fmt.Sprintf("%s %s", m.Command, m.Trailing())

	switch m.Command {
	case irc.PRIVMSG, irc.NOTICE:
		sender = colorizeNick(m.Prefix.Name)
		line = m.Trailing()

	case irc.RPL_TOPIC:
		sender = m.Prefix.Name
		line = fmt.Sprintf("%s: topic is \"%s\"", m.Params[1], m.Trailing())

	case irc.JOIN:
		nick := m.Prefix.Name
		line = fmt.Sprintf("%s joined", nick)

	case irc.PART:
		nick := m.Prefix.Name
		line = fmt.Sprintf("%s left: %s", nick, m.Trailing())

	case irc.PING, irc.RPL_TOPICWHOTIME,
		irc.RPL_NAMREPLY, irc.RPL_ENDOFNAMES:
		// These are the skippable ones.
		return ""
	}

	return fmt.Sprintf("%s %s %s", ts, sender, line)

}
<|endoftext|>


<commit_before>package plugin

import (
	log "github.com/Sirupsen/logrus"
	prom "github.com/prometheus/client_golang/prometheus"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"
	"zvr/utils"
)

// the name of metric data label
const (
	LABEL_VPC_INSTANCE = "instance"
)
type memCollector struct {
	memAvailable *prom.Desc
	memUsed *prom.Desc

	vmUUids  string
	instance string
}

type memInfo struct {
	watermark_low      uint64
	kb_Memtotal        uint64
	kb_Memfree         uint64
	kb_Buffer          uint64
	kb_Cached          uint64
	kb_InactiveFile    uint64
	kb_ActiveFile      uint64
	kb_SlabReclaimable uint64
}

func (c *memCollector) Describe(ch chan<- *prom.Desc) error {
	ch <- c.memAvailable
	ch <- c.memUsed
	return nil
}

func NewMemPrometheusCollector() MetricCollector {
	return &memCollector{
		memAvailable: prom.NewDesc(
			"vpc_memory_available",
			"available memory of VPC in bytes",
			[]string{LABEL_VPC_INSTANCE}, nil,
		),
		memUsed: prom.NewDesc(
			"vpc_memory_used",
			"memory of VPC allocated and unable to free in bytes",
			[]string{LABEL_VPC_INSTANCE}, nil,
		),

	}
}

func init() {
	RegisterPrometheusCollector(NewMemPrometheusCollector())
}

func getWaterMark_Low() uint64{
	infoFromFile, err := ioutil.ReadFile("/proc/sys/vm/min_free_kbytes")
	if err != nil {
		log.Error(err.Error())
		return 0
	}

	kb_min_free, _ :=  strconv.ParseUint(strings.Trim(string(infoFromFile), " "), 10, 64)

	watermark_low := kb_min_free * 5 / 4 /* should be equal to sum of all 'low' fields in /proc/zoneinfo */

	return watermark_low
}

/*
output example
# cat /proc/meminfo'
MemTotal:        7990336 kB
MemFree:         1228584 kB
MemAvailable:    2973840 kB
Buffers:            1072 kB
Cached:          1970788 kB
*/
func getVPCMemInfo() (*memInfo) {
	infoFromFile, err := ioutil.ReadFile("/proc/meminfo")
	if (err != nil ){
		log.Error(err.Error())
		return nil
	}
	stdout := string(infoFromFile)

	reg := regexp.MustCompile(`\s+`)
	lines := strings.Split(stdout, "\n")

	var memInfos memInfo
	memInfos.watermark_low= getWaterMark_Low()
	for _, line := range lines {
		strs := reg.Split(strings.TrimSpace(line), -1)
		strs[0] = strings.Trim(strs[0], ":")
		if (strs[0] == "MemTotal") {
			memInfos.kb_Memtotal, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "MemFree") {
			memInfos.kb_Memfree, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Buffers") {
			memInfos.kb_Buffer, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Cached") {
			memInfos.kb_Cached, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Active(file)") {
			memInfos.kb_Cached, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Inactive(file)") {
			memInfos.kb_Cached, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "SReclaimable") {
			memInfos.kb_SlabReclaimable, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		}
	}

	return &memInfos
}

func (c *memCollector) Update(ch chan <- prom.Metric ) error  {
	//mem_available = (signed long)kb_main_free - watermark_low
	//      + kb_inactive_file + kb_active_file - MIN((kb_inactive_file + kb_active_file) / 2, watermark_low)
	//      + kb_slab_reclaimable - MIN(kb_slab_reclaimable / 2, watermark_low);
	memInfo := getVPCMemInfo()
	if memInfo != nil {
		return nil
	}
	kb_mem_available := memInfo.kb_Memfree - memInfo.watermark_low +
			memInfo.kb_InactiveFile + memInfo.kb_ActiveFile + min((memInfo.kb_ActiveFile + memInfo.kb_InactiveFile)/2, memInfo.watermark_low)+
			memInfo.kb_SlabReclaimable + min((memInfo.kb_SlabReclaimable / 2),memInfo.watermark_low)

	vpcUuid := utils.GetVirtualRouterUuid()

	ch <- prom.MustNewConstMetric(c.memUsed,prom.GaugeValue, float64((memInfo.kb_Memtotal - kb_mem_available)*1024),vpcUuid)
	ch <- prom.MustNewConstMetric(c.memAvailable,prom.GaugeValue, float64((kb_mem_available)*1024),vpcUuid)

	return nil
}

func min(x, y uint64) uint64 {
	if x < y {
		return x
	}
	return y
}<commit_msg>fix-bug-24558<commit_after>package plugin

import (
	log "github.com/Sirupsen/logrus"
	prom "github.com/prometheus/client_golang/prometheus"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"
	"zvr/utils"
)

// the name of metric data label
const (
	LABEL_VPC_INSTANCE = "instance"
)
type memCollector struct {
	memAvailable *prom.Desc
	memUsed *prom.Desc

	vmUUids  string
	instance string
}

type memInfo struct {
	watermark_low      uint64
	kb_Memtotal        uint64
	kb_Memfree         uint64
	kb_Buffer          uint64
	kb_Cached          uint64
	kb_InactiveFile    uint64
	kb_ActiveFile      uint64
	kb_SlabReclaimable uint64
}

func (c *memCollector) Describe(ch chan<- *prom.Desc) error {
	ch <- c.memAvailable
	ch <- c.memUsed
	return nil
}

func NewMemPrometheusCollector() MetricCollector {
	return &memCollector{
		memAvailable: prom.NewDesc(
			"vpc_memory_available",
			"available memory of VPC in bytes",
			[]string{LABEL_VPC_INSTANCE}, nil,
		),
		memUsed: prom.NewDesc(
			"vpc_memory_used",
			"memory of VPC allocated and unable to free in bytes",
			[]string{LABEL_VPC_INSTANCE}, nil,
		),

	}
}

func init() {
	RegisterPrometheusCollector(NewMemPrometheusCollector())
}

func getWaterMark_Low() uint64{
	infoFromFile, err := ioutil.ReadFile("/proc/sys/vm/min_free_kbytes")
	if err != nil {
		log.Error(err.Error())
		return 0
	}

	kb_min_free, _ :=  strconv.ParseUint(strings.Trim(string(infoFromFile), " "), 10, 64)

	watermark_low := kb_min_free * 5 / 4 /* should be equal to sum of all 'low' fields in /proc/zoneinfo */

	return watermark_low
}

/*
output example
# cat /proc/meminfo'
MemTotal:        7990336 kB
MemFree:         1228584 kB
MemAvailable:    2973840 kB
Buffers:            1072 kB
Cached:          1970788 kB
*/
func getVPCMemInfo() (*memInfo) {
	infoFromFile, err := ioutil.ReadFile("/proc/meminfo")
	if (err != nil ){
		log.Error(err.Error())
		return nil
	}
	stdout := string(infoFromFile)

	reg := regexp.MustCompile(`\s+`)
	lines := strings.Split(stdout, "\n")

	var memInfos memInfo
	memInfos.watermark_low= getWaterMark_Low()
	for _, line := range lines {
		strs := reg.Split(strings.TrimSpace(line), -1)
		strs[0] = strings.Trim(strs[0], ":")
		if (strs[0] == "MemTotal") {
			memInfos.kb_Memtotal, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "MemFree") {
			memInfos.kb_Memfree, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Buffers") {
			memInfos.kb_Buffer, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Cached") {
			memInfos.kb_Cached, _ =strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Active(file)") {
			memInfos.kb_Cached, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "Inactive(file)") {
			memInfos.kb_Cached, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		} else if (strs[0] == "SReclaimable") {
			memInfos.kb_SlabReclaimable, _ = strconv.ParseUint(strings.Trim(strs[1], " "), 10, 64)
		}
	}

	return &memInfos
}

func (c *memCollector) Update(ch chan <- prom.Metric ) error  {
	//mem_available = (signed long)kb_main_free - watermark_low
	//      + kb_inactive_file + kb_active_file - MIN((kb_inactive_file + kb_active_file) / 2, watermark_low)
	//      + kb_slab_reclaimable - MIN(kb_slab_reclaimable / 2, watermark_low);
	memInfo := getVPCMemInfo()
	if memInfo == nil {
		return nil
	}
	kb_mem_available := memInfo.kb_Memfree - memInfo.watermark_low +
			memInfo.kb_InactiveFile + memInfo.kb_ActiveFile + min((memInfo.kb_ActiveFile + memInfo.kb_InactiveFile)/2, memInfo.watermark_low)+
			memInfo.kb_SlabReclaimable + min((memInfo.kb_SlabReclaimable / 2),memInfo.watermark_low)

	vpcUuid := utils.GetVirtualRouterUuid()

	ch <- prom.MustNewConstMetric(c.memUsed,prom.GaugeValue, float64((memInfo.kb_Memtotal - kb_mem_available)*1024),vpcUuid)
	ch <- prom.MustNewConstMetric(c.memAvailable,prom.GaugeValue, float64((kb_mem_available)*1024),vpcUuid)

	return nil
}

func min(x, y uint64) uint64 {
	if x < y {
		return x
	}
	return y
}<|endoftext|>


<commit_before>// Copyright 2013 Joyent Inc.
// Licensed under the AGPLv3, see LICENCE file for details.

package joyent

import (
	"fmt"
	"strings"
	"sync"

	"github.com/joyent/gosdc/cloudapi"
	"github.com/juju/errors"

	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/imagemetadata"
	"github.com/juju/juju/environs/simplestreams"
	"github.com/juju/juju/environs/tags"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/provider/common"
	"github.com/juju/juju/state"
)

// This file contains the core of the Joyent Environ implementation.

type joyentEnviron struct {
	common.SupportsUnitPlacementPolicy

	name string

	// supportedArchitectures caches the architectures
	// for which images can be instantiated.
	archLock               sync.Mutex
	supportedArchitectures []string

	// All mutating operations should lock the mutex. Non-mutating operations
	// should read all fields (other than name, which is immutable) from a
	// shallow copy taken with getSnapshot().
	// This advice is predicated on the goroutine-safety of the values of the
	// affected fields.
	lock    sync.Mutex
	ecfg    *environConfig
	compute *joyentCompute
}

var _ environs.Environ = (*joyentEnviron)(nil)
var _ state.Prechecker = (*joyentEnviron)(nil)

// newEnviron create a new Joyent environ instance from config.
func newEnviron(cfg *config.Config) (*joyentEnviron, error) {
	env := new(joyentEnviron)
	if err := env.SetConfig(cfg); err != nil {
		return nil, err
	}
	env.name = cfg.Name()
	var err error
	env.compute, err = newCompute(env.ecfg)
	if err != nil {
		return nil, err
	}
	return env, nil
}

func (env *joyentEnviron) SetName(envName string) {
	env.name = envName
}

func (*joyentEnviron) Provider() environs.EnvironProvider {
	return providerInstance
}

// PrecheckInstance is defined on the state.Prechecker interface.
func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error {
	if placement != "" {
		return fmt.Errorf("unknown placement directive: %s", placement)
	}
	if !cons.HasInstanceType() {
		return nil
	}
	// Constraint has an instance-type constraint so let's see if it is valid.
	instanceTypes, err := env.listInstanceTypes()
	if err != nil {
		return err
	}
	for _, instanceType := range instanceTypes {
		if instanceType.Name == *cons.InstanceType {
			return nil
		}
	}
	return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType)
}

// SupportedArchitectures is specified on the EnvironCapability interface.
func (env *joyentEnviron) SupportedArchitectures() ([]string, error) {
	env.archLock.Lock()
	defer env.archLock.Unlock()
	if env.supportedArchitectures != nil {
		return env.supportedArchitectures, nil
	}
	cfg := env.Ecfg()
	// Create a filter to get all images from our region and for the correct stream.
	cloudSpec := simplestreams.CloudSpec{
		Region:   cfg.Region(),
		Endpoint: cfg.SdcUrl(),
	}
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
		Stream:    cfg.ImageStream(),
	})
	var err error
	env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint)
	return env.supportedArchitectures, err
}

func (env *joyentEnviron) SetConfig(cfg *config.Config) error {
	env.lock.Lock()
	defer env.lock.Unlock()
	ecfg, err := providerInstance.newConfig(cfg)
	if err != nil {
		return err
	}
	env.ecfg = ecfg
	return nil
}

func (env *joyentEnviron) getSnapshot() *joyentEnviron {
	env.lock.Lock()
	clone := *env
	env.lock.Unlock()
	clone.lock = sync.Mutex{}
	return &clone
}

func (env *joyentEnviron) Config() *config.Config {
	return env.getSnapshot().ecfg.Config
}

func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) {
	return common.Bootstrap(ctx, env, args)
}

func (env *joyentEnviron) ControllerInstances() ([]instance.Id, error) {
	instanceIds := []instance.Id{}

	filter := cloudapi.NewFilter()
	filter.Set("tag.group", "juju")
	filter.Set("tag.env", env.Config().Name())
	filter.Set(tags.JujuController, "true")

	machines, err := env.compute.cloudapi.ListMachines(filter)
	if err != nil || len(machines) == 0 {
		return nil, environs.ErrNotBootstrapped
	}

	for _, m := range machines {
		if strings.EqualFold(m.State, "provisioning") || strings.EqualFold(m.State, "running") {
			copy := m
			ji := &joyentInstance{machine: &copy, env: env}
			instanceIds = append(instanceIds, ji.Id())
		}
	}

	return instanceIds, nil
}

func (env *joyentEnviron) Destroy() error {
	return errors.Trace(common.Destroy(env))
}

func (env *joyentEnviron) Ecfg() *environConfig {
	return env.getSnapshot().ecfg
}

// MetadataLookupParams returns parameters which are used to query simplestreams metadata.
func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
	if region == "" {
		region = env.Ecfg().Region()
	}
	return &simplestreams.MetadataLookupParams{
		Series:        config.PreferredSeries(env.Ecfg()),
		Region:        region,
		Endpoint:      env.Ecfg().sdcUrl(),
		Architectures: []string{"amd64", "armhf"},
	}, nil
}

// Region is specified in the HasRegion interface.
func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) {
	return simplestreams.CloudSpec{
		Region:   env.Ecfg().Region(),
		Endpoint: env.Ecfg().sdcUrl(),
	}, nil
}
<commit_msg>Filter controllers by uuid.<commit_after>// Copyright 2013 Joyent Inc.
// Licensed under the AGPLv3, see LICENCE file for details.

package joyent

import (
	"fmt"
	"strings"
	"sync"

	"github.com/joyent/gosdc/cloudapi"
	"github.com/juju/errors"

	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/imagemetadata"
	"github.com/juju/juju/environs/simplestreams"
	"github.com/juju/juju/environs/tags"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/provider/common"
	"github.com/juju/juju/state"
)

// This file contains the core of the Joyent Environ implementation.

type joyentEnviron struct {
	common.SupportsUnitPlacementPolicy

	name string

	// supportedArchitectures caches the architectures
	// for which images can be instantiated.
	archLock               sync.Mutex
	supportedArchitectures []string

	// All mutating operations should lock the mutex. Non-mutating operations
	// should read all fields (other than name, which is immutable) from a
	// shallow copy taken with getSnapshot().
	// This advice is predicated on the goroutine-safety of the values of the
	// affected fields.
	lock    sync.Mutex
	ecfg    *environConfig
	compute *joyentCompute
}

var _ environs.Environ = (*joyentEnviron)(nil)
var _ state.Prechecker = (*joyentEnviron)(nil)

// newEnviron create a new Joyent environ instance from config.
func newEnviron(cfg *config.Config) (*joyentEnviron, error) {
	env := new(joyentEnviron)
	if err := env.SetConfig(cfg); err != nil {
		return nil, err
	}
	env.name = cfg.Name()
	var err error
	env.compute, err = newCompute(env.ecfg)
	if err != nil {
		return nil, err
	}
	return env, nil
}

func (env *joyentEnviron) SetName(envName string) {
	env.name = envName
}

func (*joyentEnviron) Provider() environs.EnvironProvider {
	return providerInstance
}

// PrecheckInstance is defined on the state.Prechecker interface.
func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error {
	if placement != "" {
		return fmt.Errorf("unknown placement directive: %s", placement)
	}
	if !cons.HasInstanceType() {
		return nil
	}
	// Constraint has an instance-type constraint so let's see if it is valid.
	instanceTypes, err := env.listInstanceTypes()
	if err != nil {
		return err
	}
	for _, instanceType := range instanceTypes {
		if instanceType.Name == *cons.InstanceType {
			return nil
		}
	}
	return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType)
}

// SupportedArchitectures is specified on the EnvironCapability interface.
func (env *joyentEnviron) SupportedArchitectures() ([]string, error) {
	env.archLock.Lock()
	defer env.archLock.Unlock()
	if env.supportedArchitectures != nil {
		return env.supportedArchitectures, nil
	}
	cfg := env.Ecfg()
	// Create a filter to get all images from our region and for the correct stream.
	cloudSpec := simplestreams.CloudSpec{
		Region:   cfg.Region(),
		Endpoint: cfg.SdcUrl(),
	}
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
		Stream:    cfg.ImageStream(),
	})
	var err error
	env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint)
	return env.supportedArchitectures, err
}

func (env *joyentEnviron) SetConfig(cfg *config.Config) error {
	env.lock.Lock()
	defer env.lock.Unlock()
	ecfg, err := providerInstance.newConfig(cfg)
	if err != nil {
		return err
	}
	env.ecfg = ecfg
	return nil
}

func (env *joyentEnviron) getSnapshot() *joyentEnviron {
	env.lock.Lock()
	clone := *env
	env.lock.Unlock()
	clone.lock = sync.Mutex{}
	return &clone
}

func (env *joyentEnviron) Config() *config.Config {
	return env.getSnapshot().ecfg.Config
}

func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) {
	return common.Bootstrap(ctx, env, args)
}

func (env *joyentEnviron) ControllerInstances() ([]instance.Id, error) {
	instanceIds := []instance.Id{}

	filter := cloudapi.NewFilter()
	filter.Set("tag.group", "juju")
	filter.Set("tag.env", env.Config().Name())
	filter.Set(tags.JujuModel, env.Config().UUID())
	filter.Set(tags.JujuController, "true")

	machines, err := env.compute.cloudapi.ListMachines(filter)
	if err != nil || len(machines) == 0 {
		return nil, environs.ErrNotBootstrapped
	}

	for _, m := range machines {
		if strings.EqualFold(m.State, "provisioning") || strings.EqualFold(m.State, "running") {
			copy := m
			ji := &joyentInstance{machine: &copy, env: env}
			instanceIds = append(instanceIds, ji.Id())
		}
	}

	return instanceIds, nil
}

func (env *joyentEnviron) Destroy() error {
	return errors.Trace(common.Destroy(env))
}

func (env *joyentEnviron) Ecfg() *environConfig {
	return env.getSnapshot().ecfg
}

// MetadataLookupParams returns parameters which are used to query simplestreams metadata.
func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
	if region == "" {
		region = env.Ecfg().Region()
	}
	return &simplestreams.MetadataLookupParams{
		Series:        config.PreferredSeries(env.Ecfg()),
		Region:        region,
		Endpoint:      env.Ecfg().sdcUrl(),
		Architectures: []string{"amd64", "armhf"},
	}, nil
}

// Region is specified in the HasRegion interface.
func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) {
	return simplestreams.CloudSpec{
		Region:   env.Ecfg().Region(),
		Endpoint: env.Ecfg().sdcUrl(),
	}, nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Joyent Inc.
// Licensed under the AGPLv3, see LICENCE file for details.

package joyent

import (
	"io"

	"launchpad.net/juju-core/environs/storage"
	"launchpad.net/juju-core/utils"
	"fmt"
)

type environStorage struct {
	ecfg *environConfig
}

var _ storage.Storage = (*environStorage)(nil)

func newStorage(ecfg *environConfig) (storage.Storage, error) {
	return &environStorage{
		ecfg:			ecfg,
		containerName: 	ecfg.controlDir(),
		manta:        	manta.New(nil)}, nil
}

func (s *environStorage) List(prefix string) ([]string, error) {
	return nil, errNotImplemented
}

func (s *environStorage) URL(name string) (string, error) {
	return "", errNotImplemented
}

func (s *environStorage) Get(name string) (io.ReadCloser, error) {
	return nil, errNotImplemented
}

func (s *environStorage) Put(name string, r io.Reader, length int64) error {
	if err := s.makeContainer(s.containerName); err != nil {
		return fmt.Errorf("cannot make Manta control container: %v", err)
	}
	//obj := r.Read()
	err := s.manta.PutObject(s.containerName, name, r)
	if err != nil {
		return fmt.Errorf("cannot write file %q to control container %q: %v", name, s.containerName, err)
	}
	return nil
}

func (s *environStorage) Remove(name string) error {
	return errNotImplemented
}

func (s *environStorage) RemoveAll() error {
	return errNotImplemented
}

func (s *environStorage) DefaultConsistencyStrategy() utils.AttemptStrategy {
	return utils.AttemptStrategy{}
}

func (s *environStorage) ShouldRetry(err error) bool {
	return false
}
<commit_msg>Reverting storage.go changes<commit_after>// Copyright 2013 Joyent Inc.
// Licensed under the AGPLv3, see LICENCE file for details.

package joyent

import (
	"io"

	"launchpad.net/juju-core/environs/storage"
	"launchpad.net/juju-core/utils"
)

type environStorage struct {
	ecfg *environConfig
}

var _ storage.Storage = (*environStorage)(nil)

func newStorage(ecfg *environConfig) (storage.Storage, error) {
	return &environStorage{ecfg}, nil
}

func (s *environStorage) List(prefix string) ([]string, error) {
	return nil, errNotImplemented
}

func (s *environStorage) URL(name string) (string, error) {
	return "", errNotImplemented
}

func (s *environStorage) Get(name string) (io.ReadCloser, error) {
	return nil, errNotImplemented
}

func (s *environStorage) Put(name string, r io.Reader, length int64) error {
	return errNotImplemented
}

func (s *environStorage) Remove(name string) error {
	return errNotImplemented
}

func (s *environStorage) RemoveAll() error {
	return errNotImplemented
}

func (s *environStorage) DefaultConsistencyStrategy() utils.AttemptStrategy {
	return utils.AttemptStrategy{}
}

func (s *environStorage) ShouldRetry(err error) bool {
	return false
}
<|endoftext|>


<commit_before>// Package twitch implements the OAuth2 protocol for authenticating users through Twitch.
// This package can be used as a reference implementation of an OAuth2 provider for Twitch.
package twitch

import (
	"encoding/json"
	"io"
	"net/http"

	"fmt"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL      string = "https://api.twitch.tv/kraken/oauth2/authorize"
	tokenURL     string = "https://api.twitch.tv/kraken/oauth2/token"
	userEndpoint string = "https://api.twitch.tv/kraken/user"
)

const (
	// ScopeChannelCheckSubscription provides access to read whether a user is
	// subscribed to your channel.
	ScopeChannelCheckSubscription string = "channel_check_subscription"
	// ScopeChannelCommercial provides access to trigger commercials on
	// channel.
	ScopeChannelCommercial string = "channel_commercial"
	// ScopeChannelEditor provides access to write channel metadata
	// (game, status, etc).
	ScopeChannelEditor string = "channel_editor"
	// ScopeChannelFeedEdit provides access to add posts and reactions to a
	// channel feed.
	ScopeChannelFeedEdit string = "channel_feed_edit"
	// ScopeChannelFeedRead provides access to view a channel feed.
	ScopeChannelFeedRead string = "channel_feed_read"
	// ScopeChannelRead provides access to read nonpublic channel information,
	// including email address and stream key.
	ScopeChannelRead string = "channel_read"
	// ScopeChannelStream provides access to reset a channel’s stream key.
	ScopeChannelStream string = "channel_stream"
	// ScopeChannelSubscriptions provides access to read all subscribers to
	// your channel.
	ScopeChannelSubscriptions string = "channel_subscriptions"
	// ScopeCollectionsEdit provides access to manage a user’s collections
	// (of videos).
	ScopeCollectionsEdit string = "collections_edit"
	// ScopeCommunitiesEdit provides access to manage a user’s communities.
	ScopeCommunitiesEdit string = "communities_edit"
	// ScopeCommunitiesModerate provides access to manage community moderators.
	ScopeCommunitiesModerate string = "communities_moderate"
	// ScopeOpenID provides access to use OpenID Connect authentication.
	ScopeOpenID string = "openid"
	// ScopeUserBlocksEdit provides access to turn on/off ignoring a user.
	// Ignoring users means you cannot see them type, receive messages from
	// them, etc.
	ScopeUserBlocksEdit string = "user_blocks_edit"
	// ScopeUserBlocksRead provides access to read a user’s list of ignored
	// users.
	ScopeUserBlocksRead string = "user_blocks_read"
	// ScopeUserFollowsEdit provides access to manage a user’s followed
	// channels.
	ScopeUserFollowsEdit string = "user_follows_edit"
	// ScopeUserRead provides access to read nonpublic user information, like
	// email address.
	ScopeUserRead string = "user_read"
	// ScopeUserSubscriptions provides access to read a user’s subscriptions.
	ScopeUserSubscriptions string = "user_subscriptions"
	// ScopeViewingActivityRead provides access to turn on Viewer Heartbeat
	// Service ability to record user data.
	ScopeViewingActivityRead string = "viewing_activity_read"
)

// New creates a new Twitch provider, and sets up important connection details.
// You should always call `twitch.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey string, secret string, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "twitch",
	}
	p.config = newConfig(p, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Twitch
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
}

// Name gets the name used to retrieve this provider.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

// Client ...
func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is no-op for the Twitch package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Twitch for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	s := &Session{
		AuthURL: url,
	}
	return s, nil
}

// FetchUser will go to Twitch and access basic info about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {

	s := session.(*Session)

	user := goth.User{
		AccessToken:  s.AccessToken,
		Provider:     p.Name(),
		RefreshToken: s.RefreshToken,
		ExpiresAt:    s.ExpiresAt,
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	req, err := http.NewRequest("GET", userEndpoint, nil)
	if err != nil {
		return user, err
	}
	req.Header.Set("Accept", "application/vnd.twitchtv.v5+json")
	req.Header.Set("Authorization", "OAuth "+s.AccessToken)
	resp, err := p.Client().Do(req)
	if err != nil {
		return user, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, resp.StatusCode)
	}

	err = userFromReader(resp.Body, &user)
	return user, err
}

func userFromReader(r io.Reader, user *goth.User) error {
	u := struct {
		Name        string `json:"name"`
		Email       string `json:"email"`
		Nickname    string `json:"display_name"`
		AvatarURL   string `json:"logo"`
		Description string `json:"bio"`
		ID          string `json:"_id"`
	}{}

	err := json.NewDecoder(r).Decode(&u)
	if err != nil {
		return err
	}

	user.Name = u.Name
	user.Email = u.Email
	user.NickName = u.Nickname
	user.Location = "No location is provided by the Twitch API"
	user.AvatarURL = u.AvatarURL
	user.Description = u.Description
	user.UserID = u.ID

	return nil
}

func newConfig(p *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     p.ClientKey,
		ClientSecret: p.Secret,
		RedirectURL:  p.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	if len(scopes) > 0 {
		for _, scope := range scopes {
			c.Scopes = append(c.Scopes, scope)
		}
	} else {
		c.Scopes = []string{ScopeUserRead}
	}

	return c
}

//RefreshTokenAvailable refresh token is provided by auth provider or not
func (p *Provider) RefreshTokenAvailable() bool {
	return true
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	token := &oauth2.Token{RefreshToken: refreshToken}
	ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token)
	newToken, err := ts.Token()
	if err != nil {
		return nil, err
	}
	return newToken, err
}
<commit_msg>Re-include the deprecated chat_login scope<commit_after>// Package twitch implements the OAuth2 protocol for authenticating users through Twitch.
// This package can be used as a reference implementation of an OAuth2 provider for Twitch.
package twitch

import (
	"encoding/json"
	"io"
	"net/http"

	"fmt"

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

const (
	authURL      string = "https://api.twitch.tv/kraken/oauth2/authorize"
	tokenURL     string = "https://api.twitch.tv/kraken/oauth2/token"
	userEndpoint string = "https://api.twitch.tv/kraken/user"
)

const (
	// ScopeChannelCheckSubscription provides access to read whether a user is
	// subscribed to your channel.
	ScopeChannelCheckSubscription string = "channel_check_subscription"
	// ScopeChannelCommercial provides access to trigger commercials on
	// channel.
	ScopeChannelCommercial string = "channel_commercial"
	// ScopeChannelEditor provides access to write channel metadata
	// (game, status, etc).
	ScopeChannelEditor string = "channel_editor"
	// ScopeChannelFeedEdit provides access to add posts and reactions to a
	// channel feed.
	ScopeChannelFeedEdit string = "channel_feed_edit"
	// ScopeChannelFeedRead provides access to view a channel feed.
	ScopeChannelFeedRead string = "channel_feed_read"
	// ScopeChannelRead provides access to read nonpublic channel information,
	// including email address and stream key.
	ScopeChannelRead string = "channel_read"
	// ScopeChannelStream provides access to reset a channel’s stream key.
	ScopeChannelStream string = "channel_stream"
	// ScopeChannelSubscriptions provides access to read all subscribers to
	// your channel.
	ScopeChannelSubscriptions string = "channel_subscriptions"
	// ScopeCollectionsEdit provides access to manage a user’s collections
	// (of videos).
	ScopeCollectionsEdit string = "collections_edit"
	// ScopeCommunitiesEdit provides access to manage a user’s communities.
	ScopeCommunitiesEdit string = "communities_edit"
	// ScopeCommunitiesModerate provides access to manage community moderators.
	ScopeCommunitiesModerate string = "communities_moderate"
	// ScopeOpenID provides access to use OpenID Connect authentication.
	ScopeOpenID string = "openid"
	// ScopeUserBlocksEdit provides access to turn on/off ignoring a user.
	// Ignoring users means you cannot see them type, receive messages from
	// them, etc.
	ScopeUserBlocksEdit string = "user_blocks_edit"
	// ScopeUserBlocksRead provides access to read a user’s list of ignored
	// users.
	ScopeUserBlocksRead string = "user_blocks_read"
	// ScopeUserFollowsEdit provides access to manage a user’s followed
	// channels.
	ScopeUserFollowsEdit string = "user_follows_edit"
	// ScopeUserRead provides access to read nonpublic user information, like
	// email address.
	ScopeUserRead string = "user_read"
	// ScopeUserSubscriptions provides access to read a user’s subscriptions.
	ScopeUserSubscriptions string = "user_subscriptions"
	// ScopeViewingActivityRead provides access to turn on Viewer Heartbeat
	// Service ability to record user data.
	ScopeViewingActivityRead string = "viewing_activity_read"
	// ScopeChatLogin (Deprecated — cannot be requested by new clients.) Log
	// into chat and send messages.
	ScopeChatLogin string = "chat_login"
)

// New creates a new Twitch provider, and sets up important connection details.
// You should always call `twitch.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey string, secret string, callbackURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "twitch",
	}
	p.config = newConfig(p, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Twitch
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
}

// Name gets the name used to retrieve this provider.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

// Client ...
func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is no-op for the Twitch package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Twitch for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	s := &Session{
		AuthURL: url,
	}
	return s, nil
}

// FetchUser will go to Twitch and access basic info about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {

	s := session.(*Session)

	user := goth.User{
		AccessToken:  s.AccessToken,
		Provider:     p.Name(),
		RefreshToken: s.RefreshToken,
		ExpiresAt:    s.ExpiresAt,
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	req, err := http.NewRequest("GET", userEndpoint, nil)
	if err != nil {
		return user, err
	}
	req.Header.Set("Accept", "application/vnd.twitchtv.v5+json")
	req.Header.Set("Authorization", "OAuth "+s.AccessToken)
	resp, err := p.Client().Do(req)
	if err != nil {
		return user, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, resp.StatusCode)
	}

	err = userFromReader(resp.Body, &user)
	return user, err
}

func userFromReader(r io.Reader, user *goth.User) error {
	u := struct {
		Name        string `json:"name"`
		Email       string `json:"email"`
		Nickname    string `json:"display_name"`
		AvatarURL   string `json:"logo"`
		Description string `json:"bio"`
		ID          string `json:"_id"`
	}{}

	err := json.NewDecoder(r).Decode(&u)
	if err != nil {
		return err
	}

	user.Name = u.Name
	user.Email = u.Email
	user.NickName = u.Nickname
	user.Location = "No location is provided by the Twitch API"
	user.AvatarURL = u.AvatarURL
	user.Description = u.Description
	user.UserID = u.ID

	return nil
}

func newConfig(p *Provider, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     p.ClientKey,
		ClientSecret: p.Secret,
		RedirectURL:  p.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	if len(scopes) > 0 {
		for _, scope := range scopes {
			c.Scopes = append(c.Scopes, scope)
		}
	} else {
		c.Scopes = []string{ScopeUserRead}
	}

	return c
}

//RefreshTokenAvailable refresh token is provided by auth provider or not
func (p *Provider) RefreshTokenAvailable() bool {
	return true
}

//RefreshToken get new access token based on the refresh token
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	token := &oauth2.Token{RefreshToken: refreshToken}
	ts := p.config.TokenSource(goth.ContextForClient(p.Client()), token)
	newToken, err := ts.Token()
	if err != nil {
		return nil, err
	}
	return newToken, err
}
<|endoftext|>