<commit_before>/*
Package minhash provides probabilistic data structures for computing
MinHash signatures for streaming data.

The reader should also conf https://github.com/dgryski/go-minhash and
https://github.com/tylertreat/BoomFilters.  In fact, most of the
implementation details of this package are based off the former.

MinHash signatures can be used to estimate the Jaccard index
J(A, B) := |A & B| / |A || B| of two sets that are subsets
of some finite, totally ordered set U.  If s is a permutation
of U chosen uniformly at random, then x := argmin s(A || B) is
just a random element chosen uniformly from A || B.  It's
clear that P(x in A & B) = J(A, B).  Since min s(A) = min s(B)
if and only if x is in A & B, we have just shown that
P(min s(A) = min S(B)) = J(A, B).

The central idea of minhash signatures is to repeatedly perform
the above experiment with different permutations as a way to estimate
the underlying probability
J(A, B) = P(an element x in A || B is also  in A & B).

A length k minhash signature S(A) is theoretically generated by randomly
choosing k permutations si (i=1, ..., k) in the symmetric group of U
(group of bijective endofunctions on U) and computing  hi(A) := min si(A)
for each permutation.  We take S(A) := [h1(A), ..., hk(A)].
Since each permutation is a bijection, min si(A) = min si(B) if and
only if argmin si(A) = argmin si(B) and so we could just as
well use these argmins, which is sometimes how the signature S(A) is
defined.

Specifying permutations for large U is not efficient, and so we often
take a family of integer-valued hash functions that are minwise
independent, in the sense that for most sets A,
min h(A) ! = min g(A) for two distinct hash functions in the family.
Frequently this family is parametrically  generated.

For more information,
    http://research.neustar.biz/2012/07/09/sketch-of-the-day-k-minimum-values/

    MinHashing:
    http://infolab.stanford.edu/~ullman/mmds/ch3.pdf
    https://en.wikipedia.org/wiki/MinHash

    BottomK:
    http://www.math.tau.ac.il/~haimk/papers/p225-cohen.pdf
    http://cohenwang.org/edith/Papers/metrics394-cohen.pdf

    http://www.mpi-inf.mpg.de/~rgemulla/publications/beyer07distinct.pdf

This package works best when provided with a strong 64-bit hash function,
such as CityHash, Spooky, Murmur3, or SipHash.

*/

package minhash

import (
	"encoding/binary"
	"log"
	"math"
	"strconv"
)

const (
	MaxUint  uint   = ^uint(0)
	MaxInt   int    = int(MaxUint >> 1)
	infinity uint64 = math.MaxUint64
)

type HashFunc func([]byte) uint64

// Signature is an array representing the signature of a set.
type Signature []uint64

// MinHash is an a probabilistic data structure used to
// compute a similarity preserving signature for a set.  It ingests
// a stream of the set's elements and continuously updates the signature.
type MinHash interface {
	// Push ingests a set element, hashes it, and updates the signature.
	Push(interface{})

	// Merge updates the signature of the instance with the signature
	// of the input.  This results in the signature of the union of the
	// two sets, which is stored in the original MinHash instance.
	Merge(*MinHash)

	// Cardinality estimates the size of the set from the signature.
	Cardinality() int

	// Signature returns the signature itself.
	Signature() []uint64

	// Similarity computes the similarity between two MinHash signatures.
	// The method for computing similarity depends on whether a MinWise
	// or Bottom-K implementation is used.
	Similarity(*MinHash) float64
}

// Similarity invokes the specific
func Similarity(m1, m2 *MinHash) float64 {
	return (*m1).Similarity(m2) // dereference m1
}

// defaultSignature will return an appropriately typed array
func defaultSignature(size int) Signature {
	s := make(Signature, size)
	for i := range s {
		s[i] = infinity
	}
	return s
}

// toBytes converts various types to a byte slice
// so they can be pushed into a MinHash instance.
func toBytes(x interface{}) []byte {
	b := make([]byte, 8)
	switch t := x.(type) {
	case []byte:
		b = t
	case string:
		b = []byte(t)
	case uint, uint16, uint32, uint64:
		binary.LittleEndian.PutUint64(b, t.(uint64))
	case int, int16, int32, int64:
		binary.LittleEndian.PutUint64(b, uint64(t.(int64)))
	}
	return b
}

// stringIntToByte converts a string representation of an integer to a byte slice.
func stringIntToByte(s string) []byte {
	n, err := strconv.ParseUint(s, 0, 64)
	var b []byte
	if err != nil {
		log.Println("Could not convert string to uint64.")
		b = []byte(s)
	} else {
		b = toBytes(n)
	}
	return b
}

// Intersection estimates the cardinality of the intersection
// between two sets provided their sizes and Jaccard similarity are known.
//
// If n, m, i, u denote |A|, |B|, |A & B|, and |A || B| respectively,
// then given that A and B are not disjoint (i != 0), w have
// J := J(A, B) = i / u which is equivalent to
// 1/J = u / i = (n + m - i) / i = (n + m / i) - 1.
// Solving for i yields |A & B| = (n + m) / ((1/J)+ 1).
// Thus an estimate for the Jaccard index of A and B yields an estimate
// for the size of their intersection, provided we know the sizes of A and B.
func Intersection(js float64, size1, size2 int) int {
	var est int
	if js == 0 {
		est = 0
	} else {
		est = int(math.Floor(float64(size1+size2) / ((1.0 / js) + 1)))
	}
	return est
}
<commit_msg>Change minhash.Similarity to accept interfaces, not pointers.<commit_after>/*
Package minhash provides probabilistic data structures for computing
MinHash signatures for streaming data.

The reader should also conf https://github.com/dgryski/go-minhash and
https://github.com/tylertreat/BoomFilters.  In fact, most of the
implementation details of this package are based off the former.

MinHash signatures can be used to estimate the Jaccard index
J(A, B) := |A & B| / |A || B| of two sets that are subsets
of some finite, totally ordered set U.  If s is a permutation
of U chosen uniformly at random, then x := argmin s(A || B) is
just a random element chosen uniformly from A || B.  It's
clear that P(x in A & B) = J(A, B).  Since min s(A) = min s(B)
if and only if x is in A & B, we have just shown that
P(min s(A) = min S(B)) = J(A, B).

The central idea of minhash signatures is to repeatedly perform
the above experiment with different permutations as a way to estimate
the underlying probability
J(A, B) = P(an element x in A || B is also  in A & B).

A length k minhash signature S(A) is theoretically generated by randomly
choosing k permutations si (i=1, ..., k) in the symmetric group of U
(group of bijective endofunctions on U) and computing  hi(A) := min si(A)
for each permutation.  We take S(A) := [h1(A), ..., hk(A)].
Since each permutation is a bijection, min si(A) = min si(B) if and
only if argmin si(A) = argmin si(B) and so we could just as
well use these argmins, which is sometimes how the signature S(A) is
defined.

Specifying permutations for large U is not efficient, and so we often
take a family of integer-valued hash functions that are minwise
independent, in the sense that for most sets A,
min h(A) ! = min g(A) for two distinct hash functions in the family.
Frequently this family is parametrically  generated.

For more information,
    http://research.neustar.biz/2012/07/09/sketch-of-the-day-k-minimum-values/

    MinHashing:
    http://infolab.stanford.edu/~ullman/mmds/ch3.pdf
    https://en.wikipedia.org/wiki/MinHash

    BottomK:
    http://www.math.tau.ac.il/~haimk/papers/p225-cohen.pdf
    http://cohenwang.org/edith/Papers/metrics394-cohen.pdf

    http://www.mpi-inf.mpg.de/~rgemulla/publications/beyer07distinct.pdf

This package works best when provided with a strong 64-bit hash function,
such as CityHash, Spooky, Murmur3, or SipHash.

*/

package minhash

import (
	"encoding/binary"
	"log"
	"math"
	"strconv"
)

const (
	MaxUint  uint   = ^uint(0)
	MaxInt   int    = int(MaxUint >> 1)
	infinity uint64 = math.MaxUint64
)

type HashFunc func([]byte) uint64

// Signature is an array representing the signature of a set.
type Signature []uint64

// MinHash is an a probabilistic data structure used to
// compute a similarity preserving signature for a set.  It ingests
// a stream of the set's elements and continuously updates the signature.
type MinHash interface {
	// Push ingests a set element, hashes it, and updates the signature.
	Push(interface{})

	// Merge updates the signature of the instance with the signature
	// of the input.  This results in the signature of the union of the
	// two sets, which is stored in the original MinHash instance.
	Merge(*MinHash)

	// Cardinality estimates the size of the set from the signature.
	Cardinality() int

	// Signature returns the signature itself.
	Signature() []uint64

	// Similarity computes the similarity between two MinHash signatures.
	// The method for computing similarity depends on whether a MinWise
	// or Bottom-K implementation is used.
	Similarity(*MinHash) float64
}

// Similarity invokes the specific
func Similarity(m1, m2 MinHash) float64 {
	return m1.Similarity(&m2)
}

// defaultSignature will return an appropriately typed array
func defaultSignature(size int) Signature {
	s := make(Signature, size)
	for i := range s {
		s[i] = infinity
	}
	return s
}

// toBytes converts various types to a byte slice
// so they can be pushed into a MinHash instance.
func toBytes(x interface{}) []byte {
	b := make([]byte, 8)
	switch t := x.(type) {
	case []byte:
		b = t
	case string:
		b = []byte(t)
	case uint, uint16, uint32, uint64:
		binary.LittleEndian.PutUint64(b, t.(uint64))
	case int, int16, int32, int64:
		binary.LittleEndian.PutUint64(b, uint64(t.(int64)))
	}
	return b
}

// stringIntToByte converts a string representation of an integer to a byte slice.
func stringIntToByte(s string) []byte {
	n, err := strconv.ParseUint(s, 0, 64)
	var b []byte
	if err != nil {
		log.Println("Could not convert string to uint64.")
		b = []byte(s)
	} else {
		b = toBytes(n)
	}
	return b
}

// Intersection estimates the cardinality of the intersection
// between two sets provided their sizes and Jaccard similarity are known.
//
// If n, m, i, u denote |A|, |B|, |A & B|, and |A || B| respectively,
// then given that A and B are not disjoint (i != 0), w have
// J := J(A, B) = i / u which is equivalent to
// 1/J = u / i = (n + m - i) / i = (n + m / i) - 1.
// Solving for i yields |A & B| = (n + m) / ((1/J)+ 1).
// Thus an estimate for the Jaccard index of A and B yields an estimate
// for the size of their intersection, provided we know the sizes of A and B.
func Intersection(js float64, size1, size2 int) int {
	var est int
	if js == 0 {
		est = 0
	} else {
		est = int(math.Floor(float64(size1+size2) / ((1.0 / js) + 1)))
	}
	return est
}
<|endoftext|>


<commit_before>package client

import (
	"github.com/Hucaru/Valhalla/common/character"
	"github.com/Hucaru/Valhalla/common/constants"
	"github.com/Hucaru/gopacket"
)

func channelToLogin() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_RESTARTER)
	pac.WriteByte(0x01)

	return pac
}

func loginResponce(result byte, userID uint32, gender byte, isAdmin byte, username string, isBanned int) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_RESPONCE)
	pac.WriteByte(result)
	pac.WriteByte(0x00)
	pac.WriteInt32(0)

	if result <= 0x01 {
		pac.WriteUint32(userID)
		pac.WriteByte(gender)
		pac.WriteByte(isAdmin)
		pac.WriteByte(0x01)
		pac.WriteString(username)
	} else if result == 0x02 {
		pac.WriteByte(byte(isBanned))
		pac.WriteInt64(0) // Expire time, for now let set this to epoch
	}

	pac.WriteInt64(0)
	pac.WriteInt64(0)
	pac.WriteInt64(0)

	return pac
}

func endWorldList() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_SEND_WORLD_LIST)
	pac.WriteByte(0xFF)

	return pac
}

func displayCharacters(characters []character.Character) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_DATA)
	pac.WriteByte(0) // ?

	if len(characters) < 4 && len(characters) > 0 {
		pac.WriteByte(byte(len(characters)))

		for _, c := range characters {
			writePlayerCharacter(&pac, c.GetCharID(), c)
		}
	} else {
		pac.WriteByte(0)
	}

	return pac
}

func nameCheck(name string, nameFound int) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_NAME_CHECK_RESULT)
	pac.WriteString(name)

	if nameFound > 0 {
		pac.WriteByte(0x1) // 0 = good name, 1 = bad name
	} else {
		pac.WriteByte(0x0)
	}

	return pac
}

func createdCharacter(success bool, character character.Character) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_NEW_CHARACTER_GOOD)

	if success {
		pac.WriteByte(0x0) // if creation was sucessfull - 0 = good, 1 = bad
		writePlayerCharacter(&pac, character.GetCharID(), character)
	} else {
		pac.WriteByte(0x1)
	}

	return pac
}

func deleteCharacter(charID int32, deleted bool, hacking bool) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_DELETE_CHARACTER)
	pac.WriteInt32(charID)

	if deleted {
		pac.WriteByte(0x0)
	} else if hacking {
		pac.WriteByte(0x0A) // Could not be processed due to server load
	} else {
		pac.WriteByte(0x12)
	}

	return pac
}

func migrateClient(ip []byte, port uint16, charID int32) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_MIGRATE)
	pac.WriteByte(0x00)
	pac.WriteByte(0x00)
	pac.WriteBytes(ip)
	pac.WriteUint16(port)
	pac.WriteInt32(charID)
	pac.WriteByte(byte(0) | byte(1<<0))
	pac.WriteInt32(1)

	return pac
}

func sendBadMigrate() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_MIGRATE)
	pac.WriteByte(0x00) // flipping these 2 bytes makes the character select screen do nothing it appears
	pac.WriteByte(0x00)
	pac.WriteBytes([]byte{0, 0, 0, 0})
	pac.WriteUint16(0)
	pac.WriteInt32(8)
	pac.WriteByte(byte(0) | byte(1<<0))
	pac.WriteInt32(1)

	return pac
}

func writePlayerCharacter(pac *gopacket.Packet, pos uint32, char character.Character) {
	pac.WriteUint32(pos)

	name := char.GetName()

	if len(name) > 13 {
		name = name[:13]
	}

	padSize := 13 - len(name)

	pac.WriteBytes([]byte(name))
	for i := 0; i < padSize; i++ {
		pac.WriteByte(0x0)
	}

	pac.WriteByte(char.GetGender()) //gender
	pac.WriteByte(char.GetSkin())   // skin
	pac.WriteUint32(char.GetFace()) // face
	pac.WriteUint32(char.GetHair()) // Hair

	pac.WriteInt64(0x0) // Pet cash ID

	pac.WriteByte(char.GetLevel())   // level
	pac.WriteUint16(char.GetJob())   // Job
	pac.WriteUint16(char.GetStr())   // str
	pac.WriteUint16(char.GetDex())   // dex
	pac.WriteUint16(char.GetInt())   // int
	pac.WriteUint16(char.GetLuk())   // luk
	pac.WriteUint16(char.GetHP())    // hp
	pac.WriteUint16(char.GetMaxHP()) // max hp
	pac.WriteUint16(char.GetMP())    // mp
	pac.WriteUint16(char.GetMaxMP()) // max mp
	pac.WriteUint16(char.GetAP())    // ap
	pac.WriteUint16(char.GetSP())    // sp
	pac.WriteUint32(char.GetEXP())   // exp
	pac.WriteUint16(char.GetFame())  // fame

	pac.WriteUint32(char.GetCurrentMap())  // map id
	pac.WriteByte(char.GetCurrentMapPos()) // map

	character.WriteDisplayCharacter(&char, pac)

	pac.WriteByte(0)  // Rankings
	pac.WriteInt32(0) // ?
}
<commit_msg>Fixed dispaly character login server<commit_after>package client

import (
	"github.com/Hucaru/Valhalla/common/character"
	"github.com/Hucaru/Valhalla/common/constants"
	"github.com/Hucaru/gopacket"
)

func channelToLogin() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_RESTARTER)
	pac.WriteByte(0x01)

	return pac
}

func loginResponce(result byte, userID uint32, gender byte, isAdmin byte, username string, isBanned int) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_RESPONCE)
	pac.WriteByte(result)
	pac.WriteByte(0x00)
	pac.WriteInt32(0)

	if result <= 0x01 {
		pac.WriteUint32(userID)
		pac.WriteByte(gender)
		pac.WriteByte(isAdmin)
		pac.WriteByte(0x01)
		pac.WriteString(username)
	} else if result == 0x02 {
		pac.WriteByte(byte(isBanned))
		pac.WriteInt64(0) // Expire time, for now let set this to epoch
	}

	pac.WriteInt64(0)
	pac.WriteInt64(0)
	pac.WriteInt64(0)

	return pac
}

func endWorldList() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_SEND_WORLD_LIST)
	pac.WriteByte(0xFF)

	return pac
}

func displayCharacters(characters []character.Character) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_DATA)
	pac.WriteByte(0) // ?

	if len(characters) < 4 && len(characters) > 0 {
		pac.WriteByte(byte(len(characters)))

		for _, c := range characters {
			writePlayerCharacter(&pac, c.GetCharID(), c)
		}
	} else {
		pac.WriteByte(0)
	}

	return pac
}

func nameCheck(name string, nameFound int) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_NAME_CHECK_RESULT)
	pac.WriteString(name)

	if nameFound > 0 {
		pac.WriteByte(0x1) // 0 = good name, 1 = bad name
	} else {
		pac.WriteByte(0x0)
	}

	return pac
}

func createdCharacter(success bool, character character.Character) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_NEW_CHARACTER_GOOD)

	if success {
		pac.WriteByte(0x0) // if creation was sucessfull - 0 = good, 1 = bad
		writePlayerCharacter(&pac, character.GetCharID(), character)
	} else {
		pac.WriteByte(0x1)
	}

	return pac
}

func deleteCharacter(charID int32, deleted bool, hacking bool) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_DELETE_CHARACTER)
	pac.WriteInt32(charID)

	if deleted {
		pac.WriteByte(0x0)
	} else if hacking {
		pac.WriteByte(0x0A) // Could not be processed due to server load
	} else {
		pac.WriteByte(0x12)
	}

	return pac
}

func migrateClient(ip []byte, port uint16, charID int32) gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_MIGRATE)
	pac.WriteByte(0x00)
	pac.WriteByte(0x00)
	pac.WriteBytes(ip)
	pac.WriteUint16(port)
	pac.WriteInt32(charID)
	pac.WriteByte(byte(0) | byte(1<<0))
	pac.WriteInt32(1)

	return pac
}

func sendBadMigrate() gopacket.Packet {
	pac := gopacket.NewPacket()
	pac.WriteByte(constants.SEND_LOGIN_CHARACTER_MIGRATE)
	pac.WriteByte(0x00) // flipping these 2 bytes makes the character select screen do nothing it appears
	pac.WriteByte(0x00)
	pac.WriteBytes([]byte{0, 0, 0, 0})
	pac.WriteUint16(0)
	pac.WriteInt32(8)
	pac.WriteByte(byte(0) | byte(1<<0))
	pac.WriteInt32(1)

	return pac
}

func writePlayerCharacter(pac *gopacket.Packet, pos uint32, char character.Character) {
	pac.WriteUint32(pos)

	name := char.GetName()

	if len(name) > 13 {
		name = name[:13]
	}

	padSize := 13 - len(name)

	pac.WriteBytes([]byte(name))
	for i := 0; i < padSize; i++ {
		pac.WriteByte(0x0)
	}

	pac.WriteByte(char.GetGender()) //gender
	pac.WriteByte(char.GetSkin())   // skin
	pac.WriteUint32(char.GetFace()) // face
	pac.WriteUint32(char.GetHair()) // Hair

	pac.WriteInt64(0x0) // Pet cash ID

	pac.WriteByte(char.GetLevel())   // level
	pac.WriteUint16(char.GetJob())   // Job
	pac.WriteUint16(char.GetStr())   // str
	pac.WriteUint16(char.GetDex())   // dex
	pac.WriteUint16(char.GetInt())   // int
	pac.WriteUint16(char.GetLuk())   // luk
	pac.WriteUint16(char.GetHP())    // hp
	pac.WriteUint16(char.GetMaxHP()) // max hp
	pac.WriteUint16(char.GetMP())    // mp
	pac.WriteUint16(char.GetMaxMP()) // max mp
	pac.WriteUint16(char.GetAP())    // ap
	pac.WriteUint16(char.GetSP())    // sp
	pac.WriteUint32(char.GetEXP())   // exp
	pac.WriteUint16(char.GetFame())  // fame

	pac.WriteUint32(char.GetCurrentMap())  // map id
	pac.WriteByte(char.GetCurrentMapPos()) // map

	character.WriteDisplayCharacter(&char, pac)

	pac.WriteByte(1)     // Rankings
	pac.WriteInt32(0xFF) // ?
}
<|endoftext|>


<commit_before><commit_msg>contentenc: encryptBlocksParallel: explain why last part runs in new goroutine<commit_after><|endoftext|>


<commit_before>package main

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

// MetricCollector can be used to collect statistics and write them to a
// CSV file.
type MetricCollector struct {
	outfd   *os.File
	counter uint64
}

// MetricRecord represents a single metric entry.
type MetricRecord struct {
	collector  *MetricCollector
	StartTime  time.Time
	EndTime    time.Time
	Duration   time.Duration
	OrigSize   uint32
	ResultSize uint32
	Success    bool
}

// NewMetricCollector returns a new MetricCollector instance.
// It requires the given outfile not to exist before this call and will
// create it.
func NewMetricCollector(outfile string) (*MetricCollector, error) {
	mc := &MetricCollector{}
	// not race-condition-safe, but it's just an attempt to
	// avoid overwriting previously collected data.
	_, err := os.Stat(outfile)
	if !os.IsNotExist(err) {
		return nil, errors.New("metrics output file already exists")
	}
	mc.outfd, err = os.Create(outfile)
	if err != nil {
		return nil, fmt.Errorf("unable to open metrics output file for writing: %s", err)
	}
	err = mc.writeHeader()
	return mc, nil
}

// writeHeader outputs a CSV header to the output file.
func (mc *MetricCollector) writeHeader() error {
	_, err := mc.outfd.WriteString("StartTime;EndTime;Duration (ns);OrigSize (B);ResultSize (B);Success\n")
	if err != nil {
		return fmt.Errorf("failed to write header: %s", err)
	}
	return nil
}

// NewRecord returns a new MetricRecord instance which is initialized with
// the current time as the StartTime and is associated with this
// MetricCollector instance, so that later calls to .Commit know where to
// write.
func (mc *MetricCollector) NewRecord() *MetricRecord {
	r := &MetricRecord{}
	r.StartTime = time.Now()
	r.collector = mc
	return r
}

// Commit updates the EndTime field and passes this record to the collector
// so it can be serialized to disk.
func (mr *MetricRecord) Commit() error {
	mr.EndTime = time.Now()
	mr.Duration = mr.EndTime.Sub(mr.StartTime)
	return mr.collector.writeRecord(mr)
}

// writeRecord formats the given entry and writes it to the output file.
// A file sync is triggered every 128 seconds in order to reduce the risk
// for information loss in case of crashes.
func (mc *MetricCollector) writeRecord(r *MetricRecord) error {
	_, err := fmt.Fprintf(mc.outfd, "%s;%s;%d;%d;%d;%t\n",
		r.StartTime, r.EndTime, r.Duration, r.OrigSize, r.ResultSize, r.Success)
	if err != nil {
		return fmt.Errorf("failed to write record: %s", err)
	}
	mc.counter++
	if mc.counter%128 == 0 {
		err = mc.outfd.Sync()
		if err != nil {
			return fmt.Errorf("failed to sync to disk: %s", err)
		}
	}
	return nil
}

// Close closes the underlying file handle.
func (mc *MetricCollector) Close() error {
	return mc.outfd.Close()
}
<commit_msg>metrics: avoid crash without --write-metrics<commit_after>package main

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

// MetricCollector can be used to collect statistics and write them to a
// CSV file.
type MetricCollector struct {
	outfd   *os.File
	counter uint64
}

// MetricRecord represents a single metric entry.
type MetricRecord struct {
	collector  *MetricCollector
	StartTime  time.Time
	EndTime    time.Time
	Duration   time.Duration
	OrigSize   uint32
	ResultSize uint32
	Success    bool
}

// NewMetricCollector returns a new MetricCollector instance.
// It requires the given outfile not to exist before this call and will
// create it.
func NewMetricCollector(outfile string) (*MetricCollector, error) {
	mc := &MetricCollector{}
	// not race-condition-safe, but it's just an attempt to
	// avoid overwriting previously collected data.
	_, err := os.Stat(outfile)
	if !os.IsNotExist(err) {
		return nil, errors.New("metrics output file already exists")
	}
	mc.outfd, err = os.Create(outfile)
	if err != nil {
		return nil, fmt.Errorf("unable to open metrics output file for writing: %s", err)
	}
	err = mc.writeHeader()
	return mc, nil
}

// writeHeader outputs a CSV header to the output file.
func (mc *MetricCollector) writeHeader() error {
	_, err := mc.outfd.WriteString("StartTime;EndTime;Duration (ns);OrigSize (B);ResultSize (B);Success\n")
	if err != nil {
		return fmt.Errorf("failed to write header: %s", err)
	}
	return nil
}

// NewRecord returns a new MetricRecord instance which is initialized with
// the current time as the StartTime and is associated with this
// MetricCollector instance, so that later calls to .Commit know where to
// write.
func (mc *MetricCollector) NewRecord() *MetricRecord {
	r := &MetricRecord{}
	r.StartTime = time.Now()
	r.collector = mc
	return r
}

// Commit updates the EndTime field and passes this record to the collector
// so it can be serialized to disk.
func (mr *MetricRecord) Commit() error {
	mr.EndTime = time.Now()
	mr.Duration = mr.EndTime.Sub(mr.StartTime)
	return mr.collector.writeRecord(mr)
}

// writeRecord formats the given entry and writes it to the output file.
// A file sync is triggered every 128 seconds in order to reduce the risk
// for information loss in case of crashes.
func (mc *MetricCollector) writeRecord(r *MetricRecord) error {
	if mc == nil {
		// if we attempt to write to an uninitialized MetricCollector, we fail
		// silently as this means that none has been configured.
		return nil
	}
	_, err := fmt.Fprintf(mc.outfd, "%s;%s;%d;%d;%d;%t\n",
		r.StartTime, r.EndTime, r.Duration, r.OrigSize, r.ResultSize, r.Success)
	if err != nil {
		return fmt.Errorf("failed to write record: %s", err)
	}
	mc.counter++
	if mc.counter%128 == 0 {
		err = mc.outfd.Sync()
		if err != nil {
			return fmt.Errorf("failed to sync to disk: %s", err)
		}
	}
	return nil
}

// Close closes the underlying file handle.
func (mc *MetricCollector) Close() error {
	return mc.outfd.Close()
}
<|endoftext|>


<commit_before>package keysharecore

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/subtle"
	"encoding/binary"

	"github.com/privacybydesign/gabi/big"

	"github.com/go-errors/errors"
)

type (
	// Contains pin (bytes 0-63), secret (bytes 64-127), and identifier (bytes 128-159)
	//  The binary structure of this data structure can have security implications through its interaction
	//  with the encryption layer applied before storing it. As such, we keep it here more explicit than
	//  is standard in go. When modifying this structure, analyse whether such changes can have a
	//  security impact through error side channels.
	unencryptedUserSecrets [64 + 64 + 32]byte

	// UserSecrets contains the encrypted data of a keyshare user.
	// The size is that of unencryptedUserSecrets + 12 bytes for nonce + 16 bytes for tag + 4 bytes for key ID.
	UserSecrets [64 + 64 + 32 + 12 + 16 + 4]byte
)

var (
	ErrKeyshareSecretTooBig   = errors.New("Keyshare secret too big to store")
	ErrKeyshareSecretNegative = errors.New("Keyshare secret negative")
	ErrNoSuchKey              = errors.New("Key identifier unknown")
)

func (s *unencryptedUserSecrets) pin() [64]byte {
	var result [64]byte
	copy(result[:], s[0:64])
	return result
}

func (s *unencryptedUserSecrets) setPin(pw [64]byte) {
	copy(s[0:64], pw[:])
}

func (s *unencryptedUserSecrets) keyshareSecret() *big.Int {
	result := new(big.Int)
	return result.SetBytes(s[64:128])
}

func (s *unencryptedUserSecrets) setKeyshareSecret(val *big.Int) error {
	if val.Sign() == -1 {
		return ErrKeyshareSecretNegative
	}

	data := val.Bytes()
	if len(data) > 64 {
		return ErrKeyshareSecretTooBig
	}
	zerolen := 64 - len(data)
	for i := 0; i < zerolen; i++ {
		s[64+i] = 0
	}
	copy(s[64+zerolen:], data)

	return nil
}

func (s *unencryptedUserSecrets) id() [32]byte {
	var result [32]byte
	copy(result[:], s[128:160])
	return result
}

func (s *unencryptedUserSecrets) setID(id [32]byte) {
	copy(s[128:160], id[:])
}

func (c *Core) encryptUserSecrets(secrets unencryptedUserSecrets) (UserSecrets, error) {
	var encSecret UserSecrets

	// Store key id
	binary.LittleEndian.PutUint32(encSecret[0:], c.decryptionKeyID)

	// Generate and store nonce
	_, err := rand.Read(encSecret[4:16])
	if err != nil {
		return UserSecrets{}, err
	}

	// Encrypt secrets
	gcm, err := newGCM(c.decryptionKey)
	if err != nil {
		return UserSecrets{}, err
	}
	gcm.Seal(encSecret[:16], encSecret[4:16], secrets[:], nil)

	return encSecret, nil
}

func (c *Core) decryptUserSecrets(secrets UserSecrets) (unencryptedUserSecrets, error) {
	// determine key id
	id := binary.LittleEndian.Uint32(secrets[0:])

	// Fetch key
	key, ok := c.decryptionKeys[id]
	if !ok {
		return unencryptedUserSecrets{}, ErrNoSuchKey
	}

	// try and decrypt secrets
	gcm, err := newGCM(key)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}
	var unencSecret unencryptedUserSecrets
	_, err = gcm.Open(unencSecret[:0], secrets[4:16], secrets[16:], nil)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}
	return unencSecret, nil
}

func (c *Core) decryptUserSecretsIfPinOK(secrets UserSecrets, pin string) (unencryptedUserSecrets, error) {
	paddedPin, err := padPin(pin)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}

	s, err := c.decryptUserSecrets(secrets)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}

	refPin := s.pin()
	if subtle.ConstantTimeCompare(refPin[:], paddedPin[:]) != 1 {
		return unencryptedUserSecrets{}, ErrInvalidPin
	}
	return s, nil
}

func newGCM(key AESKey) (cipher.AEAD, error) {
	keyedAes, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}
	gcm, err := cipher.NewGCM(keyedAes)
	if err != nil {
		return nil, err
	}
	return gcm, nil
}
<commit_msg>refactor: use plural variable name for concistency<commit_after>package keysharecore

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/subtle"
	"encoding/binary"

	"github.com/privacybydesign/gabi/big"

	"github.com/go-errors/errors"
)

type (
	// Contains pin (bytes 0-63), secret (bytes 64-127), and identifier (bytes 128-159)
	//  The binary structure of this data structure can have security implications through its interaction
	//  with the encryption layer applied before storing it. As such, we keep it here more explicit than
	//  is standard in go. When modifying this structure, analyse whether such changes can have a
	//  security impact through error side channels.
	unencryptedUserSecrets [64 + 64 + 32]byte

	// UserSecrets contains the encrypted data of a keyshare user.
	// The size is that of unencryptedUserSecrets + 12 bytes for nonce + 16 bytes for tag + 4 bytes for key ID.
	UserSecrets [64 + 64 + 32 + 12 + 16 + 4]byte
)

var (
	ErrKeyshareSecretTooBig   = errors.New("Keyshare secret too big to store")
	ErrKeyshareSecretNegative = errors.New("Keyshare secret negative")
	ErrNoSuchKey              = errors.New("Key identifier unknown")
)

func (s *unencryptedUserSecrets) pin() [64]byte {
	var result [64]byte
	copy(result[:], s[0:64])
	return result
}

func (s *unencryptedUserSecrets) setPin(pw [64]byte) {
	copy(s[0:64], pw[:])
}

func (s *unencryptedUserSecrets) keyshareSecret() *big.Int {
	result := new(big.Int)
	return result.SetBytes(s[64:128])
}

func (s *unencryptedUserSecrets) setKeyshareSecret(val *big.Int) error {
	if val.Sign() == -1 {
		return ErrKeyshareSecretNegative
	}

	data := val.Bytes()
	if len(data) > 64 {
		return ErrKeyshareSecretTooBig
	}
	zerolen := 64 - len(data)
	for i := 0; i < zerolen; i++ {
		s[64+i] = 0
	}
	copy(s[64+zerolen:], data)

	return nil
}

func (s *unencryptedUserSecrets) id() [32]byte {
	var result [32]byte
	copy(result[:], s[128:160])
	return result
}

func (s *unencryptedUserSecrets) setID(id [32]byte) {
	copy(s[128:160], id[:])
}

func (c *Core) encryptUserSecrets(secrets unencryptedUserSecrets) (UserSecrets, error) {
	var encSecrets UserSecrets

	// Store key id
	binary.LittleEndian.PutUint32(encSecrets[0:], c.decryptionKeyID)

	// Generate and store nonce
	_, err := rand.Read(encSecrets[4:16])
	if err != nil {
		return UserSecrets{}, err
	}

	// Encrypt secrets
	gcm, err := newGCM(c.decryptionKey)
	if err != nil {
		return UserSecrets{}, err
	}
	gcm.Seal(encSecrets[:16], encSecrets[4:16], secrets[:], nil)

	return encSecrets, nil
}

func (c *Core) decryptUserSecrets(secrets UserSecrets) (unencryptedUserSecrets, error) {
	// determine key id
	id := binary.LittleEndian.Uint32(secrets[0:])

	// Fetch key
	key, ok := c.decryptionKeys[id]
	if !ok {
		return unencryptedUserSecrets{}, ErrNoSuchKey
	}

	// try and decrypt secrets
	gcm, err := newGCM(key)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}
	var unencSecrets unencryptedUserSecrets
	_, err = gcm.Open(unencSecrets[:0], secrets[4:16], secrets[16:], nil)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}
	return unencSecrets, nil
}

func (c *Core) decryptUserSecretsIfPinOK(secrets UserSecrets, pin string) (unencryptedUserSecrets, error) {
	paddedPin, err := padPin(pin)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}

	s, err := c.decryptUserSecrets(secrets)
	if err != nil {
		return unencryptedUserSecrets{}, err
	}

	refPin := s.pin()
	if subtle.ConstantTimeCompare(refPin[:], paddedPin[:]) != 1 {
		return unencryptedUserSecrets{}, ErrInvalidPin
	}
	return s, nil
}

func newGCM(key AESKey) (cipher.AEAD, error) {
	keyedAes, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}
	gcm, err := cipher.NewGCM(keyedAes)
	if err != nil {
		return nil, err
	}
	return gcm, nil
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"

	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	u "github.com/techjanitor/pram-get/utils"
)

// checks for session cookie and handles permissions
func Auth(perms Permissions) gin.HandlerFunc {
	return func(c *gin.Context) {

		// set default anonymous user
		user := u.User{
			Id:    1,
			Group: 0,
		}

		// parse jwt token if its there
		token, err := jwt.ParseFromRequest(c.Request, func(token *jwt.Token) (interface{}, error) {

			// check alg
			_, ok := token.Method.(*jwt.SigningMethodHMAC)
			if !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			return []byte(config.Settings.Session.Secret), nil
		})
		// if there isnt a token in the request
		if err == jwt.ErrNoTokenInRequest {
			// get anon user info
			err = user.Info()
			if err != nil {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				return
			}
		} else if err != nil {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(err)
			c.Abort()
			return
		}

		// if the token is valid set the data
		if err == nil && token.Valid {

			uid, ok := token.Claims["user_id"].(float64)
			if !ok {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				c.Abort()
				return
			}

			// set user id
			user.Id = uint(uid)

			// get the rest of the user info
			err = user.Info()
			if err == e.ErrNotFound {
				c.JSON(http.StatusBadRequest, gin.H{"error_message": e.ErrInvalidUser.Error()})
				c.Error(err)
				return
			} else if err != nil {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				return
			}

		}

		// check if user meets set permissions
		if user.Group < perms.Minimum {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(e.ErrUnauthorized)
			c.Abort()
			return
		}

		// set user data
		c.Set("userdata", user)

		c.Next()

	}

}

// permissions data
type Permissions struct {
	Minimum uint
}

func SetAuthLevel() Permissions {
	return Permissions{}
}

// All users
func (p Permissions) All() Permissions {
	p.Minimum = 0
	return p
}

// registered users
func (p Permissions) Registered() Permissions {
	p.Minimum = 1
	return p
}

// moderators
func (p Permissions) Moderators() Permissions {
	p.Minimum = 2
	return p
}

// admins
func (p Permissions) Admins() Permissions {
	p.Minimum = 3
	return p
}
<commit_msg>get userdata from auth middleware<commit_after>package middleware

import (
	"fmt"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"

	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	u "github.com/techjanitor/pram-get/utils"
)

// checks for session cookie and handles permissions
func Auth(perms Permissions) gin.HandlerFunc {
	return func(c *gin.Context) {

		// set default anonymous user
		user := u.User{
			Id:    1,
			Group: 0,
		}

		// parse jwt token if its there
		token, err := jwt.ParseFromRequest(c.Request, func(token *jwt.Token) (interface{}, error) {

			// check alg
			_, ok := token.Method.(*jwt.SigningMethodHMAC)
			if !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			return []byte(config.Settings.Session.Secret), nil
		})
		// if theres no token set the anon user info
		if err == jwt.ErrNoTokenInRequest {
			err = user.Info()
			if err != nil {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				return
			}
			// if theres some jwt error then return unauth
		} else if err != nil {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(err)
			c.Abort()
			return
		}

		// process token
		if token != nil {
			// if the token is valid set the data
			if err == nil && token.Valid {

				uid, ok := token.Claims["user_id"].(float64)
				if !ok {
					c.JSON(e.ErrorMessage(e.ErrInternalError))
					c.Error(err)
					c.Abort()
					return
				}

				// set user id
				user.Id = uint(uid)

				// get the rest of the user info
				err = user.Info()
				if err == e.ErrNotFound {
					c.JSON(http.StatusBadRequest, gin.H{"error_message": e.ErrInvalidUser.Error()})
					c.Error(err)
					return
				} else if err != nil {
					c.JSON(e.ErrorMessage(e.ErrInternalError))
					c.Error(err)
					return
				}

			}

		}

		// check if user meets set permissions
		if user.Group < perms.Minimum {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(e.ErrUnauthorized)
			c.Abort()
			return
		}

		// set user data
		c.Set("userdata", user)

		c.Next()

	}

}

// permissions data
type Permissions struct {
	Minimum uint
}

func SetAuthLevel() Permissions {
	return Permissions{}
}

// All users
func (p Permissions) All() Permissions {
	p.Minimum = 0
	return p
}

// registered users
func (p Permissions) Registered() Permissions {
	p.Minimum = 1
	return p
}

// moderators
func (p Permissions) Moderators() Permissions {
	p.Minimum = 2
	return p
}

// admins
func (p Permissions) Admins() Permissions {
	p.Minimum = 3
	return p
}
<|endoftext|>


<commit_before>package mocks_test

import (
	"go/ast"
	"go/format"
	"go/token"
	"testing"

	"github.com/a8m/expect"
	"github.com/nelsam/hel/mocks"
)

const packagePrefix = "package foo\n\n"

func TestNewErrorsForNonInterfaceTypes(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, "type Foo func()")
	_, err := mocks.New(spec)
	expect(err).Not.To.Be.Nil()
	expect(err.Error()).To.Equal("TypeSpec.Type expected to be *ast.InterfaceType, was *ast.FuncType")
}

func TestMockName(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, "type Foo interface{}")
	m, err := mocks.New(spec)
	expect(err).To.Be.Nil()
	expect(m).Not.To.Be.Nil()
	expect(m.Name()).To.Equal("mockFoo")
}

func TestMockAst(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, `
 type Foo interface {
  Foo(foo string) int
  Bar(bar int) string
 }
 `)
	m, err := mocks.New(spec)
	expect(err).To.Be.Nil()
	expect(m).Not.To.Be.Nil()

	expected, err := format.Source([]byte(`
 package foo

 type mockFoo struct {
  methods struct {
   Foo struct {
    called chan bool
    input struct {
     foo chan string
    }
    output struct {
     ret0 chan int
    }
   }
   Bar struct {
    called chan bool
    input struct {
     bar chan int
    }
    output struct {
     ret0 chan string
    }
   }
  }
 }
 `))
	expect(err).To.Be.Nil()

	decls := []ast.Decl{
		&ast.GenDecl{
			Tok:   token.TYPE,
			Specs: []ast.Spec{m.Ast()},
		},
	}
	src := source(expect, "foo", decls, nil)
	expect(src).To.Equal(string(expected))
}
<commit_msg>Add test for constructor generation<commit_after>package mocks_test

import (
	"go/ast"
	"go/format"
	"go/token"
	"testing"

	"github.com/a8m/expect"
	"github.com/nelsam/hel/mocks"
)

const packagePrefix = "package foo\n\n"

func TestNewErrorsForNonInterfaceTypes(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, "type Foo func()")
	_, err := mocks.New(spec)
	expect(err).Not.To.Be.Nil()
	expect(err.Error()).To.Equal("TypeSpec.Type expected to be *ast.InterfaceType, was *ast.FuncType")
}

func TestMockName(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, "type Foo interface{}")
	m, err := mocks.New(spec)
	expect(err).To.Be.Nil()
	expect(m).Not.To.Be.Nil()
	expect(m.Name()).To.Equal("mockFoo")
}

func TestMockAst(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, `
 type Foo interface {
  Foo(foo string) int
  Bar(bar int) string
 }
 `)
	m, err := mocks.New(spec)
	expect(err).To.Be.Nil()
	expect(m).Not.To.Be.Nil()

	expected, err := format.Source([]byte(`
 package foo

 type mockFoo struct {
  methods struct {
   Foo struct {
    called chan bool
    input struct {
     foo chan string
    }
    output struct {
     ret0 chan int
    }
   }
   Bar struct {
    called chan bool
    input struct {
     bar chan int
    }
    output struct {
     ret0 chan string
    }
   }
  }
 }
 `))
	expect(err).To.Be.Nil()

	decls := []ast.Decl{
		&ast.GenDecl{
			Tok:   token.TYPE,
			Specs: []ast.Spec{m.Ast()},
		},
	}
	src := source(expect, "foo", decls, nil)
	expect(src).To.Equal(string(expected))
}

func TestMockConstructor(t *testing.T) {
	expect := expect.New(t)

	spec := typeSpec(expect, `
 type Foo interface {
  Foo(foo string) int
  Bar(bar int) string
 }
 `)
	m, err := mocks.New(spec)
	expect(err).To.Be.Nil()
	expect(m).Not.To.Be.Nil()

	expected, err := format.Source([]byte(`
 package foo

 func newMockFoo() *mockFoo {
  m := &mockFoo{}
  m.methods.Foo.called = make(chan bool, 300)
  m.methods.Foo.input.foo = make(chan string, 300)
  m.methods.Foo.output.ret0 = make(chan int, 300)
  m.methods.Bar.called = make(chan bool, 300)
  m.methods.Bar.input.bar = make(chan int, 300)
  m.methods.Bar.output.ret0 = make(chan string, 300)
  return m
 }`))
	expect(err).To.Be.Nil()

	src := source(expect, "foo", []ast.Decl{m.Constructor(300)}, nil)
	expect(src).To.Equal(string(expected))
}
<|endoftext|>


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

package cassandra

import (
	"strings"
	"time"

	"strconv"

	"github.com/gocql/gocql"
)

type TLS struct {
	Certfile               string `json:"cert_path"`
	Keyfile                string `json:"key_path"`
	CAfile                 string `json:"ca_path"`
	EnableHostVerification bool   `json:"enable_host_verification"`
	Enabled                bool   `json:"enabled"`
}

// Config Configuration for Cassandra clients loaded from a configuration file
type Config struct {
	// A list of host addresses of cluster nodes.
	Endpoints []string `json:"endpoints"`

	// port for Cassandra (default: 9042)
	Port int `json:"port"`

	// session timeout (default: 600ms)
	OpTimeout time.Duration `json:"op_timeout"`

	// initial session timeout, used during initial dial to server (default: 600ms)
	DialTimeout time.Duration `json:"dial_timeout"`

	// If not zero, gocql attempt to reconnect known DOWN nodes in every ReconnectSleep.
	RedialInterval time.Duration `json:"redial_interval"`

	// ProtoVersion sets the version of the native protocol to use, this will
	// enable features in the driver for specific protocol versions, generally this
	// should be set to a known version (2,3,4) for the cluster being connected to.
	//
	// If it is 0 or unset (the default) then the driver will attempt to discover the
	// highest supported protocol for the cluster. In clusters with nodes of different
	// versions the protocol selected is not defined (ie, it can be any of the supported in the cluster)
	ProtocolVersion int `json:"protocol_version"`

	TLS TLS `json:"tls"`
}

// ClientConfig wrapping gocql ClusterConfig
type ClientConfig struct {
	*gocql.ClusterConfig
}

const defaultOpTimeout = 600 * time.Millisecond
const defaultDialTimeout = 600 * time.Millisecond
const defaultRedialInterval = 60 * time.Second
const defaultProtocolVersion = 4

// ConfigToClientConfig transforms the yaml configuration into ClientConfig.
// If the configuration of endpoints is invalid, error ErrInvalidEndpointConfig
// is returned.
func ConfigToClientConfig(ymlConfig *Config) (*ClientConfig, error) {

	timeout := defaultOpTimeout
	if ymlConfig.OpTimeout > 0 {
		timeout = ymlConfig.OpTimeout
	}

	connectTimeout := defaultDialTimeout
	if ymlConfig.DialTimeout > 0 {
		connectTimeout = ymlConfig.DialTimeout
	}

	reconnectInterval := defaultRedialInterval
	if ymlConfig.RedialInterval > 0 {
		reconnectInterval = ymlConfig.RedialInterval
	}

	protoVersion := defaultProtocolVersion
	if ymlConfig.ProtocolVersion > 0 {
		protoVersion = ymlConfig.ProtocolVersion
	}

	endpoints, port, err := getEndpointsAndPort(ymlConfig.Endpoints)
	if err != nil {
		return nil, err
	}

	var sslOpts *gocql.SslOptions
	if ymlConfig.TLS.Enabled {
		sslOpts = &gocql.SslOptions{
			CaPath:                 ymlConfig.TLS.CAfile,
			CertPath:               ymlConfig.TLS.Certfile,
			KeyPath:                ymlConfig.TLS.Keyfile,
			EnableHostVerification: ymlConfig.TLS.EnableHostVerification,
		}
	}

	clientConfig := &gocql.ClusterConfig{
		Hosts:             endpoints,
		Port:              port,
		Timeout:           timeout * time.Millisecond,
		ConnectTimeout:    connectTimeout * time.Millisecond,
		ReconnectInterval: reconnectInterval * time.Second,
		ProtoVersion:      protoVersion,
		SslOpts:           sslOpts,
	}

	cfg := &ClientConfig{ClusterConfig: clientConfig}

	return cfg, nil
}

// CreateSessionFromConfig creates and initializes the cluster based on the supplied config
// and returns a new session object that can be used to interact with the database.
// The function propagates errors returned from gocql.CreateSession().
func CreateSessionFromConfig(config *ClientConfig) (*gocql.Session, error) {

	gocqlClusterConfig := gocql.NewCluster(HostsAsString(config.Hosts))
	gocqlClusterConfig.Port = config.Port
	gocqlClusterConfig.ConnectTimeout = config.ConnectTimeout
	gocqlClusterConfig.ReconnectInterval = config.ReconnectInterval
	gocqlClusterConfig.Timeout = config.Timeout
	gocqlClusterConfig.ProtoVersion = config.ProtoVersion
	gocqlClusterConfig.SslOpts = config.SslOpts

	session, err := gocqlClusterConfig.CreateSession()

	if err != nil {
		return nil, err
	}

	return session, nil
}

// HostsAsString converts an array of hosts addresses into a comma separated string
func HostsAsString(hostArr []string) string {
	return strings.Join(hostArr, ",")
}

//getEndpointsAndPort does string manipulation to extract []endpoints and port eg: "127.0.0.1:9042" or "127.0.0.1:9042,127.0.0.2:9042"
func getEndpointsAndPort(endpoints []string) (endpointsR []string, portR int, err error) {
	var resultEndpoints []string
	var resultPort int

	if len(endpoints) > 1 {
		return nil, 0, ErrInvalidEndpointConfig
	}

	if len(endpoints[0]) > 0 {
		v := endpoints[0]

		if !strings.Contains(v, ":") {
			return nil, 0, ErrInvalidEndpointConfig
		}

		if strings.Contains(v, ",") {
			endpointsAndPort := strings.Split(v, ",")
			for _, val := range endpointsAndPort {
				endpointAndPort := strings.Split(val, ":")
				resultEndpoints = append(resultEndpoints, endpointAndPort[0])
				resultPort, err = strconv.Atoi(endpointAndPort[1])
				if err != nil {
					return nil, 0, err
				}
			}

		} else {
			endpointAndPort := strings.Split(v, ":")
			resultEndpoints = append(resultEndpoints, endpointAndPort[0])
			resultPort, err = strconv.Atoi(endpointAndPort[1])
			if err != nil {
				return nil, 0, err
			}
		}
	} else {
		return nil, 0, ErrInvalidEndpointConfig
	}

	return resultEndpoints, resultPort, nil
}
<commit_msg>SPOPT-1627 - Cassandra TLS<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cassandra

import (
	"strings"
	"time"

	"strconv"

	"github.com/gocql/gocql"
)

//TLS used to configure TLS
type TLS struct {
	Certfile               string `json:"cert_path"`                // client certificate
	Keyfile                string `json:"key_path"`                 // client private key
	CAfile                 string `json:"ca_path"`                  // certificate authority
	EnableHostVerification bool   `json:"enable_host_verification"` // whether to skip verification of server name & certificate
	Enabled                bool   `json:"enabled"`                  // enable/disable TLS
}

// Config Configuration for Cassandra clients loaded from a configuration file
type Config struct {
	// A list of host addresses of cluster nodes.
	Endpoints []string `json:"endpoints"`

	// port for Cassandra (default: 9042)
	Port int `json:"port"`

	// session timeout (default: 600ms)
	OpTimeout time.Duration `json:"op_timeout"`

	// initial session timeout, used during initial dial to server (default: 600ms)
	DialTimeout time.Duration `json:"dial_timeout"`

	// If not zero, gocql attempt to reconnect known DOWN nodes in every ReconnectSleep.
	RedialInterval time.Duration `json:"redial_interval"`

	// ProtoVersion sets the version of the native protocol to use, this will
	// enable features in the driver for specific protocol versions, generally this
	// should be set to a known version (2,3,4) for the cluster being connected to.
	//
	// If it is 0 or unset (the default) then the driver will attempt to discover the
	// highest supported protocol for the cluster. In clusters with nodes of different
	// versions the protocol selected is not defined (ie, it can be any of the supported in the cluster)
	ProtocolVersion int `json:"protocol_version"`

	//TLS used to configure TLS
	TLS TLS `json:"tls"`
}

// ClientConfig wrapping gocql ClusterConfig
type ClientConfig struct {
	*gocql.ClusterConfig
}

const defaultOpTimeout = 600 * time.Millisecond
const defaultDialTimeout = 600 * time.Millisecond
const defaultRedialInterval = 60 * time.Second
const defaultProtocolVersion = 4

// ConfigToClientConfig transforms the yaml configuration into ClientConfig.
// If the configuration of endpoints is invalid, error ErrInvalidEndpointConfig
// is returned.
func ConfigToClientConfig(ymlConfig *Config) (*ClientConfig, error) {

	timeout := defaultOpTimeout
	if ymlConfig.OpTimeout > 0 {
		timeout = ymlConfig.OpTimeout
	}

	connectTimeout := defaultDialTimeout
	if ymlConfig.DialTimeout > 0 {
		connectTimeout = ymlConfig.DialTimeout
	}

	reconnectInterval := defaultRedialInterval
	if ymlConfig.RedialInterval > 0 {
		reconnectInterval = ymlConfig.RedialInterval
	}

	protoVersion := defaultProtocolVersion
	if ymlConfig.ProtocolVersion > 0 {
		protoVersion = ymlConfig.ProtocolVersion
	}

	endpoints, port, err := getEndpointsAndPort(ymlConfig.Endpoints)
	if err != nil {
		return nil, err
	}

	var sslOpts *gocql.SslOptions
	if ymlConfig.TLS.Enabled {
		sslOpts = &gocql.SslOptions{
			CaPath:                 ymlConfig.TLS.CAfile,
			CertPath:               ymlConfig.TLS.Certfile,
			KeyPath:                ymlConfig.TLS.Keyfile,
			EnableHostVerification: ymlConfig.TLS.EnableHostVerification,
		}
	}

	clientConfig := &gocql.ClusterConfig{
		Hosts:             endpoints,
		Port:              port,
		Timeout:           timeout * time.Millisecond,
		ConnectTimeout:    connectTimeout * time.Millisecond,
		ReconnectInterval: reconnectInterval * time.Second,
		ProtoVersion:      protoVersion,
		SslOpts:           sslOpts,
	}

	cfg := &ClientConfig{ClusterConfig: clientConfig}

	return cfg, nil
}

// CreateSessionFromConfig creates and initializes the cluster based on the supplied config
// and returns a new session object that can be used to interact with the database.
// The function propagates errors returned from gocql.CreateSession().
func CreateSessionFromConfig(config *ClientConfig) (*gocql.Session, error) {

	gocqlClusterConfig := gocql.NewCluster(HostsAsString(config.Hosts))
	gocqlClusterConfig.Port = config.Port
	gocqlClusterConfig.ConnectTimeout = config.ConnectTimeout
	gocqlClusterConfig.ReconnectInterval = config.ReconnectInterval
	gocqlClusterConfig.Timeout = config.Timeout
	gocqlClusterConfig.ProtoVersion = config.ProtoVersion
	gocqlClusterConfig.SslOpts = config.SslOpts

	session, err := gocqlClusterConfig.CreateSession()

	if err != nil {
		return nil, err
	}

	return session, nil
}

// HostsAsString converts an array of hosts addresses into a comma separated string
func HostsAsString(hostArr []string) string {
	return strings.Join(hostArr, ",")
}

//getEndpointsAndPort does string manipulation to extract []endpoints and port eg: "127.0.0.1:9042" or "127.0.0.1:9042,127.0.0.2:9042"
func getEndpointsAndPort(endpoints []string) (endpointsR []string, portR int, err error) {
	var resultEndpoints []string
	var resultPort int

	if len(endpoints) > 1 {
		return nil, 0, ErrInvalidEndpointConfig
	}

	if len(endpoints[0]) > 0 {
		v := endpoints[0]

		if !strings.Contains(v, ":") {
			return nil, 0, ErrInvalidEndpointConfig
		}

		if strings.Contains(v, ",") {
			endpointsAndPort := strings.Split(v, ",")
			for _, val := range endpointsAndPort {
				endpointAndPort := strings.Split(val, ":")
				resultEndpoints = append(resultEndpoints, endpointAndPort[0])
				resultPort, err = strconv.Atoi(endpointAndPort[1])
				if err != nil {
					return nil, 0, err
				}
			}

		} else {
			endpointAndPort := strings.Split(v, ":")
			resultEndpoints = append(resultEndpoints, endpointAndPort[0])
			resultPort, err = strconv.Atoi(endpointAndPort[1])
			if err != nil {
				return nil, 0, err
			}
		}
	} else {
		return nil, 0, ErrInvalidEndpointConfig
	}

	return resultEndpoints, resultPort, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/russross/blackfriday"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

const (
	Help = `md2pdf [-h] [-x] [-s] [-t] [-i dir] [-o file] file.md
Transform a given Markdown file into PDF.
-h        To print this help page.
-x        Print intermediate XHTML output.
-s        Print stylesheet used for transformation.
-t        Print html output.
-i dir    To indicate image directory.
-o file   The name of the file to output.
file.md   The markdown file to convert.
Note:
This program calls pandoc, xsltproc, htmldoc and faketime that must have been
installed.`
	Stylesheet = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="ISO-8859-1"/>
  <xsl:param name="title"/>
  <xsl:param name="author"/>
  <xsl:param name="date"/>
  <xsl:param name="id"/>
  <xsl:param name="email"/>
  <xsl:param name="lang"/>
  <xsl:param name="toc"/>

  <xsl:template match="/xhtml/body">

	  <meta http-equiv='Content-Type' content='text/xhtml; charset=ISO-8859-1'/>
	  <xsl:if test="$title">
	    <title><xsl:value-of select="$title"/></title>
	  </xsl:if>

    <xsl:if test="$title">

<xsl:value-of select="$title"/>

        <xsl:if test="$author">
	      <xsl:value-of select="$author"/>

        </xsl:if>
	    <xsl:if test="$email">

		    <xsl:value-of select="$email"/>

	    </xsl:if>

	</xsl:if>
    <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="table">

        <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="pre">

		    <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="p[img]">

      <xsl:apply-templates />

  </xsl:template>

  <xsl:template match="img">

<xsl:value-of select="@alt"/>
  </xsl:template>

</xsl:stylesheet>`
)

type MetaData struct {
	Title  string
	Author string
	Date   string
	Tags   []string
	Id     string
	Email  string
	Lang   string
	Toc    string
}

func printError(err error, message string) {
	if err != nil {
		println(message)
		os.Exit(1)
	}
}

func executeCommand(command *exec.Cmd) []byte {
	result, err := command.CombinedOutput()
	if err != nil {
		println(fmt.Sprintf("Error running command \"%s\":", strings.Join(command.Args, " ")))
		println(string(result))
		os.Exit(1)
		return []byte{}
	} else {
		return result
	}
}

func (d MetaData) ToMap() map[string]string {
	data := make(map[string]string)
	if d.Title != "" {
		data["title"] = d.Title
	}
	if d.Author != "" {
		data["author"] = d.Author
	}
	if d.Date != "" {
		data["date"] = d.Date
	}
	if len(d.Tags) != 0 {
		data["tags"] = strings.Join(d.Tags, ", ")
	}
	if d.Id != "" {
		data["id"] = d.Id
	}
	if d.Email != "" {
		data["email"] = d.Email
	}
	if d.Lang != "" {
		data["lang"] = d.Lang
	}
	if d.Toc != "" {
		data["toc"] = d.Toc
	}
	return data
}

var LOCALE = map[string]string{
	"fr": "fr_FR.UTF-8",
	"en": "en_US.UTF-8",
}

func processXsl(tmpFile string, data map[string]string) {
	xslFile, err := ioutil.TempFile("/tmp", "md2pdf-")
	printError(err, "Error creating XSL temporary file")
	err = ioutil.WriteFile(xslFile.Name(), []byte(Stylesheet), 0644)
	printError(err, "Error writing XSL temporary file")
	defer os.Remove(xslFile.Name())
	params := make([]string, 0, 2+3*len(data))
	for name, value := range data {
		params = append(params, "--stringparam")
		params = append(params, name)
		params = append(params, value)
	}
	params = append(params, xslFile.Name())
	params = append(params, tmpFile)
	command := exec.Command("xsltproc", params...)
	result := executeCommand(command)
	err = ioutil.WriteFile(tmpFile, result, 0644)
	printError(err, "Error writing temporary file")
}

func markdown2xhtml(markdown string) []byte {
	flags := 0 |
		blackfriday.HTML_USE_XHTML
	extensions := 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_HEADER_IDS |
		blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
		blackfriday.EXTENSION_DEFINITION_LISTS
	renderer := blackfriday.HtmlRenderer(flags, "", "")
	output := blackfriday.Markdown([]byte(markdown), renderer, extensions)
	return []byte("<xhtml>\n\n\n" + string(output) + "\n\n</xhtml>")
}

func markdownData(text string) (MetaData, string) {
	var data MetaData
	r := regexp.MustCompile("(?ms)\\A---.*?(---|\\.\\.\\.)")
	yml := r.FindString(text)
	if yml == "" {
		return data, text
	}
	err := yaml.Unmarshal([]byte(yml), &data)
	printError(err, "Error unmarshalling YAML markdown data")
	return data, text[len(yml):]
}

func imageDir(text, imgDir string) string {
	absDir, err := filepath.Abs(imgDir)
	printError(err, "Error getting absolute file path")
	r := regexp.MustCompile(`!\[(.*?)\]\(([^/].*?/)*([^/]*?)\)`)
	return r.ReplaceAllString(text, "![$1]("+absDir+"/$3)")
}

func absoluteDir(text, filename string) string {
	absDir, err := filepath.Abs(filepath.Dir(filename))
	printError(err, "Error getting absolute file path")
	r := regexp.MustCompile(`!\[(.*?)\]\(([^/].*?)\)`)
	return r.ReplaceAllString(text, "![$1]("+absDir+"/$2)")
}

func generatePdf(xhtmlFile, outFile string, data map[string]string) {
	if data["date"] == "" {
		data["date"] = time.Now().Local().Format("20060102")
	}
	if data["lang"] == "" {
		data["lang"] = "fr"
	}
	params := []string{
		data["date"],
		"htmldoc",
		"--outfile", outFile,
		"--size", "A4",
		"--top", "2cm",
		"--bottom", "2cm",
		"--left", "2cm",
		"--right", "2cm",
		"--bodyfont", "Times",
		"--fontsize", "12",
		"--header", "...",
		"--footer", "dt1",
		"--headfootfont", "Courier-Oblique",
		"--headfootsize", "10",
		"--linkcolor", "#0000A0",
		"--linkstyle", "plain",
		"--permissions", "no-modify",
		"--charset", "iso-8859-1",
		"--no-title",
		"--no-toc",
		"--compression=9",
		"--embedfonts",
		"--webpage",
		xhtmlFile,
	}
	command := exec.Command("faketime", params...)
	env := os.Environ()
	for i, e := range env {
		if strings.HasPrefix(e, "LANG") {
			env[i] = "LANG=" + LOCALE[data["lang"]]
		}
		if strings.HasPrefix(e, "LC_ALL") {
			env[i] = "LC_ALL=" + LOCALE[data["lang"]]
		}
	}
	command.Env = env
	executeCommand(command)
}

func processFile(filename string, printXhtml, printHtml bool, imgDir, outFile string) {
	source, err := ioutil.ReadFile(filename)
	printError(err, "Error reading file")
	data, markdown := markdownData(string(source))
	if imgDir != "" {
		markdown = imageDir(markdown, imgDir)
	} else {
		markdown = absoluteDir(markdown, filename)
	}
	xhtml := markdown2xhtml(markdown)
	if printXhtml {
		fmt.Println(string(xhtml))
		return
	}
	tmpFile, err := ioutil.TempFile("/tmp", "md2pdf-")
	printError(err, "Error creating temporary file")
	defer os.Remove(tmpFile.Name())
	ioutil.WriteFile(tmpFile.Name(), xhtml, 0644)
	processXsl(tmpFile.Name(), data.ToMap())
	if printHtml {
		source, err := ioutil.ReadFile(tmpFile.Name())
		printError(err, "Error reading temporary file")
		fmt.Println(string(source))
		return
	}
	if len(outFile) == 0 {
		outFile = filename[0:len(filename)-len(filepath.Ext(filename))] + ".pdf"
	}
	generatePdf(tmpFile.Name(), outFile, data.ToMap())
}

func valueIn(value string, list []string) bool {
	for _, v := range list {
		if v == value {
			return true
		}
	}
	return false
}

func main() {
	xhtml := false
	html := false
	imgDir := ""
	outFile := ""
	file := ""
	if len(os.Args) < 2 {
		fmt.Println(Help)
		os.Exit(1)
	}
	skip := false
	args := os.Args[1:]
	for i, arg := range args {
		if skip {
			skip = false
			continue
		}
		if valueIn(arg, []string{"-h", "--help"}) {
			fmt.Println(Help)
			os.Exit(0)
		}
		if valueIn(arg, []string{"-x", "--xhtml"}) {
			xhtml = true
			continue
		}
		if valueIn(arg, []string{"-s", "--stylesheet"}) {
			fmt.Println(Stylesheet)
			os.Exit(0)
		}
		if valueIn(arg, []string{"-t", "--html"}) {
			html = true
			continue
		}
		if valueIn(arg, []string{"-i", "--image-dir"}) {
			imgDir = args[i+1]
			skip = true
			continue
		}
		if valueIn(arg, []string{"-o", "--output-file"}) {
			outFile = args[i+1]
			skip = true
			continue
		}
		file = arg
	}
	processFile(file, xhtml, html, imgDir, outFile)
}
<commit_msg>Fixed golint warnings<commit_after>package main

import (
	"fmt"
	"github.com/russross/blackfriday"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

const (
	help = `md2pdf [-h] [-x] [-s] [-t] [-i dir] [-o file] file.md
Transform a given Markdown file into PDF.
-h        To print this help page.
-x        Print intermediate XHTML output.
-s        Print stylesheet used for transformation.
-t        Print html output.
-i dir    To indicate image directory.
-o file   The name of the file to output.
file.md   The markdown file to convert.
Note:
This program calls pandoc, xsltproc, htmldoc and faketime that must have been
installed.`
	stylesheet = `<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

  <xsl:output method="xml" encoding="ISO-8859-1"/>
  <xsl:param name="title"/>
  <xsl:param name="author"/>
  <xsl:param name="date"/>
  <xsl:param name="id"/>
  <xsl:param name="email"/>
  <xsl:param name="lang"/>
  <xsl:param name="toc"/>

  <xsl:template match="/xhtml/body">

	  <meta http-equiv='Content-Type' content='text/xhtml; charset=ISO-8859-1'/>
	  <xsl:if test="$title">
	    <title><xsl:value-of select="$title"/></title>
	  </xsl:if>

    <xsl:if test="$title">

<xsl:value-of select="$title"/>

        <xsl:if test="$author">
	      <xsl:value-of select="$author"/>

        </xsl:if>
	    <xsl:if test="$email">

		    <xsl:value-of select="$email"/>

	    </xsl:if>

	</xsl:if>
    <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="table">

        <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="pre">

		    <xsl:apply-templates/>

  </xsl:template>

  <xsl:template match="p[img]">

      <xsl:apply-templates />

  </xsl:template>

  <xsl:template match="img">

<xsl:value-of select="@alt"/>
  </xsl:template>

</xsl:stylesheet>`
)

type metaData struct {
	Title  string
	Author string
	Date   string
	Tags   []string
	ID     string
	Email  string
	Lang   string
	Toc    string
}

func printError(err error, message string) {
	if err != nil {
		println(message)
		os.Exit(1)
	}
}

func executeCommand(command *exec.Cmd) []byte {
	result, err := command.CombinedOutput()
	if err != nil {
		println(fmt.Sprintf("Error running command \"%s\":", strings.Join(command.Args, " ")))
		println(string(result))
		os.Exit(1)
		return []byte{}
	}
	return result
}

func (d metaData) ToMap() map[string]string {
	data := make(map[string]string)
	if d.Title != "" {
		data["title"] = d.Title
	}
	if d.Author != "" {
		data["author"] = d.Author
	}
	if d.Date != "" {
		data["date"] = d.Date
	}
	if len(d.Tags) != 0 {
		data["tags"] = strings.Join(d.Tags, ", ")
	}
	if d.ID != "" {
		data["id"] = d.ID
	}
	if d.Email != "" {
		data["email"] = d.Email
	}
	if d.Lang != "" {
		data["lang"] = d.Lang
	}
	if d.Toc != "" {
		data["toc"] = d.Toc
	}
	return data
}

var locales = map[string]string{
	"fr": "fr_FR.UTF-8",
	"en": "en_US.UTF-8",
}

func processXsl(tmpFile string, data map[string]string) {
	xslFile, err := ioutil.TempFile("/tmp", "md2pdf-")
	printError(err, "Error creating XSL temporary file")
	err = ioutil.WriteFile(xslFile.Name(), []byte(stylesheet), 0644)
	printError(err, "Error writing XSL temporary file")
	defer os.Remove(xslFile.Name())
	params := make([]string, 0, 2+3*len(data))
	for name, value := range data {
		params = append(params, "--stringparam")
		params = append(params, name)
		params = append(params, value)
	}
	params = append(params, xslFile.Name())
	params = append(params, tmpFile)
	command := exec.Command("xsltproc", params...)
	result := executeCommand(command)
	err = ioutil.WriteFile(tmpFile, result, 0644)
	printError(err, "Error writing temporary file")
}

func markdown2xhtml(markdown string) []byte {
	flags := 0 |
		blackfriday.HTML_USE_XHTML
	extensions := 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_HEADER_IDS |
		blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
		blackfriday.EXTENSION_DEFINITION_LISTS
	renderer := blackfriday.HtmlRenderer(flags, "", "")
	output := blackfriday.Markdown([]byte(markdown), renderer, extensions)
	return []byte("<xhtml>\n\n\n" + string(output) + "\n\n</xhtml>")
}

func markdownData(text string) (metaData, string) {
	var data metaData
	r := regexp.MustCompile("(?ms)\\A---.*?(---|\\.\\.\\.)")
	yml := r.FindString(text)
	if yml == "" {
		return data, text
	}
	err := yaml.Unmarshal([]byte(yml), &data)
	printError(err, "Error unmarshalling YAML markdown data")
	return data, text[len(yml):]
}

func imageDir(text, imgDir string) string {
	absDir, err := filepath.Abs(imgDir)
	printError(err, "Error getting absolute file path")
	r := regexp.MustCompile(`!\[(.*?)\]\(([^/].*?/)*([^/]*?)\)`)
	return r.ReplaceAllString(text, "![$1]("+absDir+"/$3)")
}

func absoluteDir(text, filename string) string {
	absDir, err := filepath.Abs(filepath.Dir(filename))
	printError(err, "Error getting absolute file path")
	r := regexp.MustCompile(`!\[(.*?)\]\(([^/].*?)\)`)
	return r.ReplaceAllString(text, "![$1]("+absDir+"/$2)")
}

func generatePdf(xhtmlFile, outFile string, data map[string]string) {
	if data["date"] == "" {
		data["date"] = time.Now().Local().Format("20060102")
	}
	if data["lang"] == "" {
		data["lang"] = "fr"
	}
	params := []string{
		data["date"],
		"htmldoc",
		"--outfile", outFile,
		"--size", "A4",
		"--top", "2cm",
		"--bottom", "2cm",
		"--left", "2cm",
		"--right", "2cm",
		"--bodyfont", "Times",
		"--fontsize", "12",
		"--header", "...",
		"--footer", "dt1",
		"--headfootfont", "Courier-Oblique",
		"--headfootsize", "10",
		"--linkcolor", "#0000A0",
		"--linkstyle", "plain",
		"--permissions", "no-modify",
		"--charset", "iso-8859-1",
		"--no-title",
		"--no-toc",
		"--compression=9",
		"--embedfonts",
		"--webpage",
		xhtmlFile,
	}
	command := exec.Command("faketime", params...)
	env := os.Environ()
	for i, e := range env {
		if strings.HasPrefix(e, "LANG") {
			env[i] = "LANG=" + locales[data["lang"]]
		}
		if strings.HasPrefix(e, "LC_ALL") {
			env[i] = "LC_ALL=" + locales[data["lang"]]
		}
	}
	command.Env = env
	executeCommand(command)
}

func processFile(filename string, printXHTML, printHTML bool, imgDir, outFile string) {
	source, err := ioutil.ReadFile(filename)
	printError(err, "Error reading file")
	data, markdown := markdownData(string(source))
	if imgDir != "" {
		markdown = imageDir(markdown, imgDir)
	} else {
		markdown = absoluteDir(markdown, filename)
	}
	xhtml := markdown2xhtml(markdown)
	if printXHTML {
		fmt.Println(string(xhtml))
		return
	}
	tmpFile, err := ioutil.TempFile("/tmp", "md2pdf-")
	printError(err, "Error creating temporary file")
	defer os.Remove(tmpFile.Name())
	ioutil.WriteFile(tmpFile.Name(), xhtml, 0644)
	processXsl(tmpFile.Name(), data.ToMap())
	if printHTML {
		source, err := ioutil.ReadFile(tmpFile.Name())
		printError(err, "Error reading temporary file")
		fmt.Println(string(source))
		return
	}
	if len(outFile) == 0 {
		outFile = filename[0:len(filename)-len(filepath.Ext(filename))] + ".pdf"
	}
	generatePdf(tmpFile.Name(), outFile, data.ToMap())
}

func valueIn(value string, list []string) bool {
	for _, v := range list {
		if v == value {
			return true
		}
	}
	return false
}

func main() {
	xhtml := false
	html := false
	imgDir := ""
	outFile := ""
	file := ""
	if len(os.Args) < 2 {
		fmt.Println(help)
		os.Exit(1)
	}
	skip := false
	args := os.Args[1:]
	for i, arg := range args {
		if skip {
			skip = false
			continue
		}
		if valueIn(arg, []string{"-h", "--help"}) {
			fmt.Println(help)
			os.Exit(0)
		}
		if valueIn(arg, []string{"-x", "--xhtml"}) {
			xhtml = true
			continue
		}
		if valueIn(arg, []string{"-s", "--stylesheet"}) {
			fmt.Println(stylesheet)
			os.Exit(0)
		}
		if valueIn(arg, []string{"-t", "--html"}) {
			html = true
			continue
		}
		if valueIn(arg, []string{"-i", "--image-dir"}) {
			imgDir = args[i+1]
			skip = true
			continue
		}
		if valueIn(arg, []string{"-o", "--output-file"}) {
			outFile = args[i+1]
			skip = true
			continue
		}
		file = arg
	}
	processFile(file, xhtml, html, imgDir, outFile)
}
<|endoftext|>


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

import (
	"bufio"
	"io"
	"os"
	"strings"
	"time"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

type Controller interface {
	Authorize() menderError
	Bootstrap() menderError
	GetCurrentImageID() string
	GetUpdatePollInterval() time.Duration
	HasUpgrade() (bool, menderError)
	CheckUpdate() (*UpdateResponse, menderError)
	FetchUpdate(url string) (io.ReadCloser, int64, error)
	ReportUpdateStatus(update UpdateResponse, status string) menderError
	UploadLog(update UpdateResponse, logs []LogEntry) menderError

	UInstallCommitRebooter
	StateRunner
}

const (
	defaultManifestFile = "/etc/build_mender"
	defaultKeyFile      = "mender-agent.pem"
	defaultDataStore    = "/var/lib/mender"
)

type MenderState int

const (
	// initial state
	MenderStateInit MenderState = iota
	// client is bootstrapped, i.e. ready to go
	MenderStateBootstrapped
	// client has all authorization data available
	MenderStateAuthorized
	// wait before authorization attempt
	MenderStateAuthorizeWait
	// wait for new update
	MenderStateUpdateCheckWait
	// check update
	MenderStateUpdateCheck
	// update fetch
	MenderStateUpdateFetch
	// update install
	MenderStateUpdateInstall
	// commit needed
	MenderStateUpdateCommit
	// reboot
	MenderStateReboot
	// error
	MenderStateError
	// update error
	MenderStateUpdateError
	// exit state
	MenderStateDone
)

type mender struct {
	UInstallCommitRebooter
	updater        Updater
	env            BootEnvReadWriter
	state          State
	config         menderConfig
	manifestFile   string
	forceBootstrap bool
	authReq        AuthRequester
	authMgr        AuthManager
	api            *ApiClient
	authToken      AuthToken
}

type MenderPieces struct {
	device  UInstallCommitRebooter
	env     BootEnvReadWriter
	store   Store
	authMgr AuthManager
}

func NewMender(config menderConfig, pieces MenderPieces) (*mender, error) {
	api, err := NewApiClient(config.GetHttpConfig())
	if err != nil {
		return nil, errors.Wrap(err, "error creating HTTP client")
	}

	m := &mender{
		UInstallCommitRebooter: pieces.device,
		updater:                NewUpdateClient(),
		env:                    pieces.env,
		manifestFile:           defaultManifestFile,
		state:                  initState,
		config:                 config,
		authMgr:                pieces.authMgr,
		authReq:                NewAuthClient(),
		api:                    api,
		authToken:              noAuthToken,
	}
	return m, nil
}

func (m mender) GetCurrentImageID() string {
	// This is where Yocto stores buid information
	manifest, err := os.Open(m.manifestFile)
	if err != nil {
		log.Error("Can not read current image id.")
		return ""
	}

	imageID := ""

	scanner := bufio.NewScanner(manifest)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		log.Debug("Read data from device manifest file: ", line)
		if strings.HasPrefix(line, "IMAGE_ID") {
			log.Debug("Found device id line: ", line)
			lineID := strings.Split(line, "=")
			if len(lineID) != 2 {
				log.Errorf("Broken device manifest file: (%v)", lineID)
				return ""
			}
			log.Debug("Current image id: ", strings.TrimSpace(lineID[1]))
			return strings.TrimSpace(lineID[1])
		}
	}
	if err := scanner.Err(); err != nil {
		log.Error(err)
	}
	return imageID
}

func (m *mender) HasUpgrade() (bool, menderError) {
	env, err := m.env.ReadEnv("upgrade_available")
	if err != nil {
		return false, NewFatalError(err)
	}
	upgradeAvailable := env["upgrade_available"]

	// we are after update
	if upgradeAvailable == "1" {
		return true, nil
	}
	return false, nil
}

func (m *mender) ForceBootstrap() {
	m.forceBootstrap = true
}

func (m *mender) needsBootstrap() bool {
	if m.forceBootstrap {
		return true
	}

	if !m.authMgr.HasKey() {
		log.Debugf("needs keys")
		return true
	}

	return false
}

func (m *mender) Bootstrap() menderError {
	if !m.needsBootstrap() {
		return nil
	}

	return m.doBootstrap()
}

// cache authorization code
func (m *mender) loadAuth() menderError {
	if m.authToken != noAuthToken {
		return nil
	}

	code, err := m.authMgr.AuthToken()
	if err != nil {
		return NewFatalError(errors.Wrap(err, "failed to cache authorization code"))
	}

	m.authToken = code
	return nil
}

func (m *mender) Authorize() menderError {
	if m.authMgr.IsAuthorized() {
		log.Info("authorization data present and valid, skipping authorization attempt")
		return m.loadAuth()
	}

	m.authToken = noAuthToken

	rsp, err := m.authReq.Request(m.api, m.config.ServerURL, m.authMgr)
	if err != nil {
		return NewTransientError(errors.Wrap(err, "authorization request failed"))
	}

	err = m.authMgr.RecvAuthResponse(rsp)
	if err != nil {
		return NewTransientError(errors.Wrap(err, "failed to parse authorization response"))
	}

	log.Info("successfuly received new authorization data")

	return m.loadAuth()
}

func (m *mender) doBootstrap() menderError {
	if !m.authMgr.HasKey() || m.forceBootstrap {
		log.Infof("device keys not present or bootstrap forced, generating")
		if err := m.authMgr.GenerateKey(); err != nil {
			return NewFatalError(err)
		}

	}

	m.forceBootstrap = false

	return nil
}

func (m *mender) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	return m.updater.FetchUpdate(m.api.Request(m.authToken), url)
}

// Check if new update is available. In case of errors, returns nil and error
// that occurred. If no update is available *UpdateResponse is nil, otherwise it
// contains update information.
func (m *mender) CheckUpdate() (*UpdateResponse, menderError) {
	currentImageID := m.GetCurrentImageID()
	//TODO: if currentImageID == "" {
	// 	return errors.New("")
	// }

	haveUpdate, err := m.updater.GetScheduledUpdate(m.api.Request(m.authToken),
		m.config.ServerURL, m.config.DeviceID)
	if err != nil {
		log.Error("Error receiving scheduled update data: ", err)
		return nil, NewTransientError(err)
	}

	if haveUpdate == nil {
		log.Debug("no updates available")
		return nil, nil
	}
	update, ok := haveUpdate.(UpdateResponse)
	if !ok {
		return nil, NewTransientError(errors.Errorf("not an update response?"))
	}

	log.Debugf("received update response: %v", update)

	if update.Image.YoctoID == currentImageID {
		return nil, nil
	}
	return &update, nil
}

func (m *mender) ReportUpdateStatus(update UpdateResponse, status string) menderError {
	s := NewStatusClient()
	err := s.Report(m.api.Request(m.authToken), m.config.ServerURL,
		StatusReport{
			deploymentID: update.ID,
			Status:       status,
		})
	if err != nil {
		log.Error("error reporting update status: ", err)
		return NewTransientError(err)
	}
	return nil
}

func (m *mender) UploadLog(update UpdateResponse, logs []LogEntry) menderError {
	s := NewLogUploadClient()
	err := s.Upload(m.api.Request(m.authToken), m.config.ServerURL,
		LogData{
			deploymentID: update.ID,
			Messages:     logs,
		})
	if err != nil {
		log.Error("error uploading logs: ", err)
		return NewTransientError(err)
	}
	return nil
}

func (m mender) GetUpdatePollInterval() time.Duration {
	return time.Duration(m.config.PollIntervalSeconds) * time.Second
}

func (m *mender) SetState(s State) {
	log.Infof("Mender state: %v -> %v", m.state.Id(), s.Id())
	m.state = s
}

func (m *mender) GetState() State {
	return m.state
}

func (m *mender) RunState(ctx *StateContext) (State, bool) {
	return m.state.Handle(ctx, m)
}
<commit_msg>mender: define distinct state for update status reporting<commit_after>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
package main

import (
	"bufio"
	"io"
	"os"
	"strings"
	"time"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

type Controller interface {
	Authorize() menderError
	Bootstrap() menderError
	GetCurrentImageID() string
	GetUpdatePollInterval() time.Duration
	HasUpgrade() (bool, menderError)
	CheckUpdate() (*UpdateResponse, menderError)
	FetchUpdate(url string) (io.ReadCloser, int64, error)
	ReportUpdateStatus(update UpdateResponse, status string) menderError
	UploadLog(update UpdateResponse, logs []LogEntry) menderError

	UInstallCommitRebooter
	StateRunner
}

const (
	defaultManifestFile = "/etc/build_mender"
	defaultKeyFile      = "mender-agent.pem"
	defaultDataStore    = "/var/lib/mender"
)

type MenderState int

const (
	// initial state
	MenderStateInit MenderState = iota
	// client is bootstrapped, i.e. ready to go
	MenderStateBootstrapped
	// client has all authorization data available
	MenderStateAuthorized
	// wait before authorization attempt
	MenderStateAuthorizeWait
	// wait for new update
	MenderStateUpdateCheckWait
	// check update
	MenderStateUpdateCheck
	// update fetch
	MenderStateUpdateFetch
	// update install
	MenderStateUpdateInstall
	// commit needed
	MenderStateUpdateCommit
	// status report
	MenderStateUpdateStatusReport
	// reboot
	MenderStateReboot
	// error
	MenderStateError
	// update error
	MenderStateUpdateError
	// exit state
	MenderStateDone
)

type mender struct {
	UInstallCommitRebooter
	updater        Updater
	env            BootEnvReadWriter
	state          State
	config         menderConfig
	manifestFile   string
	forceBootstrap bool
	authReq        AuthRequester
	authMgr        AuthManager
	api            *ApiClient
	authToken      AuthToken
}

type MenderPieces struct {
	device  UInstallCommitRebooter
	env     BootEnvReadWriter
	store   Store
	authMgr AuthManager
}

func NewMender(config menderConfig, pieces MenderPieces) (*mender, error) {
	api, err := NewApiClient(config.GetHttpConfig())
	if err != nil {
		return nil, errors.Wrap(err, "error creating HTTP client")
	}

	m := &mender{
		UInstallCommitRebooter: pieces.device,
		updater:                NewUpdateClient(),
		env:                    pieces.env,
		manifestFile:           defaultManifestFile,
		state:                  initState,
		config:                 config,
		authMgr:                pieces.authMgr,
		authReq:                NewAuthClient(),
		api:                    api,
		authToken:              noAuthToken,
	}
	return m, nil
}

func (m mender) GetCurrentImageID() string {
	// This is where Yocto stores buid information
	manifest, err := os.Open(m.manifestFile)
	if err != nil {
		log.Error("Can not read current image id.")
		return ""
	}

	imageID := ""

	scanner := bufio.NewScanner(manifest)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		log.Debug("Read data from device manifest file: ", line)
		if strings.HasPrefix(line, "IMAGE_ID") {
			log.Debug("Found device id line: ", line)
			lineID := strings.Split(line, "=")
			if len(lineID) != 2 {
				log.Errorf("Broken device manifest file: (%v)", lineID)
				return ""
			}
			log.Debug("Current image id: ", strings.TrimSpace(lineID[1]))
			return strings.TrimSpace(lineID[1])
		}
	}
	if err := scanner.Err(); err != nil {
		log.Error(err)
	}
	return imageID
}

func (m *mender) HasUpgrade() (bool, menderError) {
	env, err := m.env.ReadEnv("upgrade_available")
	if err != nil {
		return false, NewFatalError(err)
	}
	upgradeAvailable := env["upgrade_available"]

	// we are after update
	if upgradeAvailable == "1" {
		return true, nil
	}
	return false, nil
}

func (m *mender) ForceBootstrap() {
	m.forceBootstrap = true
}

func (m *mender) needsBootstrap() bool {
	if m.forceBootstrap {
		return true
	}

	if !m.authMgr.HasKey() {
		log.Debugf("needs keys")
		return true
	}

	return false
}

func (m *mender) Bootstrap() menderError {
	if !m.needsBootstrap() {
		return nil
	}

	return m.doBootstrap()
}

// cache authorization code
func (m *mender) loadAuth() menderError {
	if m.authToken != noAuthToken {
		return nil
	}

	code, err := m.authMgr.AuthToken()
	if err != nil {
		return NewFatalError(errors.Wrap(err, "failed to cache authorization code"))
	}

	m.authToken = code
	return nil
}

func (m *mender) Authorize() menderError {
	if m.authMgr.IsAuthorized() {
		log.Info("authorization data present and valid, skipping authorization attempt")
		return m.loadAuth()
	}

	m.authToken = noAuthToken

	rsp, err := m.authReq.Request(m.api, m.config.ServerURL, m.authMgr)
	if err != nil {
		return NewTransientError(errors.Wrap(err, "authorization request failed"))
	}

	err = m.authMgr.RecvAuthResponse(rsp)
	if err != nil {
		return NewTransientError(errors.Wrap(err, "failed to parse authorization response"))
	}

	log.Info("successfuly received new authorization data")

	return m.loadAuth()
}

func (m *mender) doBootstrap() menderError {
	if !m.authMgr.HasKey() || m.forceBootstrap {
		log.Infof("device keys not present or bootstrap forced, generating")
		if err := m.authMgr.GenerateKey(); err != nil {
			return NewFatalError(err)
		}

	}

	m.forceBootstrap = false

	return nil
}

func (m *mender) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	return m.updater.FetchUpdate(m.api.Request(m.authToken), url)
}

// Check if new update is available. In case of errors, returns nil and error
// that occurred. If no update is available *UpdateResponse is nil, otherwise it
// contains update information.
func (m *mender) CheckUpdate() (*UpdateResponse, menderError) {
	currentImageID := m.GetCurrentImageID()
	//TODO: if currentImageID == "" {
	// 	return errors.New("")
	// }

	haveUpdate, err := m.updater.GetScheduledUpdate(m.api.Request(m.authToken),
		m.config.ServerURL, m.config.DeviceID)
	if err != nil {
		log.Error("Error receiving scheduled update data: ", err)
		return nil, NewTransientError(err)
	}

	if haveUpdate == nil {
		log.Debug("no updates available")
		return nil, nil
	}
	update, ok := haveUpdate.(UpdateResponse)
	if !ok {
		return nil, NewTransientError(errors.Errorf("not an update response?"))
	}

	log.Debugf("received update response: %v", update)

	if update.Image.YoctoID == currentImageID {
		return nil, nil
	}
	return &update, nil
}

func (m *mender) ReportUpdateStatus(update UpdateResponse, status string) menderError {
	s := NewStatusClient()
	err := s.Report(m.api.Request(m.authToken), m.config.ServerURL,
		StatusReport{
			deploymentID: update.ID,
			Status:       status,
		})
	if err != nil {
		log.Error("error reporting update status: ", err)
		return NewTransientError(err)
	}
	return nil
}

func (m *mender) UploadLog(update UpdateResponse, logs []LogEntry) menderError {
	s := NewLogUploadClient()
	err := s.Upload(m.api.Request(m.authToken), m.config.ServerURL,
		LogData{
			deploymentID: update.ID,
			Messages:     logs,
		})
	if err != nil {
		log.Error("error uploading logs: ", err)
		return NewTransientError(err)
	}
	return nil
}

func (m mender) GetUpdatePollInterval() time.Duration {
	return time.Duration(m.config.PollIntervalSeconds) * time.Second
}

func (m *mender) SetState(s State) {
	log.Infof("Mender state: %v -> %v", m.state.Id(), s.Id())
	m.state = s
}

func (m *mender) GetState() State {
	return m.state
}

func (m *mender) RunState(ctx *StateContext) (State, bool) {
	return m.state.Handle(ctx, m)
}
<|endoftext|>


<commit_before>package rbuf

// copyright (c) 2016, Jason E. Aten
// license: MIT

import "io"

// Float64RingBuf:
//
//  a fixed-size circular ring buffer of float64
//
type Float64RingBuf struct {
	A        []float64
	N        int // MaxView, the total size of A, whether or not in use.
	Beg      int // start of in-use data in A
	Readable int // number of pointers available in A (in use)
}

// constructor. NewFloat64RingBuf will allocate internally
// a slice of size maxViewInBytes.
func NewFloat64RingBuf(maxViewInBytes int) *Float64RingBuf {
	n := maxViewInBytes
	r := &Float64RingBuf{
		N:        n,
		Beg:      0,
		Readable: 0,
	}
	r.A = make([]float64, n, n)

	return r
}

// TwoContig returns all readable pointers, but in two separate slices,
// to avoid copying. The two slices are from the same buffer, but
// are not contiguous. Either or both may be empty slices.
func (b *Float64RingBuf) TwoContig(makeCopy bool) (first []float64, second []float64) {

	extent := b.Beg + b.Readable
	if extent <= b.N {
		// we fit contiguously in this buffer without wrapping to the other.
		// Let second stay an empty slice.
		return b.A[b.Beg:(b.Beg + b.Readable)], second
	}

	return b.A[b.Beg:b.N], b.A[0:(extent % b.N)]
}

// ReadFloat64():
//
// from bytes.Buffer.Read(): Read reads the next len(p) float64
// pointers from the buffer or until the buffer is drained. The return
// value n is the number of bytes read. If the buffer has no data
// to return, err is io.EOF (unless len(p) is zero); otherwise it is nil.
func (b *Float64RingBuf) ReadFloat64(p []float64) (n int, err error) {
	return b.readAndMaybeAdvance(p, true)
}

// ReadWithoutAdvance(): if you want to Read the data and leave
// it in the buffer, so as to peek ahead for example.
func (b *Float64RingBuf) ReadWithoutAdvance(p []float64) (n int, err error) {
	return b.readAndMaybeAdvance(p, false)
}

func (b *Float64RingBuf) readAndMaybeAdvance(p []float64, doAdvance bool) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	if b.Readable == 0 {
		return 0, io.EOF
	}
	extent := b.Beg + b.Readable
	if extent <= b.N {
		n += copy(p, b.A[b.Beg:extent])
	} else {
		n += copy(p, b.A[b.Beg:b.N])
		if n < len(p) {
			n += copy(p[n:], b.A[0:(extent%b.N)])
		}
	}
	if doAdvance {
		b.Advance(n)
	}
	return
}

//
// WriteAndMaybeOverwriteOldestData always consumes the full
// buffer p, even if that means blowing away the oldest
// unread bytes in the ring to make room. In reality, only the last
// min(len(p),b.N) bytes of p will end up being written to the ring.
//
// This allows the ring to act as a record of the most recent
// b.N bytes of data -- a kind of temporal LRU cache, so the
// speak. The linux kernel's dmesg ring buffer is similar.
//
func (b *Float64RingBuf) WriteAndMaybeOverwriteOldestData(p []float64) (n int, err error) {
	writeCapacity := b.N - b.Readable
	if len(p) > writeCapacity {
		b.Advance(len(p) - writeCapacity)
	}
	startPos := 0
	if len(p) > b.N {
		startPos = len(p) - b.N
	}
	n, err = b.Write(p[startPos:])
	if err != nil {
		return n, err
	}
	return len(p), nil
}

//
// Write writes len(p) float64 values from p to
// the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
//
func (b *Float64RingBuf) Write(p []float64) (n int, err error) {
	for {
		if len(p) == 0 {
			// nothing (left) to copy in; notice we shorten our
			// local copy p (below) as we read from it.
			return
		}

		writeCapacity := b.N - b.Readable
		if writeCapacity <= 0 {
			// we are all full up already.
			return n, io.ErrShortWrite
		}
		if len(p) > writeCapacity {
			err = io.ErrShortWrite
			// leave err set and
			// keep going, write what we can.
		}

		writeStart := (b.Beg + b.Readable) % b.N

		upperLim := intMin(writeStart+writeCapacity, b.N)

		k := copy(b.A[writeStart:upperLim], p)

		n += k
		b.Readable += k
		p = p[k:]

		// we can fill from b.A[0:something] from
		// p's remainder, so loop
	}
}

// Reset quickly forgets any data stored in the ring buffer. The
// data is still there, but the ring buffer will ignore it and
// overwrite those buffers as new data comes in.
func (b *Float64RingBuf) Reset() {
	b.Beg = 0
	b.Readable = 0
}

// Advance(): non-standard, but better than Next(),
// because we don't have to unwrap our buffer and pay the cpu time
// for the copy that unwrapping may need.
// Useful in conjuction/after ReadWithoutAdvance() above.
func (b *Float64RingBuf) Advance(n int) {
	if n <= 0 {
		return
	}
	if n > b.Readable {
		n = b.Readable
	}
	b.Readable -= n
	b.Beg = (b.Beg + n) % b.N
}

// Adopt(): non-standard.
//
// For efficiency's sake, (possibly) take ownership of
// already allocated slice offered in me.
//
// If me is large we will adopt it, and we will potentially then
// write to the me buffer.
// If we already have a bigger buffer, copy me into the existing
// buffer instead.
func (b *Float64RingBuf) Adopt(me []float64) {
	n := len(me)
	if n > b.N {
		b.A = me
		b.N = n
		b.Beg = 0
		b.Readable = n
	} else {
		// we already have a larger buffer, reuse it.
		copy(b.A, me)
		b.Beg = 0
		b.Readable = n
	}
}
<commit_msg>include Earliest<commit_after>package rbuf

// copyright (c) 2016, Jason E. Aten
// license: MIT

import "io"

// Float64RingBuf:
//
//  a fixed-size circular ring buffer of float64
//
type Float64RingBuf struct {
	A        []float64
	N        int // MaxView, the total size of A, whether or not in use.
	Beg      int // start of in-use data in A
	Readable int // number of pointers available in A (in use)
}

// constructor. NewFloat64RingBuf will allocate internally
// a slice of size maxViewInBytes.
func NewFloat64RingBuf(maxViewInBytes int) *Float64RingBuf {
	n := maxViewInBytes
	r := &Float64RingBuf{
		N:        n,
		Beg:      0,
		Readable: 0,
	}
	r.A = make([]float64, n, n)

	return r
}

// TwoContig returns all readable pointers, but in two separate slices,
// to avoid copying. The two slices are from the same buffer, but
// are not contiguous. Either or both may be empty slices.
func (b *Float64RingBuf) TwoContig(makeCopy bool) (first []float64, second []float64) {

	extent := b.Beg + b.Readable
	if extent <= b.N {
		// we fit contiguously in this buffer without wrapping to the other.
		// Let second stay an empty slice.
		return b.A[b.Beg:(b.Beg + b.Readable)], second
	}

	return b.A[b.Beg:b.N], b.A[0:(extent % b.N)]
}

// Earliest returns the earliest written value v. ok will be
// true unless the ring is empty, in which case ok will be false,
// and v will be zero.
func (b *Float64RingBuf) Earliest() (v float64, ok bool) {
	if b.N == 0 {
		return
	}

	extent := b.Beg + b.Readable
	if extent <= b.N {
		return b.A[(b.Beg+b.Readable)-1], true
	}

	// INVAR: extent > b.N, so extent%b.N > 0
	return b.A[(extent%b.N)-1], true
}

// ReadFloat64():
//
// from bytes.Buffer.Read(): Read reads the next len(p) float64
// pointers from the buffer or until the buffer is drained. The return
// value n is the number of bytes read. If the buffer has no data
// to return, err is io.EOF (unless len(p) is zero); otherwise it is nil.
func (b *Float64RingBuf) ReadFloat64(p []float64) (n int, err error) {
	return b.readAndMaybeAdvance(p, true)
}

// ReadWithoutAdvance(): if you want to Read the data and leave
// it in the buffer, so as to peek ahead for example.
func (b *Float64RingBuf) ReadWithoutAdvance(p []float64) (n int, err error) {
	return b.readAndMaybeAdvance(p, false)
}

func (b *Float64RingBuf) readAndMaybeAdvance(p []float64, doAdvance bool) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	if b.Readable == 0 {
		return 0, io.EOF
	}
	extent := b.Beg + b.Readable
	if extent <= b.N {
		n += copy(p, b.A[b.Beg:extent])
	} else {
		n += copy(p, b.A[b.Beg:b.N])
		if n < len(p) {
			n += copy(p[n:], b.A[0:(extent%b.N)])
		}
	}
	if doAdvance {
		b.Advance(n)
	}
	return
}

//
// WriteAndMaybeOverwriteOldestData always consumes the full
// buffer p, even if that means blowing away the oldest
// unread bytes in the ring to make room. In reality, only the last
// min(len(p),b.N) bytes of p will end up being written to the ring.
//
// This allows the ring to act as a record of the most recent
// b.N bytes of data -- a kind of temporal LRU cache, so the
// speak. The linux kernel's dmesg ring buffer is similar.
//
func (b *Float64RingBuf) WriteAndMaybeOverwriteOldestData(p []float64) (n int, err error) {
	writeCapacity := b.N - b.Readable
	if len(p) > writeCapacity {
		b.Advance(len(p) - writeCapacity)
	}
	startPos := 0
	if len(p) > b.N {
		startPos = len(p) - b.N
	}
	n, err = b.Write(p[startPos:])
	if err != nil {
		return n, err
	}
	return len(p), nil
}

//
// Write writes len(p) float64 values from p to
// the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
//
func (b *Float64RingBuf) Write(p []float64) (n int, err error) {
	for {
		if len(p) == 0 {
			// nothing (left) to copy in; notice we shorten our
			// local copy p (below) as we read from it.
			return
		}

		writeCapacity := b.N - b.Readable
		if writeCapacity <= 0 {
			// we are all full up already.
			return n, io.ErrShortWrite
		}
		if len(p) > writeCapacity {
			err = io.ErrShortWrite
			// leave err set and
			// keep going, write what we can.
		}

		writeStart := (b.Beg + b.Readable) % b.N

		upperLim := intMin(writeStart+writeCapacity, b.N)

		k := copy(b.A[writeStart:upperLim], p)

		n += k
		b.Readable += k
		p = p[k:]

		// we can fill from b.A[0:something] from
		// p's remainder, so loop
	}
}

// Reset quickly forgets any data stored in the ring buffer. The
// data is still there, but the ring buffer will ignore it and
// overwrite those buffers as new data comes in.
func (b *Float64RingBuf) Reset() {
	b.Beg = 0
	b.Readable = 0
}

// Advance(): non-standard, but better than Next(),
// because we don't have to unwrap our buffer and pay the cpu time
// for the copy that unwrapping may need.
// Useful in conjuction/after ReadWithoutAdvance() above.
func (b *Float64RingBuf) Advance(n int) {
	if n <= 0 {
		return
	}
	if n > b.Readable {
		n = b.Readable
	}
	b.Readable -= n
	b.Beg = (b.Beg + n) % b.N
}

// Adopt(): non-standard.
//
// For efficiency's sake, (possibly) take ownership of
// already allocated slice offered in me.
//
// If me is large we will adopt it, and we will potentially then
// write to the me buffer.
// If we already have a bigger buffer, copy me into the existing
// buffer instead.
func (b *Float64RingBuf) Adopt(me []float64) {
	n := len(me)
	if n > b.N {
		b.A = me
		b.N = n
		b.Beg = 0
		b.Readable = n
	} else {
		// we already have a larger buffer, reuse it.
		copy(b.A, me)
		b.Beg = 0
		b.Readable = n
	}
}
<|endoftext|>