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

package rules

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"path/filepath"
	"sync"
	"time"

	html_template "html/template"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/model"

	"github.com/prometheus/prometheus/config"
	"github.com/prometheus/prometheus/notification"
	"github.com/prometheus/prometheus/promql"
	"github.com/prometheus/prometheus/storage"
	"github.com/prometheus/prometheus/template"
	"github.com/prometheus/prometheus/util/strutil"
)

// Constants for instrumentation.
const (
	namespace = "prometheus"

	ruleTypeLabel = "rule_type"
)

var (
	evalDuration = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: namespace,
			Name:      "rule_evaluation_duration_seconds",
			Help:      "The duration for a rule to execute.",
		},
		[]string{ruleTypeLabel},
	)
	evalFailures = prometheus.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_evaluation_failures_total",
			Help:      "The total number of rule evaluation failures.",
		},
	)
	evalTotal = prometheus.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_evaluations_total",
			Help:      "The total number of rule evaluations.",
		},
	)
	iterationDuration = prometheus.NewSummary(prometheus.SummaryOpts{
		Namespace:  namespace,
		Name:       "evaluator_duration_seconds",
		Help:       "The duration for all evaluations to execute.",
		Objectives: map[float64]float64{0.01: 0.001, 0.05: 0.005, 0.5: 0.05, 0.90: 0.01, 0.99: 0.001},
	})
)

func init() {
	prometheus.MustRegister(iterationDuration)
	prometheus.MustRegister(evalFailures)
	prometheus.MustRegister(evalDuration)
}

type ruleType string

const (
	ruleTypeAlert     = "alerting"
	ruleTypeRecording = "recording"
)

// A Rule encapsulates a vector expression which is evaluated at a specified
// interval and acted upon (currently either recorded or used for alerting).
type Rule interface {
	Name() string
	// eval evaluates the rule, including any associated recording or alerting actions.
	eval(model.Time, *promql.Engine) (model.Vector, error)
	// String returns a human-readable string representation of the rule.
	String() string
	// HTMLSnippet returns a human-readable string representation of the rule,
	// decorated with HTML elements for use the web frontend.
	HTMLSnippet(pathPrefix string) html_template.HTML
}

// Group is a set of rules that have a logical relation.
type Group struct {
	name     string
	interval time.Duration
	rules    []Rule
	opts     *ManagerOptions

	done       chan struct{}
	terminated chan struct{}
}

func newGroup(name string, opts *ManagerOptions) *Group {
	return &Group{
		name:       name,
		opts:       opts,
		done:       make(chan struct{}),
		terminated: make(chan struct{}),
	}
}

func (g *Group) run() {
	defer close(g.terminated)

	// Wait an initial amount to have consistently slotted intervals.
	time.Sleep(g.offset())

	iter := func() {
		start := time.Now()
		g.eval()

		iterationDuration.Observe(float64(time.Since(start)) / float64(time.Millisecond))
	}
	iter()

	tick := time.NewTicker(g.interval)
	defer tick.Stop()

	for {
		select {
		case <-g.done:
			return
		default:
			select {
			case <-g.done:
				return
			case <-tick.C:
				iter()
			}
		}
	}
}

func (g *Group) stop() {
	close(g.done)
	<-g.terminated
}

func (g *Group) fingerprint() model.Fingerprint {
	l := model.LabelSet{"name": model.LabelValue(g.name)}
	return l.Fingerprint()
}

// offset returns until the next consistently slotted evaluation interval.
func (g *Group) offset() time.Duration {
	now := time.Now().UnixNano()

	var (
		base   = now - (now % int64(g.interval))
		offset = uint64(g.fingerprint()) % uint64(g.interval)
		next   = base + int64(offset)
	)

	if next < now {
		next += int64(g.interval)
	}
	return time.Duration(next - now)
}

// copyState copies the alerting rule state from the given group.
func (g *Group) copyState(from *Group) {
	for _, fromRule := range from.rules {
		far, ok := fromRule.(*AlertingRule)
		if !ok {
			continue
		}
		for _, rule := range g.rules {
			ar, ok := rule.(*AlertingRule)
			if !ok {
				continue
			}
			if far.Name() == ar.Name() {
				ar.active = far.active
			}
		}
	}
}

// eval runs a single evaluation cycle in which all rules are evaluated in parallel.
// In the future a single group will be evaluated sequentially to properly handle
// rule dependency.
func (g *Group) eval() {
	var (
		now = model.Now()
		wg  sync.WaitGroup
	)

	for _, rule := range g.rules {
		wg.Add(1)
		// BUG(julius): Look at fixing thundering herd.
		go func(rule Rule) {
			defer wg.Done()

			start := time.Now()
			evalTotal.Inc()

			vector, err := rule.eval(now, g.opts.QueryEngine)
			if err != nil {
				evalFailures.Inc()
				log.Warnf("Error while evaluating rule %q: %s", rule, err)
			}
			var rtyp ruleType

			switch r := rule.(type) {
			case *AlertingRule:
				rtyp = ruleTypeRecording
				g.sendAlerts(r, now)

			case *RecordingRule:
				rtyp = ruleTypeAlert

			default:
				panic(fmt.Errorf("unknown rule type: %T", rule))
			}

			evalDuration.WithLabelValues(string(rtyp)).Observe(
				float64(time.Since(start)) / float64(time.Second),
			)

			for _, s := range vector {
				g.opts.SampleAppender.Append(s)
			}
		}(rule)
	}
	wg.Wait()
}

// sendAlerts sends alert notifications for the given rule.
func (g *Group) sendAlerts(rule *AlertingRule, timestamp model.Time) error {
	var alerts model.Alerts

	for _, alert := range rule.currentAlerts() {
		// Only send actually firing alerts.
		if alert.State == StatePending {
			continue
		}

		// Provide the alert information to the template.
		l := make(map[string]string, len(alert.Labels))
		for k, v := range alert.Labels {
			l[string(k)] = string(v)
		}

		tmplData := struct {
			Labels map[string]string
			Value  float64
		}{
			Labels: l,
			Value:  float64(alert.Value),
		}
		// Inject some convenience variables that are easier to remember for users
		// who are not used to Go's templating system.
		defs := "{{$labels := .Labels}}{{$value := .Value}}"

		expand := func(text model.LabelValue) model.LabelValue {
			tmpl := template.NewTemplateExpander(
				defs+string(text),
				"__alert_"+rule.Name(),
				tmplData,
				timestamp,
				g.opts.QueryEngine,
				g.opts.ExternalURL.Path,
			)
			result, err := tmpl.Expand()
			if err != nil {
				result = fmt.Sprintf("<error expanding template: %s>", err)
				log.Warnf("Error expanding alert template %v with data '%v': %s", rule.Name(), tmplData, err)
			}
			return model.LabelValue(result)
		}

		labels := make(model.LabelSet, len(alert.Labels)+1)
		for ln, lv := range alert.Labels {
			labels[ln] = expand(lv)
		}
		labels[model.AlertNameLabel] = model.LabelValue(rule.Name())

		annotations := make(model.LabelSet, len(rule.annotations))
		for an, av := range rule.annotations {
			annotations[an] = expand(av)
		}

		a := &model.Alert{
			StartsAt:     alert.ActiveAt.Add(rule.holdDuration).Time(),
			Labels:       labels,
			Annotations:  annotations,
			GeneratorURL: g.opts.ExternalURL.String() + strutil.GraphLinkForExpression(rule.vector.String()),
		}
		if alert.ResolvedAt != 0 {
			a.EndsAt = alert.ResolvedAt.Time()
		}

		alerts = append(alerts, a)
	}

	if len(alerts) > 0 {
		g.opts.NotificationHandler.Send(alerts...)
	}

	return nil
}

// The Manager manages recording and alerting rules.
type Manager struct {
	opts   *ManagerOptions
	groups map[string]*Group
	mtx    sync.RWMutex
	block  chan struct{}
}

// ManagerOptions bundles options for the Manager.
type ManagerOptions struct {
	ExternalURL         *url.URL
	QueryEngine         *promql.Engine
	NotificationHandler *notification.Handler
	SampleAppender      storage.SampleAppender
}

// NewManager returns an implementation of Manager, ready to be started
// by calling the Run method.
func NewManager(o *ManagerOptions) *Manager {
	manager := &Manager{
		groups: map[string]*Group{},
		opts:   o,
		block:  make(chan struct{}),
	}
	return manager
}

// Run starts processing of the rule manager.
func (m *Manager) Run() {
	close(m.block)
}

// Stop the rule manager's rule evaluation cycles.
func (m *Manager) Stop() {
	log.Info("Stopping rule manager...")

	for _, eg := range m.groups {
		eg.stop()
	}

	log.Info("Rule manager stopped.")
}

// ApplyConfig updates the rule manager's state as the config requires. If
// loading the new rules failed the old rule set is restored. Returns true on success.
func (m *Manager) ApplyConfig(conf *config.Config) bool {
	m.mtx.Lock()
	defer m.mtx.Unlock()

	// Get all rule files and load the groups they define.
	var files []string
	for _, pat := range conf.RuleFiles {
		fs, err := filepath.Glob(pat)
		if err != nil {
			// The only error can be a bad pattern.
			log.Errorf("Error retrieving rule files for %s: %s", pat, err)
			return false
		}
		files = append(files, fs...)
	}

	groups, err := m.loadGroups(files...)
	if err != nil {
		log.Errorf("Error loading rules, previous rule set restored: %s", err)
		return false
	}

	var wg sync.WaitGroup

	for _, newg := range groups {
		// To be replaced with a configurable per-group interval.
		newg.interval = time.Duration(conf.GlobalConfig.EvaluationInterval)

		wg.Add(1)

		// If there is an old group with the same identifier, stop it and wait for
		// it to finish the current iteration. Then copy its into the new group.
		oldg, ok := m.groups[newg.name]
		delete(m.groups, newg.name)

		go func(newg *Group) {
			if ok {
				oldg.stop()
				newg.copyState(oldg)
			}
			go func() {
				// Wait with starting evaluation until the rule manager
				// is told to run. This is necessary to avoid running
				// queries against a bootstrapping storage.
				<-m.block
				newg.run()
			}()
			wg.Done()
		}(newg)
	}

	// Stop remaining old groups.
	for _, oldg := range m.groups {
		oldg.stop()
	}

	wg.Wait()
	m.groups = groups

	return true
}

// loadGroups reads groups from a list of files.
// As there's currently no group syntax a single group named "default" containing
// all rules will be returned.
func (m *Manager) loadGroups(filenames ...string) (map[string]*Group, error) {
	groups := map[string]*Group{}

	// Currently there is no group syntax implemented. Thus all rules
	// are read into a single default group.
	g := newGroup("default", m.opts)
	groups[g.name] = g

	for _, fn := range filenames {
		content, err := ioutil.ReadFile(fn)
		if err != nil {
			return nil, err
		}
		stmts, err := promql.ParseStmts(string(content))
		if err != nil {
			return nil, fmt.Errorf("error parsing %s: %s", fn, err)
		}

		for _, stmt := range stmts {
			var rule Rule

			switch r := stmt.(type) {
			case *promql.AlertStmt:
				rule = NewAlertingRule(r.Name, r.Expr, r.Duration, r.Labels, r.Annotations)

			case *promql.RecordStmt:
				rule = NewRecordingRule(r.Name, r.Expr, r.Labels)

			default:
				panic("retrieval.Manager.LoadRuleFiles: unknown statement type")
			}
			g.rules = append(g.rules, rule)
		}
	}

	return groups, nil
}

// Rules returns the list of the manager's rules.
func (m *Manager) Rules() []Rule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	var rules []Rule
	for _, g := range m.groups {
		rules = append(rules, g.rules...)
	}

	return rules
}

// AlertingRules returns the list of the manager's alerting rules.
func (m *Manager) AlertingRules() []*AlertingRule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	alerts := []*AlertingRule{}
	for _, rule := range m.Rules() {
		if alertingRule, ok := rule.(*AlertingRule); ok {
			alerts = append(alerts, alertingRule)
		}
	}
	return alerts
}
<commit_msg>Terminate rule groups during initial sleep<commit_after>// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rules

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"path/filepath"
	"sync"
	"time"

	html_template "html/template"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/model"

	"github.com/prometheus/prometheus/config"
	"github.com/prometheus/prometheus/notification"
	"github.com/prometheus/prometheus/promql"
	"github.com/prometheus/prometheus/storage"
	"github.com/prometheus/prometheus/template"
	"github.com/prometheus/prometheus/util/strutil"
)

// Constants for instrumentation.
const (
	namespace = "prometheus"

	ruleTypeLabel = "rule_type"
)

var (
	evalDuration = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: namespace,
			Name:      "rule_evaluation_duration_seconds",
			Help:      "The duration for a rule to execute.",
		},
		[]string{ruleTypeLabel},
	)
	evalFailures = prometheus.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_evaluation_failures_total",
			Help:      "The total number of rule evaluation failures.",
		},
	)
	evalTotal = prometheus.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "rule_evaluations_total",
			Help:      "The total number of rule evaluations.",
		},
	)
	iterationDuration = prometheus.NewSummary(prometheus.SummaryOpts{
		Namespace:  namespace,
		Name:       "evaluator_duration_seconds",
		Help:       "The duration for all evaluations to execute.",
		Objectives: map[float64]float64{0.01: 0.001, 0.05: 0.005, 0.5: 0.05, 0.90: 0.01, 0.99: 0.001},
	})
)

func init() {
	prometheus.MustRegister(iterationDuration)
	prometheus.MustRegister(evalFailures)
	prometheus.MustRegister(evalDuration)
}

type ruleType string

const (
	ruleTypeAlert     = "alerting"
	ruleTypeRecording = "recording"
)

// A Rule encapsulates a vector expression which is evaluated at a specified
// interval and acted upon (currently either recorded or used for alerting).
type Rule interface {
	Name() string
	// eval evaluates the rule, including any associated recording or alerting actions.
	eval(model.Time, *promql.Engine) (model.Vector, error)
	// String returns a human-readable string representation of the rule.
	String() string
	// HTMLSnippet returns a human-readable string representation of the rule,
	// decorated with HTML elements for use the web frontend.
	HTMLSnippet(pathPrefix string) html_template.HTML
}

// Group is a set of rules that have a logical relation.
type Group struct {
	name     string
	interval time.Duration
	rules    []Rule
	opts     *ManagerOptions

	done       chan struct{}
	terminated chan struct{}
}

func newGroup(name string, opts *ManagerOptions) *Group {
	return &Group{
		name:       name,
		opts:       opts,
		done:       make(chan struct{}),
		terminated: make(chan struct{}),
	}
}

func (g *Group) run() {
	defer close(g.terminated)

	// Wait an initial amount to have consistently slotted intervals.
	select {
	case <-time.After(g.offset()):
	case <-g.done:
		return
	}

	iter := func() {
		start := time.Now()
		g.eval()

		iterationDuration.Observe(float64(time.Since(start)) / float64(time.Millisecond))
	}
	iter()

	tick := time.NewTicker(g.interval)
	defer tick.Stop()

	for {
		select {
		case <-g.done:
			return
		default:
			select {
			case <-g.done:
				return
			case <-tick.C:
				iter()
			}
		}
	}
}

func (g *Group) stop() {
	close(g.done)
	<-g.terminated
}

func (g *Group) fingerprint() model.Fingerprint {
	l := model.LabelSet{"name": model.LabelValue(g.name)}
	return l.Fingerprint()
}

// offset returns until the next consistently slotted evaluation interval.
func (g *Group) offset() time.Duration {
	now := time.Now().UnixNano()

	var (
		base   = now - (now % int64(g.interval))
		offset = uint64(g.fingerprint()) % uint64(g.interval)
		next   = base + int64(offset)
	)

	if next < now {
		next += int64(g.interval)
	}
	return time.Duration(next - now)
}

// copyState copies the alerting rule state from the given group.
func (g *Group) copyState(from *Group) {
	for _, fromRule := range from.rules {
		far, ok := fromRule.(*AlertingRule)
		if !ok {
			continue
		}
		for _, rule := range g.rules {
			ar, ok := rule.(*AlertingRule)
			if !ok {
				continue
			}
			if far.Name() == ar.Name() {
				ar.active = far.active
			}
		}
	}
}

// eval runs a single evaluation cycle in which all rules are evaluated in parallel.
// In the future a single group will be evaluated sequentially to properly handle
// rule dependency.
func (g *Group) eval() {
	var (
		now = model.Now()
		wg  sync.WaitGroup
	)

	for _, rule := range g.rules {
		wg.Add(1)
		// BUG(julius): Look at fixing thundering herd.
		go func(rule Rule) {
			defer wg.Done()

			start := time.Now()
			evalTotal.Inc()

			vector, err := rule.eval(now, g.opts.QueryEngine)
			if err != nil {
				evalFailures.Inc()
				log.Warnf("Error while evaluating rule %q: %s", rule, err)
			}
			var rtyp ruleType

			switch r := rule.(type) {
			case *AlertingRule:
				rtyp = ruleTypeRecording
				g.sendAlerts(r, now)

			case *RecordingRule:
				rtyp = ruleTypeAlert

			default:
				panic(fmt.Errorf("unknown rule type: %T", rule))
			}

			evalDuration.WithLabelValues(string(rtyp)).Observe(
				float64(time.Since(start)) / float64(time.Second),
			)

			for _, s := range vector {
				g.opts.SampleAppender.Append(s)
			}
		}(rule)
	}
	wg.Wait()
}

// sendAlerts sends alert notifications for the given rule.
func (g *Group) sendAlerts(rule *AlertingRule, timestamp model.Time) error {
	var alerts model.Alerts

	for _, alert := range rule.currentAlerts() {
		// Only send actually firing alerts.
		if alert.State == StatePending {
			continue
		}

		// Provide the alert information to the template.
		l := make(map[string]string, len(alert.Labels))
		for k, v := range alert.Labels {
			l[string(k)] = string(v)
		}

		tmplData := struct {
			Labels map[string]string
			Value  float64
		}{
			Labels: l,
			Value:  float64(alert.Value),
		}
		// Inject some convenience variables that are easier to remember for users
		// who are not used to Go's templating system.
		defs := "{{$labels := .Labels}}{{$value := .Value}}"

		expand := func(text model.LabelValue) model.LabelValue {
			tmpl := template.NewTemplateExpander(
				defs+string(text),
				"__alert_"+rule.Name(),
				tmplData,
				timestamp,
				g.opts.QueryEngine,
				g.opts.ExternalURL.Path,
			)
			result, err := tmpl.Expand()
			if err != nil {
				result = fmt.Sprintf("<error expanding template: %s>", err)
				log.Warnf("Error expanding alert template %v with data '%v': %s", rule.Name(), tmplData, err)
			}
			return model.LabelValue(result)
		}

		labels := make(model.LabelSet, len(alert.Labels)+1)
		for ln, lv := range alert.Labels {
			labels[ln] = expand(lv)
		}
		labels[model.AlertNameLabel] = model.LabelValue(rule.Name())

		annotations := make(model.LabelSet, len(rule.annotations))
		for an, av := range rule.annotations {
			annotations[an] = expand(av)
		}

		a := &model.Alert{
			StartsAt:     alert.ActiveAt.Add(rule.holdDuration).Time(),
			Labels:       labels,
			Annotations:  annotations,
			GeneratorURL: g.opts.ExternalURL.String() + strutil.GraphLinkForExpression(rule.vector.String()),
		}
		if alert.ResolvedAt != 0 {
			a.EndsAt = alert.ResolvedAt.Time()
		}

		alerts = append(alerts, a)
	}

	if len(alerts) > 0 {
		g.opts.NotificationHandler.Send(alerts...)
	}

	return nil
}

// The Manager manages recording and alerting rules.
type Manager struct {
	opts   *ManagerOptions
	groups map[string]*Group
	mtx    sync.RWMutex
	block  chan struct{}
}

// ManagerOptions bundles options for the Manager.
type ManagerOptions struct {
	ExternalURL         *url.URL
	QueryEngine         *promql.Engine
	NotificationHandler *notification.Handler
	SampleAppender      storage.SampleAppender
}

// NewManager returns an implementation of Manager, ready to be started
// by calling the Run method.
func NewManager(o *ManagerOptions) *Manager {
	manager := &Manager{
		groups: map[string]*Group{},
		opts:   o,
		block:  make(chan struct{}),
	}
	return manager
}

// Run starts processing of the rule manager.
func (m *Manager) Run() {
	close(m.block)
}

// Stop the rule manager's rule evaluation cycles.
func (m *Manager) Stop() {
	log.Info("Stopping rule manager...")

	for _, eg := range m.groups {
		eg.stop()
	}

	log.Info("Rule manager stopped.")
}

// ApplyConfig updates the rule manager's state as the config requires. If
// loading the new rules failed the old rule set is restored. Returns true on success.
func (m *Manager) ApplyConfig(conf *config.Config) bool {
	m.mtx.Lock()
	defer m.mtx.Unlock()

	// Get all rule files and load the groups they define.
	var files []string
	for _, pat := range conf.RuleFiles {
		fs, err := filepath.Glob(pat)
		if err != nil {
			// The only error can be a bad pattern.
			log.Errorf("Error retrieving rule files for %s: %s", pat, err)
			return false
		}
		files = append(files, fs...)
	}

	groups, err := m.loadGroups(files...)
	if err != nil {
		log.Errorf("Error loading rules, previous rule set restored: %s", err)
		return false
	}

	var wg sync.WaitGroup

	for _, newg := range groups {
		// To be replaced with a configurable per-group interval.
		newg.interval = time.Duration(conf.GlobalConfig.EvaluationInterval)

		wg.Add(1)

		// If there is an old group with the same identifier, stop it and wait for
		// it to finish the current iteration. Then copy its into the new group.
		oldg, ok := m.groups[newg.name]
		delete(m.groups, newg.name)

		go func(newg *Group) {
			if ok {
				oldg.stop()
				newg.copyState(oldg)
			}
			go func() {
				// Wait with starting evaluation until the rule manager
				// is told to run. This is necessary to avoid running
				// queries against a bootstrapping storage.
				<-m.block
				newg.run()
			}()
			wg.Done()
		}(newg)
	}

	// Stop remaining old groups.
	for _, oldg := range m.groups {
		oldg.stop()
	}

	wg.Wait()
	m.groups = groups

	return true
}

// loadGroups reads groups from a list of files.
// As there's currently no group syntax a single group named "default" containing
// all rules will be returned.
func (m *Manager) loadGroups(filenames ...string) (map[string]*Group, error) {
	groups := map[string]*Group{}

	// Currently there is no group syntax implemented. Thus all rules
	// are read into a single default group.
	g := newGroup("default", m.opts)
	groups[g.name] = g

	for _, fn := range filenames {
		content, err := ioutil.ReadFile(fn)
		if err != nil {
			return nil, err
		}
		stmts, err := promql.ParseStmts(string(content))
		if err != nil {
			return nil, fmt.Errorf("error parsing %s: %s", fn, err)
		}

		for _, stmt := range stmts {
			var rule Rule

			switch r := stmt.(type) {
			case *promql.AlertStmt:
				rule = NewAlertingRule(r.Name, r.Expr, r.Duration, r.Labels, r.Annotations)

			case *promql.RecordStmt:
				rule = NewRecordingRule(r.Name, r.Expr, r.Labels)

			default:
				panic("retrieval.Manager.LoadRuleFiles: unknown statement type")
			}
			g.rules = append(g.rules, rule)
		}
	}

	return groups, nil
}

// Rules returns the list of the manager's rules.
func (m *Manager) Rules() []Rule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	var rules []Rule
	for _, g := range m.groups {
		rules = append(rules, g.rules...)
	}

	return rules
}

// AlertingRules returns the list of the manager's alerting rules.
func (m *Manager) AlertingRules() []*AlertingRule {
	m.mtx.RLock()
	defer m.mtx.RUnlock()

	alerts := []*AlertingRule{}
	for _, rule := range m.Rules() {
		if alertingRule, ok := rule.(*AlertingRule); ok {
			alerts = append(alerts, alertingRule)
		}
	}
	return alerts
}
<|endoftext|>


<commit_before>/*
Package runner implements a solution to executes one or more commands which have been defined
in a configuration file (by default "orbit.yml").

These commands, also called Orbit commands, runs one ore more external commands one by one.

Thanks to the generator package, the configuration file may be a data-driven template which is executed at runtime
(e.g. no file generated).
*/
package runner

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/gulien/orbit/context"
	"github.com/gulien/orbit/generator"
	"github.com/gulien/orbit/notifier"

	"gopkg.in/yaml.v2"
)

type (
	// OrbitRunnerConfig represents a YAML configuration file defining Orbit commands.
	OrbitRunnerConfig struct {
		// Commands slice represents the Orbit commands.
		Commands []*OrbitCommand `yaml:"commands"`
	}

	// OrbitCommand represents an Orbit command as defined in the configuration file.
	OrbitCommand struct {
		// Use is the name of the Orbit command.
		Use string `yaml:"use"`

		// Short describes what the Orbit command does (optional).
		Short string `yaml:"short,omitempty"`

		// Run is the stack of external commands to run.
		Run []string `yaml:"run"`
	}

	// OrbitRunner helps executing Orbit commands.
	OrbitRunner struct {
		// config is an instance of OrbitRunnerConfig.
		config *OrbitRunnerConfig

		// context is an instance of OrbitContext.
		context *context.OrbitContext
	}
)

// NewOrbitRunner instantiates a new instance of OrbitRunner.
func NewOrbitRunner(context *context.OrbitContext) (*OrbitRunner, error) {
	// first retrieves the data from the configuration file...
	gen := generator.NewOrbitGenerator(context)
	data, err := gen.Parse()
	if err != nil {
		return nil, err
	}

	// then populates the OrbitRunnerConfig.
	var config = &OrbitRunnerConfig{}
	if err := yaml.Unmarshal(data.Bytes(), &config); err != nil {
		return nil, fmt.Errorf("configuration file \"%s\" is not a valid YAML file:\n%s", context.TemplateFilePath, err)
	}

	return &OrbitRunner{
		config:  config,
		context: context,
	}, nil
}

// Exec executes the given Orbit commands.
func (r *OrbitRunner) Exec(names ...string) error {
	// populates a slice of instances of Orbit Command.
	// if a given name doest not match with any Orbit Command defined in the configuration file, throws an error.
	cmds := make([]*OrbitCommand, len(names))
	for index, name := range names {
		cmds[index] = r.getOrbitCommand(name)
		if cmds[index] == nil {
			return fmt.Errorf("Orbit command \"%s\" does not exist in configuration file \"%s\"", name, r.context.TemplateFilePath)
		}
	}

	// alright, let's run each Orbit command.
	for _, cmd := range cmds {
		if err := r.run(cmd); err != nil {
			return err
		}
	}

	return nil
}

// run runs the stack of external commands from the given Orbit command.
func (r *OrbitRunner) run(cmd *OrbitCommand) error {
	notifier.Info("starting Orbit command \"%s\"", cmd.Use)

	for _, c := range cmd.Run {
		notifier.Info("running \"%s\"", c)
		parts := strings.Fields(c)

		// parts[0] contains the name of the external command.
		// parts[1:] contains the arguments of the external command.
		e := exec.Command(parts[0], parts[1:]...)
		e.Stdout = os.Stdout
		e.Stderr = os.Stderr
		e.Stdin = os.Stdin

		if err := e.Run(); err != nil {
			return err
		}
	}

	return nil
}

// getOrbitCommand returns an instance of OrbitCommand if found or nil.
func (r *OrbitRunner) getOrbitCommand(name string) *OrbitCommand {
	for _, c := range r.config.Commands {
		if name == c.Use {
			return c
		}
	}

	return nil
}
<commit_msg>removing 'Short' attribute from OrbitCommand<commit_after>/*
Package runner implements a solution to executes one or more commands which have been defined
in a configuration file (by default "orbit.yml").

These commands, also called Orbit commands, runs one ore more external commands one by one.

Thanks to the generator package, the configuration file may be a data-driven template which is executed at runtime
(e.g. no file generated).
*/
package runner

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/gulien/orbit/context"
	"github.com/gulien/orbit/generator"
	"github.com/gulien/orbit/notifier"

	"gopkg.in/yaml.v2"
)

type (
	// OrbitRunnerConfig represents a YAML configuration file defining Orbit commands.
	OrbitRunnerConfig struct {
		// Commands slice represents the Orbit commands.
		Commands []*OrbitCommand `yaml:"commands"`
	}

	// OrbitCommand represents an Orbit command as defined in the configuration file.
	OrbitCommand struct {
		// Use is the name of the Orbit command.
		Use string `yaml:"use"`

		// Run is the stack of external commands to run.
		Run []string `yaml:"run"`
	}

	// OrbitRunner helps executing Orbit commands.
	OrbitRunner struct {
		// config is an instance of OrbitRunnerConfig.
		config *OrbitRunnerConfig

		// context is an instance of OrbitContext.
		context *context.OrbitContext
	}
)

// NewOrbitRunner instantiates a new instance of OrbitRunner.
func NewOrbitRunner(context *context.OrbitContext) (*OrbitRunner, error) {
	// first retrieves the data from the configuration file...
	gen := generator.NewOrbitGenerator(context)
	data, err := gen.Parse()
	if err != nil {
		return nil, err
	}

	// then populates the OrbitRunnerConfig.
	var config = &OrbitRunnerConfig{}
	if err := yaml.Unmarshal(data.Bytes(), &config); err != nil {
		return nil, fmt.Errorf("configuration file \"%s\" is not a valid YAML file:\n%s", context.TemplateFilePath, err)
	}

	return &OrbitRunner{
		config:  config,
		context: context,
	}, nil
}

// Exec executes the given Orbit commands.
func (r *OrbitRunner) Exec(names ...string) error {
	// populates a slice of instances of Orbit Command.
	// if a given name doest not match with any Orbit Command defined in the configuration file, throws an error.
	cmds := make([]*OrbitCommand, len(names))
	for index, name := range names {
		cmds[index] = r.getOrbitCommand(name)
		if cmds[index] == nil {
			return fmt.Errorf("Orbit command \"%s\" does not exist in configuration file \"%s\"", name, r.context.TemplateFilePath)
		}
	}

	// alright, let's run each Orbit command.
	for _, cmd := range cmds {
		if err := r.run(cmd); err != nil {
			return err
		}
	}

	return nil
}

// run runs the stack of external commands from the given Orbit command.
func (r *OrbitRunner) run(cmd *OrbitCommand) error {
	notifier.Info("starting Orbit command \"%s\"", cmd.Use)

	for _, c := range cmd.Run {
		notifier.Info("running \"%s\"", c)
		parts := strings.Fields(c)

		// parts[0] contains the name of the external command.
		// parts[1:] contains the arguments of the external command.
		e := exec.Command(parts[0], parts[1:]...)
		e.Stdout = os.Stdout
		e.Stderr = os.Stderr
		e.Stdin = os.Stdin

		if err := e.Run(); err != nil {
			return err
		}
	}

	return nil
}

// getOrbitCommand returns an instance of OrbitCommand if found or nil.
func (r *OrbitRunner) getOrbitCommand(name string) *OrbitCommand {
	for _, c := range r.config.Commands {
		if name == c.Use {
			return c
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2017 Wei Shen <shenwei356@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "rush",
	Short: "parallelly execute shell commands",
	Long: fmt.Sprintf(`
rush -- parallelly execute shell commands

Version: %s

Author: Wei Shen <shenwei356@gmail.com>

Documents  : http://bioinf.shenwei.me/rush
Source code: https://github.com/shenwei356/rush

`, VERSION),
	Run: func(cmd *cobra.Command, args []string) {
		config := getConfigs(cmd)

		if config.Version {
			checkVersion()
			return
		}

		var err error
		var outfh *os.File
		if isStdin(config.OutFile) {
			outfh = os.Stdout
		} else {
			outfh, err = os.Create(config.OutFile)
			defer outfh.Close()
			checkError(err)
		}

		if len(config.Infiles) == 0 {
			config.Infiles = append(config.Infiles, "-")
		}

		split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
			if atEOF && len(data) == 0 {
				return 0, nil, nil
			}
			i := bytes.IndexAny(data, config.RecordDelimiter)
			if i >= 0 {
				return i + 1, data[0:i], nil // trim config.RecordDelimiter
				// return i + 1, data[0 : i+1], nil
			}
			if atEOF {
				return len(data), data, nil
			}
			return 0, nil, nil
		}

		for _, file := range config.Infiles {
			var infh *os.File
			if isStdin(file) {
				infh = os.Stdin
			} else {
				infh, err = os.Open(file)
				checkError(err)
				defer infh.Close()
			}

			// channel of input data
			chIn := make(chan Chunk, config.Ncpus)

			// producer
			go func() {
				defer close(chIn)
				scanner := bufio.NewScanner(infh)
				scanner.Buffer(make([]byte, 0, 16384), 2147483648)
				scanner.Split(split)

				n := config.NRecords
				// lenRD := len(config.RecordDelimiter)
				var id uint64

				var records []string
				records = make([]string, 0, n)
				for scanner.Scan() {
					records = append(records, scanner.Text())

					if len(records) == n {
						// remove last config.RecordDelimiter
						// records[len(records)-1] = records[len(records)-1][0 : len(records[len(records)-1])-lenRD]
						chIn <- Chunk{ID: id, Data: records}
						id++
						records = make([]string, 0, n)
					}
				}
				if len(records) > 0 {
					// remove last config.RecordDelimiter
					// records[len(records)-1] = records[len(records)-1][0 : len(records[len(records)-1])-lenRD]
					chIn <- Chunk{ID: id, Data: records}
					id++
				}
				checkError(scanner.Err())
			}()

			// worker
			for c := range chIn {
				outfh.WriteString(fmt.Sprintf("%d: {%s}\n\n", c.ID, strings.Join(c.Data, config.RecordDelimiter)))
			}
		}

	},
}

// Chunk is data sent to workers
type Chunk struct {
	ID   uint64
	Data []string
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.Flags().BoolP("verbose", "v", false, "print verbose information")
	RootCmd.Flags().BoolP("version", "V", false, `print version information and check for update`)

	RootCmd.Flags().IntP("ncpus", "j", runtime.NumCPU(), "number of CPUs")
	RootCmd.Flags().StringP("out-file", "o", "-", `out file ("-" for stdout)`)

	RootCmd.Flags().StringSliceP("infile", "i", []string{}, "input data file")

	RootCmd.Flags().StringP("record-delimiter", "D", "\n", "record delimiter")
	RootCmd.Flags().IntP("nrecords", "n", 1, "number of records sent to a command")
	RootCmd.Flags().StringP("field-delimiter", "d", `\s+`, "field delimiter in records")

	RootCmd.Flags().IntP("retries", "r", 0, "maximum retries")
	RootCmd.Flags().IntP("retry-interval", "", 0, "retry interval (unit: second)")
	RootCmd.Flags().IntP("timeout", "t", 0, "timeout of a command (unit: second, 0 for no timeout)")

	RootCmd.Flags().BoolP("keep-order", "k", false, "keep output in order of input")
	RootCmd.Flags().BoolP("stop-on-error", "e", false, "stop all processes on any error")
	RootCmd.Flags().BoolP("continue", "c", false, `continue run commands except for finished commands in "finished.txt"`)

}

// Config is the struct containing all global flags
type Config struct {
	Verbose bool
	Version bool

	Ncpus   int
	OutFile string

	Infiles []string

	RecordDelimiter string
	NRecords        int
	FieldDelimiter  string

	Retries       int
	RetryInterval int
	Timeout       int

	KeepOrder bool
	StopOnErr bool
	Continue  bool
}

func getConfigs(cmd *cobra.Command) Config {
	return Config{
		Verbose: getFlagBool(cmd, "verbose"),
		Version: getFlagBool(cmd, "version"),

		Ncpus:   getFlagPositiveInt(cmd, "ncpus"),
		OutFile: getFlagString(cmd, "out-file"),

		Infiles: getFlagStringSlice(cmd, "infile"),

		RecordDelimiter: getFlagString(cmd, "record-delimiter"),
		NRecords:        getFlagPositiveInt(cmd, "nrecords"),
		FieldDelimiter:  getFlagString(cmd, "field-delimiter"),

		Retries:       getFlagNonNegativeInt(cmd, "retries"),
		RetryInterval: getFlagNonNegativeInt(cmd, "retry-interval"),
		Timeout:       getFlagNonNegativeInt(cmd, "timeout"),

		KeepOrder: getFlagBool(cmd, "keep-order"),
		StopOnErr: getFlagBool(cmd, "stop-on-error"),
		Continue:  getFlagBool(cmd, "continue"),
	}
}
<commit_msg>build producer-consumer model<commit_after>// Copyright © 2017 Wei Shen <shenwei356@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"runtime"
	"strings"
	"sync"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "rush",
	Short: "parallelly execute shell commands",
	Long: fmt.Sprintf(`
rush -- parallelly execute shell commands

Version: %s

Author: Wei Shen <shenwei356@gmail.com>

Documents  : http://bioinf.shenwei.me/rush
Source code: https://github.com/shenwei356/rush

`, VERSION),
	Run: func(cmd *cobra.Command, args []string) {
		config := getConfigs(cmd)

		if config.Version {
			checkVersion()
			return
		}

		var err error
		var outfh *os.File
		if isStdin(config.OutFile) {
			outfh = os.Stdout
		} else {
			outfh, err = os.Create(config.OutFile)
			defer outfh.Close()
			checkError(err)
		}

		if len(config.Infiles) == 0 {
			config.Infiles = append(config.Infiles, "-")
		}

		split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
			if atEOF && len(data) == 0 {
				return 0, nil, nil
			}
			i := bytes.IndexAny(data, config.RecordDelimiter)
			if i >= 0 {
				return i + 1, data[0:i], nil // trim config.RecordDelimiter
				// return i + 1, data[0 : i+1], nil
			}
			if atEOF {
				return len(data), data, nil
			}
			return 0, nil, nil
		}

		for _, file := range config.Infiles {
			// input file handle
			var infh *os.File
			if isStdin(file) {
				infh = os.Stdin
			} else {
				infh, err = os.Open(file)
				checkError(err)
				defer infh.Close()
			}

			// channel of input data
			chIn := make(chan Chunk, config.Ncpus)

			// producer
			go func() {
				defer close(chIn)
				scanner := bufio.NewScanner(infh)
				scanner.Buffer(make([]byte, 0, 16384), 2147483648)
				scanner.Split(split)

				n := config.NRecords
				// lenRD := len(config.RecordDelimiter)
				var id uint64

				var records []string
				records = make([]string, 0, n)
				for scanner.Scan() {
					records = append(records, scanner.Text())

					if len(records) == n {
						// remove last config.RecordDelimiter
						// records[len(records)-1] = records[len(records)-1][0 : len(records[len(records)-1])-lenRD]
						chIn <- Chunk{ID: id, Data: records}
						id++
						records = make([]string, 0, n)
					}
				}
				if len(records) > 0 {
					// remove last config.RecordDelimiter
					// records[len(records)-1] = records[len(records)-1][0 : len(records[len(records)-1])-lenRD]
					chIn <- Chunk{ID: id, Data: records}
					id++
				}

				checkError(errors.Wrap(scanner.Err(), "read data"))
			}()

			// consumer
			var wg sync.WaitGroup
			tokens := make(chan int, config.Ncpus)

			for c := range chIn {
				wg.Add(1)
				tokens <- 1
				go func(c Chunk) {
					defer func() {
						wg.Done()
						<-tokens
					}()

					outfh.WriteString(fmt.Sprintf("%d: {%s}\n\n", c.ID, strings.Join(c.Data, config.RecordDelimiter)))
				}(c)
			}

			wg.Wait()
		}

	},
}

// Chunk is data sent to workers
type Chunk struct {
	ID   uint64
	Data []string
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.Flags().BoolP("verbose", "v", false, "print verbose information")
	RootCmd.Flags().BoolP("version", "V", false, `print version information and check for update`)

	RootCmd.Flags().IntP("ncpus", "j", runtime.NumCPU(), "number of CPUs")
	RootCmd.Flags().StringP("out-file", "o", "-", `out file ("-" for stdout)`)

	RootCmd.Flags().StringSliceP("infile", "i", []string{}, "input data file")

	RootCmd.Flags().StringP("record-delimiter", "D", "\n", "record delimiter")
	RootCmd.Flags().IntP("nrecords", "n", 1, "number of records sent to a command")
	RootCmd.Flags().StringP("field-delimiter", "d", `\s+`, "field delimiter in records")

	RootCmd.Flags().IntP("retries", "r", 0, "maximum retries")
	RootCmd.Flags().IntP("retry-interval", "", 0, "retry interval (unit: second)")
	RootCmd.Flags().IntP("timeout", "t", 0, "timeout of a command (unit: second, 0 for no timeout)")

	RootCmd.Flags().BoolP("keep-order", "k", false, "keep output in order of input")
	RootCmd.Flags().BoolP("stop-on-error", "e", false, "stop all processes on any error")
	RootCmd.Flags().BoolP("continue", "c", false, `continue run commands except for finished commands in "finished.txt"`)

}

// Config is the struct containing all global flags
type Config struct {
	Verbose bool
	Version bool

	Ncpus   int
	OutFile string

	Infiles []string

	RecordDelimiter string
	NRecords        int
	FieldDelimiter  string

	Retries       int
	RetryInterval int
	Timeout       int

	KeepOrder bool
	StopOnErr bool
	Continue  bool
}

func getConfigs(cmd *cobra.Command) Config {
	return Config{
		Verbose: getFlagBool(cmd, "verbose"),
		Version: getFlagBool(cmd, "version"),

		Ncpus:   getFlagPositiveInt(cmd, "ncpus"),
		OutFile: getFlagString(cmd, "out-file"),

		Infiles: getFlagStringSlice(cmd, "infile"),

		RecordDelimiter: getFlagString(cmd, "record-delimiter"),
		NRecords:        getFlagPositiveInt(cmd, "nrecords"),
		FieldDelimiter:  getFlagString(cmd, "field-delimiter"),

		Retries:       getFlagNonNegativeInt(cmd, "retries"),
		RetryInterval: getFlagNonNegativeInt(cmd, "retry-interval"),
		Timeout:       getFlagNonNegativeInt(cmd, "timeout"),

		KeepOrder: getFlagBool(cmd, "keep-order"),
		StopOnErr: getFlagBool(cmd, "stop-on-error"),
		Continue:  getFlagBool(cmd, "continue"),
	}
}
<|endoftext|>


<commit_before>package time

type Zone struct {
	Name   string // Abbreviated name ("CET", "CEST").
	Offset int    // Seconds east of UTC.
}

// DST describes daylight saving time zone. 25 least significant bits of Start
// and End contain seconds from begining of year to the month-weekday-hour at
// which the DST starts/ends, assuming that the year is not a leap year and its
// first day is Monday. 7 most significant bits of Start and End contain margin,// a number of days that weekdays can be shifted back to do not introduce new
// last weekday at end of month or to do not lose first weekday at beginning of
// month.
type DST struct {
	Zone  Zone
	Start uint32
	End   uint32
}

// A Location maps time instants to the zone in use at that time.
// This is simplified implementation that does not support historical changes.
type Location struct {
	Name string
	Zone *Zone
	DST  *DST // Nil if DST not used in location.
}

func (l *Location) String() string {
	return l.Name
}

//emgo:const
var (
	utcZone = Zone{"UTC", 0}
	utcLoc  = Location{"UTC", &utcZone, nil}
	UTC     = &utcLoc
)

// Local is local location.
var Local = &utcLoc

// Lookup returns information about the time zone in use at an instant in time
// expressed as absolute time abs. The returned information gives the name of
// the zone (such as "CET"), the offset in seconds east of UTC, the start and
// end times bracketing abs when that zone is in effect.
func (l *Location) lookup(abs uint64) (name string, offset int, start, end uint64) {
	if l.DST == nil {
		return l.Zone.Name, l.Zone.Offset, 0, 1<<64 - 1
	}

	// This code is similar to the code of absDate. See absDate for better
	// description of any step.

	// Avoid 64-bit calculations.

	// Second of 400-year cycle.
	s400 := abs % (daysPer400Years * secondsPerDay)

	// Day of 400-year cycle.
	d400 := int(s400 / secondsPerDay)

	// Second of day.
	s := int(s400 - uint64(d400)*secondsPerDay)

	// Day of 100-year cycle.
	n100 := d400 / daysPer100Years
	n100 -= n100 >> 2
	d := d400 - daysPer100Years*n100

	// Day of 4-year cycle.
	n4 := d / daysPer4Years
	d -= daysPer4Years * n4

	// Day of year (0 means first day).
	n := d / 365
	n -= n >> 2
	d -= 365 * n

	// Calculate second of year and determine does the year is a leap year.
	ys := d*secondsPerDay + s
	isLeap := (n == 4-1 && (n4 != 25-1 || n100 == 4-1))

	// Weekday of first year day.
	wday := (d400 - d) % 7 // Zero means Monday.

	// Adjust l.DST.Start and l.DST.End that they describe always the same time
	// on the same month and the same weakday.
	dstStart, margin := int(l.DST.Start&0x1FFFFFF), int(l.DST.Start>>25)
	adj := wday
	if isLeap && dstStart > (31+28+15)*secondsPerDay {
		// BUG: dstStart > (31+28+15)*secondsPerDay is simplified condition.
		// Correct condition should use direction bit of margin (not
		// implemented) to detect that margin describes first n-th weekday
		// (Saturday, Sunday) of March or last n-th weekday of March.
		margin--
	}
	if wday >= margin {
		adj -= 7
	}
	dstStart -= adj * secondsPerDay
	dstEnd, margin := int(l.DST.End&0x1FFFFFF), int(l.DST.End>>25)
	adj = wday
	if isLeap && dstEnd > (31+28+15)*secondsPerDay {
		// BUG: See above.
		margin--
	}
	if wday >= margin {
		adj -= 7
	}
	dstEnd -= adj * secondsPerDay

	abs -= uint64(ys)              // Beginning of year.
	start = abs + uint64(dstStart) // Start of DST (absolute time).
	end = abs + uint64(dstEnd)     // End of DST (absolute time).

	// If start/end falls on the previous or next year, the approximate value of
	// start/end is returned. For now only Date uses these values and such
	if dstStart < dstEnd {
		if dstStart <= ys && ys < dstEnd {
			return l.DST.Zone.Name, l.DST.Zone.Offset, start, end
		}
		if ys < dstStart {
			return l.Zone.Name, l.Zone.Offset, end - 365*secondsPerDay, start
		}
		return l.Zone.Name, l.Zone.Offset, end, start + 365*secondsPerDay
	}
	if dstEnd <= ys && ys < dstStart {
		return l.Zone.Name, l.Zone.Offset, start, end
	}
	return l.DST.Zone.Name, l.DST.Zone.Offset, end - 365*secondsPerDay, start
}
<commit_msg>time: Fix simplifies comparisosns and fixes bug in lookup.<commit_after>package time

type Zone struct {
	Name   string // Abbreviated name ("CET", "CEST").
	Offset int    // Seconds east of UTC.
}

// DST describes daylight saving time zone. 25 least significant bits of Start
// and End contain seconds from begining of year to the month-weekday-hour at
// which the DST starts/ends, assuming that the year is not a leap year and its
// first day is Monday. 7 most significant bits of Start and End contain margin,// a number of days that weekdays can be shifted back to do not introduce new
// last weekday at end of month or to do not lose first weekday at beginning of
// month.
type DST struct {
	Zone  Zone
	Start uint32
	End   uint32
}

// A Location maps time instants to the zone in use at that time.
// This is simplified implementation that does not support historical changes.
type Location struct {
	Name string
	Zone *Zone
	DST  *DST // Nil if DST not used in location.
}

func (l *Location) String() string {
	return l.Name
}

//emgo:const
var (
	utcZone = Zone{"UTC", 0}
	utcLoc  = Location{"UTC", &utcZone, nil}
	UTC     = &utcLoc
)

// Local is local location.
var Local = &utcLoc

// Lookup returns information about the time zone in use at an instant in time
// expressed as absolute time abs. The returned information gives the name of
// the zone (such as "CET"), the offset in seconds east of UTC, the start and
// end times bracketing abs when that zone is in effect. If start/end falls on
// the previous or next year, the approximate value of start/end is returned.
// For now only Date uses these values and works fine with such approximation.
func (l *Location) lookup(abs uint64) (name string, offset int, start, end uint64) {
	if l.DST == nil {
		return l.Zone.Name, l.Zone.Offset, 0, 1<<64 - 1
	}

	// This code is similar to the code of absDate. See absDate for better
	// description of any step.

	// Avoid 64-bit calculations.

	// Second of 400-year cycle.
	s400 := abs % (daysPer400Years * secondsPerDay)

	// Day of 400-year cycle.
	d400 := int(s400 / secondsPerDay)

	// Second of day.
	s := int(s400 - uint64(d400)*secondsPerDay)

	// Day of 100-year cycle.
	n100 := d400 / daysPer100Years
	n100 -= n100 >> 2
	d := d400 - daysPer100Years*n100

	// Day of 4-year cycle.
	n4 := d / daysPer4Years
	d -= daysPer4Years * n4

	// Day of year (0 means first day).
	n := d / 365
	n -= n >> 2
	d -= 365 * n

	// Calculate second of year and determine does the year is a leap year.
	ys := d*secondsPerDay + s
	isLeap := (n == 4-1 && (n4 != 25-1 || n100 == 4-1))

	// Weekday of first year day.
	wday := (d400 - d) % 7 // Zero means Monday.

	// Adjust l.DST.Start and l.DST.End that they describe always the same time
	// on the same month and the same weakday.
	dstStart, margin := int(l.DST.Start&0x1FFFFFF), int(l.DST.Start>>25)
	adj := wday
	if isLeap && dstStart > (31+28+15)*secondsPerDay {
		// BUG: dstStart > (31+28+15)*secondsPerDay is simplified condition.
		// Correct condition should use direction bit of margin (not
		// implemented) to detect that margin describes first n-th weekday
		// (Saturday, Sunday) of March or last n-th weekday of March.
		margin--
	}
	if wday >= margin {
		adj -= 7
	}
	dstStart -= adj * secondsPerDay
	dstEnd, margin := int(l.DST.End&0x1FFFFFF), int(l.DST.End>>25)
	adj = wday
	if isLeap && dstEnd > (31+28+15)*secondsPerDay {
		// BUG: See above.
		margin--
	}
	if wday >= margin {
		adj -= 7
	}
	dstEnd -= adj * secondsPerDay

	abs -= uint64(ys)              // Beginning of year.
	start = abs + uint64(dstStart) // Start of DST (absolute time).
	end = abs + uint64(dstEnd)     // End of DST (absolute time).

	if dstStart < dstEnd {
		if ys < dstStart {
			return l.Zone.Name, l.Zone.Offset, end - 365*secondsPerDay, start
		}
		if dstEnd <= ys {
			return l.Zone.Name, l.Zone.Offset, end, start + 365*secondsPerDay
		}
		return l.DST.Zone.Name, l.DST.Zone.Offset, start, end
	}
	if ys < dstEnd {
		return l.DST.Zone.Name, l.DST.Zone.Offset, start - 365*secondsPerDay, end
	}
	if dstStart <= ys {
		return l.DST.Zone.Name, l.DST.Zone.Offset, start, end + 365*secondsPerDay
	}
	return l.Zone.Name, l.Zone.Offset, end, start
}
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/storage"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/tools"
)

// A EnvironProvider represents a computing and storage provider.
type EnvironProvider interface {
	// RestrictedConfigAttributes are provider specific attributes stored in
	// the config that really cannot or should not be changed across
	// environments running inside a single juju server.
	RestrictedConfigAttributes() []string

	// PrepareForCreateEnvironment prepares an environment for creation. Any
	// additional configuration attributes are added to the config passed in
	// and returned.  This allows providers to add additional required config
	// for new environments that may be created in an existing juju server.
	PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error)

	// PrepareForBootstrap prepares an environment for use. Any additional
	// configuration attributes in the returned environment should
	// be saved to be used later. If the environment is already
	// prepared, this call is equivalent to Open.
	PrepareForBootstrap(ctx BootstrapContext, cfg *config.Config) (Environ, error)

	// Open opens the environment and returns it.
	// The configuration must have come from a previously
	// prepared environment.
	Open(cfg *config.Config) (Environ, error)

	// Validate ensures that config is a valid configuration for this
	// provider, applying changes to it if necessary, and returns the
	// validated configuration.
	// If old is not nil, it holds the previous environment configuration
	// for consideration when validating changes.
	Validate(cfg, old *config.Config) (valid *config.Config, err error)

	// Boilerplate returns a default configuration for the environment in yaml format.
	// The text should be a key followed by some number of attributes:
	//    `environName:
	//        type: environTypeName
	//        attr1: val1
	//    `
	// The text is used as a template (see the template package) with one extra template
	// function available, rand, which expands to a random hexadecimal string when invoked.
	BoilerplateConfig() string

	// SecretAttrs filters the supplied configuration returning only values
	// which are considered sensitive. All of the values of these secret
	// attributes need to be strings.
	SecretAttrs(cfg *config.Config) (map[string]string, error)
}

// EnvironStorage implements storage access for an environment.
type EnvironStorage interface {
	// Storage returns storage specific to the environment.
	Storage() storage.Storage
}

// ConfigGetter implements access to an environment's configuration.
type ConfigGetter interface {
	// Config returns the configuration data with which the Environ was created.
	// Note that this is not necessarily current; the canonical location
	// for the configuration data is stored in the state.
	Config() *config.Config
}

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// also environs.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a InstanceConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *instancecfg.InstanceConfig) error

// An Environ represents a juju environment as specified
// in the environments.yaml file.
//
// Due to the limitations of some providers (for example ec2), the
// results of the Environ methods may not be fully sequentially
// consistent. In particular, while a provider may retry when it
// gets an error for an operation, it will not retry when
// an operation succeeds, even if that success is not
// consistent with a previous operation.
//
// Even though Juju takes care not to share an Environ between concurrent
// workers, it does allow concurrent method calls into the provider
// implementation.  The typical provider implementation needs locking to
// avoid undefined behaviour when the configuration changes.
type Environ interface {
	// Bootstrap creates a new instance with the series and architecture
	// of its choice, constrained to those of the available tools, and
	// returns the instance's architecture, series, and a function that
	// must be called to finalize the bootstrap process by transferring
	// the tools and installing the initial Juju state server.
	//
	// It is possible to direct Bootstrap to use a specific architecture
	// (or fail if it cannot start an instance of that architecture) by
	// using an architecture constraint; this will have the effect of
	// limiting the available tools to just those matching the specified
	// architecture.
	Bootstrap(ctx BootstrapContext, params BootstrapParams) (arch, series string, _ BootstrapFinalizer, _ error)

	// InstanceBroker defines methods for starting and stopping
	// instances.
	InstanceBroker

	// ConfigGetter allows the retrieval of the configuration data.
	ConfigGetter

	// EnvironCapability allows access to this environment's capabilities.
	state.EnvironCapability

	// ConstraintsValidator returns a Validator instance which
	// is used to validate and merge constraints.
	ConstraintsValidator() (constraints.Validator, error)

	// SetConfig updates the Environ's configuration.
	//
	// Calls to SetConfig do not affect the configuration of
	// values previously obtained from Storage.
	SetConfig(cfg *config.Config) error

	// Instances returns a slice of instances corresponding to the
	// given instance ids.  If no instances were found, but there
	// was no other error, it will return ErrNoInstances.  If
	// some but not all the instances were found, the returned slice
	// will have some nil slots, and an ErrPartialInstances error
	// will be returned.
	Instances(ids []instance.Id) ([]instance.Instance, error)

	// StateServerInstances returns the IDs of instances corresponding
	// to Juju state servers. If there are no state server instances,
	// ErrNoInstances is returned. If it can be determined that the
	// environment has not been bootstrapped, then ErrNotBootstrapped
	// should be returned instead.
	StateServerInstances() ([]instance.Id, error)

	// Destroy shuts down all known machines and destroys the
	// rest of the environment. Note that on some providers,
	// very recently started instances may not be destroyed
	// because they are not yet visible.
	//
	// When Destroy has been called, any Environ referring to the
	// same remote environment may become invalid
	Destroy() error

	// OpenPorts opens the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	OpenPorts(ports []network.PortRange) error

	// ClosePorts closes the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	ClosePorts(ports []network.PortRange) error

	// Ports returns the port ranges opened for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	Ports() ([]network.PortRange, error)

	// Provider returns the EnvironProvider that created this Environ.
	Provider() EnvironProvider

	state.Prechecker
}

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<commit_msg>Comment correction<commit_after>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package environs

import (
	"io"
	"os"

	"github.com/juju/juju/cloudconfig/instancecfg"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/environs/storage"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/network"
	"github.com/juju/juju/state"
	"github.com/juju/juju/tools"
)

// A EnvironProvider represents a computing and storage provider.
type EnvironProvider interface {
	// RestrictedConfigAttributes are provider specific attributes stored in
	// the config that really cannot or should not be changed across
	// environments running inside a single juju server.
	RestrictedConfigAttributes() []string

	// PrepareForCreateEnvironment prepares an environment for creation. Any
	// additional configuration attributes are added to the config passed in
	// and returned.  This allows providers to add additional required config
	// for new environments that may be created in an existing juju server.
	PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error)

	// PrepareForBootstrap prepares an environment for use. Any additional
	// configuration attributes in the returned environment should
	// be saved to be used later. If the environment is already
	// prepared, this call is equivalent to Open.
	PrepareForBootstrap(ctx BootstrapContext, cfg *config.Config) (Environ, error)

	// Open opens the environment and returns it.
	// The configuration must have come from a previously
	// prepared environment.
	Open(cfg *config.Config) (Environ, error)

	// Validate ensures that config is a valid configuration for this
	// provider, applying changes to it if necessary, and returns the
	// validated configuration.
	// If old is not nil, it holds the previous environment configuration
	// for consideration when validating changes.
	Validate(cfg, old *config.Config) (valid *config.Config, err error)

	// Boilerplate returns a default configuration for the environment in yaml format.
	// The text should be a key followed by some number of attributes:
	//    `environName:
	//        type: environTypeName
	//        attr1: val1
	//    `
	// The text is used as a template (see the template package) with one extra template
	// function available, rand, which expands to a random hexadecimal string when invoked.
	BoilerplateConfig() string

	// SecretAttrs filters the supplied configuration returning only values
	// which are considered sensitive. All of the values of these secret
	// attributes need to be strings.
	SecretAttrs(cfg *config.Config) (map[string]string, error)
}

// EnvironStorage implements storage access for an environment.
type EnvironStorage interface {
	// Storage returns storage specific to the environment.
	Storage() storage.Storage
}

// ConfigGetter implements access to an environment's configuration.
type ConfigGetter interface {
	// Config returns the configuration data with which the Environ was created.
	// Note that this is not necessarily current; the canonical location
	// for the configuration data is stored in the state.
	Config() *config.Config
}

// BootstrapParams holds the parameters for bootstrapping an environment.
type BootstrapParams struct {
	// Constraints are used to choose the initial instance specification,
	// and will be stored in the new environment's state.
	Constraints constraints.Value

	// Placement, if non-empty, holds an environment-specific placement
	// directive used to choose the initial instance.
	Placement string

	// AvailableTools is a collection of tools which the Bootstrap method
	// may use to decide which architecture/series to instantiate.
	AvailableTools tools.List

	// ContainerBridgeName, if non-empty, overrides the default
	// network bridge device to use for LXC and KVM containers. See
	// also instancecfg.DefaultBridgeName.
	ContainerBridgeName string
}

// BootstrapFinalizer is a function returned from Environ.Bootstrap.
// The caller must pass a InstanceConfig with the Tools field set.
type BootstrapFinalizer func(BootstrapContext, *instancecfg.InstanceConfig) error

// An Environ represents a juju environment as specified
// in the environments.yaml file.
//
// Due to the limitations of some providers (for example ec2), the
// results of the Environ methods may not be fully sequentially
// consistent. In particular, while a provider may retry when it
// gets an error for an operation, it will not retry when
// an operation succeeds, even if that success is not
// consistent with a previous operation.
//
// Even though Juju takes care not to share an Environ between concurrent
// workers, it does allow concurrent method calls into the provider
// implementation.  The typical provider implementation needs locking to
// avoid undefined behaviour when the configuration changes.
type Environ interface {
	// Bootstrap creates a new instance with the series and architecture
	// of its choice, constrained to those of the available tools, and
	// returns the instance's architecture, series, and a function that
	// must be called to finalize the bootstrap process by transferring
	// the tools and installing the initial Juju state server.
	//
	// It is possible to direct Bootstrap to use a specific architecture
	// (or fail if it cannot start an instance of that architecture) by
	// using an architecture constraint; this will have the effect of
	// limiting the available tools to just those matching the specified
	// architecture.
	Bootstrap(ctx BootstrapContext, params BootstrapParams) (arch, series string, _ BootstrapFinalizer, _ error)

	// InstanceBroker defines methods for starting and stopping
	// instances.
	InstanceBroker

	// ConfigGetter allows the retrieval of the configuration data.
	ConfigGetter

	// EnvironCapability allows access to this environment's capabilities.
	state.EnvironCapability

	// ConstraintsValidator returns a Validator instance which
	// is used to validate and merge constraints.
	ConstraintsValidator() (constraints.Validator, error)

	// SetConfig updates the Environ's configuration.
	//
	// Calls to SetConfig do not affect the configuration of
	// values previously obtained from Storage.
	SetConfig(cfg *config.Config) error

	// Instances returns a slice of instances corresponding to the
	// given instance ids.  If no instances were found, but there
	// was no other error, it will return ErrNoInstances.  If
	// some but not all the instances were found, the returned slice
	// will have some nil slots, and an ErrPartialInstances error
	// will be returned.
	Instances(ids []instance.Id) ([]instance.Instance, error)

	// StateServerInstances returns the IDs of instances corresponding
	// to Juju state servers. If there are no state server instances,
	// ErrNoInstances is returned. If it can be determined that the
	// environment has not been bootstrapped, then ErrNotBootstrapped
	// should be returned instead.
	StateServerInstances() ([]instance.Id, error)

	// Destroy shuts down all known machines and destroys the
	// rest of the environment. Note that on some providers,
	// very recently started instances may not be destroyed
	// because they are not yet visible.
	//
	// When Destroy has been called, any Environ referring to the
	// same remote environment may become invalid
	Destroy() error

	// OpenPorts opens the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	OpenPorts(ports []network.PortRange) error

	// ClosePorts closes the given port ranges for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	ClosePorts(ports []network.PortRange) error

	// Ports returns the port ranges opened for the whole environment.
	// Must only be used if the environment was setup with the
	// FwGlobal firewall mode.
	Ports() ([]network.PortRange, error)

	// Provider returns the EnvironProvider that created this Environ.
	Provider() EnvironProvider

	state.Prechecker
}

// BootstrapContext is an interface that is passed to
// Environ.Bootstrap, providing a means of obtaining
// information about and manipulating the context in which
// it is being invoked.
type BootstrapContext interface {
	GetStdin() io.Reader
	GetStdout() io.Writer
	GetStderr() io.Writer
	Infof(format string, params ...interface{})
	Verbosef(format string, params ...interface{})

	// InterruptNotify starts watching for interrupt signals
	// on behalf of the caller, sending them to the supplied
	// channel.
	InterruptNotify(sig chan<- os.Signal)

	// StopInterruptNotify undoes the effects of a previous
	// call to InterruptNotify with the same channel. After
	// StopInterruptNotify returns, no more signals will be
	// delivered to the channel.
	StopInterruptNotify(chan<- os.Signal)

	// ShouldVerifyCredentials indicates whether the caller's cloud
	// credentials should be verified.
	ShouldVerifyCredentials() bool
}
<|endoftext|>


<commit_before>package jobq

import "errors"

var (
	errInvalidWorkerSize = errors.New("invalid worker size")
	errInvalidQueueSize  = errors.New("invalid queue size")
)

// Job it's a type with wide application than an interface{Work(id int)}
type Job func() error

// Dispatcher share jobs between workers available.
type Dispatcher struct {
	ws    chan *Worker
	queue chan Job
	size  int
	done  chan struct{}
}

// New returns a new dispatcher.
func New(size int, queueLen int) (*Dispatcher, error) {
	if size < 1 {
		return nil, errInvalidWorkerSize
	}
	if queueLen < 1 {
		return nil, errInvalidQueueSize
	}
	d := &Dispatcher{
		ws:    make(chan *Worker, size),
		queue: make(chan Job, queueLen),
		size:  size,
		done:  make(chan struct{}, 1),
	}
	d.run()
	return d, nil
}

// run keep dispatching jobs between workers.
func (d *Dispatcher) run() {
	// init and run workers.
	for i := 0; i < d.size; i++ {
		w := newWorker(i, d.ws)
		go w.run()
		d.ws <- w
	}
	go func() {
		for {
			select {
			case job := <-d.queue:
				select {
				case wc := <-d.ws:
					select {
					case wc.jobc <- job:
					}
				}
			case <-d.done:
				return
			}
		}
	}()
}

// Add add job to queue channel.
func (d *Dispatcher) Add(j Job) {
	d.queue <- j
}

// Stop stops all workers.
func (d *Dispatcher) Stop() {
	select {
	case d.done <- struct{}{}:
	}
	for i := 0; i < d.size; i++ {
		select {
		case w := <-d.ws:
			w.stop()
		}
	}
}

// Worker struct implements own job channel and notifies owner dispatcher when is
// available for work.
type Worker struct {
	ID   int
	dc   chan *Worker
	jobc chan Job
	done chan struct{}
}

// newWorker returns a new worker.
func newWorker(id int, dc chan *Worker) *Worker {
	w := &Worker{
		ID:   id,
		dc:   dc,
		jobc: make(chan Job),
		done: make(chan struct{}, 1),
	}
	return w
}

func (w *Worker) stop() {
	w.done <- struct{}{}
}

// run method runs until Dispatcher.Stop() is called.
// keeps running jobs.
func (w *Worker) run() {
	for {
		select {
		case job := <-w.jobc:
			job()
			select {
			case w.dc <- w:
			}
		case <-w.done:
			return
		}
	}
}
<commit_msg>update<commit_after>package jobq

import "errors"

var (
	errInvalidWorkerSize = errors.New("invalid worker size")
	errInvalidQueueSize  = errors.New("invalid queue size")
)

// Job func. Can be any function with no input vars that returns error:
// task := func() error {
// 		do some work.....
//		return err
// }
type Job func() error

// Dispatcher share jobs between available workers.
type Dispatcher struct {
	ws    chan *Worker
	queue chan Job
	size  int
	done  chan struct{}
}

// New returns a new dispatcher.
// size: how many workers would init.
// queueLen: how many jobs would put in queue.
func New(size int, queueLen int) (*Dispatcher, error) {
	if size < 1 {
		return nil, errInvalidWorkerSize
	}
	if queueLen < 1 {
		return nil, errInvalidQueueSize
	}
	d := &Dispatcher{
		ws:    make(chan *Worker, size),
		queue: make(chan Job, queueLen),
		size:  size,
		done:  make(chan struct{}, 1),
	}
	d.run()
	return d, nil
}

// run keep dispatching jobs between workers.
func (d *Dispatcher) run() {
	// init and run workers.
	for i := 0; i < d.size; i++ {
		w := newWorker(i, d.ws)
		go w.run()
		d.ws <- w
	}
	go func() {
		for {
			select {
			case job := <-d.queue:
				select {
				case wc := <-d.ws:
					select {
					case wc.jobc <- job:
					}
				}
			case <-d.done:
				for i := 0; i < d.size; i++ {
					select {
					case w := <-d.ws:
						w.stop()
					}
				}
				return
			}
		}
	}()
}

// Add add job to queue channel.
// Job type func() error
func (d *Dispatcher) Add(j Job) {
	d.queue <- j
}

// Stop stops all workers.
func (d *Dispatcher) Stop() {
	d.done <- struct{}{}
}

// Worker struct implements own job channel and notifies owner dispatcher when is
// available for work.
type Worker struct {
	ID   int
	dc   chan *Worker
	jobc chan Job
	done chan struct{}
}

// newWorker returns a new worker.
func newWorker(id int, dc chan *Worker) *Worker {
	w := &Worker{
		ID:   id,
		dc:   dc,
		jobc: make(chan Job),
		done: make(chan struct{}, 1),
	}
	return w
}

func (w *Worker) stop() {
	w.done <- struct{}{}
}

// run method runs until Dispatcher.Stop() is called.
// keeps running jobs.
func (w *Worker) run() {
	for {
		select {
		case job := <-w.jobc:
			job()
			select {
			case w.dc <- w:
			}
		case <-w.done:
			return
		}
	}
}
<|endoftext|>


<commit_before>// sidcontrol project main.go
package main

import (
	"code.google.com/p/go.net/websocket"
	"flag"
	"log"
	"net/http"
	"text/template"
	"time"
)

var port uint
var homeTempl = template.Must(template.ParseFiles("home.html"))

func homeHandler(c http.ResponseWriter, req *http.Request) {
	homeTempl.Execute(c, req.Host)
}

func broadCaster() {
	for {
		time.Sleep(3 * time.Second)
		now := time.Now().String()
		log.Println("broadcasting", now)
		h.broadcast <- now
	}
}

func main() {
	flag.UintVar(&port, "port", 8080, "http service address")
	flag.StringVar(&Sidplayer.Command, "player", "sidplayer", "command for the sidplayer")
	flag.StringVar(&Browser.RootPath, "rootpath", "C64Music", "rootpath for sid files")
	flag.Parse()

	if port > 0xffff {
		log.Fatalln("Invalid port number", port)
	}

	go Sidplayer.run()
	go h.run()
	/* go broadCaster() */

	http.HandleFunc("/", homeHandler)
	http.Handle("/ws", websocket.Handler(wsHandler))

	registerService(uint16(port))
	addr := ":" + string(port)
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatal("ListenAndServe:", err)
	}
	/*
		time.Sleep(1 * time.Second)
		Sidplayer.help <- true
		time.Sleep(1 * time.Second)
		Sidplayer.help <- true
		time.Sleep(1 * time.Second)
		log.Println("exiting")
	*/

	/*
		time.Sleep(1 * time.Second)

		stdin.Write([]byte("d\n"))
		log.Println("les")

		buf := make([]byte, 128)
		stdout.Read(buf)

		log.Println(string(buf))
	*/

	/*
		done := make(chan bool)
		go func() {
			_, err = io.Copy(os.Stdout, stdout)
			if err != nil {
				log.Fatal(err)
			}
			stdout.Close()
			done <- true
		}()
		<-done
	*/

	/*
		// reader := bufio.NewReader(stdout)
		log.Println("before")
		time.Sleep(1 * time.Second)

		buf := make([]byte, 1)
		// stdin.Write([]byte("password\n"))

		// line, err := reader.ReadString('\n')
		// line, err := reader.ReadBytes('\n')
		n, err := stdout.Read(buf)
		log.Println("read %d", n)

		fmt.Printf("Aftår readstring\n")
		time.Sleep(1 * time.Second)
		io.WriteString(stdin, "d\n")
		if err != nil {
			// You may check here if err == io.EOF
			log.Fatal(err)
		}
		fmt.Printf("%q", buf)
		fmt.Printf("%s", string(buf))
	*/

	/*
		go h.run()

		if err := http.ListenAndServe(*addr, nil); err != nil {
			log.Fatal("ListenAndServe:", err)
		}
	*/

	/*
		child, err := gexpect.Spawn("/home/jgilje/src/sidplayer/sidplayer-linux/build/sidplayer-dummy")
		if err != nil {
			panic(err)
		}
		child.Interact()
		child.Expect("6510>")
		child.SendLine("d")
		child.Close()
	*/
}
<commit_msg>fixed addr string<commit_after>// sidcontrol project main.go
package main

import (
	"code.google.com/p/go.net/websocket"
	"flag"
	"log"
	"net/http"
	"strconv"
	"text/template"
	"time"
)

var port uint
var homeTempl = template.Must(template.ParseFiles("home.html"))

func homeHandler(c http.ResponseWriter, req *http.Request) {
	homeTempl.Execute(c, req.Host)
}

func broadCaster() {
	for {
		time.Sleep(3 * time.Second)
		now := time.Now().String()
		log.Println("broadcasting", now)
		h.broadcast <- now
	}
}

func main() {
	flag.UintVar(&port, "port", 8080, "http service address")
	flag.StringVar(&Sidplayer.Command, "player", "sidplayer", "command for the sidplayer")
	flag.StringVar(&Browser.RootPath, "rootpath", "C64Music", "rootpath for sid files")
	flag.Parse()

	if port > 0xffff {
		log.Fatalln("Invalid port number", port)
	}

	go Sidplayer.run()
	go h.run()
	/* go broadCaster() */

	http.HandleFunc("/", homeHandler)
	http.Handle("/ws", websocket.Handler(wsHandler))

	registerService(uint16(port))
	addr := ":" + strconv.FormatUint(uint64(port), 10)
	if err := http.ListenAndServe(addr, nil); err != nil {
		log.Fatal("ListenAndServe:", err)
	}
	/*
		time.Sleep(1 * time.Second)
		Sidplayer.help <- true
		time.Sleep(1 * time.Second)
		Sidplayer.help <- true
		time.Sleep(1 * time.Second)
		log.Println("exiting")
	*/

	/*
		time.Sleep(1 * time.Second)

		stdin.Write([]byte("d\n"))
		log.Println("les")

		buf := make([]byte, 128)
		stdout.Read(buf)

		log.Println(string(buf))
	*/

	/*
		done := make(chan bool)
		go func() {
			_, err = io.Copy(os.Stdout, stdout)
			if err != nil {
				log.Fatal(err)
			}
			stdout.Close()
			done <- true
		}()
		<-done
	*/

	/*
		// reader := bufio.NewReader(stdout)
		log.Println("before")
		time.Sleep(1 * time.Second)

		buf := make([]byte, 1)
		// stdin.Write([]byte("password\n"))

		// line, err := reader.ReadString('\n')
		// line, err := reader.ReadBytes('\n')
		n, err := stdout.Read(buf)
		log.Println("read %d", n)

		fmt.Printf("Aftår readstring\n")
		time.Sleep(1 * time.Second)
		io.WriteString(stdin, "d\n")
		if err != nil {
			// You may check here if err == io.EOF
			log.Fatal(err)
		}
		fmt.Printf("%q", buf)
		fmt.Printf("%s", string(buf))
	*/

	/*
		go h.run()

		if err := http.ListenAndServe(*addr, nil); err != nil {
			log.Fatal("ListenAndServe:", err)
		}
	*/

	/*
		child, err := gexpect.Spawn("/home/jgilje/src/sidplayer/sidplayer-linux/build/sidplayer-dummy")
		if err != nil {
			panic(err)
		}
		child.Interact()
		child.Expect("6510>")
		child.SendLine("d")
		child.Close()
	*/
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"github.com/haisum/recaptcha"
	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

type messageModel struct {
	Title   string
	Message string
}

var templates map[string]*template.Template
var reCaptchaSiteKey = os.Getenv("RECAPTCHA_SITE_KEY")
var reCaptcha = recaptcha.R{
	Secret: os.Getenv("RECAPTCHA_SECRET_KEY"),
}
var m = minify.New()

func compileTemplates(templatePaths ...string) (*template.Template, error) {
	var tmpl *template.Template
	for _, templatePath := range templatePaths {
		name := filepath.Base(templatePath)
		if tmpl == nil {
			tmpl = template.New(name)
		} else {
			tmpl = tmpl.New(name)
		}

		b, err := ioutil.ReadFile(templatePath)
		if err != nil {
			return nil, err
		}

		mb, err := m.Bytes("text/html", b)
		if err != nil {
			return nil, err
		}
		tmpl.Parse(string(mb))
	}
	return tmpl, nil
}

func minifyCSSFiles(templateDirectory string) {
	cssFileDirectory := filepath.Join(templateDirectory, "../assets/css/")
	cssFilePaths, _ := filepath.Glob(filepath.Join(cssFileDirectory, "*.css"))
	for _, cssFilePath := range cssFilePaths {
		if cssFilePath[len(cssFilePath)-8:] != ".min.css" {
			continue
		}
		cssFile, err := ioutil.ReadFile(cssFilePath)
		if err != nil {
			panic(err)
		}
		cssFile, err = m.Bytes("text/css", cssFile)
		if err != nil {
			panic(err)
		}
		cssFilePathBase := filepath.Base(cssFilePath)
		miniCSSFilePath := filepath.Join(cssFileDirectory, cssFilePathBase[:len(cssFilePathBase)-3]) + "min.css"
		err = ioutil.WriteFile(miniCSSFilePath, cssFile, 0666)
		if err != nil {
			panic(err)
		}
	}
}

// Execute loads templates from the specified directory and configures routes.
func Execute(templateDirectory string) error {
	if _, err := os.Stat(templateDirectory); err != nil {
		return fmt.Errorf("Could not find template directory '%s'.", templateDirectory)
	}

	m.AddFunc("text/html", html.Minify)
	m.AddFunc("text/css", css.Minify)
	minifyCSSFiles(templateDirectory)

	// Loads template paths.
	templatePaths, _ := filepath.Glob(filepath.Join(templateDirectory, "*.tmpl"))
	sharedPaths, _ := filepath.Glob(filepath.Join(templateDirectory, "shared/*.tmpl"))

	// Loads the templates.
	templates = make(map[string]*template.Template)

	for _, templatePath := range templatePaths {
		tmpl := template.Must(compileTemplates(append(sharedPaths, templatePath)...))

		name := strings.Split(filepath.Base(templatePath), ".")[0]
		templates[name] = tmpl
	}

	// Configures the routes.
	http.HandleFunc("/", index)
	http.HandleFunc("/events", events)
	http.HandleFunc("/team", team)
	http.HandleFunc("/gallery", gallery)
	http.HandleFunc("/partners", partners)
	http.HandleFunc("/sign-up", signUp)
	http.HandleFunc("/contact", contact)
	http.HandleFunc("/unsubscribe", unsubscribe)

	return nil
}
<commit_msg>Delete handlers.go<commit_after><|endoftext|>


<commit_before>package rest

import (
	"gopkg.in/zatiti/router.v1"
	"net/http"
)

// write creates a http handler for creating or updating a document depending on the mode provided
func (s *Service) write(modelFactory ModelFactory, mode string) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		// model is request scoped
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_" + mode + "_one"
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		// Instanciate a value of the model being created from the request body
		err := model.Decode()
		if err == nil {
			// Validate what came through the wire
			verr := model.Validate()
			if verr == nil {
				var v interface{}
				if mode == "insert" {
					v, err = model.Create()
					status = http.StatusCreated
				}
				if mode == "update" {
					v, err = model.Update()
					status = http.StatusNoContent
				}
				if mode == "upsert" {
					v, err = model.Upsert()
					status = http.StatusAccepted
				}
				if err == nil {
					// The output from model.Create could be invalid
					body, _ = model.Encode(v)
					//if err == nil {
					// Allow event broker to be optional
					if s.Broker != nil {
						err = s.Broker.Publish(event, body)
					}
					if err == nil {
						// If a metrics client is defined use it
						if s.Metrics != nil {
							s.Metrics.Incr(event, 1)
						}
					} else {
						// Something wicked happened while publishing to the event stream
						s.Logger.Error(err)
						status, body = InternalServerErrorResponse()
					}
					//} else {
					//	s.Logger.Error(err)
					//	status, body = InternalServerErrorResponse()
					//}
				} else {
					s.Logger.Error(err)
					status, body = InternalServerErrorResponse()
				}
			} else {
				s.Logger.Error(verr.Message)
				status, body = verr.Code, []byte(verr.Message)
			}
		} else {
			s.Logger.Error(err)
			status, body = BadRequestResponse()
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}

// Insert creates a http handler that will create a document in model's database.
func (s *Service) Insert(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "insert")
}

// Update creates a http handler that will updates a document by the model's update selector in model's database
func (s *Service) Update(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "update")
}

// Upsert creates a http handler that will upsert(create or update if it exists) a document selected by the model's upsert selector
func (s *Service) Upsert(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "upsert")
}

// find creates a http handler that will list documents or return one document from a model's database
func (s *Service) find(modelFactory ModelFactory, mode string) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		// model is request scoped
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_find_many"
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// Validate
		verr := model.Validate()
		if verr == nil {
			var v interface{}
			var err error
			if mode == "one" {
				v, err = model.FindOne()
			}
			if mode == "many" {
				v, err = model.FindMany()
			}
			if err == nil {
				body, _ = model.Encode(v)
				// Notify other services, if an event broker exists
				if s.Broker != nil {
					err = s.Broker.Publish(event, body)
				}
				if err == nil {
					status = http.StatusOK
					if s.Metrics != nil {
						s.Metrics.Incr(event, 1)
					}
				} else {
					s.Logger.Error(err)
					status, body = InternalServerErrorResponse()
				}
			} else {
				// Something wicked happened while fetching document/s
				s.Logger.Error(err)
				status, body = InternalServerErrorResponse()
			}
		} else {
			s.Logger.Error(verr.Message)
			status, body = verr.Code, []byte(verr.Message)
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}

// FindOne - creates a http handler that will return one document from a model's database if the id exists
func (s *Service) FindOne(modelFactory ModelFactory) router.Handler {
	return s.find(modelFactory, "one")
}

// FindMany - creates a http handler that will list documents from a model's database
func (s *Service) FindMany(modelFactory ModelFactory) router.Handler {
	return s.find(modelFactory, "many")
}

// Remove creates a http handler that will delete a document by remove selector specified in the model model
func (s *Service) Remove(modelFactory ModelFactory) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_delete_one"
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		verr := model.Validate()
		if verr == nil {
			// Remove the item if it exists
			v, err := model.Remove()
			if err == nil {
				// Encode the output into []byte
				body, _ = model.Encode(v)
				//if err == nil {
				// Notify other services, if an event broker exists
				if s.Broker != nil {
					err = s.Broker.Publish(event, body)
				}
				if err == nil {
					status, body = NoContentResponse()
					// If a metrics client is defined use it
					if s.Metrics != nil {
						s.Metrics.Incr(event, 1)
					}
				} else {
					status, body = InternalServerErrorResponse()
					s.Logger.Error(err)
				}
				//} else {
				//	status, body = InternalServerErrorResponse()
				//	s.Logger.Error(err)
				//}
			} else {
				status, body = InternalServerErrorResponse()
				s.Logger.Error(err)
			}
		} else {
			status, body = verr.Code, []byte(verr.Message)
			s.Logger.Error(verr.Message)
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}
<commit_msg>bug fix, find_one was being recorded as find_many<commit_after>package rest

import (
	"gopkg.in/zatiti/router.v1"
	"net/http"
)

// write creates a http handler for creating or updating a document depending on the mode provided
func (s *Service) write(modelFactory ModelFactory, mode string) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		// model is request scoped
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_" + mode + "_one"
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		// Instanciate a value of the model being created from the request body
		err := model.Decode()
		if err == nil {
			// Validate what came through the wire
			verr := model.Validate()
			if verr == nil {
				var v interface{}
				if mode == "insert" {
					v, err = model.Create()
					status = http.StatusCreated
				}
				if mode == "update" {
					v, err = model.Update()
					status = http.StatusNoContent
				}
				if mode == "upsert" {
					v, err = model.Upsert()
					status = http.StatusAccepted
				}
				if err == nil {
					// The output from model.Create could be invalid
					body, _ = model.Encode(v)
					//if err == nil {
					// Allow event broker to be optional
					if s.Broker != nil {
						err = s.Broker.Publish(event, body)
					}
					if err == nil {
						// If a metrics client is defined use it
						if s.Metrics != nil {
							s.Metrics.Incr(event, 1)
						}
					} else {
						// Something wicked happened while publishing to the event stream
						s.Logger.Error(err)
						status, body = InternalServerErrorResponse()
					}
					//} else {
					//	s.Logger.Error(err)
					//	status, body = InternalServerErrorResponse()
					//}
				} else {
					s.Logger.Error(err)
					status, body = InternalServerErrorResponse()
				}
			} else {
				s.Logger.Error(verr.Message)
				status, body = verr.Code, []byte(verr.Message)
			}
		} else {
			s.Logger.Error(err)
			status, body = BadRequestResponse()
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}

// Insert creates a http handler that will create a document in model's database.
func (s *Service) Insert(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "insert")
}

// Update creates a http handler that will updates a document by the model's update selector in model's database
func (s *Service) Update(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "update")
}

// Upsert creates a http handler that will upsert(create or update if it exists) a document selected by the model's upsert selector
func (s *Service) Upsert(modelFactory ModelFactory) router.Handler {
	return s.write(modelFactory, "upsert")
}

// find creates a http handler that will list documents or return one document from a model's database
func (s *Service) find(modelFactory ModelFactory, mode string) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		// model is request scoped
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_find_" + mode
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// Validate
		verr := model.Validate()
		if verr == nil {
			var v interface{}
			var err error
			if mode == "one" {
				v, err = model.FindOne()
			}
			if mode == "many" {
				v, err = model.FindMany()
			}
			if err == nil {
				body, _ = model.Encode(v)
				// Notify other services, if an event broker exists
				if s.Broker != nil {
					err = s.Broker.Publish(event, body)
				}
				if err == nil {
					status = http.StatusOK
					if s.Metrics != nil {
						s.Metrics.Incr(event, 1)
					}
				} else {
					s.Logger.Error(err)
					status, body = InternalServerErrorResponse()
				}
			} else {
				// Something wicked happened while fetching document/s
				s.Logger.Error(err)
				status, body = InternalServerErrorResponse()
			}
		} else {
			s.Logger.Error(verr.Message)
			status, body = verr.Code, []byte(verr.Message)
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}

// FindOne - creates a http handler that will return one document from a model's database if the id exists
func (s *Service) FindOne(modelFactory ModelFactory) router.Handler {
	return s.find(modelFactory, "one")
}

// FindMany - creates a http handler that will list documents from a model's database
func (s *Service) FindMany(modelFactory ModelFactory) router.Handler {
	return s.find(modelFactory, "many")
}

// Remove creates a http handler that will delete a document by remove selector specified in the model model
func (s *Service) Remove(modelFactory ModelFactory) router.Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		model := modelFactory.New(r)
		// event is the name used to track metrics
		event := model.Name() + "_delete_one"
		// Track how long this function take to return
		stop := s.NewTimer(event)
		defer stop()
		// HTTP response status code
		var status int
		// HTTP response body
		var body []byte
		verr := model.Validate()
		if verr == nil {
			// Remove the item if it exists
			v, err := model.Remove()
			if err == nil {
				// Encode the output into []byte
				body, _ = model.Encode(v)
				//if err == nil {
				// Notify other services, if an event broker exists
				if s.Broker != nil {
					err = s.Broker.Publish(event, body)
				}
				if err == nil {
					status, body = NoContentResponse()
					// If a metrics client is defined use it
					if s.Metrics != nil {
						s.Metrics.Incr(event, 1)
					}
				} else {
					status, body = InternalServerErrorResponse()
					s.Logger.Error(err)
				}
				//} else {
				//	status, body = InternalServerErrorResponse()
				//	s.Logger.Error(err)
				//}
			} else {
				status, body = InternalServerErrorResponse()
				s.Logger.Error(err)
			}
		} else {
			status, body = verr.Code, []byte(verr.Message)
			s.Logger.Error(verr.Message)
		}
		w.WriteHeader(status)
		w.Write(body)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
)

type indexHandler struct {
	chain http.Handler
}

//IndexHandler redirects requests with no path to the root of Prefix
func IndexHandler(h http.Handler) http.Handler {
	return indexHandler{h}
}

func (h indexHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if r.RequestURI == config.Prefix {
		http.Redirect(rw, r, config.Prefix+"/", 301)
		return
	}
	h.chain.ServeHTTP(rw, r)
}

type forwardedHandler struct {
	chain http.Handler
}

//ForwardedHandler replaces the Remote Address with the X-Forwarded-For header if it exists
func ForwardedHandler(h http.Handler) http.Handler {
	return forwardedHandler{h}
}

func (h forwardedHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	addr := strings.Split(r.RemoteAddr, ":")
	if len(addr) != 2 {
		log.Panicln("No Remote Address set")
	}

	if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
		r.RemoteAddr = fmt.Sprintf("%s:%s", ip, addr)
	}

	h.chain.ServeHTTP(rw, r)
}
<commit_msg>correctly parse RemoteAddr<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
)

type indexHandler struct {
	chain http.Handler
}

//IndexHandler redirects requests with no path to the root of Prefix
func IndexHandler(h http.Handler) http.Handler {
	return indexHandler{h}
}

func (h indexHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if r.RequestURI == config.Prefix {
		http.Redirect(rw, r, config.Prefix+"/", 301)
		return
	}
	h.chain.ServeHTTP(rw, r)
}

type forwardedHandler struct {
	chain http.Handler
}

//ForwardedHandler replaces the Remote Address with the X-Forwarded-For header if it exists
func ForwardedHandler(h http.Handler) http.Handler {
	return forwardedHandler{h}
}

func (h forwardedHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	_, port, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		log.Panicln("Error parsing Remote Address:", err)
	}

	if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
		r.RemoteAddr = fmt.Sprintf("%s:%s", ip, port)
	}

	h.chain.ServeHTTP(rw, r)
}
<|endoftext|>