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

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	Counter uint     `xml:"Counter"`
	Expiry  int64    `xml:"ExpiryDate"`
	P       *big.Int `xml:"Elements>p"`
	Q       *big.Int `xml:"Elements>q"`
	PPrime  *big.Int `xml:"Elements>pPrime"`
	QPrime  *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int, counter uint, expiry time.Time) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, Expiry: expiry.Unix()}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	return privk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the private key to an xml file.
func (privk *PrivateKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int `xml:"num,attr"`
	Bases []*xmlBase
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	Counter     uint              `xml:"Counter"`
	Expiry      int64             `xml:"ExpiryDate"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int, counter uint, expiry time.Time) *PublicKey {
	return &PublicKey{
		Counter:     counter,
		Expiry:      expiry.Unix(),
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      &DefaultSystemParameters,
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{Params: &DefaultSystemParameters}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	return pubk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the public key to an xml file.
func (pubk *PublicKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, attrsAmount int, counter uint, expiry time.Time) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, Expiry: expiry.Unix()}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength, Counter: counter, Expiry: expiry.Unix()}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...attrsAmount from S
	pubk.R = make([]*big.Int, attrsAmount)
	for i := 0; i < attrsAmount; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<commit_msg>Fix broken keys unmarshaling (regression from 823a80e)<commit_after>// Copyright 2016 Maarten Everts. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gabi

import (
	"crypto/rand"
	"encoding/xml"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	"github.com/credentials/safeprime"
)

const (
	//XMLHeader can be a used as the XML header when writing keys in XML format.
	XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
	// DefaultEpochLength is the default epoch length for public keys.
	DefaultEpochLength = 432000
)

// PrivateKey represents an issuer's private key.
type PrivateKey struct {
	XMLName xml.Name `xml:"http://www.zurich.ibm.com/security/idemix IssuerPrivateKey"`
	Counter uint     `xml:"Counter"`
	Expiry  int64    `xml:"ExpiryDate"`
	P       *big.Int `xml:"Elements>p"`
	Q       *big.Int `xml:"Elements>q"`
	PPrime  *big.Int `xml:"Elements>pPrime"`
	QPrime  *big.Int `xml:"Elements>qPrime"`
}

// NewPrivateKey creates a new issuer private key using the provided parameters.
func NewPrivateKey(p, q *big.Int, counter uint, expiry time.Time) *PrivateKey {
	sk := PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, Expiry: expiry.Unix()}

	sk.PPrime.Sub(p, bigONE)
	sk.PPrime.Rsh(sk.PPrime, 1)

	sk.QPrime.Sub(q, bigONE)
	sk.QPrime.Rsh(sk.QPrime, 1)

	return &sk
}

// NewPrivateKeyFromXML creates a new issuer private key using the xml data
// provided.
func NewPrivateKeyFromXML(xmlInput string) (*PrivateKey, error) {
	privk := &PrivateKey{}
	err := xml.Unmarshal([]byte(xmlInput), privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// NewPrivateKeyFromFile create a new issuer private key from an xml file.
func NewPrivateKeyFromFile(filename string) (*PrivateKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	privk := &PrivateKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, privk)
	if err != nil {
		return nil, err
	}
	return privk, nil
}

// Print prints the key to stdout.
func (privk *PrivateKey) Print() error {
	return privk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (privk *PrivateKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(privk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the private key to an xml file.
func (privk *PrivateKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return privk.WriteTo(f)
}

// xmlBases is an auxiliary struct to encode/decode the odd way bases are
// represented in the xml representation of public keys
type xmlBases struct {
	Num   int        `xml:"num,attr"`
	Bases []*xmlBase `xml:",any"`
}

type xmlBase struct {
	XMLName xml.Name
	Bigint  string `xml:",innerxml"` // Has to be a string for ",innerxml" to work
}

// xmlFeatures is an auxiliary struct to make the XML encoding/decoding a bit
// easier while keeping the struct for PublicKey somewhat simple.
type xmlFeatures struct {
	Epoch struct {
		Length int `xml:"length,attr"`
	}
}

// Bases is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type Bases []*big.Int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (bl *Bases) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlBases

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}

	arr := make([]*big.Int, t.Num)
	for i := range arr {
		arr[i], _ = new(big.Int).SetString(t.Bases[i].Bigint, 10)
	}

	*bl = Bases(arr)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (bl *Bases) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	l := len(*bl)
	bases := make([]*xmlBase, l)

	for i := range bases {
		bases[i] = &xmlBase{
			XMLName: xml.Name{Local: "Base_" + strconv.Itoa(i)},
			Bigint:  (*bl)[i].String(),
		}
	}

	t := xmlBases{
		Num:   l,
		Bases: bases,
	}
	return e.EncodeElement(t, start)
}

// EpochLength is a type that is introduced to simplify the encoding/decoding of
// a PublicKey whilst using the xml support of Go's standard library.
type EpochLength int

// UnmarshalXML is an internal function to simplify decoding a PublicKey from
// XML.
func (el *EpochLength) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var t xmlFeatures

	if err := d.DecodeElement(&t, &start); err != nil {
		return err
	}
	*el = EpochLength(t.Epoch.Length)
	return nil
}

// MarshalXML is an internal function to simplify encoding a PublicKey to XML.
func (el *EpochLength) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	var t xmlFeatures
	t.Epoch.Length = int(*el)
	return e.EncodeElement(t, start)
}

// PublicKey represents an issuer's public key.
type PublicKey struct {
	XMLName     xml.Name          `xml:"http://www.zurich.ibm.com/security/idemix IssuerPublicKey"`
	Counter     uint              `xml:"Counter"`
	Expiry      int64             `xml:"ExpiryDate"`
	N           *big.Int          `xml:"Elements>n"` // Modulus n
	Z           *big.Int          `xml:"Elements>Z"` // Generator Z
	S           *big.Int          `xml:"Elements>S"` // Generator S
	R           Bases             `xml:"Elements>Bases"`
	EpochLength EpochLength       `xml:"Features"`
	Params      *SystemParameters `xml:"-"`
}

// NewPublicKey creates and returns a new public key based on the provided parameters.
func NewPublicKey(N, Z, S *big.Int, R []*big.Int, counter uint, expiry time.Time) *PublicKey {
	return &PublicKey{
		Counter:     counter,
		Expiry:      expiry.Unix(),
		N:           N,
		Z:           Z,
		S:           S,
		R:           R,
		EpochLength: DefaultEpochLength,
		Params:      &DefaultSystemParameters,
	}
}

// NewPublicKeyFromXML creates a new issuer public key using the xml data
// provided.
func NewPublicKeyFromXML(xmlInput string) (*PublicKey, error) {
	// TODO: this might fail in the future. The DefaultSystemParameters and the
	// public key might not match!
	pubk := &PublicKey{Params: &DefaultSystemParameters}
	err := xml.Unmarshal([]byte(xmlInput), pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// NewPublicKeyFromFile create a new issuer public key from an xml file.
func NewPublicKeyFromFile(filename string) (*PublicKey, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	pubk := &PublicKey{}

	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	err = xml.Unmarshal(b, pubk)
	if err != nil {
		return nil, err
	}
	return pubk, nil
}

// Print prints the key to stdout.
func (pubk *PublicKey) Print() error {
	return pubk.WriteTo(os.Stdout)
}

// WriteTo writes the XML-serialized public key to the given writer.
func (pubk *PublicKey) WriteTo(writer io.Writer) error {
	// Write the standard XML header
	_, err := writer.Write([]byte(XMLHeader))
	if err != nil {
		return err
	}

	// And the actual xml body (with indentation)
	b, err := xml.MarshalIndent(pubk, "", "   ")
	if err != nil {
		return err
	}
	_, err = writer.Write(b)
	return err
}

// WriteToFile writes the public key to an xml file.
func (pubk *PublicKey) WriteToFile(filename string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return pubk.WriteTo(f)
}

// randomSafePrime produces a safe prime of the requested number of bits
func randomSafePrime(bits int) (*big.Int, error) {
	p2 := new(big.Int)
	for {
		p, err := rand.Prime(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		p2.Rsh(p, 1) // p2 = (p - 1)/2
		if p2.ProbablyPrime(20) {
			return p, nil
		}
	}
}

// GenerateKeyPair generates a private/public keypair for an Issuer
func GenerateKeyPair(param *SystemParameters, attrsAmount int, counter uint, expiry time.Time) (*PrivateKey, *PublicKey, error) {
	primeSize := param.Ln / 2

	// p and q need to be safe primes
	p, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	q, err := safeprime.Generate(int(primeSize))
	if err != nil {
		return nil, nil, err
	}

	priv := &PrivateKey{P: p, Q: q, PPrime: new(big.Int), QPrime: new(big.Int), Counter: counter, Expiry: expiry.Unix()}

	// compute p' and q'
	priv.PPrime.Sub(priv.P, bigONE)
	priv.PPrime.Rsh(priv.PPrime, 1)

	priv.QPrime.Sub(priv.Q, bigONE)
	priv.QPrime.Rsh(priv.QPrime, 1)

	// compute n
	pubk := &PublicKey{Params: param, EpochLength: DefaultEpochLength, Counter: counter, Expiry: expiry.Unix()}
	pubk.N = new(big.Int).Mul(priv.P, priv.Q)

	// Find an acceptable value for S; we follow lead of the Silvia code here:
	// Pick a random l_n value and check whether it is a quadratic residue modulo n

	var s *big.Int
	for {
		s, err = randomBigInt(param.Ln)
		if err != nil {
			return nil, nil, err
		}
		// check if S \elem Z_n
		if s.Cmp(pubk.N) > 0 {
			continue
		}
		if legendreSymbol(s, priv.P) == 1 && legendreSymbol(s, priv.Q) == 1 {
			break
		}
	}

	pubk.S = s

	// Derive Z from S
	var x *big.Int
	for {
		x, _ = randomBigInt(primeSize)
		if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
			break
		}
	}

	// Compute Z = S^x mod n
	pubk.Z = new(big.Int).Exp(pubk.S, x, pubk.N)

	// Derive R_i for i = 0...attrsAmount from S
	pubk.R = make([]*big.Int, attrsAmount)
	for i := 0; i < attrsAmount; i++ {
		pubk.R[i] = new(big.Int)

		var x *big.Int
		for {
			x, _ = randomBigInt(primeSize)
			if x.Cmp(bigTWO) > 0 && x.Cmp(pubk.N) < 0 {
				break
			}
		}
		// Compute R_i = S^x mod n
		pubk.R[i].Exp(pubk.S, x, pubk.N)
	}

	return priv, pubk, nil
}
<|endoftext|>


<commit_before>// beelog project klog
package klog

import (
	"fmt"
	"io"
	"log"
	"os"
	"reflect"
	"runtime"
	"strings"
)

type Level int

const (
	Fshortfile = 1 << iota // show filename:lineno
	Fcolor
	Fdevflag = Fshortfile | Fcolor // for develop use
	Fstdflag = Fcolor
)

const (
	LDebug Level = iota
	LInfo
	LWarning
	LError
	LFatal
)

var levels = []string{
	"[DEBUG]",
	"[INFO.]",
	"[WARN.]",
	"[ERROR]",
	"[FATAL]",
}

var colors = []string{
	"Cyan",
	"Green",
	"Magenta",
	"Yellow",
	"Red",
}

type Logger struct {
	out         io.Writer
	level       Level
	logging     *log.Logger
	color       *ansi
	flags       int
	colorEnable bool
}

// default level is debug
func NewLogger(out io.Writer, prefix string) *Logger {
	if out == nil {
		out = os.Stdout
	}
	return &Logger{
		level:       LInfo,
		logging:     log.New(out, prefix, log.Ldate|log.Ltime),
		color:       &ansi{},
		colorEnable: isTermOutput() && runtime.GOOS != "windows",
		flags:       Fstdflag,
	}
}

func (l *Logger) SetFlags(flag int) {
	l.flags = flag
}

func (l *Logger) SetLevel(level Level) {
	l.level = level
}

func (l *Logger) write(level Level, format string, a ...interface{}) {
	if level < l.level {
		return
	}
	var levelName string = levels[int(level)]
	var preStr string

	preStr += levelName
	if l.flags&Fshortfile != 0 {
		// Retrieve the stack infos
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "<unknown>"
			line = -1
		} else {
			file = file[strings.LastIndex(file, "/")+1:]
		}
		preStr = fmt.Sprintf("%s %s:%d", preStr, file, line)
	}

	var outstr, sep = "", " "
	if format == "" {
		outstr = preStr + sep + fmt.Sprint(a...)
	} else {
		outstr = preStr + sep + fmt.Sprintf(format, a...)
	}
	outstr = strings.TrimSuffix(outstr, "\n")

	if l.colorEnable && l.flags&Fcolor != 0 {
		var colorName string = colors[int(level)]
		method, exists := l.color.getMethod(colorName)
		if exists {
			outstr = method.Func.Call([]reflect.Value{
				reflect.ValueOf(l.color),
				reflect.ValueOf(outstr)},
			)[0].String()
		}
	}
	l.logging.Print(outstr)
}

func (l *Logger) Debug(v ...interface{}) {
	l.write(LDebug, "", v...)
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	l.write(LDebug, format, v...)
}

func (l *Logger) Info(v ...interface{}) {
	l.write(LInfo, "", v...)
}
func (l *Logger) Infof(format string, v ...interface{}) {
	l.write(LInfo, format, v...)
}
func (l *Logger) Warn(v ...interface{}) {
	l.write(LWarning, "", v...)
}
func (l *Logger) Warnf(format string, v ...interface{}) {
	l.write(LWarning, format, v...)
}
func (l *Logger) Error(v ...interface{}) {
	l.write(LError, "", v...)
}
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.write(LError, format, v...)
}

// will also call os.Exit(1)
func (l *Logger) Fatal(v ...interface{}) {
	l.Fatalf("", v...)
}

// will also call os.Exit(1)
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.write(LFatal, format, v...)
	os.Exit(1)
}
<commit_msg>fix klog.Fatal show wrong file:line<commit_after>// beelog project klog
package klog

import (
	"fmt"
	"io"
	"log"
	"os"
	"reflect"
	"runtime"
	"strings"
)

type Level int

const (
	Fshortfile = 1 << iota // show filename:lineno
	Fcolor
	Fdevflag = Fshortfile | Fcolor // for develop use
	Fstdflag = Fcolor
)

const (
	LDebug Level = iota
	LInfo
	LWarning
	LError
	LFatal
)

var levels = []string{
	"[DEBUG]",
	"[INFO.]",
	"[WARN.]",
	"[ERROR]",
	"[FATAL]",
}

var colors = []string{
	"Cyan",
	"Green",
	"Magenta",
	"Yellow",
	"Red",
}

type Logger struct {
	out         io.Writer
	level       Level
	logging     *log.Logger
	color       *ansi
	flags       int
	colorEnable bool
}

// default level is debug
func NewLogger(out io.Writer, prefix string) *Logger {
	if out == nil {
		out = os.Stdout
	}
	return &Logger{
		level:       LInfo,
		logging:     log.New(out, prefix, log.Ldate|log.Ltime),
		color:       &ansi{},
		colorEnable: isTermOutput() && runtime.GOOS != "windows",
		flags:       Fstdflag,
	}
}

func (l *Logger) SetFlags(flag int) {
	l.flags = flag
}

func (l *Logger) SetLevel(level Level) {
	l.level = level
}

func (l *Logger) write(level Level, format string, a ...interface{}) {
	if level < l.level {
		return
	}
	var levelName string = levels[int(level)]
	var preStr string

	preStr += levelName
	if l.flags&Fshortfile != 0 {
		// Retrieve the stack infos
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "<unknown>"
			line = -1
		} else {
			file = file[strings.LastIndex(file, "/")+1:]
		}
		preStr = fmt.Sprintf("%s %s:%d", preStr, file, line)
	}

	var outstr, sep = "", " "
	if format == "" {
		outstr = preStr + sep + fmt.Sprint(a...)
	} else {
		outstr = preStr + sep + fmt.Sprintf(format, a...)
	}
	outstr = strings.TrimSuffix(outstr, "\n")

	if l.colorEnable && l.flags&Fcolor != 0 {
		var colorName string = colors[int(level)]
		method, exists := l.color.getMethod(colorName)
		if exists {
			outstr = method.Func.Call([]reflect.Value{
				reflect.ValueOf(l.color),
				reflect.ValueOf(outstr)},
			)[0].String()
		}
	}
	l.logging.Print(outstr)
}

func (l *Logger) Debug(v ...interface{}) {
	l.write(LDebug, "", v...)
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	l.write(LDebug, format, v...)
}

func (l *Logger) Info(v ...interface{}) {
	l.write(LInfo, "", v...)
}
func (l *Logger) Infof(format string, v ...interface{}) {
	l.write(LInfo, format, v...)
}
func (l *Logger) Warn(v ...interface{}) {
	l.write(LWarning, "", v...)
}
func (l *Logger) Warnf(format string, v ...interface{}) {
	l.write(LWarning, format, v...)
}
func (l *Logger) Error(v ...interface{}) {
	l.write(LError, "", v...)
}
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.write(LError, format, v...)
}

// will also call os.Exit(1)
func (l *Logger) Fatal(v ...interface{}) {
	l.write(LFatal, "", v...)
	os.Exit(1)
}

// will also call os.Exit(1)
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.write(LFatal, format, v...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>/**
 * koko: Container connector
 */
package main

import (
	"fmt"
	"github.com/mattn/go-getopt"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/containernetworking/cni/pkg/ns"
	"github.com/vishvananda/netlink"
	//"github.com/s1061123/netlink"

	"github.com/docker/docker/client"
	"golang.org/x/net/context"

	"github.com/MakeNowJust/heredoc"
)

func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{
			Name:  name,
			Flags: net.FlagUp,
			MTU:   mtu,
		},
		PeerName: peer,
	}

	if err := netlink.LinkAdd(veth); err != nil {
		return nil, err
	}
	return veth, nil
}

func getVethPair(name1 string, name2 string) (link1 netlink.Link, link2 netlink.Link, err error) {

	link1, err = makeVethPair(name1, name2, 1500)
	if err != nil {
		switch {
		case os.IsExist(err):
			err = fmt.Errorf("container veth name provided (%v) already exists", name1)
			return
		default:
			err = fmt.Errorf("failed to make veth pair: %v", err)
			return
		}
	}

	link2, err = netlink.LinkByName(name2)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to lookup %q: %v\n", name2, err)
	}

	return
}

// addVxLanInterface creates VxLan interface by given vxlan object
func addVxLanInterface(vxlan vxLan, devName string) error {
	parentIF, err := netlink.LinkByName(vxlan.parentIF)

	if err != nil {
		return fmt.Errorf("Failed to get %s: %v", vxlan.parentIF, err)
	}

	vxlanconf := netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
				Name: devName,
		},
		VxlanId:	vxlan.id,
		VtepDevIndex:	parentIF.Attrs().Index,
		Group:		vxlan.ipAddr,
		Port:		4789,
		Learning:	true,
		L2miss:		true,
		L3miss:		true,
	}
	err = netlink.LinkAdd(&vxlanconf)

	if err != nil {
		return fmt.Errorf("Failed to add vxlan %s: %v", devName, err)
	}
	return nil
}

// getDockerContainerNS retrieves container's network namespace from
// docker container id, given as containerID.
func getDockerContainerNS(containerID string) (namespace string, err error) {
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}

	cli.UpdateClientVersion("1.24")

	json, err := cli.ContainerInspect(ctx, containerID)
	if err != nil {
		err = fmt.Errorf("failed to get container info: %v", err)
		return
	}
	if json.NetworkSettings == nil {
		err = fmt.Errorf("failed to get container info: %v", err)
		return
	}
	namespace = json.NetworkSettings.NetworkSettingsBase.SandboxKey
	return
}

// vEth is a structure to descrive veth interfaces.
type vEth struct {
	nsName		string		// What's the network namespace?
	linkName	string		// And what will we call the link.
	withIPAddr	bool		// Is there an ip address?
	ipAddr		net.IPNet	// What is that ip address.
}

// vxLan is a structure to descrive vxlan endpoint.
type vxLan struct {
	parentIF	string		// parent interface name
	id		int		// VxLan ID
	ipAddr		net.IP		// VxLan destination address
}

// setVethLink is low-level handler to set IP address onveth links given a single vEth data object.
// ...primarily used privately by makeVeth().
func (veth *vEth) setVethLink(link netlink.Link) (err error) {
	vethNs, err := ns.GetNS(veth.nsName)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}
	defer vethNs.Close()

	if err := netlink.LinkSetNsFd(link, int(vethNs.Fd())); err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	err = vethNs.Do(func(_ ns.NetNS) error {
		link, err := netlink.LinkByName(veth.linkName)
		if err != nil {
			return fmt.Errorf("failed to lookup %q in %q: %v", veth.linkName, vethNs.Path(), err)
		}

		if err = netlink.LinkSetUp(link); err != nil {
			return fmt.Errorf("failed to set %q up: %v", veth.linkName, err)
		}

		// Conditionally set the IP address.
		if veth.withIPAddr {
			addr := &netlink.Addr{IPNet: &veth.ipAddr, Label: ""}
			if err = netlink.AddrAdd(link, addr); err != nil {
				return fmt.Errorf("failed to add IP addr %v to %q: %v", addr, veth.linkName, err)
			}
		}

		return nil
	})

	return
}

// makeVeth is top-level handler to create veth links given two vEth data objects: veth1 and veth2.
func makeVeth(veth1 vEth, veth2 vEth) {

	link1, link2, err := getVethPair(veth1.linkName, veth2.linkName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth1.setVethLink(link1)
	veth2.setVethLink(link2)
}

// makeVxLan makes vxlan interface and put it into container namespace
func makeVxLan(veth1 vEth, vxlan vxLan) {

	err := addVxLanInterface(vxlan, veth1.linkName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "vxlan add failed: %v", err)
	}

	link, err2 := netlink.LinkByName(veth1.linkName)
	if err2 != nil {
		fmt.Fprintf(os.Stderr, "Cannot get %s: %v", veth1.linkName, err)
	}
	veth1.setVethLink(link)
}

// parseNOption parses '-n' option and put this information in veth object.
func parseNOption(s string) (veth vEth, err error) {
	n := strings.Split(s, ":")
	if len(n) != 3 && len(n) != 2 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	veth.nsName = fmt.Sprintf("/var/run/netns/%s", n[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth.linkName = n[1]

	if len(n) == 3 {
		ip, mask, err2 := net.ParseCIDR(n[2])
		if err2 != nil {
			err = fmt.Errorf("failed to parse IP addr %s: %v",
				n[2], err2)
			return
		}
		veth.ipAddr.IP = ip
		veth.ipAddr.Mask = mask.Mask
		veth.withIPAddr = true
	} else {
		veth.withIPAddr = false
	}

	return
}

// parseNOption parses '-n' option and put this information in veth object.
func parseDOption(s string) (veth vEth, err error) {
	n := strings.Split(s, ":")
	if len(n) != 3 && len(n) != 2 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	veth.nsName, err = getDockerContainerNS(n[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth.linkName = n[1]

	if len(n) == 3 {
		ip, mask, err2 := net.ParseCIDR(n[2])
		if err2 != nil {
			err = fmt.Errorf("failed to parse IP addr %s: %v",
				n[2], err2)
			return
		}
		veth.ipAddr.IP = ip
		veth.ipAddr.Mask = mask.Mask
		veth.withIPAddr = true
	} else {
		veth.withIPAddr = false
	}

	return
}

// parseXOption parses '-x' option and put this information in veth object.
func parseXOption(s string) (vxlan vxLan, err error) {
	var err2 error // if we encounter an error, it's marked here.

	n := strings.Split(s, ":")
	if len(n) != 3 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	vxlan.parentIF = n[0]
	vxlan.ipAddr = net.ParseIP(n[1])
	vxlan.id, err2 = strconv.Atoi(n[2])
	if err2 != nil {
		err = fmt.Errorf("failed to parse VXID %s: %v", n[2], err2)
		return
	}

	return
}

// usage shows usage when user invokes it with '-h' option.
func usage() {
	doc := heredoc.Doc(`

		Usage:
		./koko -d centos1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24 #with IP addr
		./koko -d centos1:link1 -d centos2:link2  #without IP addr
		./koko -n /var/run/netns/test1:link1:192.168.1.1/24 <other>
	`)

	fmt.Print(doc)

}

/**
Usage:
* case1: connect between docker container, with ip address
./koko -d centos1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24
* case2: connect between docker container, without ip address
./koko -d centos1:link1 -d centos2:link2
* case3: connect between linux ns container (a.k.a. 'ip netns'), with ip address
./koko -n /var/run/netns/test1:link1:192.168.1.1/24 -n <snip>
* case4: connect between linux ns and docker container
./koko -n /var/run/netns/test1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24
* case5: connect docker/linux ns container to vxlan interface
./koko -d centos1:link1:192.168.1.1/24 -x eth1:1.1.1.1:10
*/
func main() {

	var c int		// command line parameters.
	var err error		// if we encounter an error, it's marked here.
	var toVxlan bool	// endpoint is to VxLan?

	cnt := 0          // Count of command line parameters.
	getopt.OptErr = 0 // Any errors with peeling apart the command line options.

	// Create some empty vEth data objects.
	veth1 := vEth{}
	veth2 := vEth{}
	vxlan := vxLan{}
	toVxlan = false

	// Parse options and and exit if they don't meet our criteria.
	for {
		if c = getopt.Getopt("d:n:x:h"); c == getopt.EOF {
			break
		}
		switch c {
		case 'd':
			if cnt == 0 {
				veth1, err = parseDOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else if cnt == 1 {
				veth2, err = parseDOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else {
				fmt.Fprintf(os.Stderr, "Too many config!")
				usage()
				os.Exit(1)
			}
			cnt++

		case 'n':
			if cnt == 0 {
				veth1, err = parseNOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else if cnt == 1 {
				veth2, err = parseNOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else {
				fmt.Fprintf(os.Stderr, "Too many config!")
				usage()
				os.Exit(1)
			}
			cnt++

		case 'x':
			vxlan, err = parseXOption(getopt.OptArg)
			toVxlan = true

		case 'h':
			usage()
			os.Exit(0)

		}

	}

	// Assuming everything else above has worked out -- we'll continue on and make the vth pair.
	// You'll node at this point we've created vEth data objects and pass them along to the makeVeth method.
	if toVxlan == false && cnt == 2 {
		// case 1: two container endpoint.
		fmt.Printf("Create veth...")
		makeVeth(veth1, veth2)
		fmt.Printf("done\n")
	} else if toVxlan == true && cnt == 1 {
		// case 2: one endpoint with vxlan
		fmt.Printf("Create vxlan %s\n", veth1.linkName)
		makeVxLan(veth1, vxlan)
	}

}
<commit_msg>Add queuelen in vxlan mode and add missing error handling<commit_after>/**
 * koko: Container connector
 */
package main

import (
	"fmt"
	"github.com/mattn/go-getopt"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/containernetworking/cni/pkg/ns"
	"github.com/vishvananda/netlink"

	"github.com/docker/docker/client"
	"golang.org/x/net/context"

	"github.com/MakeNowJust/heredoc"
)

func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{
			Name:  name,
			Flags: net.FlagUp,
			MTU:   mtu,
		},
		PeerName: peer,
	}

	if err := netlink.LinkAdd(veth); err != nil {
		return nil, err
	}
	return veth, nil
}

func getVethPair(name1 string, name2 string) (link1 netlink.Link, link2 netlink.Link, err error) {

	link1, err = makeVethPair(name1, name2, 1500)
	if err != nil {
		switch {
		case os.IsExist(err):
			err = fmt.Errorf("container veth name provided (%v) already exists", name1)
			return
		default:
			err = fmt.Errorf("failed to make veth pair: %v", err)
			return
		}
	}

	link2, err = netlink.LinkByName(name2)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to lookup %q: %v\n", name2, err)
	}

	return
}

// addVxLanInterface creates VxLan interface by given vxlan object
func addVxLanInterface(vxlan vxLan, devName string) error {
	parentIF, err := netlink.LinkByName(vxlan.parentIF)

	if err != nil {
		return fmt.Errorf("Failed to get %s: %v", vxlan.parentIF, err)
	}

	vxlanconf := netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
				Name:		devName,
				TxQLen:		1000,
		},
		VxlanId:	vxlan.id,
		VtepDevIndex:	parentIF.Attrs().Index,
		Group:		vxlan.ipAddr,
		Port:		4789,
		Learning:	true,
		L2miss:		true,
		L3miss:		true,
	}
	err = netlink.LinkAdd(&vxlanconf)

	if err != nil {
		return fmt.Errorf("Failed to add vxlan %s: %v", devName, err)
	}
	return nil
}

// getDockerContainerNS retrieves container's network namespace from
// docker container id, given as containerID.
func getDockerContainerNS(containerID string) (namespace string, err error) {
	ctx := context.Background()
	cli, err := client.NewEnvClient()
	if err != nil {
		panic(err)
	}

	cli.UpdateClientVersion("1.24")

	json, err := cli.ContainerInspect(ctx, containerID)
	if err != nil {
		err = fmt.Errorf("failed to get container info: %v", err)
		return
	}
	if json.NetworkSettings == nil {
		err = fmt.Errorf("failed to get container info: %v", err)
		return
	}
	namespace = json.NetworkSettings.NetworkSettingsBase.SandboxKey
	return
}

// vEth is a structure to descrive veth interfaces.
type vEth struct {
	nsName		string		// What's the network namespace?
	linkName	string		// And what will we call the link.
	withIPAddr	bool		// Is there an ip address?
	ipAddr		net.IPNet	// What is that ip address.
}

// vxLan is a structure to descrive vxlan endpoint.
type vxLan struct {
	parentIF	string		// parent interface name
	id		int		// VxLan ID
	ipAddr		net.IP		// VxLan destination address
}

// setVethLink is low-level handler to set IP address onveth links given a single vEth data object.
// ...primarily used privately by makeVeth().
func (veth *vEth) setVethLink(link netlink.Link) (err error) {
	vethNs, err := ns.GetNS(veth.nsName)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}
	defer vethNs.Close()

	if err := netlink.LinkSetNsFd(link, int(vethNs.Fd())); err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	err = vethNs.Do(func(_ ns.NetNS) error {
		link, err := netlink.LinkByName(veth.linkName)
		if err != nil {
			return fmt.Errorf("failed to lookup %q in %q: %v", veth.linkName, vethNs.Path(), err)
		}

		if err = netlink.LinkSetUp(link); err != nil {
			return fmt.Errorf("failed to set %q up: %v", veth.linkName, err)
		}

		// Conditionally set the IP address.
		if veth.withIPAddr {
			addr := &netlink.Addr{IPNet: &veth.ipAddr, Label: ""}
			if err = netlink.AddrAdd(link, addr); err != nil {
				return fmt.Errorf("failed to add IP addr %v to %q: %v", addr, veth.linkName, err)
			}
		}

		return nil
	})

	return
}

// makeVeth is top-level handler to create veth links given two vEth data objects: veth1 and veth2.
func makeVeth(veth1 vEth, veth2 vEth) {

	link1, link2, err := getVethPair(veth1.linkName, veth2.linkName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth1.setVethLink(link1)
	veth2.setVethLink(link2)
}

// makeVxLan makes vxlan interface and put it into container namespace
func makeVxLan(veth1 vEth, vxlan vxLan) {

	err := addVxLanInterface(vxlan, veth1.linkName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "vxlan add failed: %v", err)
	}

	link, err2 := netlink.LinkByName(veth1.linkName)
	if err2 != nil {
		fmt.Fprintf(os.Stderr, "Cannot get %s: %v", veth1.linkName, err)
	}
	err = veth1.setVethLink(link)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot add IPaddr/netns failed: %v", err)
	}
}

// parseNOption parses '-n' option and put this information in veth object.
func parseNOption(s string) (veth vEth, err error) {
	n := strings.Split(s, ":")
	if len(n) != 3 && len(n) != 2 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	veth.nsName = fmt.Sprintf("/var/run/netns/%s", n[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth.linkName = n[1]

	if len(n) == 3 {
		ip, mask, err2 := net.ParseCIDR(n[2])
		if err2 != nil {
			err = fmt.Errorf("failed to parse IP addr %s: %v",
				n[2], err2)
			return
		}
		veth.ipAddr.IP = ip
		veth.ipAddr.Mask = mask.Mask
		veth.withIPAddr = true
	} else {
		veth.withIPAddr = false
	}

	return
}

// parseNOption parses '-n' option and put this information in veth object.
func parseDOption(s string) (veth vEth, err error) {
	n := strings.Split(s, ":")
	if len(n) != 3 && len(n) != 2 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	veth.nsName, err = getDockerContainerNS(n[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}

	veth.linkName = n[1]

	if len(n) == 3 {
		ip, mask, err2 := net.ParseCIDR(n[2])
		if err2 != nil {
			err = fmt.Errorf("failed to parse IP addr %s: %v",
				n[2], err2)
			return
		}
		veth.ipAddr.IP = ip
		veth.ipAddr.Mask = mask.Mask
		veth.withIPAddr = true
	} else {
		veth.withIPAddr = false
	}

	return
}

// parseXOption parses '-x' option and put this information in veth object.
func parseXOption(s string) (vxlan vxLan, err error) {
	var err2 error // if we encounter an error, it's marked here.

	n := strings.Split(s, ":")
	if len(n) != 3 {
		err = fmt.Errorf("failed to parse %s", s)
		return
	}

	vxlan.parentIF = n[0]
	vxlan.ipAddr = net.ParseIP(n[1])
	vxlan.id, err2 = strconv.Atoi(n[2])
	if err2 != nil {
		err = fmt.Errorf("failed to parse VXID %s: %v", n[2], err2)
		return
	}

	return
}

// usage shows usage when user invokes it with '-h' option.
func usage() {
	doc := heredoc.Doc(`

		Usage:
		./koko -d centos1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24 #with IP addr
		./koko -d centos1:link1 -d centos2:link2  #without IP addr
		./koko -n /var/run/netns/test1:link1:192.168.1.1/24 <other>
	`)

	fmt.Print(doc)

}

/**
Usage:
* case1: connect between docker container, with ip address
./koko -d centos1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24
* case2: connect between docker container, without ip address
./koko -d centos1:link1 -d centos2:link2
* case3: connect between linux ns container (a.k.a. 'ip netns'), with ip address
./koko -n /var/run/netns/test1:link1:192.168.1.1/24 -n <snip>
* case4: connect between linux ns and docker container
./koko -n /var/run/netns/test1:link1:192.168.1.1/24 -d centos2:link2:192.168.1.2/24
* case5: connect docker/linux ns container to vxlan interface
./koko -d centos1:link1:192.168.1.1/24 -x eth1:1.1.1.1:10
*/
func main() {

	var c int		// command line parameters.
	var err error		// if we encounter an error, it's marked here.
	var toVxlan bool	// endpoint is to VxLan?

	cnt := 0          // Count of command line parameters.
	getopt.OptErr = 0 // Any errors with peeling apart the command line options.

	// Create some empty vEth data objects.
	veth1 := vEth{}
	veth2 := vEth{}
	vxlan := vxLan{}
	toVxlan = false

	// Parse options and and exit if they don't meet our criteria.
	for {
		if c = getopt.Getopt("d:n:x:h"); c == getopt.EOF {
			break
		}
		switch c {
		case 'd':
			if cnt == 0 {
				veth1, err = parseDOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else if cnt == 1 {
				veth2, err = parseDOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else {
				fmt.Fprintf(os.Stderr, "Too many config!")
				usage()
				os.Exit(1)
			}
			cnt++

		case 'n':
			if cnt == 0 {
				veth1, err = parseNOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else if cnt == 1 {
				veth2, err = parseNOption(getopt.OptArg)
				if err != nil {
					fmt.Fprintf(os.Stderr, "Parse failed %s!:%v", getopt.OptArg, err)
					usage()
					os.Exit(1)
				}
			} else {
				fmt.Fprintf(os.Stderr, "Too many config!")
				usage()
				os.Exit(1)
			}
			cnt++

		case 'x':
			vxlan, err = parseXOption(getopt.OptArg)
			toVxlan = true

		case 'h':
			usage()
			os.Exit(0)

		}

	}

	// Assuming everything else above has worked out -- we'll continue on and make the vth pair.
	// You'll node at this point we've created vEth data objects and pass them along to the makeVeth method.
	if toVxlan == false && cnt == 2 {
		// case 1: two container endpoint.
		fmt.Printf("Create veth...")
		makeVeth(veth1, veth2)
		fmt.Printf("done\n")
	} else if toVxlan == true && cnt == 1 {
		// case 2: one endpoint with vxlan
		fmt.Printf("Create vxlan %s\n", veth1.linkName)
		makeVxLan(veth1, vxlan)
	}

}
<|endoftext|>


<commit_before>package postgresrunner

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strconv"

	"github.com/BurntSushi/migration"
	"github.com/concourse/atc/db/migrations"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Port int
}

func (runner Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	defer ginkgo.GinkgoRecover()

	tmpdir, err := ioutil.TempDir("", "postgres")
	Expect(err).NotTo(HaveOccurred())

	currentUser, err := user.Current()
	Expect(err).NotTo(HaveOccurred())

	var initCmd, startCmd *exec.Cmd

	initdbPath, err := exec.LookPath("initdb")
	Expect(err).NotTo(HaveOccurred())

	postgresPath, err := exec.LookPath("postgres")
	Expect(err).NotTo(HaveOccurred())

	initdb := initdbPath + " -U postgres -D " + tmpdir
	postgres := fmt.Sprintf("%s -d 2 -D %s -h 127.0.0.1 -p %d", postgresPath, tmpdir, runner.Port)

	if currentUser.Uid == "0" {
		pgUser, err := user.Lookup("postgres")
		Expect(err).NotTo(HaveOccurred())

		uid, err := strconv.Atoi(pgUser.Uid)
		Expect(err).NotTo(HaveOccurred())

		gid, err := strconv.Atoi(pgUser.Gid)
		Expect(err).NotTo(HaveOccurred())

		err = os.Chown(tmpdir, uid, gid)
		Expect(err).NotTo(HaveOccurred())

		initCmd = exec.Command("su", "postgres", "-c", initdb)
		startCmd = exec.Command("su", "postgres", "-c", postgres)
	} else {
		initCmd = exec.Command("bash", "-c", initdb)
		startCmd = exec.Command("bash", "-c", postgres)
	}

	session, err := gexec.Start(
		initCmd,
		gexec.NewPrefixedWriter("[o][initdb] ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("[e][initdb] ", ginkgo.GinkgoWriter),
	)
	Expect(err).NotTo(HaveOccurred())

	<-session.Exited

	Expect(session).To(gexec.Exit(0))

	ginkgoRunner := &ginkgomon.Runner{
		Name:          "postgres",
		Command:       startCmd,
		AnsiColorCode: "90m",
		StartCheck:    "database system is ready to accept connections",
		Cleanup: func() {
			os.RemoveAll(tmpdir)
		},
	}

	return ginkgoRunner.Run(signals, ready)
}

func (runner *Runner) Open() *sql.DB {
	dbConn, err := migration.Open(
		"postgres",
		runner.DataSourceName(),
		migrations.Migrations,
	)
	Expect(err).NotTo(HaveOccurred())

	return dbConn
}

func (runner *Runner) DataSourceName() string {
	return fmt.Sprintf("user=postgres dbname=testdb sslmode=disable port=%d", runner.Port)
}

func (runner *Runner) CreateTestDB() {
	createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")

	createS, err := gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-createS.Exited

	if createS.ExitCode() != 0 {
		runner.DropTestDB()

		createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
		createS, err = gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
		Expect(err).NotTo(HaveOccurred())
	}

	<-createS.Exited

	Expect(createS).To(gexec.Exit(0))
}

func (runner *Runner) DropTestDB() {
	dropdb := exec.Command("dropdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	dropS, err := gexec.Start(dropdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-dropS.Exited

	Expect(dropS).To(gexec.Exit(0))
}

func (runner *Runner) Truncate() {
	truncate := exec.Command(
		"psql",
		"-U", "postgres",
		"-p", strconv.Itoa(runner.Port),
		"testdb",
		"-c", `
			CREATE OR REPLACE FUNCTION truncate_tables() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT tablename FROM pg_tables
							WHERE schemaname = 'public' AND tablename != 'migration_version';
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' RESTART IDENTITY CASCADE;';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			CREATE OR REPLACE FUNCTION drop_ephemeral_sequences() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT relname FROM pg_class
							WHERE relname LIKE 'build_event_id_seq_%';
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'DROP SEQUENCE ' || quote_ident(stmt.relname) || ';';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			CREATE OR REPLACE FUNCTION reset_global_sequences() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT relname FROM pg_class
							WHERE relname IN ('one_off_name', 'config_version_seq');
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'ALTER SEQUENCE ' || quote_ident(stmt.relname) || ' RESTART WITH 1;';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			SELECT truncate_tables();
			SELECT drop_ephemeral_sequences();
			SELECT reset_global_sequences();
		`,
	)

	truncateS, err := gexec.Start(truncate, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-truncateS.Exited

	Expect(truncateS).To(gexec.Exit(0))
}
<commit_msg>silence postgres logs; not usually useful<commit_after>package postgresrunner

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strconv"

	"github.com/BurntSushi/migration"
	"github.com/concourse/atc/db/migrations"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Port int
}

func (runner Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	defer ginkgo.GinkgoRecover()

	tmpdir, err := ioutil.TempDir("", "postgres")
	Expect(err).NotTo(HaveOccurred())

	currentUser, err := user.Current()
	Expect(err).NotTo(HaveOccurred())

	var initCmd, startCmd *exec.Cmd

	initdbPath, err := exec.LookPath("initdb")
	Expect(err).NotTo(HaveOccurred())

	postgresPath, err := exec.LookPath("postgres")
	Expect(err).NotTo(HaveOccurred())

	initdb := initdbPath + " -U postgres -D " + tmpdir
	postgres := fmt.Sprintf("%s -D %s -h 127.0.0.1 -p %d", postgresPath, tmpdir, runner.Port)

	if currentUser.Uid == "0" {
		pgUser, err := user.Lookup("postgres")
		Expect(err).NotTo(HaveOccurred())

		uid, err := strconv.Atoi(pgUser.Uid)
		Expect(err).NotTo(HaveOccurred())

		gid, err := strconv.Atoi(pgUser.Gid)
		Expect(err).NotTo(HaveOccurred())

		err = os.Chown(tmpdir, uid, gid)
		Expect(err).NotTo(HaveOccurred())

		initCmd = exec.Command("su", "postgres", "-c", initdb)
		startCmd = exec.Command("su", "postgres", "-c", postgres)
	} else {
		initCmd = exec.Command("bash", "-c", initdb)
		startCmd = exec.Command("bash", "-c", postgres)
	}

	session, err := gexec.Start(
		initCmd,
		gexec.NewPrefixedWriter("[o][initdb] ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("[e][initdb] ", ginkgo.GinkgoWriter),
	)
	Expect(err).NotTo(HaveOccurred())

	<-session.Exited

	Expect(session).To(gexec.Exit(0))

	ginkgoRunner := &ginkgomon.Runner{
		Name:          "postgres",
		Command:       startCmd,
		AnsiColorCode: "90m",
		StartCheck:    "database system is ready to accept connections",
		Cleanup: func() {
			os.RemoveAll(tmpdir)
		},
	}

	return ginkgoRunner.Run(signals, ready)
}

func (runner *Runner) Open() *sql.DB {
	dbConn, err := migration.Open(
		"postgres",
		runner.DataSourceName(),
		migrations.Migrations,
	)
	Expect(err).NotTo(HaveOccurred())

	return dbConn
}

func (runner *Runner) DataSourceName() string {
	return fmt.Sprintf("user=postgres dbname=testdb sslmode=disable port=%d", runner.Port)
}

func (runner *Runner) CreateTestDB() {
	createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")

	createS, err := gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-createS.Exited

	if createS.ExitCode() != 0 {
		runner.DropTestDB()

		createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
		createS, err = gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
		Expect(err).NotTo(HaveOccurred())
	}

	<-createS.Exited

	Expect(createS).To(gexec.Exit(0))
}

func (runner *Runner) DropTestDB() {
	dropdb := exec.Command("dropdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	dropS, err := gexec.Start(dropdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-dropS.Exited

	Expect(dropS).To(gexec.Exit(0))
}

func (runner *Runner) Truncate() {
	truncate := exec.Command(
		"psql",
		"-U", "postgres",
		"-p", strconv.Itoa(runner.Port),
		"testdb",
		"-c", `
			SET client_min_messages TO WARNING;

			CREATE OR REPLACE FUNCTION truncate_tables() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT tablename FROM pg_tables
							WHERE schemaname = 'public' AND tablename != 'migration_version';
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' RESTART IDENTITY CASCADE;';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			CREATE OR REPLACE FUNCTION drop_ephemeral_sequences() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT relname FROM pg_class
							WHERE relname LIKE 'build_event_id_seq_%';
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'DROP SEQUENCE ' || quote_ident(stmt.relname) || ';';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			CREATE OR REPLACE FUNCTION reset_global_sequences() RETURNS void AS $$
			DECLARE
					statements CURSOR FOR
							SELECT relname FROM pg_class
							WHERE relname IN ('one_off_name', 'config_version_seq');
			BEGIN
					FOR stmt IN statements LOOP
							EXECUTE 'ALTER SEQUENCE ' || quote_ident(stmt.relname) || ' RESTART WITH 1;';
					END LOOP;
			END;
			$$ LANGUAGE plpgsql;

			SELECT truncate_tables();
			SELECT drop_ephemeral_sequences();
			SELECT reset_global_sequences();
		`,
	)

	truncateS, err := gexec.Start(truncate, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	<-truncateS.Exited

	Expect(truncateS).To(gexec.Exit(0))
}
<|endoftext|>


<commit_before>package thermal

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"log"
	"time"
)

// routeToLine will route packets to their appropriate line
func routeToLine() {
}

//-----------------------------------------------------------------------------
// Line Store
// The line store is a service which manages access to lines
//-----------------------------------------------------------------------------

type lineStoreRequest struct {
	peer     *peerSwitch
	response chan *lineSession
}

type lineStore struct {
	sw      *Switch
	lineMap map[string]*lineSession
	request chan *lineStoreRequest
}

func (store *lineStore) service() {
	for {
		select {

		case request := <-store.request:
			// Get or Create a line for the hashname
			line, exists := store.lineMap[request.peer.hashname]
			if !exists {
				line := new(lineSession)
				line.start(store.sw, request.peer)
				store.lineMap[request.peer.hashname] = line
			}
			request.response <- line

		default:
		}
	}
}

func (store *lineStore) start(sw *Switch) {
	store.sw = sw
	go store.service()
}

//-----------------------------------------------------------------------------
// Line(s)
// Representation and logic for telehash lines
//-----------------------------------------------------------------------------

type lineHalf struct {
	id     string
	at     int64
	secret [32]byte
}

type lineSession struct {
	csid            string
	cset            cipherSet
	remotePublicKey [32]byte

	local         lineHalf
	remote        lineHalf
	encryptionKey [32]byte
	decryptionKey [32]byte

	ready      bool
	openLocal  chan bool
	openRemote chan []byte
	send       chan decodedPacket
	recv       chan []byte
}

func (line *lineSession) service() {

	for {

		select {

		case msg := <-line.openLocal:
			log.Println("openLocal...")
			log.Printf("msg: %s", msg)
			//line.newLocalLine()

		case msg := <-line.openRemote:
			log.Println("openRemote...")
			log.Printf("msg: %s", msg)
			//line.openRemote()

		default:
			//
		}

		if line.ready {
			select {

			case msg := <-line.send:
				log.Println("line send request...")
				log.Printf("msg: %s", msg)

			case msg := <-line.recv:
				log.Println("line recv request...")
				log.Printf("msg: %s", msg)

			default:

			}
		}

	}
}

func (line *lineSession) start(sw *Switch, peer *peerSwitch) {

	// determine best cipher set which both switches support
	// todo - getBestCSMatch(sw, peer)
	agreedCSID := "3a"
	line.csid = agreedCSID
	cp := *sw.cpack
	line.cset = cp[line.csid]

	// set the remotePublicKey for later use (decode from base64)
	peerKey, _ := base64.StdEncoding.DecodeString(peer.keys[line.csid])
	copy(line.remotePublicKey[:], peerKey[:])

	// setup the channels
	line.openLocal = make(chan bool)
	line.openRemote = make(chan []byte)
	line.send = make(chan decodedPacket)
	line.recv = make(chan []byte)

	// queue up a message to begin the open process
	line.ready = false
	line.openLocal <- true

	go line.service()
}

func (line *lineSession) newLocalLine() {

	line.local.id = generateLineId()
	line.local.at = generateLineAt()

	// todo
	// json := make the json (to, from(parts), at, localLineId)
	// to == remoteHashname
	// parts will be retrieved over in the openMaker()?
	// line.local.id
	cset := line.cset
	jsonHead := []byte("{}")
	body := cset.pubKey()[:]
	packet, err := encodePacket(jsonHead, body)
	openPacketBody, localLineSecret, err := cset.encryptOpenPacketBody(packet, &line.remotePublicKey)
	if err != nil {
		log.Printf("Error encrypting open packet body (err: %s)", err)
		return
	}

	line.local.secret = localLineSecret

	// todo
	// the head needs to be a single byte, representing the csid
	// the encodePacket() function is not setup to handle that as-is
	openPacketHead := []byte("")
	openPacket, err := encodePacket(openPacketHead, openPacketBody)
	if err != nil {
		log.Printf("Error encoding open packet (err: %s)", err)
		return
	}
	log.Println(openPacket)

	// todo
	// return or send
}

func (line *lineSession) newRemoteLine() {
}

// generateLineId returns a random 16 char hex encoded string
func generateLineId() string {
	var idBin [8]byte
	rand.Reader.Read(idBin[:])
	idHex := fmt.Sprintf("%x", idBin)
	return idHex
}

// generateLineAt returds an integer timestamp suitable for a line at
func generateLineAt() int64 {
	return time.Now().Unix()
}
<commit_msg>add reminder note<commit_after>package thermal

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"log"
	"time"
)

// routeToLine will route packets to their appropriate line
func routeToLine() {
}

//-----------------------------------------------------------------------------
// Line Store
// The line store is a service which manages access to lines
//-----------------------------------------------------------------------------

type lineStoreRequest struct {
	peer     *peerSwitch
	response chan *lineSession
}

type lineStore struct {
	sw      *Switch
	lineMap map[string]*lineSession
	request chan *lineStoreRequest
}

func (store *lineStore) service() {
	for {
		select {

		case request := <-store.request:
			// Get or Create a line for the hashname
			line, exists := store.lineMap[request.peer.hashname]
			if !exists {
				line := new(lineSession)
				line.start(store.sw, request.peer)
				store.lineMap[request.peer.hashname] = line
			}
			request.response <- line

		default:
		}
	}
}

func (store *lineStore) start(sw *Switch) {
	store.sw = sw
	go store.service()
}

//-----------------------------------------------------------------------------
// Line(s)
// Representation and logic for telehash lines
//-----------------------------------------------------------------------------

type lineHalf struct {
	id     string
	at     int64
	secret [32]byte
}

type lineSession struct {
	csid            string
	cset            cipherSet
	remotePublicKey [32]byte

	local         lineHalf
	remote        lineHalf
	encryptionKey [32]byte
	decryptionKey [32]byte

	ready      bool
	openLocal  chan bool
	openRemote chan []byte
	send       chan decodedPacket
	recv       chan []byte
}

func (line *lineSession) service() {

	for {

		select {

		case msg := <-line.openLocal:
			log.Println("openLocal...")
			log.Printf("msg: %s", msg)
			//line.newLocalLine()

		case msg := <-line.openRemote:
			log.Println("openRemote...")
			log.Printf("msg: %s", msg)
			//line.openRemote()

		default:
			//
		}

		if line.ready {
			select {

			case msg := <-line.send:
				log.Println("line send request...")
				log.Printf("msg: %s", msg)

			case msg := <-line.recv:
				log.Println("line recv request...")
				log.Printf("msg: %s", msg)

			default:

			}
		}

	}
}

func (line *lineSession) start(sw *Switch, peer *peerSwitch) {

	// determine best cipher set which both switches support
	// todo - getBestCSMatch(sw, peer)
	agreedCSID := "3a"
	line.csid = agreedCSID
	// todo - better way to dereference
	cp := *sw.cpack
	line.cset = cp[line.csid]

	// set the remotePublicKey for later use (decode from base64)
	peerKey, _ := base64.StdEncoding.DecodeString(peer.keys[line.csid])
	copy(line.remotePublicKey[:], peerKey[:])

	// setup the channels
	line.openLocal = make(chan bool)
	line.openRemote = make(chan []byte)
	line.send = make(chan decodedPacket)
	line.recv = make(chan []byte)

	// queue up a message to begin the open process
	line.ready = false
	line.openLocal <- true

	go line.service()
}

func (line *lineSession) newLocalLine() {

	line.local.id = generateLineId()
	line.local.at = generateLineAt()

	// todo
	// json := make the json (to, from(parts), at, localLineId)
	// to == remoteHashname
	// parts will be retrieved over in the openMaker()?
	// line.local.id
	cset := line.cset
	jsonHead := []byte("{}")
	body := cset.pubKey()[:]
	packet, err := encodePacket(jsonHead, body)
	openPacketBody, localLineSecret, err := cset.encryptOpenPacketBody(packet, &line.remotePublicKey)
	if err != nil {
		log.Printf("Error encrypting open packet body (err: %s)", err)
		return
	}

	line.local.secret = localLineSecret

	// todo
	// the head needs to be a single byte, representing the csid
	// the encodePacket() function is not setup to handle that as-is
	openPacketHead := []byte("")
	openPacket, err := encodePacket(openPacketHead, openPacketBody)
	if err != nil {
		log.Printf("Error encoding open packet (err: %s)", err)
		return
	}
	log.Println(openPacket)

	// todo
	// return or send
}

func (line *lineSession) newRemoteLine() {
}

// generateLineId returns a random 16 char hex encoded string
func generateLineId() string {
	var idBin [8]byte
	rand.Reader.Read(idBin[:])
	idHex := fmt.Sprintf("%x", idBin)
	return idHex
}

// generateLineAt returds an integer timestamp suitable for a line at
func generateLineAt() int64 {
	return time.Now().Unix()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"math"

	"github.com/jmhodges/levigo"
)

// Keys stored in LevelDB for lists
//
// MetaKey | key = ListLengthValue | 1 byte flags | uint32 list length | int64 sequence number of the leftmost element | int64 sequence number of the rightmost element
//
// For each list item:
// ListKey | key length uint32 | key | int64 sequence number = value

type listDetails struct {
	flags  byte
	length uint32
	left   int64
	right  int64
}

const (
	listLooseSeq byte = 1 << iota
)

func Lrange(args [][]byte, wb *levigo.WriteBatch) interface{} {
	snapshot := DB.NewSnapshot()
	opts := levigo.NewReadOptions()
	opts.SetSnapshot(snapshot)

	l, err := llen(metaKey(args[0]), opts)
	if err != nil {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return err
	}
	if l.length == 0 {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return []interface{}{}
	}

	start, end, err := parseRange(args[1:], int64(l.length))
	if err != nil {
		return err
	}
	// the start comes after the end, so we're not going to find anything
	if start > end {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return []interface{}{}
	}

	count := end + 1 - start
	stream := &cmdReplyStream{count, make(chan interface{})}

	go func() {
		defer close(stream.items)
		it := DB.NewIterator(opts)
		defer it.Close()

		iterKey := NewKeyBuffer(ListKey, args[0], 8)
		binary.BigEndian.PutUint64(iterKey.SuffixForRead(8), uint64(l.left+1+start-math.MinInt64))
		it.Seek(iterKey.Key())
		for i := int64(0); it.Valid() && i < count; i++ {
			stream.items <- it.Value()
			it.Next()
		}
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
	}()
	return stream
}

func Llen(args [][]byte, wb *levigo.WriteBatch) interface{} {
	l, err := llen(metaKey(args[0]), nil)
	if err != nil {
		return err
	}
	return l.length
}

// A LPUSH onto a list takes the seq number of the leftmost element,
// decrements it and inserts the item.
func Lpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, true, true, wb)
	if err != nil {
		return err
	}
	return res
}

func Lpushx(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, true, false, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, false, true, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpushx(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, false, false, wb)
	if err != nil {
		return err
	}
	return res
}

func lpush(args [][]byte, left bool, create bool, wb *levigo.WriteBatch) (interface{}, error) {
	mk := metaKey(args[0])
	l, err := llen(mk, nil)
	if err != nil {
		return nil, err
	}
	if create || l.length > 0 {
		key := NewKeyBuffer(ListKey, args[0], 8)
		for _, value := range args[1:] {
			l.length++
			var seq int64
			if left {
				seq = l.left
				l.left--
			} else {
				seq = l.right
				l.right++
			}
			// To sort negative ints in order before positive, we subtract math.MinInt64
			// which wraps the numbers around and sorts correctly
			binary.BigEndian.PutUint64(key.SuffixForRead(8), uint64(seq-math.MinInt64))
			wb.Put(key.Key(), value)
		}
		setLlen(mk, l, wb)
	}
	return l.length, nil
}

func Lpop(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], true, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpop(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], false, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpoplpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], false, wb)
	if err != nil {
		return err
	}
	if res == nil {
		return nil
	}
	_, err = lpush([][]byte{args[1], res.([]byte)}, true, true, wb)
	if err != nil {
		return err
	}
	return res
}

func lpop(key []byte, left bool, wb *levigo.WriteBatch) (interface{}, error) {
	mk := metaKey(key)
	l, err := llen(mk, nil)
	if err != nil {
		return nil, err
	}
	if l.length == 0 {
		return nil, nil
	}

	iterKey := NewKeyBuffer(ListKey, key, 0)
	it := DB.NewIterator(ReadWithoutCacheFill)
	defer it.Close()
	if !left {
		iterKey.ReverseIterKey()
	}
	it.Seek(iterKey.Key())
	if !left {
		it.Prev()
	}
	if !it.Valid() {
		return nil, nil
	}
	k := it.Key()
	if !iterKey.IsPrefixOf(k) {
		return nil, nil
	}
	res := it.Value()

	wb.Delete(k)
	l.length--
	if l.length == 0 {
		wb.Delete(mk)
	} else {
		// decode the sequence number from the list item key
		seq := int64(binary.BigEndian.Uint64(k[len(key)+5:])) + math.MinInt64
		if left {
			l.left = seq
		} else {
			l.right = seq
		}
		setLlen(mk, l, wb)
	}

	return res, nil
}

func llen(key []byte, opts *levigo.ReadOptions) (*listDetails, error) {
	if opts == nil {
		opts = DefaultReadOptions
	}
	res, err := DB.Get(opts, key)
	if err != nil {
		return nil, err
	}
	l := &listDetails{right: 1}
	if res == nil {
		return l, nil
	}
	if len(res) < 22 || res[0] != ListLengthValue {
		return nil, InvalidDataError
	}
	l.flags = res[1]
	l.length = binary.BigEndian.Uint32(res[2:])
	l.left = int64(binary.BigEndian.Uint64(res[6:]))
	l.right = int64(binary.BigEndian.Uint64(res[14:]))
	return l, nil
}

func setLlen(key []byte, l *listDetails, wb *levigo.WriteBatch) {
	data := make([]byte, 22)
	data[0] = ListLengthValue
	data[1] = l.flags
	binary.BigEndian.PutUint32(data[2:], l.length)
	binary.BigEndian.PutUint64(data[6:], uint64(l.left))
	binary.BigEndian.PutUint64(data[14:], uint64(l.right))
	wb.Put(key, data)
}

// BLPOP
// BRPOP
// BRPOPLPUSH
// LINDEX
// LINSERT
// LRANGE
// LREM
// LSET
// LTRIM
<commit_msg>Move list flags in metakey<commit_after>package main

import (
	"encoding/binary"
	"math"

	"github.com/jmhodges/levigo"
)

// Keys stored in LevelDB for lists
//
// MetaKey | key = ListLengthValue | uint32 list length | 1 byte flags | int64 sequence number of the leftmost element | int64 sequence number of the rightmost element
//
// For each list item:
// ListKey | key length uint32 | key | int64 sequence number = value

type listDetails struct {
	flags  byte
	length uint32
	left   int64
	right  int64
}

const (
	listLooseSeq byte = 1 << iota
)

func Lrange(args [][]byte, wb *levigo.WriteBatch) interface{} {
	snapshot := DB.NewSnapshot()
	opts := levigo.NewReadOptions()
	opts.SetSnapshot(snapshot)

	l, err := llen(metaKey(args[0]), opts)
	if err != nil {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return err
	}
	if l.length == 0 {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return []interface{}{}
	}

	start, end, err := parseRange(args[1:], int64(l.length))
	if err != nil {
		return err
	}
	// the start comes after the end, so we're not going to find anything
	if start > end {
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
		return []interface{}{}
	}

	count := end + 1 - start
	stream := &cmdReplyStream{count, make(chan interface{})}

	go func() {
		defer close(stream.items)
		it := DB.NewIterator(opts)
		defer it.Close()

		iterKey := NewKeyBuffer(ListKey, args[0], 8)
		binary.BigEndian.PutUint64(iterKey.SuffixForRead(8), uint64(l.left+1+start-math.MinInt64))
		it.Seek(iterKey.Key())
		for i := int64(0); it.Valid() && i < count; i++ {
			stream.items <- it.Value()
			it.Next()
		}
		DB.ReleaseSnapshot(snapshot)
		opts.Close()
	}()
	return stream
}

func Llen(args [][]byte, wb *levigo.WriteBatch) interface{} {
	l, err := llen(metaKey(args[0]), nil)
	if err != nil {
		return err
	}
	return l.length
}

// A LPUSH onto a list takes the seq number of the leftmost element,
// decrements it and inserts the item.
func Lpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, true, true, wb)
	if err != nil {
		return err
	}
	return res
}

func Lpushx(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, true, false, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, false, true, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpushx(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpush(args, false, false, wb)
	if err != nil {
		return err
	}
	return res
}

func lpush(args [][]byte, left bool, create bool, wb *levigo.WriteBatch) (interface{}, error) {
	mk := metaKey(args[0])
	l, err := llen(mk, nil)
	if err != nil {
		return nil, err
	}
	if create || l.length > 0 {
		key := NewKeyBuffer(ListKey, args[0], 8)
		for _, value := range args[1:] {
			l.length++
			var seq int64
			if left {
				seq = l.left
				l.left--
			} else {
				seq = l.right
				l.right++
			}
			// To sort negative ints in order before positive, we subtract math.MinInt64
			// which wraps the numbers around and sorts correctly
			binary.BigEndian.PutUint64(key.SuffixForRead(8), uint64(seq-math.MinInt64))
			wb.Put(key.Key(), value)
		}
		setLlen(mk, l, wb)
	}
	return l.length, nil
}

func Lpop(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], true, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpop(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], false, wb)
	if err != nil {
		return err
	}
	return res
}

func Rpoplpush(args [][]byte, wb *levigo.WriteBatch) interface{} {
	res, err := lpop(args[0], false, wb)
	if err != nil {
		return err
	}
	if res == nil {
		return nil
	}
	_, err = lpush([][]byte{args[1], res.([]byte)}, true, true, wb)
	if err != nil {
		return err
	}
	return res
}

func lpop(key []byte, left bool, wb *levigo.WriteBatch) (interface{}, error) {
	mk := metaKey(key)
	l, err := llen(mk, nil)
	if err != nil {
		return nil, err
	}
	if l.length == 0 {
		return nil, nil
	}

	iterKey := NewKeyBuffer(ListKey, key, 0)
	it := DB.NewIterator(ReadWithoutCacheFill)
	defer it.Close()
	if !left {
		iterKey.ReverseIterKey()
	}
	it.Seek(iterKey.Key())
	if !left {
		it.Prev()
	}
	if !it.Valid() {
		return nil, nil
	}
	k := it.Key()
	if !iterKey.IsPrefixOf(k) {
		return nil, nil
	}
	res := it.Value()

	wb.Delete(k)
	l.length--
	if l.length == 0 {
		wb.Delete(mk)
	} else {
		// decode the sequence number from the list item key
		seq := int64(binary.BigEndian.Uint64(k[len(key)+5:])) + math.MinInt64
		if left {
			l.left = seq
		} else {
			l.right = seq
		}
		setLlen(mk, l, wb)
	}

	return res, nil
}

func llen(key []byte, opts *levigo.ReadOptions) (*listDetails, error) {
	if opts == nil {
		opts = DefaultReadOptions
	}
	res, err := DB.Get(opts, key)
	if err != nil {
		return nil, err
	}
	l := &listDetails{right: 1}
	if res == nil {
		return l, nil
	}
	if len(res) < 22 || res[0] != ListLengthValue {
		return nil, InvalidDataError
	}
	l.length = binary.BigEndian.Uint32(res[1:])
	l.flags = res[5]
	l.left = int64(binary.BigEndian.Uint64(res[6:]))
	l.right = int64(binary.BigEndian.Uint64(res[14:]))
	return l, nil
}

func setLlen(key []byte, l *listDetails, wb *levigo.WriteBatch) {
	data := make([]byte, 22)
	data[0] = ListLengthValue
	binary.BigEndian.PutUint32(data[1:], l.length)
	data[5] = l.flags
	binary.BigEndian.PutUint64(data[6:], uint64(l.left))
	binary.BigEndian.PutUint64(data[14:], uint64(l.right))
	wb.Put(key, data)
}

// BLPOP
// BRPOP
// BRPOPLPUSH
// LINDEX
// LINSERT
// LRANGE
// LREM
// LSET
// LTRIM
<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.

package markdown

import (
	"strconv"

	"github.com/opennota/byteutil"
)

var (
	bullet     [256]bool
	afterdigit [256]bool
)

func init() {
	bullet['*'], bullet['+'], bullet['-'] = true, true, true
	afterdigit[')'], afterdigit['.'] = true, true
}

var listTerminatedBy []BlockRule

func skipBulletListMarker(s *StateBlock, startLine int) int {
	pos := s.BMarks[startLine] + s.TShift[startLine]
	src := s.Src

	if !bullet[src[pos]] {
		return -1
	}

	pos++
	max := s.EMarks[startLine]

	if pos < max && src[pos] != ' ' {
		return -1
	}

	return pos
}

func skipOrderedListMarker(s *StateBlock, startLine int) int {
	pos := s.BMarks[startLine] + s.TShift[startLine]
	max := s.EMarks[startLine]

	if pos+1 >= max {
		return -1
	}

	src := s.Src
	b := src[pos]

	if !byteutil.IsDigit(b) {
		return -1
	}

	for {
		if pos >= max {
			return -1
		}

		b = src[pos]
		pos++

		if byteutil.IsDigit(b) {
			continue
		}

		if afterdigit[b] {
			break
		}

		return -1
	}

	if pos < max && src[pos] != ' ' {
		return -1
	}

	return pos
}

func markParagraphsTight(s *StateBlock, idx int) {
	level := s.Level + 2
	tokens := s.Tokens

	for i := idx + 2; i < len(tokens)-2; i++ {
		if tokens[i].Level() == level {
			if tok, ok := tokens[i].(*ParagraphOpen); ok {
				tok.Tight = true
				i += 2
				tokens[i].(*ParagraphClose).Tight = true
			}
		}
	}
}

func ruleList(s *StateBlock, startLine, endLine int, silent bool) (_ bool) {
	shift := s.TShift[startLine]
	if shift < 0 {
		return
	}

	isOrdered := false
	posAfterMarker := skipOrderedListMarker(s, startLine)
	if posAfterMarker > 0 {
		isOrdered = true
	} else {
		posAfterMarker = skipBulletListMarker(s, startLine)
		if posAfterMarker < 0 {
			return
		}
	}

	src := s.Src
	markerChar := src[posAfterMarker-1]

	if silent {
		return true
	}

	tokenIdx := len(s.Tokens)

	var listMap *[2]int
	if isOrdered {
		start := s.BMarks[startLine] + shift
		markerValue, _ := strconv.Atoi(src[start : posAfterMarker-1])

		tok := &OrderedListOpen{
			Order: markerValue,
			Map:   [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		listMap = &tok.Map
	} else {
		tok := &BulletListOpen{
			Map: [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		listMap = &tok.Map
	}

	nextLine := startLine
	prevEmptyEnd := false

	tight := true
outer:
	for nextLine < endLine {
		contentStart := s.SkipSpaces(posAfterMarker)
		max := s.EMarks[nextLine]

		var indentAfterMarker int
		if contentStart >= max {
			indentAfterMarker = 1
		} else {
			indentAfterMarker = contentStart - posAfterMarker
		}

		if indentAfterMarker > 4 {
			indentAfterMarker = 1
		}

		indent := posAfterMarker - s.BMarks[nextLine] + indentAfterMarker

		tok := &ListItemOpen{
			Map: [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		itemMap := &tok.Map

		oldIndent := s.BlkIndent
		oldTight := s.Tight
		oldTShift := s.TShift[startLine]
		oldParentType := s.ParentType
		s.TShift[startLine] = contentStart - s.BMarks[startLine]
		s.BlkIndent = indent
		s.Tight = true
		s.ParentType = ptList

		s.Md.Block.Tokenize(s, startLine, endLine)

		if !s.Tight || prevEmptyEnd {
			tight = false
		}
		prevEmptyEnd = s.Line-startLine > 1 && s.IsLineEmpty(s.Line-1)
		if prevEmptyEnd {
			lastToken := s.Tokens[len(s.Tokens)-1]
			if _, ok := lastToken.(*BlockquoteClose); ok {
				prevEmptyEnd = false
			}
		}

		s.BlkIndent = oldIndent
		s.TShift[startLine] = oldTShift
		s.Tight = oldTight
		s.ParentType = oldParentType

		s.PushClosingToken(&ListItemClose{})

		startLine = s.Line
		nextLine = startLine
		(*itemMap)[1] = nextLine
		contentStart = s.BMarks[startLine]

		if nextLine >= endLine {
			break
		}

		if s.IsLineEmpty(nextLine) {
			break
		}

		if s.TShift[nextLine] < s.BlkIndent {
			break
		}

		for _, r := range listTerminatedBy {
			if r(s, nextLine, endLine, true) {
				break outer
			}
		}

		if isOrdered {
			posAfterMarker = skipOrderedListMarker(s, nextLine)
			if posAfterMarker < 0 {
				break
			}
		} else {
			posAfterMarker = skipBulletListMarker(s, nextLine)
			if posAfterMarker < 0 {
				break
			}
		}

		if markerChar != src[posAfterMarker-1] {
			break
		}
	}

	if isOrdered {
		s.PushClosingToken(&OrderedListClose{})
	} else {
		s.PushClosingToken(&BulletListClose{})
	}
	(*listMap)[1] = nextLine

	s.Line = nextLine

	if tight {
		markParagraphsTight(s, tokenIdx)
	}

	return true
}
<commit_msg>Limit ordered list marker length<commit_after>// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.

package markdown

import (
	"strconv"

	"github.com/opennota/byteutil"
)

var (
	bullet     [256]bool
	afterdigit [256]bool
)

func init() {
	bullet['*'], bullet['+'], bullet['-'] = true, true, true
	afterdigit[')'], afterdigit['.'] = true, true
}

var listTerminatedBy []BlockRule

func skipBulletListMarker(s *StateBlock, startLine int) int {
	pos := s.BMarks[startLine] + s.TShift[startLine]
	src := s.Src

	if !bullet[src[pos]] {
		return -1
	}

	pos++
	max := s.EMarks[startLine]

	if pos < max && src[pos] != ' ' {
		return -1
	}

	return pos
}

func skipOrderedListMarker(s *StateBlock, startLine int) int {
	pos := s.BMarks[startLine] + s.TShift[startLine]
	max := s.EMarks[startLine]

	if pos+1 >= max {
		return -1
	}

	src := s.Src
	b := src[pos]

	if !byteutil.IsDigit(b) {
		return -1
	}

	start := pos

	for {
		if pos >= max {
			return -1
		}

		b = src[pos]
		pos++

		if byteutil.IsDigit(b) {
			if pos-start > 9 {
				return -1
			}
			continue
		}

		if afterdigit[b] {
			break
		}

		return -1
	}

	if pos < max && src[pos] != ' ' {
		return -1
	}

	return pos
}

func markParagraphsTight(s *StateBlock, idx int) {
	level := s.Level + 2
	tokens := s.Tokens

	for i := idx + 2; i < len(tokens)-2; i++ {
		if tokens[i].Level() == level {
			if tok, ok := tokens[i].(*ParagraphOpen); ok {
				tok.Tight = true
				i += 2
				tokens[i].(*ParagraphClose).Tight = true
			}
		}
	}
}

func ruleList(s *StateBlock, startLine, endLine int, silent bool) (_ bool) {
	shift := s.TShift[startLine]
	if shift < 0 {
		return
	}

	isOrdered := false
	posAfterMarker := skipOrderedListMarker(s, startLine)
	if posAfterMarker > 0 {
		isOrdered = true
	} else {
		posAfterMarker = skipBulletListMarker(s, startLine)
		if posAfterMarker < 0 {
			return
		}
	}

	src := s.Src
	markerChar := src[posAfterMarker-1]

	if silent {
		return true
	}

	tokenIdx := len(s.Tokens)

	var listMap *[2]int
	if isOrdered {
		start := s.BMarks[startLine] + shift
		markerValue, _ := strconv.Atoi(src[start : posAfterMarker-1])

		tok := &OrderedListOpen{
			Order: markerValue,
			Map:   [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		listMap = &tok.Map
	} else {
		tok := &BulletListOpen{
			Map: [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		listMap = &tok.Map
	}

	nextLine := startLine
	prevEmptyEnd := false

	tight := true
outer:
	for nextLine < endLine {
		contentStart := s.SkipSpaces(posAfterMarker)
		max := s.EMarks[nextLine]

		var indentAfterMarker int
		if contentStart >= max {
			indentAfterMarker = 1
		} else {
			indentAfterMarker = contentStart - posAfterMarker
		}

		if indentAfterMarker > 4 {
			indentAfterMarker = 1
		}

		indent := posAfterMarker - s.BMarks[nextLine] + indentAfterMarker

		tok := &ListItemOpen{
			Map: [2]int{startLine, 0},
		}
		s.PushOpeningToken(tok)
		itemMap := &tok.Map

		oldIndent := s.BlkIndent
		oldTight := s.Tight
		oldTShift := s.TShift[startLine]
		oldParentType := s.ParentType
		s.TShift[startLine] = contentStart - s.BMarks[startLine]
		s.BlkIndent = indent
		s.Tight = true
		s.ParentType = ptList

		s.Md.Block.Tokenize(s, startLine, endLine)

		if !s.Tight || prevEmptyEnd {
			tight = false
		}
		prevEmptyEnd = s.Line-startLine > 1 && s.IsLineEmpty(s.Line-1)
		if prevEmptyEnd {
			lastToken := s.Tokens[len(s.Tokens)-1]
			if _, ok := lastToken.(*BlockquoteClose); ok {
				prevEmptyEnd = false
			}
		}

		s.BlkIndent = oldIndent
		s.TShift[startLine] = oldTShift
		s.Tight = oldTight
		s.ParentType = oldParentType

		s.PushClosingToken(&ListItemClose{})

		startLine = s.Line
		nextLine = startLine
		(*itemMap)[1] = nextLine
		contentStart = s.BMarks[startLine]

		if nextLine >= endLine {
			break
		}

		if s.IsLineEmpty(nextLine) {
			break
		}

		if s.TShift[nextLine] < s.BlkIndent {
			break
		}

		for _, r := range listTerminatedBy {
			if r(s, nextLine, endLine, true) {
				break outer
			}
		}

		if isOrdered {
			posAfterMarker = skipOrderedListMarker(s, nextLine)
			if posAfterMarker < 0 {
				break
			}
		} else {
			posAfterMarker = skipBulletListMarker(s, nextLine)
			if posAfterMarker < 0 {
				break
			}
		}

		if markerChar != src[posAfterMarker-1] {
			break
		}
	}

	if isOrdered {
		s.PushClosingToken(&OrderedListClose{})
	} else {
		s.PushClosingToken(&BulletListClose{})
	}
	(*listMap)[1] = nextLine

	s.Line = nextLine

	if tight {
		markParagraphsTight(s, tokenIdx)
	}

	return true
}
<|endoftext|>


<commit_before>package llog

import (
	"errors"
	"fmt"
	"os"
	"time"
)

const (
	RED     = "\033[31m"
	GREEN   = "\033[32m"
	YELLOW  = "\033[93m"
	CYAN    = "\033[36m"
	MAGENTA = "\033[95m"
)

const (
	LevelNull = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
)

var (
	level int = 1
)

func coloredLog(color string, s string) {
	fmt.Fprintf(
		os.Stdout,
		"%v[%v] %v\n",
		color,
		time.Now().Format("2006-01-02  15:04:05"),
		s,
	)
}

func coloredLogF(color string, s string, a ...interface{}) {
	fmt.Fprintf(
		os.Stdout,
		"%v[%v] %v\n",
		color,
		time.Now().Format("2006-01-02  15:04:05"),
		fmt.Sprintf(s, a...),
	)
}

func SetLevel(i int) error {
	if i < 1 || i > 4 {
		return errors.New("log level out of range")
	}
	level = i
	return nil
}

func Debug(s string) {
	if level > LevelDebug || level == LevelNull {
		return
	}
	coloredLog(YELLOW, s)
}

func FDebug(s string, a ...interface{}) {
	if level > LevelDebug || level == LevelNull {
		return
	}
	coloredLogF(YELLOW, s, a)
}

func Info(s string) {
	if level > LevelInfo || level == LevelNull {
		return
	}
	coloredLog(CYAN, s)
}

func FInfo(s string, a ...interface{}) {
	if level > LevelInfo || level == LevelNull {
		return
	}
	coloredLogF(CYAN, s, a)
}

func Warn(s string) {
	if level > LevelWarn || level == LevelNull {
		return
	}
	coloredLog(MAGENTA, s)
}

func FWarn(s string, a ...interface{}) {
	if level > LevelWarn || level == LevelNull {
		return
	}
	coloredLogF(MAGENTA, s, a)
}

func Error(s string) {
	coloredLog(RED, s)
}

func FError(s string, a ...interface{}) {
	coloredLogF(RED, s, a)
}

func Success(s string) {
	coloredLog(GREEN, s)
}

func FSuccess(s string, a ...interface{}) {
	coloredLogF(GREEN, s, a)
}
<commit_msg>dont need two write methods<commit_after>package llog

import (
	"errors"
	"fmt"
	"io"
	"os"
	"time"
)

const (
	RED     = "\033[31m"
	GREEN   = "\033[32m"
	YELLOW  = "\033[93m"
	CYAN    = "\033[36m"
	MAGENTA = "\033[95m"
)

const (
	LevelNull = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
)

var (
	level int = 1
)

type Logger struct {
	io.Writer
}

func write(w io.Writer, color string, s string, a ...interface{}) {
	fmt.Fprintf(
		w,
		"%v[%v] %v\n",
		color,
		time.Now().Format("2006-01-02  15:04:05"),
		fmt.Sprintf(s, a...),
	)
}

func SetLevel(i int) error {
	if i < 1 || i > 4 {
		return errors.New("log level out of range")
	}
	level = i
	return nil
}

func (l *Logger) Debug(s string) {
	if !(level > LevelDebug || level == LevelNull) {
		write(l, YELLOW, s)
	}
}

func (l *Logger) FDebug(s string, a ...interface{}) {
	if !(level > LevelDebug || level == LevelNull) {
		write(l, YELLOW, s, a)
	}
}

func (l *Logger) Info(s string) {
	if !(level > LevelInfo || level == LevelNull) {
		write(l, CYAN, s)
	}
}

func (l *Logger) FInfo(s string, a ...interface{}) {
	if !(level > LevelDebug || level == LevelNull) {
		write(l, CYAN, s, a)
	}
}

func (l *Logger) Warn(s string) {
	if !(level > LevelWarn || level == LevelNull) {
		write(l, MAGENTA, s)
	}
}

func (l *Logger) FWarn(s string, a ...interface{}) {
	if !(level > LevelWarn || level == LevelNull) {
		write(l, MAGENTA, s, a)
	}
}

func (l *Logger) Error(s string) {
	write(l, RED, s)
}

func (l *Logger) FError(s string, a ...interface{}) {
	write(l, RED, s, a)
}

func (l *Logger) Success(s string) {
	write(l, GREEN, s)
}

func (l *Logger) FSuccess(s string, a ...interface{}) {
	write(l, GREEN, s, a)
}

func Debug(s string) {
	if !(level > LevelDebug || level == LevelNull) {
		write(os.Stdout, YELLOW, s)
	}
}

func FDebug(s string, a ...interface{}) {
	if !(level > LevelDebug || level == LevelNull) {
		write(os.Stdout, YELLOW, s, a)
	}
}

func Info(s string) {
	if !(level > LevelInfo || level == LevelNull) {
		write(os.Stdout, CYAN, s)
	}
}

func FInfo(s string, a ...interface{}) {
	if !(level > LevelInfo || level == LevelNull) {
		write(os.Stdout, CYAN, s, a)
	}
}

func Warn(s string) {
	if !(level > LevelWarn || level == LevelNull) {
		write(os.Stdout, MAGENTA, s)
	}
}

func FWarn(s string, a ...interface{}) {
	if !(level > LevelWarn || level == LevelNull) {
		write(os.Stdout, MAGENTA, s, a)
	}
}

func Error(s string) {
	write(os.Stdout, RED, s)
}

func FError(s string, a ...interface{}) {
	write(os.Stdout, RED, s, a)
}

func Success(s string) {
	write(os.Stdout, GREEN, s)
}

func FSuccess(s string, a ...interface{}) {
	write(os.Stdout, GREEN, s, a)
}
<|endoftext|>


<commit_before>package main

// #cgo LDFLAGS: -lm
// #include "tclled.h"
import "C"
import "fmt"
import "time"
import "errors"

// import "time"

type Strand struct {
	device   C.int
	buffer   *_Ctype_tcl_buffer
	ledCount int
}

func (s *Strand) Connect(ledCount int) error {
	s.ledCount = ledCount
	s.device = C.open_device()

	if s.device <= 0 {
		return errors.New("Device init failed")
	}

	C.set_gamma(2.2, 2.2, 2.2)
	spiStatus := C.spi_init(s.device)
	if spiStatus != 0 {
		return errors.New("SPI init failed")
	}

	s.buffer = &C.tcl_buffer{}
	tclStatus := C.tcl_init(s.buffer, C.int(s.ledCount))
	if tclStatus != 0 {
		return errors.New("TCL init failed")
	}

	return nil
}

func (s *Strand) SetColor(ledNumber int, r int, g int, b int) {
	C.write_gamma_color_to_buffer(s.buffer, C.int(ledNumber), C.uint8_t(r), C.uint8_t(g), C.uint8_t(b))
}

func (s *Strand) Save() {
	C.send_buffer(s.device, s.buffer)
}

func main() {
	strand := Strand{}
	ledCount := 30
	err := strand.Connect(ledCount)

	if err != nil {
		fmt.Print("Error: ")
		fmt.Println(err)
		return
	}

	color := 0
	goingDown := false
	for j := 0; j < 1000; j++ {
		if goingDown {
			color--
		} else {
			color++
		}
		if color < 0 {
			goingDown = false
			color = 0
		} else if color > 255 {
			goingDown = true
			color = 255
		}

		for i := 0; i < ledCount; i++ {
			strand.SetColor(i, color, color, color)
		}
		strand.Save()
		time.Sleep(10 * time.Millisecond)
	}
}
<commit_msg>Add Board<commit_after>package main

// #cgo LDFLAGS: -lm
// #include "tclled.h"
import "C"
import "fmt"

// import "time"
import "errors"

// import "time"

//////////////////
// STRAND CODE
//////////////////

type Strand struct {
	device   C.int
	buffer   *_Ctype_tcl_buffer
	ledCount int
}

func (s *Strand) Connect(ledCount int) error {
	s.ledCount = ledCount
	s.device = C.open_device()

	if s.device <= 0 {
		return errors.New("Device init failed")
	}

	C.set_gamma(2.2, 2.2, 2.2)
	spiStatus := C.spi_init(s.device)
	if spiStatus != 0 {
		return errors.New("SPI init failed")
	}

	s.buffer = &C.tcl_buffer{}
	tclStatus := C.tcl_init(s.buffer, C.int(s.ledCount))
	if tclStatus != 0 {
		return errors.New("TCL init failed")
	}

	return nil
}

func (s *Strand) SetColor(ledNumber int, r int, g int, b int) {
	C.write_gamma_color_to_buffer(s.buffer, C.int(ledNumber), C.uint8_t(r), C.uint8_t(g), C.uint8_t(b))
}

func (s *Strand) Save() {
	fmt.Println("Strand (", s, ") saving...")
	C.send_buffer(s.device, s.buffer)
}

//////////////////
// BOARD CODE
//////////////////

type Board struct {
	strand  *Strand
	pixelW  int
	pixelH  int
	squareW int
	squareH int
}

func (brd *Board) Connect(pixelW int, pixelH int, squareW int, squareH int) error {
	brd.pixelW = pixelW
	brd.pixelH = pixelH
	brd.squareW = squareW
	brd.squareH = squareH
	brd.strand = &Strand{}
	return brd.strand.Connect(pixelW * pixelH)
}

func (brd *Board) Save() {
	brd.strand.Save()
}

func getPixelNum(x int, y int) int {
	xSq := x / 5
	ySq := y / 5
	var boardNum, pixelNum int

	// NOTE: this is hardcoded for a 4 x 5 board with 25px/square
	if ySq%2 == 0 {
		boardNum = ySq*4 + xSq
	} else {
		boardNum = ySq*4 + 3 - xSq
	}

	xPixelInSq := x % 5
	yPixelInSq := y % 5

	if yPixelInSq%2 == 0 {
		pixelNum = yPixelInSq*5 + xPixelInSq
	} else {
		pixelNum = yPixelInSq*5 + 4 - xPixelInSq
	}

	return boardNum*25 + pixelNum
}

func (brd *Board) DrawPixel(x int, y int, r int, g int, b int) {
	pixelNum := getPixelNum(x, y)
	fmt.Println("Pixel Drawn at: (", x, y, ") ->", pixelNum)
	brd.strand.SetColor(pixelNum, r, g, b)
}

func (brd *Board) SetPixel(x int, r int, g int, b int) {
	fmt.Println("(", r, g, b, ") Pixel Drawn ->", x)
	fmt.Println("Double Checking: () ->", x)
	brd.strand.SetColor(x, r, g, b)
}

func main() {
	// board := Board{}
	// w := 100
	// h := 125
	// err := board.Connect(w, h, 4, 5)

	// if err != nil {
	// 	fmt.Print("Error: ")
	// 	fmt.Println(err)
	// 	return
	// }
	// for {
	// 	x := 0
	// 	r := 0
	// 	g := 0
	// 	b := 0

	// 	fmt.Scan(&x, &r, &g, &b)
	// 	board.SetPixel(x, r, g, b)
	// 	board.Save()
	// }

	board := Strand{}
	c := 500
	err := board.Connect(c)

	if err != nil {
		fmt.Print("Error: ")
		fmt.Println(err)
		return
	}
	for {
		x := 0
		r := 0
		g := 0
		b := 0

		fmt.Scan(&x, &r, &g, &b)
		board.SetColor(x, r, g, b)
		board.Save()
	}

	// xPix := 0
	// yPix := 0
	// for {
	// 	xPix++
	// 	if xPix > w {
	// 		xPix = 0
	// 		yPix++
	// 	}
	// 	if yPix > h {
	// 		xPix = 0
	// 		yPix = 0
	// 	}

	// 	for x := 0; x < w; x++ {
	// 		for y := 0; y < h; y++ {
	// 			if x == xPix && y == yPix {
	// 				board.DrawPixel(x, y, 100, 100, 100)
	// 			} else {
	// 				board.DrawPixel(x, y, 0, 0, 0)
	// 			}
	// 		}
	// 	}
	// 	board.Save()
	// 	time.Sleep(20 * time.Millisecond)
	// }
}
<|endoftext|>