<commit_before>package blackjack

import (
	"math/big"
	"testing"

	"github.com/dwlnetnl/cards/card"

	"github.com/shopspring/decimal"
)

type testRules struct {
	surrender SurrenderRule
}

func (r testRules) NumDecks() uint                  { return 6 }
func (r testRules) DealerHitSoft17() bool           { return true }
func (r testRules) Surrender() SurrenderRule        { return r.surrender }
func (r testRules) CanSplit([]Hand) bool            { return true }
func (r testRules) Double() DoubleRule              { return DoubleAny }
func (r testRules) DoubleAfterSplit() bool          { return true }
func (r testRules) NoHoleCard() bool                { return true }
func (r testRules) OriginalBetsOnly() bool          { return false }
func (r testRules) BlackjackRatio() *big.Rat        { return big.NewRat(3, 2) }
func (r testRules) DealerWinsTie() bool             { return true }
func (r testRules) PerfectPair() bool               { return false }
func (r testRules) PerfectPairRatio() (m, s, p int) { return }

func TestDoubleAfterSplit(t *testing.T) {
	rules := testRules{surrender: EarlySurrender}
	testPlay(t, 38, rules, 10, 5, []event{
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Diamond(card.Ten)},
		},
		nextAction{[]Action{Surrender, Continue}, Continue},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Diamond(card.Ten)},
		},
		nextAction{[]Action{Hit, Stand, Split, Double}, Split},
		splitHand{
			left:  Hand{card.Diamond(card.Ten), card.Spade(card.Four)},
			right: Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Spade(card.Four)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Double},
		doubleHand{
			hand: Hand{
				card.Diamond(card.Ten),
				card.Spade(card.Four),
				card.Diamond(card.Nine),
			},
			withdrawn: decimal.New(10, 0),
		},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Stand},
		outcome{
			outcome: Bust,
			amount:  decimal.New(20, 0),
			dealer:  Hand{card.Diamond(card.Nine), card.Diamond(card.Ten)},
			player: Hand{
				card.Diamond(card.Ten),
				card.Spade(card.Four),
				card.Diamond(card.Nine),
			},
		},
		outcome{
			outcome: Won,
			amount:  decimal.New(20, 0),
			dealer:  Hand{card.Diamond(card.Nine), card.Diamond(card.Ten)},
			player:  Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
	})
}

func TestDealerWinsTie(t *testing.T) {
	rules := testRules{surrender: NoSurrender}
	testPlay(t, 10, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Heart(card.King)},
			player: Hand{card.Heart(card.Three), card.Club(card.Queen)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Hit},
		hand{
			dealer: Hand{card.Heart(card.King)},
			player: Hand{
				card.Heart(card.Three),
				card.Club(card.Queen),
				card.Heart(card.Eight),
			},
		},
		nextAction{[]Action{Hit, Stand}, Stand},
		outcome{
			outcome: Lost,
			amount:  decimal.New(10, 0),
			dealer:  Hand{card.Heart(card.King), card.Spade(card.Ace)},
			player: Hand{
				card.Heart(card.Three),
				card.Club(card.Queen),
				card.Heart(card.Eight),
			},
		},
	})
}

// func TestDealerHitSoft17(t *testing.T) {
// 	rules := testRules{surrender: NoSurrender}
// 	testPlay(t, seed, rules, 10, 0, []event{
//
// 	})
// }

func TestEarlySurrendered(t *testing.T) {
	rules := testRules{surrender: EarlySurrender}
	testPlay(t, 5, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Spade(card.King)},
			player: Hand{card.Diamond(card.Five), card.Diamond(card.Jack)},
		},
		nextAction{[]Action{Surrender, Continue}, Surrender},
		outcome{
			outcome: Surrendered,
			amount:  decimal.New(5, 0),
			dealer:  Hand{card.Spade(card.King)},
			player:  Hand{card.Diamond(card.Five), card.Diamond(card.Jack)},
		},
	})
}

func TestLateSurrendered(t *testing.T) {
	rules := testRules{surrender: LateSurrender}
	testPlay(t, 164, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Diamond(card.Ten)},
			player: Hand{card.Heart(card.Six), card.Club(card.Jack)},
		},
		nextAction{[]Action{Surrender, Continue}, Surrender},
		outcome{
			outcome: Surrendered,
			amount:  decimal.New(5, 0),
			dealer:  Hand{card.Diamond(card.Ten)},
			player:  Hand{card.Heart(card.Six), card.Club(card.Jack)},
		},
	})
}
<commit_msg>blackjack: test dealer hit soft 17<commit_after>package blackjack

import (
	"math/big"
	"testing"

	"github.com/dwlnetnl/cards/card"

	"github.com/shopspring/decimal"
)

type testRules struct {
	surrender SurrenderRule
}

func (r testRules) NumDecks() uint                  { return 6 }
func (r testRules) DealerHitSoft17() bool           { return true }
func (r testRules) Surrender() SurrenderRule        { return r.surrender }
func (r testRules) CanSplit([]Hand) bool            { return true }
func (r testRules) Double() DoubleRule              { return DoubleAny }
func (r testRules) DoubleAfterSplit() bool          { return true }
func (r testRules) NoHoleCard() bool                { return true }
func (r testRules) OriginalBetsOnly() bool          { return false }
func (r testRules) BlackjackRatio() *big.Rat        { return big.NewRat(3, 2) }
func (r testRules) DealerWinsTie() bool             { return true }
func (r testRules) PerfectPair() bool               { return false }
func (r testRules) PerfectPairRatio() (m, s, p int) { return }

func TestDoubleAfterSplit(t *testing.T) {
	rules := testRules{surrender: EarlySurrender}
	testPlay(t, 38, rules, 10, 5, []event{
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Diamond(card.Ten)},
		},
		nextAction{[]Action{Surrender, Continue}, Continue},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Diamond(card.Ten)},
		},
		nextAction{[]Action{Hit, Stand, Split, Double}, Split},
		splitHand{
			left:  Hand{card.Diamond(card.Ten), card.Spade(card.Four)},
			right: Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Spade(card.Four)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Double},
		doubleHand{
			hand: Hand{
				card.Diamond(card.Ten),
				card.Spade(card.Four),
				card.Diamond(card.Nine),
			},
			withdrawn: decimal.New(10, 0),
		},
		hand{
			dealer: Hand{card.Diamond(card.Nine)},
			player: Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Stand},
		outcome{
			outcome: Bust,
			amount:  decimal.New(20, 0),
			dealer:  Hand{card.Diamond(card.Nine), card.Diamond(card.Ten)},
			player: Hand{
				card.Diamond(card.Ten),
				card.Spade(card.Four),
				card.Diamond(card.Nine),
			},
		},
		outcome{
			outcome: Won,
			amount:  decimal.New(20, 0),
			dealer:  Hand{card.Diamond(card.Nine), card.Diamond(card.Ten)},
			player:  Hand{card.Diamond(card.Ten), card.Spade(card.Ace)},
		},
	})
}

func TestDealerWinsTie(t *testing.T) {
	rules := testRules{surrender: NoSurrender}
	testPlay(t, 10, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Heart(card.King)},
			player: Hand{card.Heart(card.Three), card.Club(card.Queen)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Hit},
		hand{
			dealer: Hand{card.Heart(card.King)},
			player: Hand{
				card.Heart(card.Three),
				card.Club(card.Queen),
				card.Heart(card.Eight),
			},
		},
		nextAction{[]Action{Hit, Stand}, Stand},
		outcome{
			outcome: Lost,
			amount:  decimal.New(10, 0),
			dealer:  Hand{card.Heart(card.King), card.Spade(card.Ace)},
			player: Hand{
				card.Heart(card.Three),
				card.Club(card.Queen),
				card.Heart(card.Eight),
			},
		},
	})
}

func TestDealerHitSoft17(t *testing.T) {
	rules := testRules{surrender: NoSurrender}
	testPlay(t, 20, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Heart(card.Ten)},
			player: Hand{card.Club(card.Three), card.Heart(card.Ace)},
		},
		nextAction{[]Action{Hit, Stand, Double}, Stand},
		outcome{
			outcome: Won,
			amount:  decimal.New(20, 0),
			dealer: Hand{
				card.Heart(card.Ten),
				card.Spade(card.Seven),
				card.Club(card.King),
			},
			player: Hand{card.Club(card.Three), card.Heart(card.Ace)},
		},
	})
}

func TestEarlySurrendered(t *testing.T) {
	rules := testRules{surrender: EarlySurrender}
	testPlay(t, 5, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Spade(card.King)},
			player: Hand{card.Diamond(card.Five), card.Diamond(card.Jack)},
		},
		nextAction{[]Action{Surrender, Continue}, Surrender},
		outcome{
			outcome: Surrendered,
			amount:  decimal.New(5, 0),
			dealer:  Hand{card.Spade(card.King)},
			player:  Hand{card.Diamond(card.Five), card.Diamond(card.Jack)},
		},
	})
}

func TestLateSurrendered(t *testing.T) {
	rules := testRules{surrender: LateSurrender}
	testPlay(t, 164, rules, 10, 0, []event{
		hand{
			dealer: Hand{card.Diamond(card.Ten)},
			player: Hand{card.Heart(card.Six), card.Club(card.Jack)},
		},
		nextAction{[]Action{Surrender, Continue}, Surrender},
		outcome{
			outcome: Surrendered,
			amount:  decimal.New(5, 0),
			dealer:  Hand{card.Diamond(card.Ten)},
			player:  Hand{card.Heart(card.Six), card.Club(card.Jack)},
		},
	})
}
<|endoftext|>


<commit_before>package srnd

import (
	"bufio"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"net/textproto"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var TlsNotSupported = errors.New("TLS not supported")
var TlsFailedToLoadCA = errors.New("could not load CA files")

// handle STARTTLS on connection
func HandleStartTLS(conn net.Conn, config *tls.Config) (econn *textproto.Conn, state tls.ConnectionState, err error) {
	if config == nil {
		_, err = io.WriteString(conn, "580 can not intitiate TLS negotiation\r\n")
		if err == nil {
			err = TlsNotSupported
		}
	} else {
		_, err = io.WriteString(conn, "382 Continue with TLS negotiation\r\n")
		if err == nil {
			// begin tls crap here
			tconn := tls.Server(conn, config)
			if err == nil {
				state = tconn.ConnectionState()
				econn = textproto.NewConn(tconn)
				return
			} else {
				tconn.Close()
			}
		}
	}
	return
}

func SendStartTLS(conn net.Conn, config *tls.Config) (econn *textproto.Conn, state tls.ConnectionState, err error) {
	_, err = io.WriteString(conn, "STARTTLS\r\n")
	if err == nil {
		r := bufio.NewReader(conn)
		var line string
		line, err = r.ReadString(10)
		if strings.HasPrefix(line, "382 ") {
			// we gud
			tconn := tls.Client(conn, config)
			// tls okay
			log.Println("TLS Handshake done", config.ServerName)
			state = tconn.ConnectionState()
			econn = textproto.NewConn(tconn)
			return
		} else {
			// it won't do tls
			err = TlsNotSupported
		}
		r = nil
	}
	return
}

// create base tls certificate
func newTLSCert() x509.Certificate {
	return x509.Certificate{
		Subject: pkix.Name{
			Organization: []string{"overchan"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Date(9005, 1, 1, 1, 1, 1, 1, time.UTC),
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
		IsCA: true,
	}
}

// generate tls config, private key and certificate
func GenTLS(cfg *CryptoConfig) (tcfg *tls.Config, err error) {
	EnsureDir(cfg.cert_dir)
	// check for private key
	if !CheckFile(cfg.privkey_file) {
		// no private key, let's generate it
		log.Println("generating 4096 RSA private key...")
		k := newTLSCert()
		var priv *rsa.PrivateKey
		priv, err = rsa.GenerateKey(rand.Reader, 4096)
		if err == nil {
			serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256)
			k.SerialNumber, err = rand.Int(rand.Reader, serialNumberLimit)
			k.DNSNames = append(k.DNSNames, cfg.hostname)
			k.Subject.CommonName = cfg.hostname
			if err == nil {
				var derBytes []byte
				derBytes, err = x509.CreateCertificate(rand.Reader, &k, &k, &priv.PublicKey, priv)
				var f io.WriteCloser
				f, err = os.Create(cfg.cert_file)
				if err == nil {
					err = pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
					f.Close()
					if err == nil {
						f, err = os.Create(cfg.privkey_file)
						if err == nil {
							err = pem.Encode(f, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
							f.Close()
						}
					}
				}
			}
		}
	}
	if err == nil {

		caPool := x509.NewCertPool()
		var m []string
		log.Println("checking", cfg.cert_dir, "for certificates")
		m, err = filepath.Glob(filepath.Join(cfg.cert_dir, "*.crt"))
		log.Println("loading", len(m), "trusted certificates")
		var data []byte
		for _, f := range m {
			var d []byte
			d, err = ioutil.ReadFile(f)
			if err == nil {
				data = append(data, d...)
			} else {
				return
			}
		}
		ok := caPool.AppendCertsFromPEM(data)
		if !ok {
			err = TlsFailedToLoadCA
			return
		}
		// we should have the key generated and stored by now
		var cert tls.Certificate
		cert, err = tls.LoadX509KeyPair(cfg.cert_file, cfg.privkey_file)
		if err == nil {
			tcfg = &tls.Config{
				CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
				RootCAs:      caPool,
				ClientCAs:    caPool,
				Certificates: []tls.Certificate{cert},
				ClientAuth:   tls.RequireAndVerifyClientCert,
			}
		}
	}
	return
}
<commit_msg>try adding tls debug info<commit_after>package srnd

import (
	"bufio"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"net/textproto"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var TlsNotSupported = errors.New("TLS not supported")
var TlsFailedToLoadCA = errors.New("could not load CA files")

// handle STARTTLS on connection
func HandleStartTLS(conn net.Conn, config *tls.Config) (econn *textproto.Conn, state tls.ConnectionState, err error) {
	if config == nil {
		_, err = io.WriteString(conn, "580 can not intitiate TLS negotiation\r\n")
		if err == nil {
			err = TlsNotSupported
		}
	} else {
		_, err = io.WriteString(conn, "382 Continue with TLS negotiation\r\n")
		if err == nil {
			// begin tls crap here
			tconn := tls.Server(conn, config)
			err = tconn.Handshake()
			state = tconn.ConnectionState()
			if err == nil {
				econn = textproto.NewConn(tconn)
				return
			} else {
				certs := state.PeerCertificates
				if len(certs) == 0 {
					log.Println("starttls failed, no peer certs provided")
				} else {
					for _, cert := range certs {
						for _, dns := range cert.DNSNames {
							log.Println("starttls peer cert from", dns, "not valid")
						}
					}
				}
				tconn.Close()
			}
		}
	}
	return
}

func SendStartTLS(conn net.Conn, config *tls.Config) (econn *textproto.Conn, state tls.ConnectionState, err error) {
	_, err = io.WriteString(conn, "STARTTLS\r\n")
	if err == nil {
		r := bufio.NewReader(conn)
		var line string
		line, err = r.ReadString(10)
		if strings.HasPrefix(line, "382 ") {
			// we gud
			tconn := tls.Client(conn, config)
			// tls okay
			log.Println("TLS Handshake done", config.ServerName)
			state = tconn.ConnectionState()
			econn = textproto.NewConn(tconn)
			return
		} else {
			// it won't do tls
			err = TlsNotSupported
		}
		r = nil
	}
	return
}

// create base tls certificate
func newTLSCert() x509.Certificate {
	return x509.Certificate{
		Subject: pkix.Name{
			Organization: []string{"overchan"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Date(9005, 1, 1, 1, 1, 1, 1, time.UTC),
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
		IsCA: true,
	}
}

// generate tls config, private key and certificate
func GenTLS(cfg *CryptoConfig) (tcfg *tls.Config, err error) {
	EnsureDir(cfg.cert_dir)
	// check for private key
	if !CheckFile(cfg.privkey_file) {
		// no private key, let's generate it
		log.Println("generating 4096 RSA private key...")
		k := newTLSCert()
		var priv *rsa.PrivateKey
		priv, err = rsa.GenerateKey(rand.Reader, 4096)
		if err == nil {
			serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256)
			k.SerialNumber, err = rand.Int(rand.Reader, serialNumberLimit)
			k.DNSNames = append(k.DNSNames, cfg.hostname)
			k.Subject.CommonName = cfg.hostname
			if err == nil {
				var derBytes []byte
				derBytes, err = x509.CreateCertificate(rand.Reader, &k, &k, &priv.PublicKey, priv)
				var f io.WriteCloser
				f, err = os.Create(cfg.cert_file)
				if err == nil {
					err = pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
					f.Close()
					if err == nil {
						f, err = os.Create(cfg.privkey_file)
						if err == nil {
							err = pem.Encode(f, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
							f.Close()
						}
					}
				}
			}
		}
	}
	if err == nil {

		caPool := x509.NewCertPool()
		var m []string
		log.Println("checking", cfg.cert_dir, "for certificates")
		m, err = filepath.Glob(filepath.Join(cfg.cert_dir, "*.crt"))
		log.Println("loading", len(m), "trusted certificates")
		var data []byte
		for _, f := range m {
			var d []byte
			d, err = ioutil.ReadFile(f)
			if err == nil {
				data = append(data, d...)
			} else {
				return
			}
		}
		ok := caPool.AppendCertsFromPEM(data)
		if !ok {
			err = TlsFailedToLoadCA
			return
		}
		// we should have the key generated and stored by now
		var cert tls.Certificate
		cert, err = tls.LoadX509KeyPair(cfg.cert_file, cfg.privkey_file)
		if err == nil {
			tcfg = &tls.Config{
				CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
				RootCAs:      caPool,
				ClientCAs:    caPool,
				Certificates: []tls.Certificate{cert},
				ClientAuth:   tls.RequireAndVerifyClientCert,
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"

	"my/itto/verify/packet/itto"
	"my/itto/verify/sim"
)

type SimLogger struct {
	w              io.Writer
	tobOld, tobNew []sim.PriceLevel
	efhLogger      EfhLogger
}

const SimLoggerSupernodeLevels = 32

func NewSimLogger(w io.Writer) *SimLogger {
	s := &SimLogger{w: w}
	s.efhLogger = *NewEfhLogger(s)
	return s
}
func (s *SimLogger) printf(format string, vs ...interface{}) {
	if _, err := fmt.Fprintf(s.w, format, vs...); err != nil {
		log.Fatal("output error", err)
	}
}
func (s *SimLogger) printfln(format string, vs ...interface{}) {
	f := format + "\n"
	s.printf(f, vs...)
}
func (s *SimLogger) MessageArrived(idm *sim.IttoDbMessage) {
	out := func(name string, typ itto.IttoMessageType, f string, vs ...interface{}) {
		s.printf("NORM %s %c ", name, typ)
		s.printfln(f, vs...)
	}
	sideChar := func(s itto.MarketSide) byte {
		if s == itto.MarketSideAsk {
			return 'S'
		}
		return byte(s)
	}
	switch im := idm.Pam.Layer().(type) {
	case *itto.IttoMessageAddOrder:
		out("ORDER", im.Type, "%c %08x %08x %08x %08x", sideChar(im.Side), im.OId, im.RefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageAddQuote:
		out("QBID", im.Type, "%08x %08x %08x %08x", im.OId, im.Bid.RefNumD.Delta(), im.Bid.Size, im.Bid.Price)
		out("QASK", im.Type, "%08x %08x %08x %08x", im.OId, im.Ask.RefNumD.Delta(), im.Ask.Size, im.Ask.Price)
	case *itto.IttoMessageSingleSideExecuted:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageSingleSideExecutedWithPrice:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageOrderCancel:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageSingleSideReplace:
		out("ORDER", im.Type, "%08x %08x %08x %08x", im.RefNumD.Delta(), im.OrigRefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageSingleSideDelete:
		out("ORDER", im.Type, "%08x", im.OrigRefNumD.Delta())
	case *itto.IttoMessageSingleSideUpdate:
		out("ORDER", im.Type, "%08x %08x %08x", im.RefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageQuoteReplace:
		out("QBID", im.Type, "%08x %08x %08x %08x", im.Bid.RefNumD.Delta(), im.Bid.OrigRefNumD.Delta(), im.Bid.Size, im.Bid.Price)
		out("QASK", im.Type, "%08x %08x %08x %08x", im.Ask.RefNumD.Delta(), im.Ask.OrigRefNumD.Delta(), im.Ask.Size, im.Ask.Price)
	case *itto.IttoMessageQuoteDelete:
		out("QBID", im.Type, "%08x", im.BidOrigRefNumD.Delta())
		out("QASK", im.Type, "%08x", im.AskOrigRefNumD.Delta())
	case *itto.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			out("ORDER", im.Type, "%08x", r.Delta())
		}
	}
	s.efhLogger.MessageArrived(idm)
}
func (s *SimLogger) OperationAppliedToOrders(operation sim.IttoOperation) {
	type ordrespLogInfo struct {
		notFound, addOp, refNum uint32
		optionId                itto.OptionId
		side, price, size       int
		ordlSuffix              string
	}
	type orduLogInfo struct {
		refNum            uint32
		optionId          itto.OptionId
		side, price, size int
	}

	var or ordrespLogInfo
	var ou orduLogInfo
	if op, ok := operation.(*sim.OperationAdd); ok {
		var oid itto.OptionId
		if op.Independent() {
			oid = op.GetOptionId()
		}
		or = ordrespLogInfo{
			addOp:      1,
			refNum:     op.RefNumD.Delta(),
			optionId:   oid,
			ordlSuffix: fmt.Sprintf(" %08x", oid),
		}
		ou = orduLogInfo{
			refNum:   or.refNum,
			optionId: op.GetOptionId(),
			price:    op.GetPrice(),
			size:     op.GetNewSize(),
		}
		if op.GetSide() == itto.MarketSideAsk {
			ou.side = 1
		}
	} else {
		if operation.GetOptionId().Invalid() {
			or = ordrespLogInfo{notFound: 1}
		} else {
			or = ordrespLogInfo{
				optionId: operation.GetOptionId(),
				price:    operation.GetPrice(),
				size:     operation.GetNewSize() - operation.GetSizeDelta(),
			}
			if operation.GetSide() == itto.MarketSideAsk {
				or.side = 1
			}
			if operation.GetNewSize() != 0 {
				ou = orduLogInfo{
					optionId: or.optionId,
					side:     or.side,
					price:    or.price,
					size:     operation.GetNewSize(),
				}
			}
		}
		or.refNum = operation.GetOrigRef().Delta()
		ou.refNum = or.refNum
	}
	s.printfln("ORDL %d %08x%s", or.addOp, or.refNum, or.ordlSuffix)
	s.printfln("ORDRESP %d %d %d %08x %08x %08x %08x", or.notFound, or.addOp, or.side, or.size, or.price, or.optionId, or.refNum)
	if operation.GetOptionId().Valid() {
		s.printfln("ORDU %08x %08x %d %08x %08x", ou.refNum, ou.optionId, ou.side, ou.price, ou.size)
	}
}
func (s *SimLogger) BeforeBookUpdate(book sim.Book, operation sim.IttoOperation) {
	s.tobOld = book.GetTop(operation.GetOptionId(), operation.GetSide(), SimLoggerSupernodeLevels)
	s.efhLogger.BeforeBookUpdate(book, operation)
}
func (s *SimLogger) AfterBookUpdate(book sim.Book, operation sim.IttoOperation) {
	if operation.GetOptionId().Valid() {
		s.tobNew = book.GetTop(operation.GetOptionId(), operation.GetSide(), 0)
		if len(s.tobNew) > SimLoggerSupernodeLevels {
			log.Printf("WARNING book (oid %d, side %s) has %d levels (>%d)",
				operation.GetOptionId(), operation.GetSide(),
				len(s.tobNew), SimLoggerSupernodeLevels)
		}

		empty := sim.PriceLevel{}
		if operation.GetSide() == itto.MarketSideAsk {
			empty.Price = -1
		}
		for i := 0; i < SimLoggerSupernodeLevels; i++ {
			plo, pln := empty, empty
			if i < len(s.tobOld) {
				plo = s.tobOld[i]
			}
			if i < len(s.tobNew) {
				pln = s.tobNew[i]
			}
			s.printfln("SN_OLD_NEW %02d %08x %08x  %08x %08x", i,
				plo.Size, uint32(plo.Price),
				pln.Size, uint32(pln.Price),
			)
		}
	}
	s.efhLogger.AfterBookUpdate(book, operation)
}

func (s *SimLogger) PrintOrder(m efhm_order) {
	s.genAppUpdate(m)
}
func (s *SimLogger) PrintQuote(m efhm_quote) {
	s.genAppUpdate(m)
}
func (s *SimLogger) PrintTrade(m efhm_trade) {
	s.genAppUpdate(m)
}

func (s *SimLogger) genAppUpdate(appMessage interface{}) {
	var bb bytes.Buffer
	if err := binary.Write(&bb, binary.LittleEndian, appMessage); err != nil {
		log.Fatal(err)
	}

	for {
		var qw uint64
		if err := binary.Read(&bb, binary.LittleEndian, &qw); err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		} else {
			s.printfln("DMATOHOST_DATA %016x", qw)
		}
	}
	s.printfln("DMATOHOST_TRAILER 00656e696c616b45")
}
<commit_msg>vsim: update hw price levels number to 256<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"

	"my/itto/verify/packet/itto"
	"my/itto/verify/sim"
)

type SimLogger struct {
	w              io.Writer
	tobOld, tobNew []sim.PriceLevel
	efhLogger      EfhLogger
}

const SimLoggerSupernodeLevels = 256

func NewSimLogger(w io.Writer) *SimLogger {
	s := &SimLogger{w: w}
	s.efhLogger = *NewEfhLogger(s)
	return s
}
func (s *SimLogger) printf(format string, vs ...interface{}) {
	if _, err := fmt.Fprintf(s.w, format, vs...); err != nil {
		log.Fatal("output error", err)
	}
}
func (s *SimLogger) printfln(format string, vs ...interface{}) {
	f := format + "\n"
	s.printf(f, vs...)
}
func (s *SimLogger) MessageArrived(idm *sim.IttoDbMessage) {
	out := func(name string, typ itto.IttoMessageType, f string, vs ...interface{}) {
		s.printf("NORM %s %c ", name, typ)
		s.printfln(f, vs...)
	}
	sideChar := func(s itto.MarketSide) byte {
		if s == itto.MarketSideAsk {
			return 'S'
		}
		return byte(s)
	}
	switch im := idm.Pam.Layer().(type) {
	case *itto.IttoMessageAddOrder:
		out("ORDER", im.Type, "%c %08x %08x %08x %08x", sideChar(im.Side), im.OId, im.RefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageAddQuote:
		out("QBID", im.Type, "%08x %08x %08x %08x", im.OId, im.Bid.RefNumD.Delta(), im.Bid.Size, im.Bid.Price)
		out("QASK", im.Type, "%08x %08x %08x %08x", im.OId, im.Ask.RefNumD.Delta(), im.Ask.Size, im.Ask.Price)
	case *itto.IttoMessageSingleSideExecuted:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageSingleSideExecutedWithPrice:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageOrderCancel:
		out("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.Delta(), im.Size)
	case *itto.IttoMessageSingleSideReplace:
		out("ORDER", im.Type, "%08x %08x %08x %08x", im.RefNumD.Delta(), im.OrigRefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageSingleSideDelete:
		out("ORDER", im.Type, "%08x", im.OrigRefNumD.Delta())
	case *itto.IttoMessageSingleSideUpdate:
		out("ORDER", im.Type, "%08x %08x %08x", im.RefNumD.Delta(), im.Size, im.Price)
	case *itto.IttoMessageQuoteReplace:
		out("QBID", im.Type, "%08x %08x %08x %08x", im.Bid.RefNumD.Delta(), im.Bid.OrigRefNumD.Delta(), im.Bid.Size, im.Bid.Price)
		out("QASK", im.Type, "%08x %08x %08x %08x", im.Ask.RefNumD.Delta(), im.Ask.OrigRefNumD.Delta(), im.Ask.Size, im.Ask.Price)
	case *itto.IttoMessageQuoteDelete:
		out("QBID", im.Type, "%08x", im.BidOrigRefNumD.Delta())
		out("QASK", im.Type, "%08x", im.AskOrigRefNumD.Delta())
	case *itto.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			out("ORDER", im.Type, "%08x", r.Delta())
		}
	}
	s.efhLogger.MessageArrived(idm)
}
func (s *SimLogger) OperationAppliedToOrders(operation sim.IttoOperation) {
	type ordrespLogInfo struct {
		notFound, addOp, refNum uint32
		optionId                itto.OptionId
		side, price, size       int
		ordlSuffix              string
	}
	type orduLogInfo struct {
		refNum            uint32
		optionId          itto.OptionId
		side, price, size int
	}

	var or ordrespLogInfo
	var ou orduLogInfo
	if op, ok := operation.(*sim.OperationAdd); ok {
		var oid itto.OptionId
		if op.Independent() {
			oid = op.GetOptionId()
		}
		or = ordrespLogInfo{
			addOp:      1,
			refNum:     op.RefNumD.Delta(),
			optionId:   oid,
			ordlSuffix: fmt.Sprintf(" %08x", oid),
		}
		ou = orduLogInfo{
			refNum:   or.refNum,
			optionId: op.GetOptionId(),
			price:    op.GetPrice(),
			size:     op.GetNewSize(),
		}
		if op.GetSide() == itto.MarketSideAsk {
			ou.side = 1
		}
	} else {
		if operation.GetOptionId().Invalid() {
			or = ordrespLogInfo{notFound: 1}
		} else {
			or = ordrespLogInfo{
				optionId: operation.GetOptionId(),
				price:    operation.GetPrice(),
				size:     operation.GetNewSize() - operation.GetSizeDelta(),
			}
			if operation.GetSide() == itto.MarketSideAsk {
				or.side = 1
			}
			if operation.GetNewSize() != 0 {
				ou = orduLogInfo{
					optionId: or.optionId,
					side:     or.side,
					price:    or.price,
					size:     operation.GetNewSize(),
				}
			}
		}
		or.refNum = operation.GetOrigRef().Delta()
		ou.refNum = or.refNum
	}
	s.printfln("ORDL %d %08x%s", or.addOp, or.refNum, or.ordlSuffix)
	s.printfln("ORDRESP %d %d %d %08x %08x %08x %08x", or.notFound, or.addOp, or.side, or.size, or.price, or.optionId, or.refNum)
	if operation.GetOptionId().Valid() {
		s.printfln("ORDU %08x %08x %d %08x %08x", ou.refNum, ou.optionId, ou.side, ou.price, ou.size)
	}
}
func (s *SimLogger) BeforeBookUpdate(book sim.Book, operation sim.IttoOperation) {
	s.tobOld = book.GetTop(operation.GetOptionId(), operation.GetSide(), SimLoggerSupernodeLevels)
	s.efhLogger.BeforeBookUpdate(book, operation)
}
func (s *SimLogger) AfterBookUpdate(book sim.Book, operation sim.IttoOperation) {
	if operation.GetOptionId().Valid() {
		s.tobNew = book.GetTop(operation.GetOptionId(), operation.GetSide(), 0)
		if len(s.tobNew) > SimLoggerSupernodeLevels {
			log.Printf("WARNING book (oid %d, side %s) has %d levels (>%d)",
				operation.GetOptionId(), operation.GetSide(),
				len(s.tobNew), SimLoggerSupernodeLevels)
		}

		empty := sim.PriceLevel{}
		if operation.GetSide() == itto.MarketSideAsk {
			empty.Price = -1
		}
		for i := 0; i < SimLoggerSupernodeLevels; i++ {
			plo, pln := empty, empty
			if i < len(s.tobOld) {
				plo = s.tobOld[i]
			}
			if i < len(s.tobNew) {
				pln = s.tobNew[i]
			}
			s.printfln("SN_OLD_NEW %02d %08x %08x  %08x %08x", i,
				plo.Size, uint32(plo.Price),
				pln.Size, uint32(pln.Price),
			)
		}
	}
	s.efhLogger.AfterBookUpdate(book, operation)
}

func (s *SimLogger) PrintOrder(m efhm_order) {
	s.genAppUpdate(m)
}
func (s *SimLogger) PrintQuote(m efhm_quote) {
	s.genAppUpdate(m)
}
func (s *SimLogger) PrintTrade(m efhm_trade) {
	s.genAppUpdate(m)
}

func (s *SimLogger) genAppUpdate(appMessage interface{}) {
	var bb bytes.Buffer
	if err := binary.Write(&bb, binary.LittleEndian, appMessage); err != nil {
		log.Fatal(err)
	}

	for {
		var qw uint64
		if err := binary.Read(&bb, binary.LittleEndian, &qw); err != nil {
			if err == io.EOF {
				break
			}
			log.Fatal(err)
		} else {
			s.printfln("DMATOHOST_DATA %016x", qw)
		}
	}
	s.printfln("DMATOHOST_TRAILER 00656e696c616b45")
}
<|endoftext|>


<commit_before>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.5"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>set development version to 1.9.6<commit_after>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.6"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.5.1"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<commit_msg>hub 2.6.0<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.6.0"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.13.0"

	// https://semver.org/#spec-item-10
	VersionMetadata = ""

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"

	// The date/time of the build
	BuildDate string
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	release := VersionPrerelease
	metadata := VersionMetadata

	if release != "" {
		version += fmt.Sprintf("-%s", release)
	}

	if metadata != "" {
		version += fmt.Sprintf("+%s", metadata)
	}

	// Strip off any single quotes added by the git information.
	return strings.ReplaceAll(version, "'", "")
}
<commit_msg>Set default for build date<commit_after>package version

import (
	"fmt"
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.13.0"

	// https://semver.org/#spec-item-10
	VersionMetadata = ""

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"

	// The date/time of the build (actually the HEAD commit in git, to preserve stability)
	BuildDate string = "2022-06-02T18:28:32Z"
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	release := VersionPrerelease
	metadata := VersionMetadata

	if release != "" {
		version += fmt.Sprintf("-%s", release)
	}

	if metadata != "" {
		version += fmt.Sprintf("+%s", metadata)
	}

	// Strip off any single quotes added by the git information.
	return strings.ReplaceAll(version, "'", "")
}
<|endoftext|>


<commit_before>// Copyright 2014 CoreOS, Inc.
//
// 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 version

const Version = "0.5.4"
<commit_msg>version: bump to v0.5.4+git<commit_after>// Copyright 2014 CoreOS, Inc.
//
// 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 version

const Version = "0.5.4+git"
<|endoftext|>


<commit_before>// Copyright 2017 The nats-operator 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 version

var (
	OperatorVersion = "0.2.0-v1alpha2+git"
	GitSHA          = "Not provided (use ./build instead of go build)"
)
<commit_msg>Bump version of operator to v0.2.1<commit_after>// Copyright 2017 The nats-operator 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 version

var (
	OperatorVersion = "0.2.1-v1alpha2+git"
	GitSHA          = "Not provided"
)
<|endoftext|>


<commit_before>package version

import (
	"fmt"
)

// Version is the application's current version
var Version = newVersionNumber(0, 2, 0)

type semverNumber struct {
	major int
	minor int
	patch int
}

// String returns the version number as a string
func (v *semverNumber) String() string {
	return fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch)
}

func newVersionNumber(major, minor, patch int) semverNumber {
	return semverNumber{major: major, minor: minor, patch: patch}
}
<commit_msg>Update version to v0.3.0<commit_after>package version

import (
	"fmt"
)

// Version is the application's current version
var Version = newVersionNumber(0, 3, 0)

type semverNumber struct {
	major int
	minor int
	patch int
}

// String returns the version number as a string
func (v *semverNumber) String() string {
	return fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch)
}

func newVersionNumber(major, minor, patch int) semverNumber {
	return semverNumber{major: major, minor: minor, patch: patch}
}
<|endoftext|>


<commit_before>// Copyright 2019 Istio 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 version

import (
	goversion "github.com/hashicorp/go-version"

	pkgversion "istio.io/operator/pkg/version"
	buildversion "istio.io/pkg/version"
)

const (
	// OperatorVersionString is the version string of this operator binary.
	OperatorVersionString = "1.4.3"
)

var (
	// OperatorBinaryVersion is the Istio operator version.
	OperatorBinaryVersion pkgversion.Version
	// OperatorBinaryGoVersion is the Istio operator version in go-version format.
	OperatorBinaryGoVersion *goversion.Version
)

func init() {
	var err error
	operatorVer := OperatorVersionString
	// If dockerinfo has a tag (e.g., specified by LDFlags), we will use it as the version of operator
	tag := buildversion.DockerInfo.Tag
	if tag != "" && tag != "unknown" {
		operatorVer = tag
	}
	OperatorBinaryGoVersion, err = goversion.NewVersion(operatorVer)
	if err != nil {
		panic(err)
	}
	v, err := pkgversion.NewVersionFromString(operatorVer)
	if err != nil {
		panic(err)
	}
	OperatorBinaryVersion = *v
}
<commit_msg>fix invalid version format from docker build info. (#716)<commit_after>// Copyright 2019 Istio 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 version

import (
	goversion "github.com/hashicorp/go-version"

	pkgversion "istio.io/operator/pkg/version"
)

const (
	// OperatorVersionString is the version string of this operator binary.
	OperatorVersionString = "1.4.3"
)

var (
	// OperatorBinaryVersion is the Istio operator version.
	OperatorBinaryVersion pkgversion.Version
	// OperatorBinaryGoVersion is the Istio operator version in go-version format.
	OperatorBinaryGoVersion *goversion.Version
)

func init() {
	var err error
	operatorVer := OperatorVersionString
	OperatorBinaryGoVersion, err = goversion.NewVersion(operatorVer)
	if err != nil {
		panic(err)
	}
	v, err := pkgversion.NewVersionFromString(operatorVer)
	if err != nil {
		panic(err)
	}
	OperatorBinaryVersion = *v
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 version

var (
	Version         = "2.0.0"
	InternalVersion = "2"
)
<commit_msg>*: bump to 2.0.1<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 version

var (
	Version         = "2.0.1"
	InternalVersion = "2"
)
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre22"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<commit_msg>Update version<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre23"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, Inc.

   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 version

import (
	"github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const Version = "0.8.3+git"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<commit_msg>version: bump to v0.9.0+git<commit_after>/*
   Copyright 2014 CoreOS, Inc.

   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 version

import (
	"github.com/coreos/fleet/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
)

const Version = "0.9.0+git"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "0.8"
<commit_msg>preparation for v1.0<commit_after>package version

// VERSION ...
const VERSION = "1.-1"
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-rc3"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bumping version to 0.6.0-dev<commit_after>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>package version

var (
	VERSION = "0.2.7"

	// GITCOMMIT will be overwritten automatically by the build system
	GITCOMMIT = "HEAD"

	FULL_VERSION = VERSION + " (" + GITCOMMIT + ")"
)
<commit_msg>bump 0.2.9<commit_after>package version

var (
	VERSION = "0.2.9"

	// GITCOMMIT will be overwritten automatically by the build system
	GITCOMMIT = "HEAD"

	FULL_VERSION = VERSION + " (" + GITCOMMIT + ")"
)
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 web

import (
	"crypto/tls"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/control-center/serviced/proxy"

	"github.com/control-center/serviced/coordinator/client"
	"github.com/control-center/serviced/dao"
	domainService "github.com/control-center/serviced/domain/service"
	"github.com/control-center/serviced/utils"
	"github.com/control-center/serviced/zzk"
	"github.com/control-center/serviced/zzk/registry"
	"github.com/control-center/serviced/zzk/service"
	"github.com/zenoss/glog"
)

var (
	allportsLock sync.RWMutex
	allports     map[string]chan bool // map of port number to channel that destroys the server
	cpDao        dao.ControlPlane
)

func init() {
	allports = make(map[string]chan bool)
}

// Removes the port from our local cache and updates the service so the UI will flip to "disabled".
//  Only needs to be called if the port is being disabled unexpectedly due to an error
func disablePort(node service.ServicePublicEndpointNode) {
	//TODO: Add control plane methods to enable/disable public endpoints so we don't have to do a GetService and then UpdateService

	// remove the port from our local cache
	delete(allports, node.Name)

	// find the endpoint that matches this port number for this service (there will only be 1)
	var myService domainService.Service
	var myEndpoint domainService.ServiceEndpoint
	var unused int
	cpDao.GetService(node.ServiceID, &myService)
	for _, endpoint := range myService.Endpoints {
		for _, endpointPort := range endpoint.PortList {
			if endpointPort.PortAddr == node.Name {
				myEndpoint = endpoint
			}
		}
	}

	// disable port
	myService.EnablePort(myEndpoint.Name, node.Name, false)
	if err := cpDao.UpdateService(myService, &unused); err != nil {
		glog.Errorf("Error in disablePort(%s:%s): %v", node.ServiceID, node.Name, err)
	}
}

func (sc *ServiceConfig) ServePublicPorts(shutdown <-chan (interface{}), dao dao.ControlPlane) {
	cpDao = dao
	go sc.syncAllPublicPorts(shutdown)
}

func (sc *ServiceConfig) createPublicPortServer(node service.ServicePublicEndpointNode, stopChan chan bool, shutdown <-chan (interface{})) error {
	port := node.Name
	useTLS := node.UseTLS

	// Declare our listener..
	var listener net.Listener
	var err error

	glog.V(1).Infof("About to listen on port %s; UseTLS=%t", port, useTLS)

	if useTLS {
		// Gather our certs files.
		certFile, keyFile := sc.getCertFiles()

		// Create our certificate from the cert files (strings).
		glog.V(2).Infof("Loading certs from %s, %s", certFile, keyFile)
		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
		if err != nil {
			glog.Errorf("Could not set up tls certificate for public endpoint on port %s for %s: %s", port, node.ServiceID, err)
			disablePort(node)
			return err
		}

		// The list of certs to use for our secure listener on this port.
		certs := []tls.Certificate { cert }

		// This cipher suites and tls min version change may not be needed with golang 1.5
		// https://github.com/golang/go/issues/10094
		// https://github.com/golang/go/issues/9364
		config := &tls.Config{
			MinVersion:               utils.MinTLS(),
			PreferServerCipherSuites: true,
			CipherSuites:             utils.CipherSuites(),
			Certificates:             certs,
		}

		glog.V(1).Infof("Listening with TLS")
		listener, err = tls.Listen("tcp", port, config)
	} else {
		glog.V(1).Infof("Listening without TLS")
		listener, err = net.Listen("tcp", port)
	}

	if err != nil {
		glog.Errorf("Could not setup TCP listener for port %s for public endpoint %s: %s", port, node.ServiceID, err)
		disablePort(node)
		return err
	}

	glog.Infof("Listening on port %s; UseTLS=%t", port, useTLS)

	go func() {
		for {
			// accept connection on public port
			localConn, err := listener.Accept()
			if err != nil {
				glog.V(1).Infof("Stopping accept on port %s", port)
				return
			}

			// lookup remote endpoint for this public port
			pepEPInfo, err := sc.getPublicEndpoint(fmt.Sprintf("%s-%d", node.Name, int(node.Type)))
			if err != nil {
				// This happens if an endpoint is accessed and the containers have died or not come up yet.
				glog.Errorf("Error retrieving public endpoint %s-%d: %s", node.Name, int(node.Type), err)
				// close the accepted connection and continue waiting for connections.
				if err := localConn.Close(); err != nil {
					glog.Errorf("Error closing client connection: %s", err)
				}
				continue
			}

			// setup remote connection
			var remoteAddr string
			_, isLocalContainer := sc.localAddrs[pepEPInfo.hostIP]
			if isLocalContainer {
				remoteAddr = fmt.Sprintf("%s:%d", pepEPInfo.privateIP, pepEPInfo.epPort)
			} else {
				remoteAddr = fmt.Sprintf("%s:%d", pepEPInfo.hostIP, sc.muxPort)
			}
			remoteConn, err := sc.getRemoteConnection(remoteAddr, isLocalContainer, sc.muxPort, pepEPInfo.privateIP, pepEPInfo.epPort, sc.muxTLS && (sc.muxPort > 0))
			if err != nil {
				glog.Errorf("Error getting remote connection for public endpoint %s-%d: %v", node.Name, int(node.Type), err)
				continue
			}

			glog.V(2).Infof("Established remote connection to %s", remoteConn.RemoteAddr())

			// Serve proxied requests/responses.  We pass our own port stop channel so that
			// all proxy loops end when our port is shutdown.
			go proxy.ProxyLoop(localConn, remoteConn, stopChan)
		}
	}()

	go func() {
		// Wait for shutdown, then kill all your connections
		select {
		case <-shutdown:
			// Received an application shutdown. Close the port channel to halt all proxy loops.
			glog.Infof("Shutting down port %s", port)
			close(stopChan)
		case <-stopChan:
		}

		listener.Close()
		glog.Infof("Closed port %s", port)
		return
	}()

	return nil
}

func (sc *ServiceConfig) syncAllPublicPorts(shutdown <-chan interface{}) error {
	rootConn, err := zzk.GetLocalConnection("/")
	if err != nil {
		glog.Errorf("syncAllPublicPorts - Error getting root zk connection: %v", err)
		return err
	}

	cancelChan := make(chan interface{})
	zkServicePEPService := service.ZKServicePublicEndpoints

	syncPorts := func(conn client.Connection, parentPath string, childIDs ...string) {
		allportsLock.Lock()
		defer allportsLock.Unlock()

		glog.V(1).Infof("syncPorts STARTING for parentPath:%s childIDs:%v", parentPath, childIDs)

		// start all servers that have been not started and enabled
		newPorts := make(map[string]chan bool)
		for _, pepID := range childIDs {

			// The pepID is the ZK child key. Get the node so we have all of the node data.
			glog.V(1).Infof("zkServicePEPService: %s, pepID: %s", zkServicePEPService, pepID)
			nodePath := fmt.Sprintf("%s/%s", zkServicePEPService, pepID)
			var node service.ServicePublicEndpointNode
			err := rootConn.Get(nodePath, &node)
			if err != nil {
				glog.Errorf("Unable to get the ZK Node from PepID")
				continue
			}

			if node.Type == registry.EPTypePort && node.Enabled {
				port := node.Name
				stopChan, running := allports[port]

				if !running {
					// recently enabled port - port should be opened
					stopChan = make(chan bool)
					if err := sc.createPublicPortServer(node, stopChan, shutdown); err != nil {
						continue
					}
				}

				newPorts[port] = stopChan
			}
		}

		// stop all servers that have been deleted or disabled
		for port, stopChan := range allports {
			_, found := newPorts[port]
			if !found {
				glog.V(2).Infof("Stopping port server for port %s", port)
				close(stopChan)
				glog.Infof("Port server shut down for port %s", port)
			}
		}

		allports = newPorts
		glog.V(2).Infof("Portserver allports: %+v", allports)
	}

	for {
		glog.V(1).Infof("Running registry.WatchChildren for zookeeper path: %s", zkServicePEPService)
		err := registry.WatchChildren(rootConn, zkServicePEPService, cancelChan, syncPorts, pepWatchError)
		if err != nil {
			glog.V(1).Infof("Will retry in 10 seconds to WatchChildren(%s) due to error: %v", zkServicePEPService, err)
			<-time.After(time.Second * 10)
			continue
		}
		select {
		case <-shutdown:
			close(cancelChan)
			return nil
		default:
		}
	}
}
<commit_msg>Quick patch to portservers for https<commit_after>// Copyright 2014 The Serviced 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 web

import (
	"crypto/tls"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/control-center/serviced/proxy"

	"github.com/control-center/serviced/coordinator/client"
	"github.com/control-center/serviced/dao"
	domainService "github.com/control-center/serviced/domain/service"
	"github.com/control-center/serviced/utils"
	"github.com/control-center/serviced/zzk"
	"github.com/control-center/serviced/zzk/registry"
	"github.com/control-center/serviced/zzk/service"
	"github.com/zenoss/glog"

	"net/http"
)

var (
	allportsLock sync.RWMutex
	allports     map[string]chan bool // map of port number to channel that destroys the server
	cpDao        dao.ControlPlane
)

func init() {
	allports = make(map[string]chan bool)
}

// Removes the port from our local cache and updates the service so the UI will flip to "disabled".
//  Only needs to be called if the port is being disabled unexpectedly due to an error
func disablePort(node service.ServicePublicEndpointNode) {
	//TODO: Add control plane methods to enable/disable public endpoints so we don't have to do a GetService and then UpdateService

	// remove the port from our local cache
	delete(allports, node.Name)

	// find the endpoint that matches this port number for this service (there will only be 1)
	var myService domainService.Service
	var myEndpoint domainService.ServiceEndpoint
	var unused int
	cpDao.GetService(node.ServiceID, &myService)
	for _, endpoint := range myService.Endpoints {
		for _, endpointPort := range endpoint.PortList {
			if endpointPort.PortAddr == node.Name {
				myEndpoint = endpoint
			}
		}
	}

	// disable port
	myService.EnablePort(myEndpoint.Name, node.Name, false)
	if err := cpDao.UpdateService(myService, &unused); err != nil {
		glog.Errorf("Error in disablePort(%s:%s): %v", node.ServiceID, node.Name, err)
	}
}

func (sc *ServiceConfig) ServePublicPorts(shutdown <-chan (interface{}), dao dao.ControlPlane) {
	cpDao = dao
	go sc.syncAllPublicPorts(shutdown)
}

// For HTTPS connections, we need to inject a header for downstream servers.
func (sc *ServiceConfig) createPortHttpServer(node service.ServicePublicEndpointNode, stopChan chan bool, shutdown <-chan (interface{})) error {
	port := node.Name
	useTLS := true

	glog.V(1).Infof("About to listen on port (https) %s; UseTLS=%t", port, useTLS)
	glog.V(0).Infof("About to listen on port (https) %s; UseTLS=%t", port, useTLS)

	// Copied from cpserver.go (needs to reuse)
	httphandler := func(w http.ResponseWriter, r *http.Request) {
		glog.V(2).Infof("httphandler (port) handling request: %+v", r)
		glog.V(0).Infof("httphandler (port) handling request: %+v", r)

		pepKey := registry.GetPublicEndpointKey(node.Name, node.Type)
		pepEP, err := sc.getPublicEndpoint(string(pepKey))
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}

		rp := sc.getReverseProxy(pepEP.hostIP, sc.muxPort, pepEP.privateIP, pepEP.epPort, sc.muxTLS && (sc.muxPort > 0))
		glog.V(1).Infof("Time to set up %s public endpoint proxy for %v", pepKey, r.URL)
		glog.V(0).Infof("Time to set up %s public endpoint proxy for %v", pepKey, r.URL)

		// Set up the X-Forwarded-Proto header so that downstream servers know
		// the request originated as HTTPS.
		if _, found := r.Header["X-Forwarded-Proto"]; !found {
			r.Header.Set("X-Forwarded-Proto", "https")
		}

		rp.ServeHTTP(w, r)
		return
	}

	portServer := http.NewServeMux()
	portServer.HandleFunc("/", httphandler)

	// FIXME: bubble up these errors to the caller
	certFile, keyFile := sc.getCertFiles()

	go func() {
		// This cipher suites and tls min version change may not be needed with golang 1.5
		// https://github.com/golang/go/issues/10094
		// https://github.com/golang/go/issues/9364
		config := &tls.Config{
			MinVersion:               utils.MinTLS(),
			PreferServerCipherSuites: true,
			CipherSuites:             utils.CipherSuites(),
		}
		server := &http.Server{Addr: port, TLSConfig: config, Handler: portServer}
		err := server.ListenAndServeTLS(certFile, keyFile)
		if err != nil {
			glog.Fatalf("could not setup HTTPS (port) webserver: %s", err)
		}
	}()

	return nil
}

func (sc *ServiceConfig) createPublicPortServer(node service.ServicePublicEndpointNode, stopChan chan bool, shutdown <-chan (interface{})) error {
	port := node.Name
	useTLS := node.UseTLS
	proto := node.Protocol

	// Declare our listener..
	var listener net.Listener
	var err error

	glog.V(1).Infof("About to listen on port %s; UseTLS=%t", port, useTLS)

	if proto == "https" {
		// We have to set up an HttpListener to inject headers for downstram servers.
		return sc.createPortHttpServer(node, stopChan, shutdown)
	} else if useTLS {
		// Gather our certs files.
		certFile, keyFile := sc.getCertFiles()

		// Create our certificate from the cert files (strings).
		glog.V(2).Infof("Loading certs from %s, %s", certFile, keyFile)
		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
		if err != nil {
			glog.Errorf("Could not set up tls certificate for public endpoint on port %s for %s: %s", port, node.ServiceID, err)
			disablePort(node)
			return err
		}

		// The list of certs to use for our secure listener on this port.
		certs := []tls.Certificate { cert }

		// This cipher suites and tls min version change may not be needed with golang 1.5
		// https://github.com/golang/go/issues/10094
		// https://github.com/golang/go/issues/9364
		config := &tls.Config{
			MinVersion:               utils.MinTLS(),
			PreferServerCipherSuites: true,
			CipherSuites:             utils.CipherSuites(),
			Certificates:             certs,
		}

		glog.V(1).Infof("Listening with TLS")
		listener, err = tls.Listen("tcp", port, config)
	} else {
		glog.V(1).Infof("Listening without TLS")
		listener, err = net.Listen("tcp", port)
	}

	if err != nil {
		glog.Errorf("Could not setup TCP listener for port %s for public endpoint %s: %s", port, node.ServiceID, err)
		disablePort(node)
		return err
	}

	glog.Infof("Listening on port %s; UseTLS=%t", port, useTLS)

	go func() {
		for {
			// accept connection on public port
			localConn, err := listener.Accept()
			if err != nil {
				glog.V(1).Infof("Stopping accept on port %s", port)
				return
			}

			// lookup remote endpoint for this public port
			pepEPInfo, err := sc.getPublicEndpoint(fmt.Sprintf("%s-%d", node.Name, int(node.Type)))
			if err != nil {
				// This happens if an endpoint is accessed and the containers have died or not come up yet.
				glog.Errorf("Error retrieving public endpoint %s-%d: %s", node.Name, int(node.Type), err)
				// close the accepted connection and continue waiting for connections.
				if err := localConn.Close(); err != nil {
					glog.Errorf("Error closing client connection: %s", err)
				}
				continue
			}

			// setup remote connection
			var remoteAddr string
			_, isLocalContainer := sc.localAddrs[pepEPInfo.hostIP]
			if isLocalContainer {
				remoteAddr = fmt.Sprintf("%s:%d", pepEPInfo.privateIP, pepEPInfo.epPort)
			} else {
				remoteAddr = fmt.Sprintf("%s:%d", pepEPInfo.hostIP, sc.muxPort)
			}
			remoteConn, err := sc.getRemoteConnection(remoteAddr, isLocalContainer, sc.muxPort, pepEPInfo.privateIP, pepEPInfo.epPort, sc.muxTLS && (sc.muxPort > 0))
			if err != nil {
				glog.Errorf("Error getting remote connection for public endpoint %s-%d: %v", node.Name, int(node.Type), err)
				continue
			}

			glog.V(2).Infof("Established remote connection to %s", remoteConn.RemoteAddr())

			// Serve proxied requests/responses.  We pass our own port stop channel so that
			// all proxy loops end when our port is shutdown.
			go proxy.ProxyLoop(localConn, remoteConn, stopChan)
		}
	}()

	go func() {
		// Wait for shutdown, then kill all your connections
		select {
		case <-shutdown:
			// Received an application shutdown. Close the port channel to halt all proxy loops.
			glog.Infof("Shutting down port %s", port)
			close(stopChan)
		case <-stopChan:
		}

		listener.Close()
		glog.Infof("Closed port %s", port)
		return
	}()

	return nil
}

func (sc *ServiceConfig) syncAllPublicPorts(shutdown <-chan interface{}) error {
	rootConn, err := zzk.GetLocalConnection("/")
	if err != nil {
		glog.Errorf("syncAllPublicPorts - Error getting root zk connection: %v", err)
		return err
	}

	cancelChan := make(chan interface{})
	zkServicePEPService := service.ZKServicePublicEndpoints

	syncPorts := func(conn client.Connection, parentPath string, childIDs ...string) {
		allportsLock.Lock()
		defer allportsLock.Unlock()

		glog.V(1).Infof("syncPorts STARTING for parentPath:%s childIDs:%v", parentPath, childIDs)

		// start all servers that have been not started and enabled
		newPorts := make(map[string]chan bool)
		for _, pepID := range childIDs {

			// The pepID is the ZK child key. Get the node so we have all of the node data.
			glog.V(1).Infof("zkServicePEPService: %s, pepID: %s", zkServicePEPService, pepID)
			nodePath := fmt.Sprintf("%s/%s", zkServicePEPService, pepID)
			var node service.ServicePublicEndpointNode
			err := rootConn.Get(nodePath, &node)
			if err != nil {
				glog.Errorf("Unable to get the ZK Node from PepID")
				continue
			}

			if node.Type == registry.EPTypePort && node.Enabled {
				port := node.Name
				stopChan, running := allports[port]

				if !running {
					// recently enabled port - port should be opened
					stopChan = make(chan bool)
					if err := sc.createPublicPortServer(node, stopChan, shutdown); err != nil {
						continue
					}
				}

				newPorts[port] = stopChan
			}
		}

		// stop all servers that have been deleted or disabled
		for port, stopChan := range allports {
			_, found := newPorts[port]
			if !found {
				glog.V(2).Infof("Stopping port server for port %s", port)
				close(stopChan)
				glog.Infof("Port server shut down for port %s", port)
			}
		}

		allports = newPorts
		glog.V(2).Infof("Portserver allports: %+v", allports)
	}

	for {
		glog.V(1).Infof("Running registry.WatchChildren for zookeeper path: %s", zkServicePEPService)
		err := registry.WatchChildren(rootConn, zkServicePEPService, cancelChan, syncPorts, pepWatchError)
		if err != nil {
			glog.V(1).Infof("Will retry in 10 seconds to WatchChildren(%s) due to error: %v", zkServicePEPService, err)
			<-time.After(time.Second * 10)
			continue
		}
		select {
		case <-shutdown:
			close(cancelChan)
			return nil
		default:
		}
	}
}
<|endoftext|>


<commit_before>package webhook

import (
	"sync/atomic"
	"time"
)

const (
	DEFAULT_EXPIRATION_DURATION time.Duration = time.Second * 300
)

// W is the structure that represents the Webhook listener
// data we share.
//
// (Note to Wes: this follows the golang naming conventions.  webhook.Webhook "stutters",
// and this type is really the central type of this package.  Calling it a single letter is the norm.
// This could also go in the server package, in which case I'd change the name to Webhook, since
// service.Webhook works better.  See https://blog.golang.org/package-names)
type W struct {
	// Configuration for message delivery
	Config struct {
		// The URL to deliver messages to.
		URL string `json:"url"`

		// The content-type to set the messages to (unless specified by WRP).
		ContentType string `json:"content_type"`

		// The secret to use for the SHA1 HMAC.
		// Optional, set to "" to disable behavior.
		Secret string `json:"secret,omitempty"`
	} `json:"config"`

	// The URL to notify when we cut off a client due to overflow.
	// Optional, set to "" to disable behavior
	FailureURL string `json:"failure_url"`

	// The list of regular expressions to match event type against.
	Events []string `json:"events"`

	// Matcher type contains values to match against the metadata.
	Matcher struct {
		// The list of regular expressions to match device id type against.
		DeviceId []string `json:"device_id"`
	} `json:"matcher,omitempty"`

	// The specified duration for this hook to live
	Duration time.Duration `json:"duration"`

	// The absolute time when this hook is to be disabled
	Until time.Time `json:"until"`

	// The address that performed the registration
	Address string `json:"registered_from_address"`
}

// ID creates the canonical string identifing a WebhookListener
func (w *W) ID() string {
	return w.Config.URL
}

// DurationValidator performs a check on a W.Duration value.
// if found to be invalid it is set to the DEFAULT_EXPIRATION_DURATION
func (w *W) DurationValidator() {
	if w.Duration <= 0 || w.Duration > DEFAULT_EXPIRATION_DURATION {
		w.Duration = DEFAULT_EXPIRATION_DURATION
	}
}

// List is a read-only random access interface to a set of W's
// We don't necessarily need an implementation of just this interface alone.
type List interface {
	Len() int
	Get(int) *W
}

// UpdatableList is mutable list that can be updated en masse
type UpdatableList interface {
	List

	// Update performs a bulk update of this webhooks known to this list
	Update([]W)

	// Filter atomically filters the elements of this list
	Filter(func([]W) []W)
}

type updatableList struct {
	value atomic.Value
}

func (ul *updatableList) set(list []W) {
	ul.value.Store(list)
}

func (ul *updatableList) Len() int {
	if list, ok := ul.value.Load().([]W); ok {
		return len(list)
	}

	return 0
}

func (ul *updatableList) Get(index int) *W {
	if list, ok := ul.value.Load().([]W); ok {
		return &list[index]
	}

	// TODO: design choice.  may want to panic here, to mimic
	// the behavior of the golang runtime for slices.  Alternatively,
	// could return a second parameter that is an error (consistentHash does that).
	return nil
}

func (ul *updatableList) Update(newItems []W) {
	for _, newItem := range newItems {
		found := false
		var items []*W
		for i := 0; i < ul.Len(); i++ {
			items = append(items, ul.Get(i))
		}

		newItem.DurationValidator()
		newItem.Until = time.Now().Add(newItem.Duration)

		// update item
		for i := 0; i < len(items) && !found; i++ {
			if items[i].ID() == newItem.ID() {
				found = true

				items[i].Matcher = newItem.Matcher
				items[i].Events = newItem.Events
				items[i].Config.ContentType = newItem.Config.ContentType
				items[i].Config.Secret = newItem.Config.Secret
			}
		}

		// add item
		if !found {
			items = append(items, &newItem)
		}

		var itemsCopy []W
		for _, i := range items {
			itemsCopy = append(itemsCopy, *i)
		}

		// store items
		ul.set(itemsCopy)
	}
}

func (ul *updatableList) Filter(filter func([]W) []W) {
	if list, ok := ul.value.Load().([]W); ok {
		copyOf := make([]W, len(list))
		for i, w := range list {
			copyOf[i] = w
		}

		ul.set(filter(copyOf))
	}
}

// NewList just creates an UpdatableList.  Don't forget:
// NewList(nil) is valid!
func NewList(initial []W) UpdatableList {
	ul := &updatableList{}
	ul.Update(initial)
	return ul
}
<commit_msg>update for logic for incoming listener addition/update requests.<commit_after>package webhook

import (
	"sync/atomic"
	"time"
)

const (
	DEFAULT_EXPIRATION_DURATION time.Duration = time.Second * 300
)

// W is the structure that represents the Webhook listener
// data we share.
//
// (Note to Wes: this follows the golang naming conventions.  webhook.Webhook "stutters",
// and this type is really the central type of this package.  Calling it a single letter is the norm.
// This could also go in the server package, in which case I'd change the name to Webhook, since
// service.Webhook works better.  See https://blog.golang.org/package-names)
type W struct {
	// Configuration for message delivery
	Config struct {
		// The URL to deliver messages to.
		URL string `json:"url"`

		// The content-type to set the messages to (unless specified by WRP).
		ContentType string `json:"content_type"`

		// The secret to use for the SHA1 HMAC.
		// Optional, set to "" to disable behavior.
		Secret string `json:"secret,omitempty"`
	} `json:"config"`

	// The URL to notify when we cut off a client due to overflow.
	// Optional, set to "" to disable behavior
	FailureURL string `json:"failure_url"`

	// The list of regular expressions to match event type against.
	Events []string `json:"events"`

	// Matcher type contains values to match against the metadata.
	Matcher struct {
		// The list of regular expressions to match device id type against.
		DeviceId []string `json:"device_id"`
	} `json:"matcher,omitempty"`

	// The specified duration for this hook to live
	Duration time.Duration `json:"duration"`

	// The absolute time when this hook is to be disabled
	Until time.Time `json:"until"`

	// The address that performed the registration
	Address string `json:"registered_from_address"`
}

// ID creates the canonical string identifing a WebhookListener
func (w *W) ID() string {
	return w.Config.URL
}

// DurationValidator performs a check on a W.Duration value.
// if found to be invalid it is set to the DEFAULT_EXPIRATION_DURATION
func (w *W) DurationValidator() {
	if w.Duration <= 0 || w.Duration > DEFAULT_EXPIRATION_DURATION {
		w.Duration = DEFAULT_EXPIRATION_DURATION
	}
}

// List is a read-only random access interface to a set of W's
// We don't necessarily need an implementation of just this interface alone.
type List interface {
	Len() int
	Get(int) *W
}

// UpdatableList is mutable list that can be updated en masse
type UpdatableList interface {
	List

	// Update performs a bulk update of this webhooks known to this list
	Update([]W)

	// Filter atomically filters the elements of this list
	Filter(func([]W) []W)
}

type updatableList struct {
	value atomic.Value
}

func (ul *updatableList) set(list []W) {
	ul.value.Store(list)
}

func (ul *updatableList) Len() int {
	if list, ok := ul.value.Load().([]W); ok {
		return len(list)
	}

	return 0
}

func (ul *updatableList) Get(index int) *W {
	if list, ok := ul.value.Load().([]W); ok {
		return &list[index]
	}

	// TODO: design choice.  may want to panic here, to mimic
	// the behavior of the golang runtime for slices.  Alternatively,
	// could return a second parameter that is an error (consistentHash does that).
	return nil
}

func (ul *updatableList) Update(newItems []W) {
	for _, newItem := range newItems {
		found := false
		var items []*W
		for i := 0; i < ul.Len(); i++ {
			items = append(items, ul.Get(i))
		}

		// for new items.  we don't want to change a valid expiration time.
		if &newItem.Until == nil || newItem.Until.Equal(time.Time{}) {
			newItem.DurationValidator()
			newItem.Until = time.Now().Add(newItem.Duration)
		}

		// we want to add items that will expire in the future
		if newItem.Until.After(time.Now()) {
			for i := 0; i < len(items) && !found; i++ {
				if items[i].ID() == newItem.ID() {
					found = true

					items[i].Matcher = newItem.Matcher
					items[i].Events = newItem.Events
					items[i].Config.ContentType = newItem.Config.ContentType
					items[i].Config.Secret = newItem.Config.Secret
				}
			}

			// add item
			if !found {
				items = append(items, &newItem)
			}

			var itemsCopy []W
			for _, i := range items {
				itemsCopy = append(itemsCopy, *i)
			}

			// store items
			ul.set(itemsCopy)
		}
	}
}

func (ul *updatableList) Filter(filter func([]W) []W) {
	if list, ok := ul.value.Load().([]W); ok {
		copyOf := make([]W, len(list))
		for i, w := range list {
			copyOf[i] = w
		}

		ul.set(filter(copyOf))
	}
}

// NewList just creates an UpdatableList.  Don't forget:
// NewList(nil) is valid!
func NewList(initial []W) UpdatableList {
	ul := &updatableList{}
	ul.Update(initial)
	return ul
}
<|endoftext|>


<commit_before>package webmagic

import (
	"bytes"
	"github.com/scottkiss/gomagic/utilmagic"
	"html/template"
	"io/ioutil"
	"log"
	"path/filepath"
)

type Render struct {
	root    string
	TplName string
	Data    map[interface{}]interface{}
	FuncMap template.FuncMap
}

func (self *Render) Build() ([]byte, error) {
	outbytes := bytes.NewBufferString("")
	var t *template.Template
	var err error
	t, err = getTemplate(self.FuncMap, self.root, self.TplName, "")
	if err != nil {
		log.Panic("getTemplate err:", err)
		return nil, err
	}
	err = t.ExecuteTemplate(outbytes, self.TplName, self.Data)
	if err != nil {
		log.Panic("template Execute error:", err)
		return nil, err
	}

	content, _ := ioutil.ReadAll(outbytes)
	return content, nil

}

func getTemplate(funcmap template.FuncMap, root, file string, others ...string) (t *template.Template, err error) {
	var filepathAbs string
	filepathAbs = filepath.Join(root, file)
	if exist := utilmagic.FileExists(filepathAbs); !exist {
		panic("can not find template file:" + file)
	}
	data, err := ioutil.ReadFile(filepathAbs)
	if err != nil {
		return nil, err
	}
	t = template.New(file)
	t.Funcs(funcmap)
	t.Parse(string(data))
	if err != nil {
		return nil, err
	}
	return t, nil
}
<commit_msg>add new method<commit_after>package webmagic

import (
	"bytes"
	"github.com/scottkiss/gomagic/utilmagic"
	"html/template"
	"io/ioutil"
	"log"
	"path/filepath"
)

type Render struct {
	root    string
	TplName string
	Data    map[interface{}]interface{}
	FuncMap template.FuncMap
}

func (self *Render) Build() ([]byte, error) {
	outbytes := bytes.NewBufferString("")
	var t *template.Template
	var err error
	t, err = getTemplate(self.FuncMap, self.root, self.TplName, "")
	if err != nil {
		log.Panic("getTemplate err:", err)
		return nil, err
	}
	err = t.ExecuteTemplate(outbytes, self.TplName, self.Data)
	if err != nil {
		log.Panic("template Execute error:", err)
		return nil, err
	}

	content, _ := ioutil.ReadAll(outbytes)
	return content, nil

}

func (self *Render) BuildAllTemplate() {}

func getTemplate(funcmap template.FuncMap, root, file string, others ...string) (t *template.Template, err error) {
	var filepathAbs string
	filepathAbs = filepath.Join(root, file)
	if exist := utilmagic.FileExists(filepathAbs); !exist {
		panic("can not find template file:" + file)
	}
	data, err := ioutil.ReadFile(filepathAbs)
	if err != nil {
		return nil, err
	}
	t = template.New(file)
	t.Funcs(funcmap)
	t.Parse(string(data))
	if err != nil {
		return nil, err
	}
	return t, nil
}
<|endoftext|>


<commit_before>package awspurge

import (
	"errors"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/elb"
)

type Config struct {
	Regions        []string      `toml:"regions" json:"regions"`
	RegionsExclude []string      `toml:"regions_exclude" json:"regions_exclude"`
	AccessKey      string        `toml:"access_key" json:"access_key"`
	SecretKey      string        `toml:"secret_key" json:"secret_key"`
	Timeout        time.Duration `toml:"timeout" json:"timeout"`
}

type resources struct {
	instances       []*ec2.Instance
	volumes         []*ec2.Volume
	keyPairs        []*ec2.KeyPairInfo
	placementGroups []*ec2.PlacementGroup
	addresses       []*ec2.Address
	snapshots       []*ec2.Snapshot
	loadBalancers   []*elb.LoadBalancerDescription
	securityGroups  []*ec2.SecurityGroup
}

type Purge struct {
	services *multiRegion

	// resources represents the current available resources per region. It's
	// populated by the Fetch() method.
	resources  map[string]*resources
	resourceMu sync.Mutex // protects resources

	// fetch synchronization
	wg   sync.WaitGroup
	mu   sync.Mutex
	errs error
}

func New(conf *Config) (*Purge, error) {
	checkCfg := "Please check your configuration"

	if len(conf.Regions) == 0 {
		return nil, errors.New("AWS Regions are not set. " + checkCfg)
	}

	if conf.AccessKey == "" {
		return nil, errors.New("AWS Access Key is not set. " + checkCfg)
	}

	if conf.SecretKey == "" {
		return nil, errors.New("AWS Secret Key is not set. " + checkCfg)
	}

	if conf.Timeout == 0 {
		conf.Timeout = time.Second * 30
	}

	client := &http.Client{
		Transport: &http.Transport{TLSHandshakeTimeout: conf.Timeout},
		Timeout:   conf.Timeout,
	}

	creds := credentials.NewStaticCredentials(conf.AccessKey, conf.SecretKey, "")
	awsCfg := &aws.Config{
		Credentials: creds,
		HTTPClient:  client,
		Logger:      aws.NewDefaultLogger(),
	}

	m := newMultiRegion(awsCfg, filterRegions(conf.Regions, conf.RegionsExclude))

	// initialize resources
	res := make(map[string]*resources, 0)
	for _, region := range allRegions {
		res[region] = &resources{}
	}

	return &Purge{
		services:  m,
		resources: res,
	}, nil
}

func (p *Purge) Do() error {
	if err := p.Fetch(); err != nil {
		return err
	}

	if err := p.Print(); err != nil {
		return err
	}

	return nil
}

// Print prints all fetched resources
func (p *Purge) Print() error {
	for region, resources := range p.resources {
		fmt.Println("REGION:", region)
		fmt.Printf("\t'%d' instances\n", len(resources.instances))
		fmt.Printf("\t'%d' volumes\n", len(resources.volumes))
		fmt.Printf("\t'%d' keyPairs\n", len(resources.keyPairs))
		fmt.Printf("\t'%d' placementGroups\n", len(resources.placementGroups))
		fmt.Printf("\t'%d' addresses\n", len(resources.addresses))
		fmt.Printf("\t'%d' snapshots\n", len(resources.snapshots))
		fmt.Printf("\t'%d' loadbalancers\n", len(resources.loadBalancers))
		fmt.Printf("\t'%d' securitygroups\n", len(resources.securityGroups))
	}
	return nil
}

// Fetch fetches all given resources and stores them internally. To print them
// use the Print() method
func (p *Purge) Fetch() error {
	p.wg.Add(8)

	go p.FetchInstances()
	go p.FetchVolumes()
	go p.FetchKeyPairs()
	go p.FetchPlacementGroups()
	go p.FetchAddresses()
	go p.FetchSnapshots()
	go p.FetchLoadBalancers()
	go p.FetchSecurityGroups()

	p.wg.Wait()
	return nil
}
<commit_msg>awspurge: return fetch errors<commit_after>package awspurge

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/elb"
)

type Config struct {
	Regions        []string      `toml:"regions" json:"regions"`
	RegionsExclude []string      `toml:"regions_exclude" json:"regions_exclude"`
	AccessKey      string        `toml:"access_key" json:"access_key"`
	SecretKey      string        `toml:"secret_key" json:"secret_key"`
	Timeout        time.Duration `toml:"timeout" json:"timeout"`
}

type resources struct {
	instances       []*ec2.Instance
	volumes         []*ec2.Volume
	keyPairs        []*ec2.KeyPairInfo
	placementGroups []*ec2.PlacementGroup
	addresses       []*ec2.Address
	snapshots       []*ec2.Snapshot
	loadBalancers   []*elb.LoadBalancerDescription
	securityGroups  []*ec2.SecurityGroup
}

type Purge struct {
	services *multiRegion

	// resources represents the current available resources per region. It's
	// populated by the Fetch() method.
	resources  map[string]*resources
	resourceMu sync.Mutex // protects resources

	// fetch synchronization
	wg   sync.WaitGroup
	mu   sync.Mutex
	errs error
}

func New(conf *Config) (*Purge, error) {
	checkCfg := "Please check your configuration"

	if len(conf.Regions) == 0 {
		return nil, errors.New("AWS Regions are not set. " + checkCfg)
	}

	if conf.AccessKey == "" {
		return nil, errors.New("AWS Access Key is not set. " + checkCfg)
	}

	if conf.SecretKey == "" {
		return nil, errors.New("AWS Secret Key is not set. " + checkCfg)
	}

	if conf.Timeout == 0 {
		conf.Timeout = time.Second * 30
	}

	client := &http.Client{
		Transport: &http.Transport{TLSHandshakeTimeout: conf.Timeout},
		Timeout:   conf.Timeout,
	}

	creds := credentials.NewStaticCredentials(conf.AccessKey, conf.SecretKey, "")
	awsCfg := &aws.Config{
		Credentials: creds,
		HTTPClient:  client,
		Logger:      aws.NewDefaultLogger(),
	}

	m := newMultiRegion(awsCfg, filterRegions(conf.Regions, conf.RegionsExclude))

	// initialize resources
	res := make(map[string]*resources, 0)
	for _, region := range allRegions {
		res[region] = &resources{}
	}

	return &Purge{
		services:  m,
		resources: res,
	}, nil
}

func (p *Purge) Do() error {
	if err := p.Fetch(); err != nil {
		log.Println("Fetch err: %s", err)
	}

	if err := p.Print(); err != nil {
		return err
	}

	return nil
}

// Print prints all fetched resources
func (p *Purge) Print() error {
	for region, resources := range p.resources {
		fmt.Println("REGION:", region)
		fmt.Printf("\t'%d' instances\n", len(resources.instances))
		fmt.Printf("\t'%d' volumes\n", len(resources.volumes))
		fmt.Printf("\t'%d' keyPairs\n", len(resources.keyPairs))
		fmt.Printf("\t'%d' placementGroups\n", len(resources.placementGroups))
		fmt.Printf("\t'%d' addresses\n", len(resources.addresses))
		fmt.Printf("\t'%d' snapshots\n", len(resources.snapshots))
		fmt.Printf("\t'%d' loadbalancers\n", len(resources.loadBalancers))
		fmt.Printf("\t'%d' securitygroups\n", len(resources.securityGroups))
	}
	return nil
}

// Fetch fetches all given resources and stores them internally. To print them
// use the Print() method
func (p *Purge) Fetch() error {
	p.wg.Add(8)

	go p.FetchInstances()
	go p.FetchVolumes()
	go p.FetchKeyPairs()
	go p.FetchPlacementGroups()
	go p.FetchAddresses()
	go p.FetchSnapshots()
	go p.FetchLoadBalancers()
	go p.FetchSecurityGroups()

	p.wg.Wait()
	return p.errs
}
<|endoftext|>