<commit_before>// Copyright 2017 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 remote

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"sort"

	"github.com/gogo/protobuf/proto"
	"github.com/golang/snappy"
	"github.com/prometheus/common/model"

	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/prompb"
	"github.com/prometheus/prometheus/storage"
)

// decodeReadLimit is the maximum size of a read request body in bytes.
const decodeReadLimit = 32 * 1024 * 1024

// DecodeReadRequest reads a remote.Request from a http.Request.
func DecodeReadRequest(r *http.Request) (*prompb.ReadRequest, error) {
	compressed, err := ioutil.ReadAll(io.LimitReader(r.Body, decodeReadLimit))
	if err != nil {
		return nil, err
	}

	reqBuf, err := snappy.Decode(nil, compressed)
	if err != nil {
		return nil, err
	}

	var req prompb.ReadRequest
	if err := proto.Unmarshal(reqBuf, &req); err != nil {
		return nil, err
	}

	return &req, nil
}

// EncodeReadResponse writes a remote.Response to a http.ResponseWriter.
func EncodeReadResponse(resp *prompb.ReadResponse, w http.ResponseWriter) error {
	data, err := proto.Marshal(resp)
	if err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/x-protobuf")
	w.Header().Set("Content-Encoding", "snappy")

	compressed := snappy.Encode(nil, data)
	_, err = w.Write(compressed)
	return err
}

// ToWriteRequest converts an array of samples into a WriteRequest proto.
func ToWriteRequest(samples []*model.Sample) *prompb.WriteRequest {
	req := &prompb.WriteRequest{
		Timeseries: make([]*prompb.TimeSeries, 0, len(samples)),
	}

	for _, s := range samples {
		ts := prompb.TimeSeries{
			Labels: MetricToLabelProtos(s.Metric),
			Samples: []*prompb.Sample{
				{
					Value:     float64(s.Value),
					Timestamp: int64(s.Timestamp),
				},
			},
		}
		req.Timeseries = append(req.Timeseries, &ts)
	}

	return req
}

// ToQuery builds a Query proto.
func ToQuery(from, to int64, matchers []*labels.Matcher, p *storage.SelectParams) (*prompb.Query, error) {
	ms, err := toLabelMatchers(matchers)
	if err != nil {
		return nil, err
	}
	var rp *prompb.ReadHints = nil

	if p != nil {
		rp = &prompb.ReadHints{
			StepMs: p.Step,
			Func:   p.Func,
		}
	}

	return &prompb.Query{
		StartTimestampMs: from,
		EndTimestampMs:   to,
		Matchers:         ms,
		Hints:            rp,
	}, nil
}

// FromQuery unpacks a Query proto.
func FromQuery(req *prompb.Query) (int64, int64, []*labels.Matcher, error) {
	matchers, err := fromLabelMatchers(req.Matchers)
	if err != nil {
		return 0, 0, nil, err
	}
	return req.StartTimestampMs, req.EndTimestampMs, matchers, nil
}

// ToQueryResult builds a QueryResult proto.
func ToQueryResult(ss storage.SeriesSet) (*prompb.QueryResult, error) {
	resp := &prompb.QueryResult{}
	for ss.Next() {
		series := ss.At()
		iter := series.Iterator()
		samples := []*prompb.Sample{}

		for iter.Next() {
			ts, val := iter.At()
			samples = append(samples, &prompb.Sample{
				Timestamp: ts,
				Value:     val,
			})
		}
		if err := iter.Err(); err != nil {
			return nil, err
		}

		resp.Timeseries = append(resp.Timeseries, &prompb.TimeSeries{
			Labels:  labelsToLabelsProto(series.Labels()),
			Samples: samples,
		})
	}
	if err := ss.Err(); err != nil {
		return nil, err
	}
	return resp, nil
}

// FromQueryResult unpacks a QueryResult proto.
func FromQueryResult(res *prompb.QueryResult) storage.SeriesSet {
	series := make([]storage.Series, 0, len(res.Timeseries))
	for _, ts := range res.Timeseries {
		labels := labelProtosToLabels(ts.Labels)
		if err := validateLabelsAndMetricName(labels); err != nil {
			return errSeriesSet{err: err}
		}

		series = append(series, &concreteSeries{
			labels:  labels,
			samples: ts.Samples,
		})
	}
	sort.Sort(byLabel(series))
	return &concreteSeriesSet{
		series: series,
	}
}

type byLabel []storage.Series

func (a byLabel) Len() int           { return len(a) }
func (a byLabel) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byLabel) Less(i, j int) bool { return labels.Compare(a[i].Labels(), a[j].Labels()) < 0 }

// errSeriesSet implements storage.SeriesSet, just returning an error.
type errSeriesSet struct {
	err error
}

func (errSeriesSet) Next() bool {
	return false
}

func (errSeriesSet) At() storage.Series {
	return nil
}

func (e errSeriesSet) Err() error {
	return e.err
}

// concreteSeriesSet implements storage.SeriesSet.
type concreteSeriesSet struct {
	cur    int
	series []storage.Series
}

func (c *concreteSeriesSet) Next() bool {
	c.cur++
	return c.cur-1 < len(c.series)
}

func (c *concreteSeriesSet) At() storage.Series {
	return c.series[c.cur-1]
}

func (c *concreteSeriesSet) Err() error {
	return nil
}

// concreteSeries implements storage.Series.
type concreteSeries struct {
	labels  labels.Labels
	samples []*prompb.Sample
}

func (c *concreteSeries) Labels() labels.Labels {
	return labels.New(c.labels...)
}

func (c *concreteSeries) Iterator() storage.SeriesIterator {
	return newConcreteSeriersIterator(c)
}

// concreteSeriesIterator implements storage.SeriesIterator.
type concreteSeriesIterator struct {
	cur    int
	series *concreteSeries
}

func newConcreteSeriersIterator(series *concreteSeries) storage.SeriesIterator {
	return &concreteSeriesIterator{
		cur:    -1,
		series: series,
	}
}

// Seek implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Seek(t int64) bool {
	c.cur = sort.Search(len(c.series.samples), func(n int) bool {
		return c.series.samples[n].Timestamp >= t
	})
	return c.cur < len(c.series.samples)
}

// At implements storage.SeriesIterator.
func (c *concreteSeriesIterator) At() (t int64, v float64) {
	s := c.series.samples[c.cur]
	return s.Timestamp, s.Value
}

// Next implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Next() bool {
	c.cur++
	return c.cur < len(c.series.samples)
}

// Err implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Err() error {
	return nil
}

// validateLabelsAndMetricName validates the label names/values and metric names returned from remote read.
func validateLabelsAndMetricName(ls labels.Labels) error {
	for _, l := range ls {
		if l.Name == labels.MetricName && !model.IsValidMetricName(model.LabelValue(l.Value)) {
			return fmt.Errorf("Invalid metric name: %v", l.Value)
		}
		if !model.LabelName(l.Name).IsValid() {
			return fmt.Errorf("Invalid label name: %v", l.Name)
		}
		if !model.LabelValue(l.Value).IsValid() {
			return fmt.Errorf("Invalid label value: %v", l.Value)
		}
	}
	return nil
}

func toLabelMatchers(matchers []*labels.Matcher) ([]*prompb.LabelMatcher, error) {
	pbMatchers := make([]*prompb.LabelMatcher, 0, len(matchers))
	for _, m := range matchers {
		var mType prompb.LabelMatcher_Type
		switch m.Type {
		case labels.MatchEqual:
			mType = prompb.LabelMatcher_EQ
		case labels.MatchNotEqual:
			mType = prompb.LabelMatcher_NEQ
		case labels.MatchRegexp:
			mType = prompb.LabelMatcher_RE
		case labels.MatchNotRegexp:
			mType = prompb.LabelMatcher_NRE
		default:
			return nil, fmt.Errorf("invalid matcher type")
		}
		pbMatchers = append(pbMatchers, &prompb.LabelMatcher{
			Type:  mType,
			Name:  m.Name,
			Value: m.Value,
		})
	}
	return pbMatchers, nil
}

func fromLabelMatchers(matchers []*prompb.LabelMatcher) ([]*labels.Matcher, error) {
	result := make([]*labels.Matcher, 0, len(matchers))
	for _, matcher := range matchers {
		var mtype labels.MatchType
		switch matcher.Type {
		case prompb.LabelMatcher_EQ:
			mtype = labels.MatchEqual
		case prompb.LabelMatcher_NEQ:
			mtype = labels.MatchNotEqual
		case prompb.LabelMatcher_RE:
			mtype = labels.MatchRegexp
		case prompb.LabelMatcher_NRE:
			mtype = labels.MatchNotRegexp
		default:
			return nil, fmt.Errorf("invalid matcher type")
		}
		matcher, err := labels.NewMatcher(mtype, matcher.Name, matcher.Value)
		if err != nil {
			return nil, err
		}
		result = append(result, matcher)
	}
	return result, nil
}

// MetricToLabelProtos builds a []*prompb.Label from a model.Metric
func MetricToLabelProtos(metric model.Metric) []*prompb.Label {
	labels := make([]*prompb.Label, 0, len(metric))
	for k, v := range metric {
		labels = append(labels, &prompb.Label{
			Name:  string(k),
			Value: string(v),
		})
	}
	sort.Slice(labels, func(i int, j int) bool {
		return labels[i].Name < labels[j].Name
	})
	return labels
}

// LabelProtosToMetric unpack a []*prompb.Label to a model.Metric
func LabelProtosToMetric(labelPairs []*prompb.Label) model.Metric {
	metric := make(model.Metric, len(labelPairs))
	for _, l := range labelPairs {
		metric[model.LabelName(l.Name)] = model.LabelValue(l.Value)
	}
	return metric
}

func labelProtosToLabels(labelPairs []*prompb.Label) labels.Labels {
	result := make(labels.Labels, 0, len(labelPairs))
	for _, l := range labelPairs {
		result = append(result, labels.Label{
			Name:  l.Name,
			Value: l.Value,
		})
	}
	sort.Sort(result)
	return result
}

func labelsToLabelsProto(labels labels.Labels) []*prompb.Label {
	result := make([]*prompb.Label, 0, len(labels))
	for _, l := range labels {
		result = append(result, &prompb.Label{
			Name:  l.Name,
			Value: l.Value,
		})
	}
	return result
}

func labelsToMetric(ls labels.Labels) model.Metric {
	metric := make(model.Metric, len(ls))
	for _, l := range ls {
		metric[model.LabelName(l.Name)] = model.LabelValue(l.Value)
	}
	return metric
}
<commit_msg>Review feedback.<commit_after>// Copyright 2017 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 remote

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"sort"

	"github.com/gogo/protobuf/proto"
	"github.com/golang/snappy"
	"github.com/prometheus/common/model"

	"github.com/prometheus/prometheus/pkg/labels"
	"github.com/prometheus/prometheus/prompb"
	"github.com/prometheus/prometheus/storage"
)

// decodeReadLimit is the maximum size of a read request body in bytes.
const decodeReadLimit = 32 * 1024 * 1024

// DecodeReadRequest reads a remote.Request from a http.Request.
func DecodeReadRequest(r *http.Request) (*prompb.ReadRequest, error) {
	compressed, err := ioutil.ReadAll(io.LimitReader(r.Body, decodeReadLimit))
	if err != nil {
		return nil, err
	}

	reqBuf, err := snappy.Decode(nil, compressed)
	if err != nil {
		return nil, err
	}

	var req prompb.ReadRequest
	if err := proto.Unmarshal(reqBuf, &req); err != nil {
		return nil, err
	}

	return &req, nil
}

// EncodeReadResponse writes a remote.Response to a http.ResponseWriter.
func EncodeReadResponse(resp *prompb.ReadResponse, w http.ResponseWriter) error {
	data, err := proto.Marshal(resp)
	if err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/x-protobuf")
	w.Header().Set("Content-Encoding", "snappy")

	compressed := snappy.Encode(nil, data)
	_, err = w.Write(compressed)
	return err
}

// ToWriteRequest converts an array of samples into a WriteRequest proto.
func ToWriteRequest(samples []*model.Sample) *prompb.WriteRequest {
	req := &prompb.WriteRequest{
		Timeseries: make([]*prompb.TimeSeries, 0, len(samples)),
	}

	for _, s := range samples {
		ts := prompb.TimeSeries{
			Labels: MetricToLabelProtos(s.Metric),
			Samples: []*prompb.Sample{
				{
					Value:     float64(s.Value),
					Timestamp: int64(s.Timestamp),
				},
			},
		}
		req.Timeseries = append(req.Timeseries, &ts)
	}

	return req
}

// ToQuery builds a Query proto.
func ToQuery(from, to int64, matchers []*labels.Matcher, p *storage.SelectParams) (*prompb.Query, error) {
	ms, err := toLabelMatchers(matchers)
	if err != nil {
		return nil, err
	}

	var rp *prompb.ReadHints
	if p != nil {
		rp = &prompb.ReadHints{
			StepMs: p.Step,
			Func:   p.Func,
		}
	}

	return &prompb.Query{
		StartTimestampMs: from,
		EndTimestampMs:   to,
		Matchers:         ms,
		Hints:            rp,
	}, nil
}

// FromQuery unpacks a Query proto.
func FromQuery(req *prompb.Query) (int64, int64, []*labels.Matcher, error) {
	matchers, err := fromLabelMatchers(req.Matchers)
	if err != nil {
		return 0, 0, nil, err
	}
	return req.StartTimestampMs, req.EndTimestampMs, matchers, nil
}

// ToQueryResult builds a QueryResult proto.
func ToQueryResult(ss storage.SeriesSet) (*prompb.QueryResult, error) {
	resp := &prompb.QueryResult{}
	for ss.Next() {
		series := ss.At()
		iter := series.Iterator()
		samples := []*prompb.Sample{}

		for iter.Next() {
			ts, val := iter.At()
			samples = append(samples, &prompb.Sample{
				Timestamp: ts,
				Value:     val,
			})
		}
		if err := iter.Err(); err != nil {
			return nil, err
		}

		resp.Timeseries = append(resp.Timeseries, &prompb.TimeSeries{
			Labels:  labelsToLabelsProto(series.Labels()),
			Samples: samples,
		})
	}
	if err := ss.Err(); err != nil {
		return nil, err
	}
	return resp, nil
}

// FromQueryResult unpacks a QueryResult proto.
func FromQueryResult(res *prompb.QueryResult) storage.SeriesSet {
	series := make([]storage.Series, 0, len(res.Timeseries))
	for _, ts := range res.Timeseries {
		labels := labelProtosToLabels(ts.Labels)
		if err := validateLabelsAndMetricName(labels); err != nil {
			return errSeriesSet{err: err}
		}

		series = append(series, &concreteSeries{
			labels:  labels,
			samples: ts.Samples,
		})
	}
	sort.Sort(byLabel(series))
	return &concreteSeriesSet{
		series: series,
	}
}

type byLabel []storage.Series

func (a byLabel) Len() int           { return len(a) }
func (a byLabel) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byLabel) Less(i, j int) bool { return labels.Compare(a[i].Labels(), a[j].Labels()) < 0 }

// errSeriesSet implements storage.SeriesSet, just returning an error.
type errSeriesSet struct {
	err error
}

func (errSeriesSet) Next() bool {
	return false
}

func (errSeriesSet) At() storage.Series {
	return nil
}

func (e errSeriesSet) Err() error {
	return e.err
}

// concreteSeriesSet implements storage.SeriesSet.
type concreteSeriesSet struct {
	cur    int
	series []storage.Series
}

func (c *concreteSeriesSet) Next() bool {
	c.cur++
	return c.cur-1 < len(c.series)
}

func (c *concreteSeriesSet) At() storage.Series {
	return c.series[c.cur-1]
}

func (c *concreteSeriesSet) Err() error {
	return nil
}

// concreteSeries implements storage.Series.
type concreteSeries struct {
	labels  labels.Labels
	samples []*prompb.Sample
}

func (c *concreteSeries) Labels() labels.Labels {
	return labels.New(c.labels...)
}

func (c *concreteSeries) Iterator() storage.SeriesIterator {
	return newConcreteSeriersIterator(c)
}

// concreteSeriesIterator implements storage.SeriesIterator.
type concreteSeriesIterator struct {
	cur    int
	series *concreteSeries
}

func newConcreteSeriersIterator(series *concreteSeries) storage.SeriesIterator {
	return &concreteSeriesIterator{
		cur:    -1,
		series: series,
	}
}

// Seek implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Seek(t int64) bool {
	c.cur = sort.Search(len(c.series.samples), func(n int) bool {
		return c.series.samples[n].Timestamp >= t
	})
	return c.cur < len(c.series.samples)
}

// At implements storage.SeriesIterator.
func (c *concreteSeriesIterator) At() (t int64, v float64) {
	s := c.series.samples[c.cur]
	return s.Timestamp, s.Value
}

// Next implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Next() bool {
	c.cur++
	return c.cur < len(c.series.samples)
}

// Err implements storage.SeriesIterator.
func (c *concreteSeriesIterator) Err() error {
	return nil
}

// validateLabelsAndMetricName validates the label names/values and metric names returned from remote read.
func validateLabelsAndMetricName(ls labels.Labels) error {
	for _, l := range ls {
		if l.Name == labels.MetricName && !model.IsValidMetricName(model.LabelValue(l.Value)) {
			return fmt.Errorf("Invalid metric name: %v", l.Value)
		}
		if !model.LabelName(l.Name).IsValid() {
			return fmt.Errorf("Invalid label name: %v", l.Name)
		}
		if !model.LabelValue(l.Value).IsValid() {
			return fmt.Errorf("Invalid label value: %v", l.Value)
		}
	}
	return nil
}

func toLabelMatchers(matchers []*labels.Matcher) ([]*prompb.LabelMatcher, error) {
	pbMatchers := make([]*prompb.LabelMatcher, 0, len(matchers))
	for _, m := range matchers {
		var mType prompb.LabelMatcher_Type
		switch m.Type {
		case labels.MatchEqual:
			mType = prompb.LabelMatcher_EQ
		case labels.MatchNotEqual:
			mType = prompb.LabelMatcher_NEQ
		case labels.MatchRegexp:
			mType = prompb.LabelMatcher_RE
		case labels.MatchNotRegexp:
			mType = prompb.LabelMatcher_NRE
		default:
			return nil, fmt.Errorf("invalid matcher type")
		}
		pbMatchers = append(pbMatchers, &prompb.LabelMatcher{
			Type:  mType,
			Name:  m.Name,
			Value: m.Value,
		})
	}
	return pbMatchers, nil
}

func fromLabelMatchers(matchers []*prompb.LabelMatcher) ([]*labels.Matcher, error) {
	result := make([]*labels.Matcher, 0, len(matchers))
	for _, matcher := range matchers {
		var mtype labels.MatchType
		switch matcher.Type {
		case prompb.LabelMatcher_EQ:
			mtype = labels.MatchEqual
		case prompb.LabelMatcher_NEQ:
			mtype = labels.MatchNotEqual
		case prompb.LabelMatcher_RE:
			mtype = labels.MatchRegexp
		case prompb.LabelMatcher_NRE:
			mtype = labels.MatchNotRegexp
		default:
			return nil, fmt.Errorf("invalid matcher type")
		}
		matcher, err := labels.NewMatcher(mtype, matcher.Name, matcher.Value)
		if err != nil {
			return nil, err
		}
		result = append(result, matcher)
	}
	return result, nil
}

// MetricToLabelProtos builds a []*prompb.Label from a model.Metric
func MetricToLabelProtos(metric model.Metric) []*prompb.Label {
	labels := make([]*prompb.Label, 0, len(metric))
	for k, v := range metric {
		labels = append(labels, &prompb.Label{
			Name:  string(k),
			Value: string(v),
		})
	}
	sort.Slice(labels, func(i int, j int) bool {
		return labels[i].Name < labels[j].Name
	})
	return labels
}

// LabelProtosToMetric unpack a []*prompb.Label to a model.Metric
func LabelProtosToMetric(labelPairs []*prompb.Label) model.Metric {
	metric := make(model.Metric, len(labelPairs))
	for _, l := range labelPairs {
		metric[model.LabelName(l.Name)] = model.LabelValue(l.Value)
	}
	return metric
}

func labelProtosToLabels(labelPairs []*prompb.Label) labels.Labels {
	result := make(labels.Labels, 0, len(labelPairs))
	for _, l := range labelPairs {
		result = append(result, labels.Label{
			Name:  l.Name,
			Value: l.Value,
		})
	}
	sort.Sort(result)
	return result
}

func labelsToLabelsProto(labels labels.Labels) []*prompb.Label {
	result := make([]*prompb.Label, 0, len(labels))
	for _, l := range labels {
		result = append(result, &prompb.Label{
			Name:  l.Name,
			Value: l.Value,
		})
	}
	return result
}

func labelsToMetric(ls labels.Labels) model.Metric {
	metric := make(model.Metric, len(ls))
	for _, l := range ls {
		metric[model.LabelName(l.Name)] = model.LabelValue(l.Value)
	}
	return metric
}
<|endoftext|>


<commit_before>package streamtools

import (
	"encoding/xml"
	"github.com/bitly/go-simplejson"
	"github.com/mrallen1/aws4"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"time"
)

var (
	AWSAccessKeyId      string = os.Getenv("AWS_ACCESS_KEY_ID")
	AWSAccessSecret     string = os.Getenv("AWS_SECRET_ACCESS_KEY")
	AWSSQSAPIVersion    string = "2012-11-05"
	AWSSignatureVersion string = "4"
)

type Message struct {
	// this is a list in case I'm ever brave enough to up the "MaxNumberOfMessages" away from 1
	Body          []string `xml:"ReceiveMessageResult>Message>Body"`
	ReceiptHandle []string `xml:"ReceiveMessageResult>Message>ReceiptHandle"`
}

func PollSQS(SQSEndpoint string) Message {
	query := make(url.Values)
	query.Add("Action", "ReceiveMessage")
	query.Add("AttributeName", "All")
	query.Add("Version", AWSSQSAPIVersion)
	query.Add("SignatureVersion", AWSSignatureVersion)
	query.Add("WaitTimeSeconds", "10")

	keys := &aws4.Keys{
		AccessKey: AWSAccessKeyId,
		SecretKey: AWSAccessSecret,
	}

	c := aws4.Client{Keys: keys}

	resp, err := c.Get(SQSEndpoint + query.Encode())
	if err != nil {
		log.Fatal(err.Error())
	}

	var v Message

	body, err := ioutil.ReadAll(resp.Body)
	err = xml.Unmarshal(body, &v)
	if err != nil {
		log.Fatal(err.Error())
	}
	return v

}

func deleteMessage(SQSEndpoint string, ReceiptHandle string) {
	query := make(url.Values)
	query.Add("Action", "DeleteMessage")
	query.Add("ReceiptHandle", ReceiptHandle)
	query.Add("Version", AWSSQSAPIVersion)
	query.Add("SignatureVersion", AWSSignatureVersion)

	keys := &aws4.Keys{
		AccessKey: AWSAccessKeyId,
		SecretKey: AWSAccessSecret,
	}

	c := aws4.Client{Keys: keys}

	_, err := c.Get(SQSEndpoint + query.Encode())
	if err != nil {
		log.Fatal(err.Error())
	}
}

func FromSQS(outChan chan *simplejson.Json, ruleChan chan *simplejson.Json) {

	log.Println("[FROMSQS] AccessKey:", AWSAccessKeyId)
	log.Println("[FROMSQS] AccessSecret:", AWSAccessSecret)

	rules := <-ruleChan

	SQSEndpoint, err := rules.Get("SQSEndpoint").String()
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Println("[FROMSQS] Listening to", SQSEndpoint)

	timer := time.NewTimer(1)

	for {
		select {
		case <-ruleChan:
		case <-timer.C:
			m := PollSQS(SQSEndpoint)
			if len(m.Body) > 0 {
				for i, body := range m.Body {
					out, err := simplejson.NewJson([]byte(body))
					if err != nil {
						log.Fatal(err.Error())
					}
					outChan <- out
					deleteMessage(SQSEndpoint, m.ReceiptHandle[i])
				}
				timer.Reset(time.Duration(10) * time.Millisecond)
			} else {
				timer.Reset(time.Duration(10) * time.Second)
			}

		}

	}

}
<commit_msg>using my fork of aws4<commit_after>package streamtools

import (
	"encoding/xml"
	"github.com/bitly/go-simplejson"
	"github.com/mikedewar/aws4"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"time"
)

var (
	AWSAccessKeyId      string = os.Getenv("AWS_ACCESS_KEY_ID")
	AWSAccessSecret     string = os.Getenv("AWS_SECRET_ACCESS_KEY")
	AWSSQSAPIVersion    string = "2012-11-05"
	AWSSignatureVersion string = "4"
)

type Message struct {
	// this is a list in case I'm ever brave enough to up the "MaxNumberOfMessages" away from 1
	Body          []string `xml:"ReceiveMessageResult>Message>Body"`
	ReceiptHandle []string `xml:"ReceiveMessageResult>Message>ReceiptHandle"`
}

func PollSQS(SQSEndpoint string) Message {
	query := make(url.Values)
	query.Add("Action", "ReceiveMessage")
	query.Add("AttributeName", "All")
	query.Add("Version", AWSSQSAPIVersion)
	query.Add("SignatureVersion", AWSSignatureVersion)
	query.Add("WaitTimeSeconds", "10")

	keys := &aws4.Keys{
		AccessKey: AWSAccessKeyId,
		SecretKey: AWSAccessSecret,
	}

	c := aws4.Client{Keys: keys}

	resp, err := c.Get(SQSEndpoint + query.Encode())
	if err != nil {
		log.Fatal(err.Error())
	}

	var v Message

	body, err := ioutil.ReadAll(resp.Body)
	err = xml.Unmarshal(body, &v)
	if err != nil {
		log.Fatal(err.Error())
	}
	return v

}

func deleteMessage(SQSEndpoint string, ReceiptHandle string) {
	query := make(url.Values)
	query.Add("Action", "DeleteMessage")
	query.Add("ReceiptHandle", ReceiptHandle)
	query.Add("Version", AWSSQSAPIVersion)
	query.Add("SignatureVersion", AWSSignatureVersion)

	keys := &aws4.Keys{
		AccessKey: AWSAccessKeyId,
		SecretKey: AWSAccessSecret,
	}

	c := aws4.Client{Keys: keys}

	_, err := c.Get(SQSEndpoint + query.Encode())
	if err != nil {
		log.Fatal(err.Error())
	}
}

func FromSQS(outChan chan *simplejson.Json, ruleChan chan *simplejson.Json) {

	log.Println("[FROMSQS] AccessKey:", AWSAccessKeyId)
	log.Println("[FROMSQS] AccessSecret:", AWSAccessSecret)

	rules := <-ruleChan

	SQSEndpoint, err := rules.Get("SQSEndpoint").String()
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Println("[FROMSQS] Listening to", SQSEndpoint)

	timer := time.NewTimer(1)

	for {
		select {
		case <-ruleChan:
		case <-timer.C:
			m := PollSQS(SQSEndpoint)
			if len(m.Body) > 0 {
				for i, body := range m.Body {
					out, err := simplejson.NewJson([]byte(body))
					if err != nil {
						log.Fatal(err.Error())
					}
					outChan <- out
					deleteMessage(SQSEndpoint, m.ReceiptHandle[i])
				}
				timer.Reset(time.Duration(10) * time.Millisecond)
			} else {
				timer.Reset(time.Duration(10) * time.Second)
			}

		}

	}

}
<|endoftext|>


<commit_before>// +build linux windows

package libnetwork

import (
	"net"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/common"
)

func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t", eID, svcName, addService)

	// Add container resolution mappings
	c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)

	// Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
	n.(*network).addSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
	for _, alias := range serviceAliases {
		n.(*network).addSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
	}

	// Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
	if len(vip) == 0 {
		n.(*network).addSvcRecords(eID, svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).addSvcRecords(eID, alias, ip, nil, false, method)
		}
	}

	if addService && len(vip) != 0 {
		n.(*network).addSvcRecords(eID, svcName, vip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).addSvcRecords(eID, alias, vip, nil, false, method)
		}
	}

	return nil
}

func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}
	logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)

	// Add resolution for container name
	n.(*network).addSvcRecords(eID, containerName, ip, nil, true, method)

	// Add resolution for taskaliases
	for _, alias := range taskAliases {
		n.(*network).addSvcRecords(eID, alias, ip, nil, true, method)
	}

	return nil
}

func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t", eID, svcName, rmService, multipleEntries)

	// Delete container resolution mappings
	c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)

	// Delete the special "tasks.svc_name" backend record.
	if !multipleEntries {
		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
		}
	}

	// If we are doing DNS RR delete the endpoint IP from DNS record right away.
	if !multipleEntries && len(vip) == 0 {
		n.(*network).deleteSvcRecords(eID, svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, alias, ip, nil, false, method)
		}
	}

	// Remove the DNS record for VIP only if we are removing the service
	if rmService && len(vip) != 0 && !multipleEntries {
		n.(*network).deleteSvcRecords(eID, svcName, vip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, alias, vip, nil, false, method)
		}
	}

	return nil
}

func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}
	logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)

	// Delete resolution for container name
	n.(*network).deleteSvcRecords(eID, containerName, ip, nil, true, method)

	// Delete resolution for taskaliases
	for _, alias := range taskAliases {
		n.(*network).deleteSvcRecords(eID, alias, ip, nil, true, method)
	}

	return nil
}

func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service {
	return &service{
		name:          name,
		id:            id,
		ingressPorts:  ingressPorts,
		loadBalancers: make(map[string]*loadBalancer),
		aliases:       serviceAliases,
		ipToEndpoint:  common.NewSetMatrix(),
	}
}

func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
	skey := serviceKey{
		id:    sid,
		ports: portConfigs(ingressPorts).String(),
	}
	c.Lock()
	s, ok := c.serviceBindings[skey]
	c.Unlock()

	if !ok {
		return 0
	}

	s.Lock()
	lb := s.loadBalancers[nid]
	s.Unlock()

	return int(lb.fwMark)
}

func (c *controller) cleanupServiceBindings(cleanupNID string) {
	var cleanupFuncs []func()

	c.Lock()
	services := make([]*service, 0, len(c.serviceBindings))
	for _, s := range c.serviceBindings {
		services = append(services, s)
	}
	c.Unlock()

	for _, s := range services {
		s.Lock()
		// Skip the serviceBindings that got deleted
		if s.deleted {
			s.Unlock()
			continue
		}
		for nid, lb := range s.loadBalancers {
			if cleanupNID != "" && nid != cleanupNID {
				continue
			}

			for eid, be := range lb.backEnds {
				service := s
				loadBalancer := lb
				networkID := nid
				epID := eid
				epIP := be.ip

				cleanupFuncs = append(cleanupFuncs, func() {
					if err := c.rmServiceBinding(service.name, service.id, networkID, epID, be.containerName, loadBalancer.vip,
						service.ingressPorts, service.aliases, be.taskAliases, epIP, "cleanupServiceBindings"); err != nil {
						logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v",
							service.id, networkID, epID, err)
					}
				})
			}
		}
		s.Unlock()
	}

	for _, f := range cleanupFuncs {
		f()
	}

}

func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error {
	var addService bool

	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	skey := serviceKey{
		id:    svcID,
		ports: portConfigs(ingressPorts).String(),
	}

	var s *service
	for {
		c.Lock()
		var ok bool
		s, ok = c.serviceBindings[skey]
		if !ok {
			// Create a new service if we are seeing this service
			// for the first time.
			s = newService(svcName, svcID, ingressPorts, serviceAliases)
			c.serviceBindings[skey] = s
		}
		c.Unlock()
		s.Lock()
		if !s.deleted {
			// ok the object is good to be used
			break
		}
		s.Unlock()
	}
	logrus.Debugf("addServiceBinding from %s START for %s %s", method, svcName, eID)

	defer s.Unlock()

	lb, ok := s.loadBalancers[nID]
	if !ok {
		// Create a new load balancer if we are seeing this
		// network attachment on the service for the first
		// time.
		lb = &loadBalancer{
			vip:      vip,
			fwMark:   fwMarkCtr,
			backEnds: make(map[string]loadBalancerBackend),
			service:  s,
		}

		fwMarkCtrMu.Lock()
		fwMarkCtr++
		fwMarkCtrMu.Unlock()

		s.loadBalancers[nID] = lb
		addService = true
	}

	lb.backEnds[eID] = loadBalancerBackend{ip: ip,
		containerName: containerName,
		taskAliases:   taskAliases}

	ok, entries := s.assignIPToEndpoint(ip.String(), eID)
	if !ok || entries > 1 {
		setStr, b := s.printIPToEndpoint(ip.String())
		logrus.Warnf("addServiceBinding %s possible trainsient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
	}

	// Add loadbalancer service and backend in all sandboxes in
	// the network only if vip is valid.
	if len(vip) != 0 {
		n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts)
	}

	// Add the appropriate name resolutions
	c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding")

	logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID)

	return nil
}

func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string) error {

	var rmService bool

	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	skey := serviceKey{
		id:    svcID,
		ports: portConfigs(ingressPorts).String(),
	}

	c.Lock()
	s, ok := c.serviceBindings[skey]
	c.Unlock()
	logrus.Debugf("rmServiceBinding from %s START for %s %s", method, svcName, eID)
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
		return nil
	}

	s.Lock()
	defer s.Unlock()
	lb, ok := s.loadBalancers[nID]
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
		return nil
	}

	_, ok = lb.backEnds[eID]
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] !ok", method, svcName, eID)
		return nil
	}

	delete(lb.backEnds, eID)
	if len(lb.backEnds) == 0 {
		// All the backends for this service have been
		// removed. Time to remove the load balancer and also
		// remove the service entry in IPVS.
		rmService = true

		delete(s.loadBalancers, nID)
	}

	if len(s.loadBalancers) == 0 {
		// All loadbalancers for the service removed. Time to
		// remove the service itself.
		c.Lock()

		// Mark the object as deleted so that the add won't use it wrongly
		s.deleted = true
		delete(c.serviceBindings, skey)
		c.Unlock()
	}

	ok, entries := s.removeIPToEndpoint(ip.String(), eID)
	if !ok || entries > 0 {
		setStr, b := s.printIPToEndpoint(ip.String())
		logrus.Warnf("rmServiceBinding %s possible trainsient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
	}

	// Remove loadbalancer service(if needed) and backend in all
	// sandboxes in the network only if the vip is valid.
	if len(vip) != 0 {
		n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
	}

	// Delete the name resolutions
	c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")

	logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
	return nil
}
<commit_msg>IPVS fix<commit_after>// +build linux windows

package libnetwork

import (
	"net"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/common"
)

func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t", eID, svcName, addService)

	// Add container resolution mappings
	c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)

	// Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
	n.(*network).addSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
	for _, alias := range serviceAliases {
		n.(*network).addSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
	}

	// Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
	if len(vip) == 0 {
		n.(*network).addSvcRecords(eID, svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).addSvcRecords(eID, alias, ip, nil, false, method)
		}
	}

	if addService && len(vip) != 0 {
		n.(*network).addSvcRecords(eID, svcName, vip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).addSvcRecords(eID, alias, vip, nil, false, method)
		}
	}

	return nil
}

func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}
	logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)

	// Add resolution for container name
	n.(*network).addSvcRecords(eID, containerName, ip, nil, true, method)

	// Add resolution for taskaliases
	for _, alias := range taskAliases {
		n.(*network).addSvcRecords(eID, alias, ip, nil, true, method)
	}

	return nil
}

func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t", eID, svcName, rmService, multipleEntries)

	// Delete container resolution mappings
	c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)

	// Delete the special "tasks.svc_name" backend record.
	if !multipleEntries {
		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
		}
	}

	// If we are doing DNS RR delete the endpoint IP from DNS record right away.
	if !multipleEntries && len(vip) == 0 {
		n.(*network).deleteSvcRecords(eID, svcName, ip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, alias, ip, nil, false, method)
		}
	}

	// Remove the DNS record for VIP only if we are removing the service
	if rmService && len(vip) != 0 && !multipleEntries {
		n.(*network).deleteSvcRecords(eID, svcName, vip, nil, false, method)
		for _, alias := range serviceAliases {
			n.(*network).deleteSvcRecords(eID, alias, vip, nil, false, method)
		}
	}

	return nil
}

func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}
	logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)

	// Delete resolution for container name
	n.(*network).deleteSvcRecords(eID, containerName, ip, nil, true, method)

	// Delete resolution for taskaliases
	for _, alias := range taskAliases {
		n.(*network).deleteSvcRecords(eID, alias, ip, nil, true, method)
	}

	return nil
}

func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service {
	return &service{
		name:          name,
		id:            id,
		ingressPorts:  ingressPorts,
		loadBalancers: make(map[string]*loadBalancer),
		aliases:       serviceAliases,
		ipToEndpoint:  common.NewSetMatrix(),
	}
}

func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
	skey := serviceKey{
		id:    sid,
		ports: portConfigs(ingressPorts).String(),
	}
	c.Lock()
	s, ok := c.serviceBindings[skey]
	c.Unlock()

	if !ok {
		return 0
	}

	s.Lock()
	lb := s.loadBalancers[nid]
	s.Unlock()

	return int(lb.fwMark)
}

func (c *controller) cleanupServiceBindings(cleanupNID string) {
	var cleanupFuncs []func()

	c.Lock()
	services := make([]*service, 0, len(c.serviceBindings))
	for _, s := range c.serviceBindings {
		services = append(services, s)
	}
	c.Unlock()

	for _, s := range services {
		s.Lock()
		// Skip the serviceBindings that got deleted
		if s.deleted {
			s.Unlock()
			continue
		}
		for nid, lb := range s.loadBalancers {
			if cleanupNID != "" && nid != cleanupNID {
				continue
			}

			for eid, be := range lb.backEnds {
				service := s
				loadBalancer := lb
				networkID := nid
				epID := eid
				epIP := be.ip

				cleanupFuncs = append(cleanupFuncs, func() {
					if err := c.rmServiceBinding(service.name, service.id, networkID, epID, be.containerName, loadBalancer.vip,
						service.ingressPorts, service.aliases, be.taskAliases, epIP, "cleanupServiceBindings"); err != nil {
						logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v",
							service.id, networkID, epID, err)
					}
				})
			}
		}
		s.Unlock()
	}

	for _, f := range cleanupFuncs {
		f()
	}

}

func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error {
	var addService bool

	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	skey := serviceKey{
		id:    svcID,
		ports: portConfigs(ingressPorts).String(),
	}

	var s *service
	for {
		c.Lock()
		var ok bool
		s, ok = c.serviceBindings[skey]
		if !ok {
			// Create a new service if we are seeing this service
			// for the first time.
			s = newService(svcName, svcID, ingressPorts, serviceAliases)
			c.serviceBindings[skey] = s
		}
		c.Unlock()
		s.Lock()
		if !s.deleted {
			// ok the object is good to be used
			break
		}
		s.Unlock()
	}
	logrus.Debugf("addServiceBinding from %s START for %s %s", method, svcName, eID)

	defer s.Unlock()

	lb, ok := s.loadBalancers[nID]
	if !ok {
		// Create a new load balancer if we are seeing this
		// network attachment on the service for the first
		// time.
		fwMarkCtrMu.Lock()

		lb = &loadBalancer{
			vip:      vip,
			fwMark:   fwMarkCtr,
			backEnds: make(map[string]loadBalancerBackend),
			service:  s,
		}

		fwMarkCtr++
		fwMarkCtrMu.Unlock()

		s.loadBalancers[nID] = lb
		addService = true
	}

	lb.backEnds[eID] = loadBalancerBackend{ip: ip,
		containerName: containerName,
		taskAliases:   taskAliases}

	ok, entries := s.assignIPToEndpoint(ip.String(), eID)
	if !ok || entries > 1 {
		setStr, b := s.printIPToEndpoint(ip.String())
		logrus.Warnf("addServiceBinding %s possible trainsient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
	}

	// Add loadbalancer service and backend in all sandboxes in
	// the network only if vip is valid.
	if len(vip) != 0 {
		n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts)
	}

	// Add the appropriate name resolutions
	c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding")

	logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID)

	return nil
}

func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string) error {

	var rmService bool

	n, err := c.NetworkByID(nID)
	if err != nil {
		return err
	}

	skey := serviceKey{
		id:    svcID,
		ports: portConfigs(ingressPorts).String(),
	}

	c.Lock()
	s, ok := c.serviceBindings[skey]
	c.Unlock()
	logrus.Debugf("rmServiceBinding from %s START for %s %s", method, svcName, eID)
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
		return nil
	}

	s.Lock()
	defer s.Unlock()
	lb, ok := s.loadBalancers[nID]
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
		return nil
	}

	_, ok = lb.backEnds[eID]
	if !ok {
		logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] !ok", method, svcName, eID)
		return nil
	}

	delete(lb.backEnds, eID)
	if len(lb.backEnds) == 0 {
		// All the backends for this service have been
		// removed. Time to remove the load balancer and also
		// remove the service entry in IPVS.
		rmService = true

		delete(s.loadBalancers, nID)
	}

	if len(s.loadBalancers) == 0 {
		// All loadbalancers for the service removed. Time to
		// remove the service itself.
		c.Lock()

		// Mark the object as deleted so that the add won't use it wrongly
		s.deleted = true
		delete(c.serviceBindings, skey)
		c.Unlock()
	}

	ok, entries := s.removeIPToEndpoint(ip.String(), eID)
	if !ok || entries > 0 {
		setStr, b := s.printIPToEndpoint(ip.String())
		logrus.Warnf("rmServiceBinding %s possible trainsient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
	}

	// Remove loadbalancer service(if needed) and backend in all
	// sandboxes in the network only if the vip is valid.
	if len(vip) != 0 && entries == 0 {
		n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
	}

	// Delete the name resolutions
	c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")

	logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Tamás Gulácsi

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 structs

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/golang/glog"
)

var _ = glog.Infof

func SaveFunctions(dst io.Writer, functions []Function, pkg string) error {
	var err error
	if pkg != "" {
		if _, err = io.WriteString(dst,
			"package "+pkg+"\n\nimport (\n\t_ \"time\"\t// for datetimes\n)\n\n"); err != nil {
			return err
		}
	}
	types := make(map[string]string)
	for _, fun := range functions {
		for _, dir := range []bool{false, true} {
			if err = fun.SaveStruct(dst, types, dir); err != nil {
				return err
			}
			if _, err = fmt.Fprintf(dst, "\nconst %s = `",
				capitalize(fun.Package+"__"+fun.name+"__plsql")); err != nil {
				return err
			}
			if err = fun.SavePlsqlBlock(dst); err != nil {
				return err
			}
			if _, err = io.WriteString(dst, "`\n"); err != nil {
				return err
			}
		}
	}
	for _, text := range types {
		if _, err = io.WriteString(dst, text); err != nil {
			return err
		}
	}

	return nil
}

func (f Function) SaveStruct(dst io.Writer, types map[string]string, out bool) error {
	//glog.Infof("f=%s", f)
	dirmap, dirname := uint8(DIR_IN), "input"
	if out {
		dirmap, dirname = DIR_OUT, "output"
	}
	var (
		err                    error
		aName, structName, got string
		checks                 []string
	)
	args := make([]Argument, 0, len(f.Args))
	for _, arg := range f.Args {
		//glog.Infof("dir=%d map=%d => %d", arg.Direction, dirmap, arg.Direction&dirmap)
		if arg.Direction&dirmap > 0 {
			args = append(args, arg)
		}
	}
	//glog.Infof("args[%d]: %s", dirmap, args)

	if len(args) == 0 { // no args
		return nil
	}

	if dirmap == uint8(DIR_IN) {
		checks = make([]string, 0, len(args))
	}
	structName = capitalize(f.Package + "__" + f.name + "__" + dirname)
	if _, err = io.WriteString(dst,
		"\n// "+f.Name()+" "+dirname+"\ntype "+structName+" struct {\n"); err != nil {
		return err
	}

	for _, arg := range args {
		aName = capitalize(goName(arg.Name))
		got = arg.goType(types)
		if _, err = io.WriteString(dst, "\t"+aName+" "+got+"\n"); err != nil {
			return err
		}
		if checks != nil {
			checks = genChecks(checks, arg, types, "s")
		}
	}

	if _, err = io.WriteString(dst, "}\n"); err != nil {
		return err
	}

	if checks != nil {
		if _, err = fmt.Fprintf(dst, "\n// Check checks input bounds for %s\nfunc (s %s) Check() error {\n", structName, structName); err != nil {
			return err
		}
		for _, line := range checks {
			if _, err = fmt.Fprintf(dst, line+"\n"); err != nil {
				return err
			}
		}
		if _, err = io.WriteString(dst, "\n\treturn nil\n}\n"); err != nil {
			return err
		}
	}
	return nil
}

func genChecks(checks []string, arg Argument, types map[string]string, base string) []string {
	aName := capitalize(goName(arg.Name))
	got := arg.goType(types)
	switch arg.Flavor {
	case FLAVOR_SIMPLE:
		switch got {
		case "string":
			checks = append(checks,
				fmt.Sprintf(`if len(%s.%s) > %d {
    return errors.New("%s.%s is longer then accepted (%d)")
}`,
					base, aName, arg.Charlength,
					base, aName, arg.Charlength))
		case "int64", "float64":
			if arg.Precision > 0 {
				cons := strings.Repeat("9", int(arg.Precision))
				checks = append(checks,
					fmt.Sprintf(`if (%s.%s <= -%s || %s.%s > %s) {
    return errors.New("%s.%s is out of bounds (-%s..%s)")
}`,
						base, aName, cons, base, aName, cons,
						base, aName, cons, cons))
			}
		}
	case FLAVOR_RECORD:
		for k, sub := range arg.RecordOf {
			_ = k
			checks = genChecks(checks, sub, types, base)
		}
	case FLAVOR_TABLE:
		plus := strings.Join(genChecks(nil, *arg.TableOf, types, "v"), "\n\t")
		checks = append(checks,
			fmt.Sprintf("for i, v := range %s.%s {\n\t%s\n}", base, aName, plus))
	default:
		log.Fatalf("unknown flavor %q", arg.Flavor)
	}
	return checks
}

func capitalize(text string) string {
	if text == "" {
		return text
	}
	return strings.ToUpper(text[:1]) + strings.ToLower(text[1:])
}

func unocap(text string) string {
	i := strings.Index(text, "_")
	if i == 0 {
		return capitalize(text)
	}
	return strings.ToUpper(text[:i]) + "_" + strings.ToLower(text[i+1:])
}

// returns a go type for the argument's type
func (arg Argument) goType(typedefs map[string]string) string {
	if arg.Flavor == FLAVOR_SIMPLE {
		switch arg.Type {
		case "CHAR", "VARCHAR2":
			return "string"
		case "NUMBER":
			return "float64"
		case "INTEGER":
			return "int64"
		case "PLS_INTEGER", "BINARY_INTEGER":
			return "int32"
		case "DATE", "DATETIME", "TIME", "TIMESTAMP":
			return "time.Time"
		case "BOOLEAN", "PL/SQL BOOLEAN":
			return "bool"
		case "REF CURSOR":
			return "*goracle.Cursor"
		case "CLOB":
			return "*goracle.Clob"
		case "BLOB":
			return "*goracle.Blob"
		default:
			log.Fatalf("unknown simple type %s (%s)", arg.Type, arg)
		}
	}
	typName := arg.TypeName
	chunks := strings.Split(typName, ".")
	switch len(chunks) {
	case 1:
	case 2:
		typName = chunks[1] + "__" + chunks[0]
	default:
		typName = strings.Join(chunks[1:], "__") + "__" + chunks[0]
	}
	typName = capitalize(typName)
	if _, ok := typedefs[typName]; ok {
		return typName
	}
	if arg.Flavor == FLAVOR_TABLE {
		glog.Infof("arg=%s tof=%s", arg, arg.TableOf)
		return "[]" + arg.TableOf.goType(typedefs)
	}
	buf := bytes.NewBuffer(make([]byte, 0, 256))
	buf.WriteString("\n// " + arg.TypeName + "\n")
	buf.WriteString("type " + typName + " struct {\n")
	for k, v := range arg.RecordOf {
		buf.WriteString("\t" + capitalize(goName(k)) + " " + v.goType(typedefs) + "\n")
	}
	buf.WriteString("}\n")
	typedefs[typName] = buf.String()
	return typName
}

func goName(text string) string {
	if text == "" {
		return text
	}
	if text[len(text)-1] == '#' {
		return text[:len(text)-1] + "匿" // 0x533f = hide
	}
	return text
}
<commit_msg>move to sql.NullXxxx<commit_after>/*
Copyright 2013 Tamás Gulácsi

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 structs

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/golang/glog"
)

var _ = glog.Infof

func SaveFunctions(dst io.Writer, functions []Function, pkg string) error {
	var err error
	if pkg != "" {
		if _, err = io.WriteString(dst,
			"package "+pkg+`
import (
    _ "time"    // for datetimes
    _ "database/sql"    // for NullXxx
)

`); err != nil {
			return err
		}
	}
	types := make(map[string]string)
	for _, fun := range functions {
		for _, dir := range []bool{false, true} {
			if err = fun.SaveStruct(dst, types, dir); err != nil {
				return err
			}
			if _, err = fmt.Fprintf(dst, "\nconst %s = `",
				capitalize(fun.Package+"__"+fun.name+"__plsql")); err != nil {
				return err
			}
			if err = fun.SavePlsqlBlock(dst); err != nil {
				return err
			}
			if _, err = io.WriteString(dst, "`\n"); err != nil {
				return err
			}
		}
	}
	for _, text := range types {
		if _, err = io.WriteString(dst, text); err != nil {
			return err
		}
	}

	return nil
}

func (f Function) SaveStruct(dst io.Writer, types map[string]string, out bool) error {
	//glog.Infof("f=%s", f)
	dirmap, dirname := uint8(DIR_IN), "input"
	if out {
		dirmap, dirname = DIR_OUT, "output"
	}
	var (
		err                    error
		aName, structName, got string
		checks                 []string
	)
	args := make([]Argument, 0, len(f.Args))
	for _, arg := range f.Args {
		//glog.Infof("dir=%d map=%d => %d", arg.Direction, dirmap, arg.Direction&dirmap)
		if arg.Direction&dirmap > 0 {
			args = append(args, arg)
		}
	}
	//glog.Infof("args[%d]: %s", dirmap, args)

	if len(args) == 0 { // no args
		return nil
	}

	if dirmap == uint8(DIR_IN) {
		checks = make([]string, 0, len(args))
	}
	structName = capitalize(f.Package + "__" + f.name + "__" + dirname)
	if _, err = io.WriteString(dst,
		"\n// "+f.Name()+" "+dirname+"\ntype "+structName+" struct {\n"); err != nil {
		return err
	}

	for _, arg := range args {
		aName = capitalize(goName(arg.Name))
		got = arg.goType(true, types)
        if strings.Index(got, "__") > 0 {
            got = "*" + got
        }
		if _, err = io.WriteString(dst, "\t"+aName+" "+got+"\n"); err != nil {
			return err
		}
		if checks != nil {
			checks = genChecks(checks, arg, types, "s")
		}
	}

	if _, err = io.WriteString(dst, "}\n"); err != nil {
		return err
	}

	if checks != nil {
		if _, err = fmt.Fprintf(dst, "\n// Check checks input bounds for %s\nfunc (s %s) Check() error {\n", structName, structName); err != nil {
			return err
		}
		for _, line := range checks {
			if _, err = fmt.Fprintf(dst, line+"\n"); err != nil {
				return err
			}
		}
		if _, err = io.WriteString(dst, "\n\treturn nil\n}\n"); err != nil {
			return err
		}
	}
	return nil
}

func genChecks(checks []string, arg Argument, types map[string]string, base string) []string {
	aName := capitalize(goName(arg.Name))
	got := arg.goType(true, types)
	var name string
	if aName == "" {
		name = base
	} else {
		name = base + "." + aName
	}
	switch arg.Flavor {
	case FLAVOR_SIMPLE:
		switch got {
		case "string":
			checks = append(checks,
				fmt.Sprintf(`if len(%s) > %d {
        return errors.New("%s is longer then accepted (%d)")
    }`,
					name, arg.Charlength,
					name, arg.Charlength))
		case "sql.NullString":
			checks = append(checks,
				fmt.Sprintf(`if %s.Valid && len(%s.String) > %d {
        return errors.New("%s is longer then accepted (%d)")
    }`,
					name, name, arg.Charlength,
					name, arg.Charlength))
		case "int64", "float64":
			if arg.Precision > 0 {
				cons := strings.Repeat("9", int(arg.Precision))
				checks = append(checks,
					fmt.Sprintf(`if (%s <= -%s || %s > %s) {
        return errors.New("%s is out of bounds (-%s..%s)")
    }`,
						name, cons, name, cons,
						name, cons, cons))
			}
		case "sql.NullInt64", "sql.NullFloat64":
			if arg.Precision > 0 {
				vn := got[8:]
				cons := strings.Repeat("9", int(arg.Precision))
				checks = append(checks,
					fmt.Sprintf(`if %s.Valid && (%s.%s <= -%s || %s.%s > %s) {
        return errors.New("%s is out of bounds (-%s..%s)")
    }`,
						name, name, vn, cons, name, vn, cons,
						name, cons, cons))
			}
		}
	case FLAVOR_RECORD:
		for k, sub := range arg.RecordOf {
			_ = k
			checks = genChecks(checks, sub, types, base)
		}
	case FLAVOR_TABLE:
		plus := strings.Join(genChecks(nil, *arg.TableOf, types, "v"), "\n\t")
		checks = append(checks,
			fmt.Sprintf("for i, v := range %s.%s {\n\t%s\n}", base, aName, plus))
	default:
		log.Fatalf("unknown flavor %q", arg.Flavor)
	}
	return checks
}

func capitalize(text string) string {
	if text == "" {
		return text
	}
	return strings.ToUpper(text[:1]) + strings.ToLower(text[1:])
}

func unocap(text string) string {
	i := strings.Index(text, "_")
	if i == 0 {
		return capitalize(text)
	}
	return strings.ToUpper(text[:i]) + "_" + strings.ToLower(text[i+1:])
}

// returns a go type for the argument's type
func (arg Argument) goType(nullable bool, typedefs map[string]string) string {
	if arg.Flavor == FLAVOR_SIMPLE {
		switch arg.Type {
		case "CHAR", "VARCHAR2":
			if nullable {
				return "sql.NullString"
			}
			return "string"
		case "NUMBER":
			if nullable {
				return "sql.NullFloat64"
			}
			return "float64"
		case "INTEGER":
			if nullable {
				return "sql.NullInt64"
			}
			return "int64"
		case "PLS_INTEGER", "BINARY_INTEGER":
			if nullable {
				return "sql.NullInt64"
			}
			return "int32"
		case "BOOLEAN", "PL/SQL BOOLEAN":
			if nullable {
				return "sql.NullBool"
			}
			return "bool"
		case "DATE", "DATETIME", "TIME", "TIMESTAMP":
			return "time.Time"
		case "REF CURSOR":
			return "*goracle.Cursor"
		case "CLOB":
			return "*goracle.Clob"
		case "BLOB":
			return "*goracle.Blob"
		default:
			log.Fatalf("unknown simple type %s (%s)", arg.Type, arg)
		}
	}
	typName := arg.TypeName
	chunks := strings.Split(typName, ".")
	switch len(chunks) {
	case 1:
	case 2:
		typName = chunks[1] + "__" + chunks[0]
	default:
		typName = strings.Join(chunks[1:], "__") + "__" + chunks[0]
	}
	typName = capitalize(typName)
	if _, ok := typedefs[typName]; ok {
		return typName
	}
	if arg.Flavor == FLAVOR_TABLE {
		glog.Infof("arg=%s tof=%s", arg, arg.TableOf)
		return "[]" + arg.TableOf.goType(true, typedefs)
	}
	buf := bytes.NewBuffer(make([]byte, 0, 256))
	buf.WriteString("\n// " + arg.TypeName + "\n")
	buf.WriteString("type " + typName + " struct {\n")
	for k, v := range arg.RecordOf {
		buf.WriteString("\t" + capitalize(goName(k)) + " " + v.goType(true, typedefs) + "\n")
	}
	buf.WriteString("}\n")
	typedefs[typName] = buf.String()
	return typName
}

func goName(text string) string {
	if text == "" {
		return text
	}
	if text[len(text)-1] == '#' {
		return text[:len(text)-1] + "匿" // 0x533f = hide
	}
	return text
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			name := path.Base(path.Clean(saveGame.Player.Name)) // please don't hacko me mister

			ts := time.Now()

			farm, _, err := stardb.FindFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}

			// DEPRECATED filesystem write.
			//
			// Write the save game, then write the screenshot.
			// TODO: deal with races and conflicts.
			saveFile := path.Join(wwwDir(), "saveGames", fmt.Sprintf("%v-%d.xml", name, ts.Unix()))
			sf, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666)
			if err != nil {
				log.Printf("Error opening saveGames %v: %v", saveFile, err)
				continue
			}
			if _, err := sf.Write(d.Body); err != nil {
				log.Printf("Failed to write save file at %v: %v", saveFile, err)
				continue
			} else {
				log.Printf("Wrote saveGame file %v", saveFile)
			}
			sf.Close()

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}

			// DEPRECATED filesystem write.
			mapFile := path.Join(wwwDir(), fmt.Sprintf("map-%v-%d.png", name, ts))
			f, err := os.OpenFile(mapFile, os.O_CREATE|os.O_WRONLY, 0666)
			if err != nil {
				log.Printf("Error opening screenshot file %v: %v", mapFile, err)
				continue
			}
			view.WriteImage(farmMap, saveGame, f)
			f.Close()
			log.Printf("Wrote map file %v", mapFile)

			// GridFs screenshot write.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
				continue
			}

			if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
				log.Print(err)
				fs.Close()
				continue
			}
			fs.Close()
			log.Printf("Wrote grid map file %v", farm.ScreenshotPath())

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<commit_msg>Use the decimal time.<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nictuku/stardew-rocks/parser"
	"github.com/nictuku/stardew-rocks/stardb"
	"github.com/nictuku/stardew-rocks/view"

	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

func wwwDir() string {
	home := os.Getenv("HOME")
	if home == "" {
		home = string(filepath.Separator)
	}
	return filepath.Clean(filepath.Join(home, "www"))
}

func main() {
	conn, err := amqp.Dial("amqp://guest:guest@amqp.stardew.rocks:5672/")
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()
	for _, exc := range []string{"SaveGameInfo-1", "OtherFiles-1"} {
		err = ch.ExchangeDeclare(
			exc,      // name
			"fanout", // type
			false,    // durable
			false,    // auto-deleted
			false,    // internal
			false,    // no-wait
			nil,      // arguments
		)

		failOnError(err, "Failed to declare an exchange")
	}
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,         // queue name
		"",             // routing key
		"OtherFiles-1", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto-ack
		false,  // exclusive
		false,  // no-local
		false,  // no-wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	count := 0

	farmMap := parser.LoadFarmMap()

	go func() {
		for d := range msgs {
			count++
			var reader io.Reader = bytes.NewReader(d.Body)
			// The content is usually gzip encoded by we don't have to worry about that.
			// Apparently rabbitMQ or the Go library will decompress it transparently.
			// d.ContentEncoding == "gzip" {
			saveGame, err := parser.ParseSaveGame(reader)
			if err != nil {
				log.Print("Error parsing saved game:", err)
				continue
			}
			if saveGame.Player.Name == "" {
				log.Print("Ignoring save with blank player name")
				continue
			}

			name := path.Base(path.Clean(saveGame.Player.Name)) // please don't hacko me mister

			ts := time.Now()

			farm, _, err := stardb.FindFarm(stardb.FarmCollection, saveGame.UniqueIDForThisGame, saveGame.Player.Name, saveGame.Player.FarmName)
			if err != nil {
				log.Print("Error fetching farm ID:", err)
				continue
			}

			// DEPRECATED filesystem write.
			//
			// Write the save game, then write the screenshot.
			// TODO: deal with races and conflicts.
			saveFile := path.Join(wwwDir(), "saveGames", fmt.Sprintf("%v-%d.xml", name, ts.Unix()))
			sf, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666)
			if err != nil {
				log.Printf("Error opening saveGames %v: %v", saveFile, err)
				continue
			}
			if _, err := sf.Write(d.Body); err != nil {
				log.Printf("Failed to write save file at %v: %v", saveFile, err)
				continue
			} else {
				log.Printf("Wrote saveGame file %v", saveFile)
			}
			sf.Close()

			// GridFS XML save file write.
			// TODO: broken saves (length 0)
			if err := stardb.WriteSaveFile(farm, d.Body, ts); err != nil {
				log.Print("write save file:", err)
				continue
			}
			// The save file is the most critical and it's been updated, so we should be fine.
			if err := stardb.UpdateFarmTime(farm.InternalID, ts); err != nil {
				log.Print("update farm time:", err)
				continue
			}

			// DEPRECATED filesystem write.
			mapFile := path.Join(wwwDir(), fmt.Sprintf("map-%v-%d.png", name, ts.Unix()))
			f, err := os.OpenFile(mapFile, os.O_CREATE|os.O_WRONLY, 0666)
			if err != nil {
				log.Printf("Error opening screenshot file %v: %v", mapFile, err)
				continue
			}
			view.WriteImage(farmMap, saveGame, f)
			f.Close()
			log.Printf("Wrote map file %v", mapFile)

			// GridFs screenshot write.
			fs, err := stardb.NewScreenshotWriter(farm, ts)
			if err != nil {
				log.Print("Error writing grid screenshot:", err)
				continue
			}

			if err := view.WriteImage(farmMap, saveGame, fs); err != nil {
				log.Print(err)
				fs.Close()
				continue
			}
			fs.Close()
			log.Printf("Wrote grid map file %v", farm.ScreenshotPath())

		}
		log.Printf("Total messages so far: %d", count)

	}()

	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	select {}
}
<|endoftext|>


<commit_before>package scene

import (
	"github.com/mikee385/GolangRayTracer/color"
	"github.com/mikee385/GolangRayTracer/geometry"
	"github.com/mikee385/GolangRayTracer/material"
)

type SceneLight struct {
	sphere Sphere
}

func NewLight(center geometry.Point3D, radius float32, color color.ColorRGB) SceneLight {
	return SceneLight{sphere: NewSphere(center, radius, material.NewMaterial(color))}
}

func (light SceneLight) Center() geometry.Point3D {
	return light.sphere.Center()
}

func (light SceneLight) Radius() float32 {
	return light.sphere.Radius()
}

func (light SceneLight) Intersect(ray geometry.Ray3D) (float32, bool) {
	return light.Intersect(ray)
}

func (light SceneLight) Normal(point geometry.Point3D) geometry.Direction3D {
	return light.sphere.Normal(point)
}

func (light SceneLight) Material(point geometry.Point3D) material.Material {
	return light.sphere.Material(point)
}
<commit_msg>Fixes a bug in `Intersect` of `SceneLight`.<commit_after>package scene

import (
	"github.com/mikee385/GolangRayTracer/color"
	"github.com/mikee385/GolangRayTracer/geometry"
	"github.com/mikee385/GolangRayTracer/material"
)

type SceneLight struct {
	sphere Sphere
}

func NewLight(center geometry.Point3D, radius float32, color color.ColorRGB) SceneLight {
	return SceneLight{sphere: NewSphere(center, radius, material.NewMaterial(color))}
}

func (light SceneLight) Center() geometry.Point3D {
	return light.sphere.Center()
}

func (light SceneLight) Radius() float32 {
	return light.sphere.Radius()
}

func (light SceneLight) Intersect(ray geometry.Ray3D) (float32, bool) {
	return light.sphere.Intersect(ray)
}

func (light SceneLight) Normal(point geometry.Point3D) geometry.Direction3D {
	return light.sphere.Normal(point)
}

func (light SceneLight) Material(point geometry.Point3D) material.Material {
	return light.sphere.Material(point)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux"
)

func main() {
	m := mux.New().
		TransformRaw().
		WithAPIKEY("YOUR_API_KEY").
		WithAPISEC("YOUR_API_SECRET").
		Start()

	crash := make(chan error)
	auth := make(chan bool)

	go func() {
		// if listener will fail, program will exit by passing error to crash channel
		crash <- m.Listen(func(msg interface{}, err error) {
			if err != nil {
				log.Printf("error received: %s\n", err)
			}

			switch v := msg.(type) {
			case event.Info:
				if v.Event == "auth" && v.Status == "OK" {
					auth <- true
				}
			case order.New:
				log.Printf("%T: %+v\n", v, v)
				close(crash)
			}
		})
	}()

	for {
		select {
		case err := <-crash:
			fmt.Printf("err: %s\n", err)
			os.Exit(1)
		case <-auth:
			// authenticated, safe to submit orders etc
			if err := m.Send(&order.NewRequest{
				CID:    788,
				Type:   "EXCHANGE LIMIT",
				Symbol: "tBTCUSD",
				Price:  33,
				Amount: 0.001,
			}); err != nil {
				fmt.Printf("err submitting new order: %s\n", err)
			}
		}
	}
}
<commit_msg>for consistency<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux"
)

func main() {
	m := mux.
		New().
		TransformRaw().
		WithAPIKEY("YOUR_API_KEY").
		WithAPISEC("YOUR_API_SECRET").
		Start()

	crash := make(chan error)
	auth := make(chan bool)

	go func() {
		// if listener will fail, program will exit by passing error to crash channel
		crash <- m.Listen(func(msg interface{}, err error) {
			if err != nil {
				log.Printf("error received: %s\n", err)
			}

			switch v := msg.(type) {
			case event.Info:
				if v.Event == "auth" && v.Status == "OK" {
					auth <- true
				}
			case order.New:
				log.Printf("%T: %+v\n", v, v)
				close(crash)
			}
		})
	}()

	for {
		select {
		case err := <-crash:
			fmt.Printf("err: %s\n", err)
			os.Exit(1)
		case <-auth:
			// authenticated, safe to submit orders etc
			if err := m.Send(&order.NewRequest{
				CID:    788,
				Type:   "EXCHANGE LIMIT",
				Symbol: "tBTCUSD",
				Price:  33,
				Amount: 0.001,
			}); err != nil {
				fmt.Printf("err submitting new order: %s\n", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package logger

import (
	"fmt"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"strings"
)

type DBLogger struct {
	database   *mgo.Database
	collection string
}

type Entry struct {
	Id      bson.ObjectId `bson:"_id"`
	Message string        `bson:"message"`
}

func New(c string, db *mgo.Database) *DBLogger {
	return &DBLogger{
		database:   db,
		collection: c,
	}
}

func (l *DBLogger) Write(data []byte) (int, error) {
	err := l.database.C(l.collection).Insert(Entry{
		Message: strings.TrimSpace(string(data)),
	})

	return len(data), err
}

func Tail(out io.Writer, log string, db *mgo.Database) {
	var entry Entry
	// Find the last entry in the tailable collection, then
	// use that to determine where to begin the cursor
	db.C(log).Find(nil).Sort("-$natural").Limit(1).One(&entry)

	query := func(id string) *mgo.Query {
		return db.C(log).Find(bson.M{
			"_id": bson.M{
				"$gt": id,
			},
		})
	}

	iter := query(entry.Message).Sort("$natural").Tail(-1)
	for {
		for iter.Next(&entry) {
			fmt.Fprintf(out, entry.Message)

			if err := iter.Close(); err != nil {
				fmt.Println(err)
				return
			}

			iter = query(entry.Message).Sort("$natural").Tail(-1)
		}
	}
}
<commit_msg>Log errors when logging to db<commit_after>package logger

import (
	"fmt"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"strings"
)

type DBLogger struct {
	database   *mgo.Database
	collection string
}

type Entry struct {
	Id      bson.ObjectId `bson:"_id"`
	Message string        `bson:"message"`
}

func New(c string, db *mgo.Database) *DBLogger {
	return &DBLogger{
		database:   db,
		collection: c,
	}
}

func (l *DBLogger) Write(data []byte) (int, error) {
	err := l.database.C(l.collection).Insert(Entry{
		Id:      bson.NewObjectId(),
		Message: strings.TrimSpace(string(data)),
	})

	if err != nil {
		fmt.Println(err.Error())
	}
	return len(data), err
}

func Tail(out io.Writer, log string, db *mgo.Database) {
	var entry Entry
	// Find the last entry in the tailable collection, then
	// use that to determine where to begin the cursor
	db.C(log).Find(nil).Sort("-$natural").Limit(1).One(&entry)

	query := func(id string) *mgo.Query {
		return db.C(log).Find(bson.M{
			"_id": bson.M{
				"$gt": id,
			},
		})
	}

	iter := query(entry.Message).Sort("$natural").Tail(-1)
	for {
		for iter.Next(&entry) {
			fmt.Fprintf(out, entry.Message)

			if err := iter.Close(); err != nil {
				fmt.Println(err)
				return
			}

			iter = query(entry.Message).Sort("$natural").Tail(-1)
		}
	}
}
<|endoftext|>


<commit_before>package questions

import (
	"fmt"
	"math"
	"math/bits"
	"math/rand"
	"strconv"
	"strings"
)

// QuestionOne performs addition without using arithmetic operators
func QuestionOne(x, y int64) int64 {
	/*
		 No arithmetic, so binary operations required
		 addition:
			 0 + 0 = 00
			 0 + 1 = 01
			 1 + 0 = 01
			 1 + 1 = 10
		can split addition into adding the result without carrying one
		with the result of carrying the one, without the addition
		this is adding an XOR of the two numbers with and AND shifted by one bit
		101 + 011 = 110 + 010 = 100 + 100 = 000 + 1000

		Alternatively you can iterate through the bits in increasing order of significance and perform AND, carrying the one to the next bit if required.
	*/

	if y == 0 {
		return x
	}
	addition := x ^ y
	carry := (x & y) << 1
	return QuestionOne(addition, carry)
}

const (
	Spade = iota
	Club
	Diamond
	Heart
)

type Card struct {
	suit  int
	value int
}

func (c Card) Print() string {
	switch c.suit {
	case Spade:
		return fmt.Sprintf("S%d ", c.value)
	case Club:
		return fmt.Sprintf("C%d ", c.value)
	case Diamond:
		return fmt.Sprintf("D%d ", c.value)
	case Heart:
		return fmt.Sprintf("H%d ", c.value)
	default:
		return "nope"
	}
}

// QuestionTwo performs a shuffle of a deck of cards, using a perfect random number generator
func QuestionTwo(deck []*Card, position int) []*Card {
	for i := len(deck) - 1; i > 1; i-- {
		k := random(i)
		temp := deck[k]
		deck[k] = deck[i]
		deck[i] = temp
	}
	return deck
}

func initDeck() []*Card {
	deck := []*Card{}
	for _, suit := range []int{Spade, Club, Diamond, Heart} {
		for i := 1; i < 14; i++ {
			deck = append(deck, &Card{suit: suit, value: i})
		}
	}
	return deck
}

// random returns a random int between the 0 and x
func random(x int) int64 {
	return rand.Int63n(int64(x))
}

// QuestionThree generates a random subset of the provided set
func QuestionThree(set []int, count int) []int {
	subset := make([]int, count)
	copy(subset, set[:count])

	for i := count; i < len(set); i++ {
		random := random(len(set))
		if random < int64(count) {
			subset[random] = set[i]
		}
	}
	return subset
}

// Question Four,
func QuestionFour(list []*IntMod, column int64) int64 {
	/*
		An array contains integers from 0 to N, except one is missing
		the integers cannot be accessed directly, but only by the jth bit of array[i]
		find the missing integer in O(n) time

		the missing number will be revealed based on
	*/
	if column >= bits.UintSize {
		return 0
	}

	zeroes := []*IntMod{}
	ones := []*IntMod{}

	for _, i := range list {
		if i.Get(column) {
			// column bit is 1
			ones = append(ones, i)
		} else {
			zeroes = append(zeroes, i)
		}
	}

	if len(zeroes) > len(ones) {
		return (QuestionFour(ones, column+1) << 1) | 1
	} else {
		return (QuestionFour(zeroes, column+1) << 1) | 0
	}
}

type IntMod struct {
	value int64
}

func (i *IntMod) Get(j int64) bool {
	return bits.OnesCount(uint((1<<j)&i.value)) > 0
}

/*
QuestionFive

Given an array of A and B, build the longest sublist containing an equal
number of letters and numbers
*/
func QuestionFive(list []string) []string {
	/*
		Sub string must be even in length
		brute force by checking all subarrays, with some optimisations to allow for early exit

		complexity: N3
	*/
	var subArray []string
	differences := map[int]int{0: -1}
	aCount := 0
	bCount := 0
	for i, element := range list {
		if element == "A" {
			aCount++
		} else {
			bCount++
		}
		difference := aCount - bCount
		marker, ok := differences[difference]
		if !ok {
			differences[difference] = i
		} else {
			subLength := i - marker
			if len(subArray) < subLength {
				subArray = list[marker+1 : i+1]
			}
		}
	}
	return subArray
}

/*
QuestionSix

Write a method to count the total number of 2s between 0 and N inclusive
i.e. 22 -> 2, 12, 20, 21, 22 -> 6
*/
func QuestionSix(N int) int {
	count := 0
	for i := 0; i < len(strconv.Itoa(N)); i++ {
		count = count + CountTwosAtDigit(N, i)
	}
	return count
}

func CountTwosAtDigit(N, d int) int {
	power := int(math.Pow10(d))
	next := power * 10
	right := N % power

	roundDown := N - N%next
	roundUp := roundDown + next

	digit := (N / power) % 10
	if digit < 2 {
		return roundDown / 10
	} else if digit == 2 {
		return roundDown/10 + right + 1
	} else {
		return roundUp / 10
	}
}

/*
QuestionSeven

Given a list of keys and frequencies, and a separate list of synonym key lists
construct a true frequency list
*/
func QuestionSeven(freq map[string]int, synonyms [][]string) map[string]int {
	/*
		key to this is the data structure we use for converting from synonyms
	*/
	g := InitGraph(freq)
	AddSynonyms(g, synonyms)
	return g.CountFrequencies()
}

func InitGraph(freq map[string]int) *FrequencyGraph {
	g := &FrequencyGraph{nodes: map[string]*FrequencyNode{}}
	for k, v := range freq {
		g.AddNode(&FrequencyNode{
			name: k,
			freq: v,
		})
	}
	return g
}

func AddSynonyms(graph *FrequencyGraph, synonyms [][]string) {
	for _, pair := range synonyms {
		graph.AddEdge(pair[0], pair[1])
	}
}

type FrequencyGraph struct {
	nodes map[string]*FrequencyNode
}

func (g *FrequencyGraph) AddNode(node *FrequencyNode) {
	g.nodes[node.name] = node
}

func (g *FrequencyGraph) AddEdge(a, b string) {
	aNode, ok := g.nodes[a]
	if !ok {
		aNode = &FrequencyNode{
			name: a,
			freq: 0,
		}
		g.AddNode(aNode)
	}
	bNode, ok := g.nodes[b]
	if !ok {
		bNode = &FrequencyNode{
			name: b,
			freq: 0,
		}
		g.AddNode(bNode)
	}
	aNode.AddChild(bNode)
}

func (g *FrequencyGraph) Print() string {
	nodes := []string{}
	for k, node := range g.nodes {
		nodes = append(nodes, fmt.Sprintf("%s: %s", k, node.Print()))
	}
	return strings.Join(nodes, "\n")
}

func (g *FrequencyGraph) CountFrequencies() map[string]int {
	fmt.Println(g.Print())
	counts := map[string]int{}
	for _, node := range g.nodes {
		fmt.Println(node.visited, node.name, node.freq)
		if !node.visited {
			counts[node.name] = node.CountFrequencies()
		}
	}
	return counts
}

type FrequencyNode struct {
	name     string
	freq     int
	children []*FrequencyNode
	visited  bool
}

func (n *FrequencyNode) AddChild(node *FrequencyNode) {
	n.children = append(n.children, node)
	node.children = append(node.children, n)
}

func (n *FrequencyNode) CountFrequencies() int {
	n.visited = true
	count := n.freq
	for _, child := range n.children {
		if !child.visited {
			count = count + child.CountFrequencies()
		}
	}
	return count
}

func (n *FrequencyNode) Print() string {
	names := []string{}
	for _, child := range n.children {
		names = append(names, child.name)
	}
	return fmt.Sprintf("%s %d %t children: %s", n.name, n.freq, n.visited, strings.Join(names, ","))
}
<commit_msg>Question changes<commit_after>package questions

import (
	"fmt"
	"math"
	"math/bits"
	"math/rand"
	"strconv"
	"strings"
)

// QuestionOne performs addition without using arithmetic operators
func QuestionOne(x, y int64) int64 {
	/*
		 No arithmetic, so binary operations required
		 addition:
			 0 + 0 = 00
			 0 + 1 = 01
			 1 + 0 = 01
			 1 + 1 = 10
		can split addition into adding the result without carrying one
		with the result of carrying the one, without the addition
		this is adding an XOR of the two numbers with and AND shifted by one bit
		101 + 011 = 110 + 010 = 100 + 100 = 000 + 1000

		Alternatively you can iterate through the bits in increasing order of significance and perform AND, carrying the one to the next bit if required.
	*/

	if y == 0 {
		return x
	}
	addition := x ^ y
	carry := (x & y) << 1
	return QuestionOne(addition, carry)
}

const (
	Spade = iota
	Club
	Diamond
	Heart
)

type Card struct {
	suit  int
	value int
}

func (c Card) Print() string {
	switch c.suit {
	case Spade:
		return fmt.Sprintf("S%d ", c.value)
	case Club:
		return fmt.Sprintf("C%d ", c.value)
	case Diamond:
		return fmt.Sprintf("D%d ", c.value)
	case Heart:
		return fmt.Sprintf("H%d ", c.value)
	default:
		return "nope"
	}
}

// QuestionTwo performs a shuffle of a deck of cards, using a perfect random number generator
func QuestionTwo(deck []*Card, position int) []*Card {
	for i := len(deck) - 1; i > 0; i-- {
		k := random(i)
		temp := deck[k]
		deck[k] = deck[i]
		deck[i] = temp
	}
	return deck
}

func initDeck() []*Card {
	deck := []*Card{}
	for _, suit := range []int{Spade, Club, Diamond, Heart} {
		for i := 1; i < 14; i++ {
			deck = append(deck, &Card{suit: suit, value: i})
		}
	}
	return deck
}

// random returns a random int between the 0 and x
func random(x int) int64 {
	return rand.Int63n(int64(x))
}

// QuestionThree generates a random subset of the provided set
func QuestionThree(set []int, count int) []int {
	subset := make([]int, count)
	copy(subset, set[:count])

	for i := count; i < len(set); i++ {
		random := random(len(set))
		if random < int64(count) {
			subset[random] = set[i]
		}
	}
	return subset
}

// Question Four,
func QuestionFour(list []*IntMod, column int64) int64 {
	/*
		An array contains integers from 0 to N, except one is missing
		the integers cannot be accessed directly, but only by the jth bit of array[i]
		find the missing integer in O(n) time

		the missing number will be revealed based on
	*/
	if column >= bits.UintSize {
		return 0
	}

	zeroes := []*IntMod{}
	ones := []*IntMod{}

	for _, i := range list {
		if i.Get(column) {
			// column bit is 1
			ones = append(ones, i)
		} else {
			zeroes = append(zeroes, i)
		}
	}

	if len(zeroes) > len(ones) {
		return (QuestionFour(ones, column+1) << 1) | 1
	} else {
		return (QuestionFour(zeroes, column+1) << 1) | 0
	}
}

type IntMod struct {
	value int64
}

func (i *IntMod) Get(j int64) bool {
	return bits.OnesCount(uint((1<<j)&i.value)) > 0
}

/*
QuestionFive

Given an array of A and B, build the longest sublist containing an equal
number of letters and numbers
*/
func QuestionFive(list []string) []string {
	/*
		Sub string must be even in length
		brute force by checking all subarrays, with some optimisations to allow for early exit

		complexity: N3
	*/
	var subArray []string
	differences := map[int]int{0: -1}
	aCount := 0
	bCount := 0
	for i, element := range list {
		if element == "A" {
			aCount++
		} else {
			bCount++
		}
		difference := aCount - bCount
		marker, ok := differences[difference]
		if !ok {
			differences[difference] = i
		} else {
			subLength := i - marker
			if len(subArray) < subLength {
				subArray = list[marker+1 : i+1]
			}
		}
	}
	return subArray
}

/*
QuestionSix

Write a method to count the total number of 2s between 0 and N inclusive
i.e. 22 -> 2, 12, 20, 21, 22 -> 6
*/
func QuestionSix(N int) int {
	count := 0
	for i := 0; i < len(strconv.Itoa(N)); i++ {
		count = count + CountTwosAtDigit(N, i)
	}
	return count
}

func CountTwosAtDigit(N, d int) int {
	power := int(math.Pow10(d))
	next := power * 10
	right := N % power

	roundDown := N - N%next
	roundUp := roundDown + next

	digit := (N / power) % 10
	if digit < 2 {
		return roundDown / 10
	} else if digit == 2 {
		return roundDown/10 + right + 1
	} else {
		return roundUp / 10
	}
}

/*
QuestionSeven

Given a list of keys and frequencies, and a separate list of synonym key lists
construct a true frequency list
*/
func QuestionSeven(freq map[string]int, synonyms [][]string) map[string]int {
	/*
		key to this is the data structure we use for converting from synonyms
	*/
	g := InitGraph(freq)
	AddSynonyms(g, synonyms)
	return g.CountFrequencies()
}

func InitGraph(freq map[string]int) *FrequencyGraph {
	g := &FrequencyGraph{nodes: map[string]*FrequencyNode{}}
	for k, v := range freq {
		g.AddNode(&FrequencyNode{
			name: k,
			freq: v,
		})
	}
	return g
}

func AddSynonyms(graph *FrequencyGraph, synonyms [][]string) {
	for _, pair := range synonyms {
		graph.AddEdge(pair[0], pair[1])
	}
}

type FrequencyGraph struct {
	nodes map[string]*FrequencyNode
}

func (g *FrequencyGraph) AddNode(node *FrequencyNode) {
	g.nodes[node.name] = node
}

func (g *FrequencyGraph) AddEdge(a, b string) {
	aNode, ok := g.nodes[a]
	if !ok {
		aNode = &FrequencyNode{
			name: a,
			freq: 0,
		}
		g.AddNode(aNode)
	}
	bNode, ok := g.nodes[b]
	if !ok {
		bNode = &FrequencyNode{
			name: b,
			freq: 0,
		}
		g.AddNode(bNode)
	}
	aNode.AddChild(bNode)
}

func (g *FrequencyGraph) Print() string {
	nodes := []string{}
	for k, node := range g.nodes {
		nodes = append(nodes, fmt.Sprintf("%s: %s", k, node.Print()))
	}
	return strings.Join(nodes, "\n")
}

func (g *FrequencyGraph) CountFrequencies() map[string]int {
	fmt.Println(g.Print())
	counts := map[string]int{}
	for _, node := range g.nodes {
		fmt.Println(node.visited, node.name, node.freq)
		if !node.visited {
			counts[node.name] = node.CountFrequencies()
		}
	}
	return counts
}

type FrequencyNode struct {
	name     string
	freq     int
	children []*FrequencyNode
	visited  bool
}

func (n *FrequencyNode) AddChild(node *FrequencyNode) {
	n.children = append(n.children, node)
	node.children = append(node.children, n)
}

func (n *FrequencyNode) CountFrequencies() int {
	n.visited = true
	count := n.freq
	for _, child := range n.children {
		if !child.visited {
			count = count + child.CountFrequencies()
		}
	}
	return count
}

func (n *FrequencyNode) Print() string {
	names := []string{}
	for _, child := range n.children {
		names = append(names, child.name)
	}
	return fmt.Sprintf("%s %d %t children: %s", n.name, n.freq, n.visited, strings.Join(names, ","))
}
<|endoftext|>