<commit_before>package node

//IMPORT parts ----------------------------------------------------------
import (
	// ggv "code.google.com/p/gographviz"
	"fmt"
	sender "github.com/tgermain/grandRepositorySky/communicator/sender"
	"github.com/tgermain/grandRepositorySky/dht"
	"github.com/tgermain/grandRepositorySky/shared"
	"sync"
	"time"
)

//Const parts -----------------------------------------------------------
const SPACESIZE = 160
const UPDATEPERIOD = time.Minute
const HEARTBEATPERIOD = time.Second * 10
const HEARBEATTIMEOUT = time.Second * 2
const LOOKUPTIMEOUT = time.Second * 2

//Mutex part -------------------------------------------------------
var mutexSucc = &sync.Mutex{}
var mutexPred = &sync.Mutex{}

//Objects parts ---------------------------------------------------------
type DHTnode struct {
	fingers     []*fingerEntry
	successor   *shared.DistantNode
	predecessor *shared.DistantNode
	commLib     *sender.SenderLink
}

type fingerEntry struct {
	IdKey    string
	nodeResp *shared.DistantNode
}

//Method parts ----------------------------------------------------------

func (currentNode *DHTnode) JoinRing(newNode *shared.DistantNode) {
	currentNode.commLib.SendJoinRing(newNode)
}

func (currentNode *DHTnode) AddToRing(newNode *shared.DistantNode) {
	whereToInsert := currentNode.Lookup(newNode.Id)
	currentNode.commLib.SendUpdateSuccessor(whereToInsert, newNode)
}

//Tell your actual successor that you are no longer its predecessor
//set your succesor to the new value
//tell to your new successor that you are its predecessor
func (d *DHTnode) UpdateSuccessor(newNode *shared.DistantNode) {
	mutexSucc.Lock()
	defer mutexSucc.Unlock()
	//possible TODO : condition on the origin of the message for this sending ?
	if d.successor.Id != newNode.Id {
		// if d.successor.Id != newNode.Id {
		d.commLib.SendUpdatePredecessor(d.successor, newNode)
		// }

		d.successor = newNode
		d.commLib.SendUpdatePredecessor(newNode, d.ToDistantNode())

	} else {
		shared.Logger.Info("Succesor stable !!")
		d.PrintNodeInfo()
	}
}

func (d *DHTnode) UpdatePredecessor(newNode *shared.DistantNode) {
	mutexPred.Lock()
	defer mutexPred.Unlock()
	if d.predecessor.Id != newNode.Id {

		d.predecessor = newNode
		d.commLib.SendUpdateSuccessor(newNode, d.ToDistantNode())
		// d.UpdateFingerTable()

	} else {
		shared.Logger.Info("predecessor stable !!")
		d.PrintNodeInfo()
	}
}

func (currentNode *DHTnode) ToDistantNode() *shared.DistantNode {
	return &shared.DistantNode{
		shared.LocalId,
		shared.LocalIp,
		shared.LocalPort,
	}
}

func (currentNode *DHTnode) IsResponsible(IdToSearch string) bool {
	switch {
	case shared.LocalId == currentNode.GetSuccesor().Id:
		{
			return true
		}
	case dht.Between(shared.LocalId, currentNode.GetSuccesor().Id, IdToSearch):
		{
			return true
		}
	default:
		{
			return false
		}
	}
}

func (currentNode *DHTnode) Lookup(IdToSearch string) *shared.DistantNode {
	shared.Logger.Info("Node [%s] made a lookup to [%s]\n", shared.LocalId, IdToSearch)
	// currentNode.PrintNodeInfo()
	if currentNode.IsResponsible(IdToSearch) {
		//replace with send
		return currentNode.ToDistantNode()
	} else {
		// fmt.Println("go to the next one")
		//TODO use the fingers table here
		responseChan := currentNode.commLib.SendLookup(currentNode.FindClosestNode(IdToSearch), IdToSearch)
		select {
		case res := <-responseChan:
			return &res
		//case of timeout ?
		case <-time.After(LOOKUPTIMEOUT):
			shared.Logger.Error("Lookup for %s timeout", IdToSearch)
			return nil
		}
	}

}

func (currentNode *DHTnode) FindClosestNode(IdToSearch string) *shared.DistantNode {
	bestFinger := currentNode.GetSuccesor()

	minDistance := dht.Distance([]byte(currentNode.GetSuccesor().Id), []byte(IdToSearch), SPACESIZE)
	// fmt.Println("distance successor " + minDistance.String())
	// var bestIndex int
	for _, v := range currentNode.fingers {
		if v != nil {
			if dht.Between(v.nodeResp.Id, shared.LocalId, IdToSearch) {

				//If the finger lead the node to itself, it's not an optimization
				if v.nodeResp.Id != shared.LocalId {

					//if a member of finger table brought closer than the actual one, we udate the value of minDistance and of the chosen finger
					currentDistance := dht.Distance([]byte(v.nodeResp.Id), []byte(IdToSearch), SPACESIZE)

					// x.cmp(y)
					// -1 if x <  y
					//  0 if x == y
					// +1 if x >  y

					if minDistance.Cmp(currentDistance) == 1 {
						fmt.Printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Better finger ellected ! Lookup for [%s] ->[%s] instead of [%s]\n", IdToSearch, v.nodeResp.Id, bestFinger.Id)
						// fmt.Println("Old best distance " + minDistance.String())
						// fmt.Println("New best distance " + currentDistance.String())
						// currentNode.PrintNodeInfo()
						// bestIndex = i
						// v.tmp.PrintNodeInfo()
						minDistance = currentDistance
						bestFinger = v.nodeResp
					}
				}
			}
		}
	}
	// fmt.Printf("From [%s] We have found the bes way to go to [%s] : we go throught finger[%d], [%s]\n", shared.LocalId, IdToSearch, bestIndex, bestFinger.Id)
	return bestFinger
}

func (node *DHTnode) UpdateFingerTable() {
	// fmt.Printf("****************************************************************Node [%s] : init finger table \n", shared.LocalId)
	for i := 0; i < SPACESIZE; i++ {
		// fmt.Printf("Calculatin fingers [%d]\n", i)
		//TODO make a condition to voId to always calculate the fingerId
		fingerId, _ := dht.CalcFinger([]byte(shared.LocalId), i+1, SPACESIZE)
		responsibleNode := node.Lookup(fingerId)
		node.fingers[i] = &fingerEntry{fingerId, &shared.DistantNode{responsibleNode.Id, responsibleNode.Ip, responsibleNode.Port}}

	}
	// fmt.Println("****************************************************************Fingers table init DONE : ")
}

func (node *DHTnode) PrintRing() {
	daString := ""
	node.PrintNodeName(&daString)
	node.commLib.SendPrintRing(node.GetSuccesor(), &daString)
}

func (node *DHTnode) PrintNodeName(currentString *string) {
	*currentString += fmt.Sprintf("%s\n", shared.LocalId)
}

func (node *DHTnode) PrintNodeInfo() {
	shared.Logger.Info("---------------------------------")
	shared.Logger.Info("Node info")
	shared.Logger.Info("---------------------------------")
	shared.Logger.Info("	Id			%s", shared.LocalId)
	shared.Logger.Info("	Ip			%s", shared.LocalIp)
	shared.Logger.Info("	Port		%s", shared.LocalPort)
	shared.Logger.Info(" 	Succesor	%s", node.successor.Id)
	shared.Logger.Info(" 	Predecesor	%s", node.predecessor.Id)
	// fmt.Println("  Fingers table :")
	// fmt.Println("  ---------------------------------")
	// fmt.Println("  Index		Idkey			IdNode ")
	// for i, v := range node.fingers {
	// 	if v != nil {
	// 		fmt.Printf("  %d 		%s					%s\n", i, v.IdKey, v.IdResp)
	// 	}
	// }
	shared.Logger.Info("---------------------------------")
}

// func (node *DHTnode) gimmeGraph(g *ggv.Graph, firstNodeId *string) string {
// 	if &shared.LocalId == firstNodeId {
// 		return g.String()
// 	} else {
// 		if g == nil {
// 			g = ggv.NewGraph()
// 			g.SetName("DHTRing")
// 			g.SetDir(true)
// 		}
// 		if firstNodeId == nil {
// 			firstNodeId = &shared.LocalId
// 		}
// 		g.AddNode(g.Name, shared.LocalId, nil)
// 		g.AddNode(g.Name, node.successor.Id, nil)
// 		g.AddNode(g.Name, node.predecessor.Id, nil)
// 		// g.AddEdge(shared.LocalId, node.successor.Id, true, map[string]string{
// 		// 	"label": "succ",
// 		// })
// 		// g.AddEdge(shared.LocalId, node.predecessor.Id, true, map[string]string{
// 		// 	"label": "pred",
// 		// })

// 		for i, v := range node.fingers {
// 			g.AddEdge(shared.LocalId, v.IdKey, true, map[string]string{
// 				"label":         fmt.Sprintf("\"%s.%d\"", shared.LocalId, i),
// 				"label_scheme":  "3",
// 				"decorate":      "true",
// 				"labelfontsize": "5.0",
// 				"labelfloat":    "true",
// 				"color":         "blue",
// 			})
// 		}

// 		//recursion !
// 		//TODO successor.tmp not accessible anymore later
// 		return node.successor.tmp.gimmeGraph(g, firstNodeId)

// 	}
// }

func (d *DHTnode) GetSuccesor() *shared.DistantNode {
	mutexSucc.Lock()
	defer mutexSucc.Unlock()
	temp := *d.successor
	return &temp
}

func (d *DHTnode) GetPredecessor() *shared.DistantNode {
	mutexPred.Lock()
	defer mutexPred.Unlock()
	temp := *d.predecessor
	return &temp
}

func (d *DHTnode) GetFingerTable() []*fingerEntry {
	temp := d.fingers
	return temp
}
func (d *DHTnode) updateFingersRoutine() {
	shared.Logger.Info("Starting update fingers table routing")
	for {
		time.Sleep(UPDATEPERIOD)
		shared.Logger.Info("Auto updating finger table of node %s", shared.LocalId)
		d.UpdateFingerTable()
	}
}

func (d *DHTnode) heartBeatRoutine() {
	shared.Logger.Info("Starting heartBeat routing")
	for {
		time.Sleep(HEARTBEATPERIOD)
		d.sendHeartBeat(d.GetSuccesor())
	}
}

func (d *DHTnode) sendHeartBeat(destination *shared.DistantNode) {

	responseChan := d.commLib.SendHeartBeat(d.GetSuccesor())
	select {
	case <-responseChan:
		{
			//Everything this node is alive. Do nothing more
		}
	//case of timeout ?
	case <-time.After(HEARBEATTIMEOUT):
		shared.Logger.Error("heartBeat to %s timeout", destination.Id)
		//DANGER
	}
}

//other functions parts --------------------------------------------------------
//Create the node with it's communication interface
//Does not start to liten for message
func MakeNode() (*DHTnode, *sender.SenderLink) {
	daComInterface := sender.NewSenderLink()
	daNode := DHTnode{
		fingers: make([]*fingerEntry, SPACESIZE),
		commLib: daComInterface,
	}
	mySelf := daNode.ToDistantNode()
	daNode.successor = mySelf

	daNode.predecessor = mySelf
	// initialization of fingers table is done while adding the node to the ring
	// The fingers table of the first node of a ring is initialized when a second node is added to the ring

	//Initialize the finger table with each finger pointing to the node frehly created itself
	shared.Logger.Info("New node [%.5s] createde", shared.LocalId)
	go daNode.heartBeatRoutine()
	go daNode.updateFingersRoutine()

	return &daNode, daComInterface
}
<commit_msg>Deal with the lookup timeout error<commit_after>package node

//IMPORT parts ----------------------------------------------------------
import (
	// ggv "code.google.com/p/gographviz"
	"fmt"
	sender "github.com/tgermain/grandRepositorySky/communicator/sender"
	"github.com/tgermain/grandRepositorySky/dht"
	"github.com/tgermain/grandRepositorySky/shared"
	"sync"
	"time"
)

//Const parts -----------------------------------------------------------
const SPACESIZE = 160
const UPDATEPERIOD = time.Minute
const HEARTBEATPERIOD = time.Second * 10
const HEARBEATTIMEOUT = time.Second * 2
const LOOKUPTIMEOUT = time.Second * 2

//Mutex part -------------------------------------------------------
var mutexSucc = &sync.Mutex{}
var mutexPred = &sync.Mutex{}

//Objects parts ---------------------------------------------------------
type DHTnode struct {
	fingers     []*fingerEntry
	successor   *shared.DistantNode
	predecessor *shared.DistantNode
	commLib     *sender.SenderLink
}

type fingerEntry struct {
	IdKey    string
	nodeResp *shared.DistantNode
}

//Method parts ----------------------------------------------------------

func (currentNode *DHTnode) JoinRing(newNode *shared.DistantNode) {
	currentNode.commLib.SendJoinRing(newNode)
}

func (currentNode *DHTnode) AddToRing(newNode *shared.DistantNode) {
	whereToInsert := currentNode.Lookup(newNode.Id)
	if whereToInsert != nil {
		currentNode.commLib.SendUpdateSuccessor(whereToInsert, newNode)
	} else {
		shared.Logger.Error("Add to ring of %s fail due to a lookup timeout", newNode.Id)
	}
}

//Tell your actual successor that you are no longer its predecessor
//set your succesor to the new value
//tell to your new successor that you are its predecessor
func (d *DHTnode) UpdateSuccessor(newNode *shared.DistantNode) {
	mutexSucc.Lock()
	defer mutexSucc.Unlock()
	//possible TODO : condition on the origin of the message for this sending ?
	if d.successor.Id != newNode.Id {
		// if d.successor.Id != newNode.Id {
		d.commLib.SendUpdatePredecessor(d.successor, newNode)
		// }

		d.successor = newNode
		d.commLib.SendUpdatePredecessor(newNode, d.ToDistantNode())

	} else {
		shared.Logger.Info("Succesor stable !!")
		d.PrintNodeInfo()
	}
}

func (d *DHTnode) UpdatePredecessor(newNode *shared.DistantNode) {
	mutexPred.Lock()
	defer mutexPred.Unlock()
	if d.predecessor.Id != newNode.Id {

		d.predecessor = newNode
		d.commLib.SendUpdateSuccessor(newNode, d.ToDistantNode())
		// d.UpdateFingerTable()

	} else {
		shared.Logger.Info("predecessor stable !!")
		d.PrintNodeInfo()
	}
}

func (currentNode *DHTnode) ToDistantNode() *shared.DistantNode {
	return &shared.DistantNode{
		shared.LocalId,
		shared.LocalIp,
		shared.LocalPort,
	}
}

func (currentNode *DHTnode) IsResponsible(IdToSearch string) bool {
	switch {
	case shared.LocalId == currentNode.GetSuccesor().Id:
		{
			return true
		}
	case dht.Between(shared.LocalId, currentNode.GetSuccesor().Id, IdToSearch):
		{
			return true
		}
	default:
		{
			return false
		}
	}
}

func (currentNode *DHTnode) Lookup(IdToSearch string) *shared.DistantNode {
	shared.Logger.Info("Node [%s] made a lookup to [%s]\n", shared.LocalId, IdToSearch)
	// currentNode.PrintNodeInfo()
	if currentNode.IsResponsible(IdToSearch) {
		//replace with send
		return currentNode.ToDistantNode()
	} else {
		// fmt.Println("go to the next one")
		//TODO use the fingers table here
		responseChan := currentNode.commLib.SendLookup(currentNode.FindClosestNode(IdToSearch), IdToSearch)
		select {
		case res := <-responseChan:
			return &res
		//case of timeout ?
		case <-time.After(LOOKUPTIMEOUT):
			shared.Logger.Error("Lookup for %s timeout", IdToSearch)
			return nil
		}
	}

}

func (currentNode *DHTnode) FindClosestNode(IdToSearch string) *shared.DistantNode {
	bestFinger := currentNode.GetSuccesor()

	minDistance := dht.Distance([]byte(currentNode.GetSuccesor().Id), []byte(IdToSearch), SPACESIZE)
	// fmt.Println("distance successor " + minDistance.String())
	// var bestIndex int
	for _, v := range currentNode.fingers {
		if v != nil {
			if dht.Between(v.nodeResp.Id, shared.LocalId, IdToSearch) {

				//If the finger lead the node to itself, it's not an optimization
				if v.nodeResp.Id != shared.LocalId {

					//if a member of finger table brought closer than the actual one, we udate the value of minDistance and of the chosen finger
					currentDistance := dht.Distance([]byte(v.nodeResp.Id), []byte(IdToSearch), SPACESIZE)

					// x.cmp(y)
					// -1 if x <  y
					//  0 if x == y
					// +1 if x >  y

					if minDistance.Cmp(currentDistance) == 1 {
						fmt.Printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Better finger ellected ! Lookup for [%s] ->[%s] instead of [%s]\n", IdToSearch, v.nodeResp.Id, bestFinger.Id)
						// fmt.Println("Old best distance " + minDistance.String())
						// fmt.Println("New best distance " + currentDistance.String())
						// currentNode.PrintNodeInfo()
						// bestIndex = i
						// v.tmp.PrintNodeInfo()
						minDistance = currentDistance
						bestFinger = v.nodeResp
					}
				}
			}
		}
	}
	// fmt.Printf("From [%s] We have found the bes way to go to [%s] : we go throught finger[%d], [%s]\n", shared.LocalId, IdToSearch, bestIndex, bestFinger.Id)
	return bestFinger
}

func (node *DHTnode) UpdateFingerTable() {
	// fmt.Printf("****************************************************************Node [%s] : init finger table \n", shared.LocalId)
	for i := 0; i < SPACESIZE; i++ {
		// fmt.Printf("Calculatin fingers [%d]\n", i)
		//TODO make a condition to voId to always calculate the fingerId
		fingerId, _ := dht.CalcFinger([]byte(shared.LocalId), i+1, SPACESIZE)
		responsibleNode := node.Lookup(fingerId)
		if responsibleNode != nil {

			node.fingers[i] = &fingerEntry{fingerId, &shared.DistantNode{responsibleNode.Id, responsibleNode.Ip, responsibleNode.Port}}
		} else {
			shared.Logger.Error("Update of finger %d fail due to a lookup timeout", i)
		}

	}
	// fmt.Println("****************************************************************Fingers table init DONE : ")
}

func (node *DHTnode) PrintRing() {
	daString := ""
	node.PrintNodeName(&daString)
	node.commLib.SendPrintRing(node.GetSuccesor(), &daString)
}

func (node *DHTnode) PrintNodeName(currentString *string) {
	*currentString += fmt.Sprintf("%s\n", shared.LocalId)
}

func (node *DHTnode) PrintNodeInfo() {
	shared.Logger.Info("---------------------------------")
	shared.Logger.Info("Node info")
	shared.Logger.Info("---------------------------------")
	shared.Logger.Info("	Id			%s", shared.LocalId)
	shared.Logger.Info("	Ip			%s", shared.LocalIp)
	shared.Logger.Info("	Port		%s", shared.LocalPort)
	shared.Logger.Info(" 	Succesor	%s", node.successor.Id)
	shared.Logger.Info(" 	Predecesor	%s", node.predecessor.Id)
	// fmt.Println("  Fingers table :")
	// fmt.Println("  ---------------------------------")
	// fmt.Println("  Index		Idkey			IdNode ")
	// for i, v := range node.fingers {
	// 	if v != nil {
	// 		fmt.Printf("  %d 		%s					%s\n", i, v.IdKey, v.IdResp)
	// 	}
	// }
	shared.Logger.Info("---------------------------------")
}

// func (node *DHTnode) gimmeGraph(g *ggv.Graph, firstNodeId *string) string {
// 	if &shared.LocalId == firstNodeId {
// 		return g.String()
// 	} else {
// 		if g == nil {
// 			g = ggv.NewGraph()
// 			g.SetName("DHTRing")
// 			g.SetDir(true)
// 		}
// 		if firstNodeId == nil {
// 			firstNodeId = &shared.LocalId
// 		}
// 		g.AddNode(g.Name, shared.LocalId, nil)
// 		g.AddNode(g.Name, node.successor.Id, nil)
// 		g.AddNode(g.Name, node.predecessor.Id, nil)
// 		// g.AddEdge(shared.LocalId, node.successor.Id, true, map[string]string{
// 		// 	"label": "succ",
// 		// })
// 		// g.AddEdge(shared.LocalId, node.predecessor.Id, true, map[string]string{
// 		// 	"label": "pred",
// 		// })

// 		for i, v := range node.fingers {
// 			g.AddEdge(shared.LocalId, v.IdKey, true, map[string]string{
// 				"label":         fmt.Sprintf("\"%s.%d\"", shared.LocalId, i),
// 				"label_scheme":  "3",
// 				"decorate":      "true",
// 				"labelfontsize": "5.0",
// 				"labelfloat":    "true",
// 				"color":         "blue",
// 			})
// 		}

// 		//recursion !
// 		//TODO successor.tmp not accessible anymore later
// 		return node.successor.tmp.gimmeGraph(g, firstNodeId)

// 	}
// }

func (d *DHTnode) GetSuccesor() *shared.DistantNode {
	mutexSucc.Lock()
	defer mutexSucc.Unlock()
	temp := *d.successor
	return &temp
}

func (d *DHTnode) GetPredecessor() *shared.DistantNode {
	mutexPred.Lock()
	defer mutexPred.Unlock()
	temp := *d.predecessor
	return &temp
}

func (d *DHTnode) GetFingerTable() []*fingerEntry {
	temp := d.fingers
	return temp
}
func (d *DHTnode) updateFingersRoutine() {
	shared.Logger.Info("Starting update fingers table routing")
	for {
		time.Sleep(UPDATEPERIOD)
		shared.Logger.Info("Auto updating finger table of node %s", shared.LocalId)
		d.UpdateFingerTable()
	}
}

func (d *DHTnode) heartBeatRoutine() {
	shared.Logger.Info("Starting heartBeat routing")
	for {
		time.Sleep(HEARTBEATPERIOD)
		d.sendHeartBeat(d.GetSuccesor())
	}
}

func (d *DHTnode) sendHeartBeat(destination *shared.DistantNode) {

	responseChan := d.commLib.SendHeartBeat(d.GetSuccesor())
	select {
	case <-responseChan:
		{
			//Everything this node is alive. Do nothing more
		}
	//case of timeout ?
	case <-time.After(HEARBEATTIMEOUT):
		shared.Logger.Error("heartBeat to %s timeout", destination.Id)
		//DANGER
	}
}

//other functions parts --------------------------------------------------------
//Create the node with it's communication interface
//Does not start to liten for message
func MakeNode() (*DHTnode, *sender.SenderLink) {
	daComInterface := sender.NewSenderLink()
	daNode := DHTnode{
		fingers: make([]*fingerEntry, SPACESIZE),
		commLib: daComInterface,
	}
	mySelf := daNode.ToDistantNode()
	daNode.successor = mySelf

	daNode.predecessor = mySelf
	// initialization of fingers table is done while adding the node to the ring
	// The fingers table of the first node of a ring is initialized when a second node is added to the ring

	//Initialize the finger table with each finger pointing to the node frehly created itself
	shared.Logger.Info("New node [%.5s] createde", shared.LocalId)
	go daNode.heartBeatRoutine()
	go daNode.updateFingersRoutine()

	return &daNode, daComInterface
}
<|endoftext|>


<commit_before>package samlsp

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"time"

	"github.com/dgrijalva/jwt-go"

	"github.com/crewjam/saml"
)

const defaultSessionMaxAge = time.Hour

// JWTSessionCodec implements SessionCoded to encode and decode Sessions from
// the corresponding JWT.
type JWTSessionCodec struct {
	SigningMethod jwt.SigningMethod
	Audience      string
	Issuer        string
	MaxAge        time.Duration
	Key           *rsa.PrivateKey
}

var _ SessionCodec = JWTSessionCodec{}

// New creates a Session from the SAML assertion.
//
// The returned Session is a JWTSessionClaims.
func (c JWTSessionCodec) New(assertion *saml.Assertion) (Session, error) {
	now := saml.TimeNow()
	claims := JWTSessionClaims{}
	claims.SAMLSession = true
	claims.Audience = c.Audience
	claims.Issuer = c.Issuer
	claims.IssuedAt = now.Unix()
	claims.ExpiresAt = now.Add(c.MaxAge).Unix()
	claims.NotBefore = now.Unix()
	if sub := assertion.Subject; sub != nil {
		if nameID := sub.NameID; nameID != nil {
			claims.Subject = nameID.Value
		}
	}
	for _, attributeStatement := range assertion.AttributeStatements {
		claims.Attributes = map[string][]string{}
		for _, attr := range attributeStatement.Attributes {
			claimName := attr.FriendlyName
			if claimName == "" {
				claimName = attr.Name
			}
			for _, value := range attr.Values {
				claims.Attributes[claimName] = append(claims.Attributes[claimName], value.Value)
			}
		}
	}

	return claims, nil
}

// Encode returns a serialized version of the Session.
//
// The provided session must be a JWTSessionClaims, otherwise this
// function will panic.
func (c JWTSessionCodec) Encode(s Session) (string, error) {
	claims := s.(JWTSessionClaims) // this will panic if you pass the wrong kind of session

	token := jwt.NewWithClaims(c.SigningMethod, claims)
	signedString, err := token.SignedString(c.Key)
	if err != nil {
		return "", err
	}

	return signedString, nil
}

// Decode parses the serialized session that may have been returned by Encode
// and returns a Session.
func (c JWTSessionCodec) Decode(signed string) (Session, error) {
	parser := jwt.Parser{
		ValidMethods: []string{c.SigningMethod.Alg()},
	}
	claims := JWTSessionClaims{}
	_, err := parser.ParseWithClaims(signed, &claims, func(*jwt.Token) (interface{}, error) {
		return c.Key.Public(), nil
	})
	// TODO(ross): check for errors due to bad time and return ErrNoSession
	if err != nil {
		return nil, err
	}
	if !claims.VerifyAudience(c.Audience, true) {
		return nil, fmt.Errorf("expected audience %q, got %q", c.Audience, claims.Audience)
	}
	if !claims.VerifyIssuer(c.Issuer, true) {
		return nil, fmt.Errorf("expected issuer %q, got %q", c.Issuer, claims.Issuer)
	}
	if claims.SAMLSession != true {
		return nil, errors.New("expected saml-session")
	}
	return claims, nil
}

// JWTSessionClaims represents the JWT claims in the encoded session
type JWTSessionClaims struct {
	jwt.StandardClaims
	Attributes  Attributes `json:"attr"`
	SAMLSession bool       `json:"saml-session"`
}

var _ Session = JWTSessionClaims{}

// GetAttributes implements SessionWithAttributes. It returns the SAMl attributes.
func (c JWTSessionClaims) GetAttributes() Attributes {
	return c.Attributes
}

// Attributes is a map of attributes provided in the SAML assertion
type Attributes map[string][]string

// Get returns the first attribute named `key` or an empty string if
// no such attributes is present.
func (a Attributes) Get(key string) string {
	if a == nil {
		return ""
	}
	v := a[key]
	if len(v) == 0 {
		return ""
	}
	return v[0]
}
<commit_msg>add SessionIndex to claims Attributes<commit_after>package samlsp

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"time"

	"github.com/dgrijalva/jwt-go"

	"github.com/crewjam/saml"
)

const (
	defaultSessionMaxAge  = time.Hour
	claimNameSessionIndex = "SessionIndex"
)

// JWTSessionCodec implements SessionCoded to encode and decode Sessions from
// the corresponding JWT.
type JWTSessionCodec struct {
	SigningMethod jwt.SigningMethod
	Audience      string
	Issuer        string
	MaxAge        time.Duration
	Key           *rsa.PrivateKey
}

var _ SessionCodec = JWTSessionCodec{}

// New creates a Session from the SAML assertion.
//
// The returned Session is a JWTSessionClaims.
func (c JWTSessionCodec) New(assertion *saml.Assertion) (Session, error) {
	now := saml.TimeNow()
	claims := JWTSessionClaims{}
	claims.SAMLSession = true
	claims.Audience = c.Audience
	claims.Issuer = c.Issuer
	claims.IssuedAt = now.Unix()
	claims.ExpiresAt = now.Add(c.MaxAge).Unix()
	claims.NotBefore = now.Unix()

	if sub := assertion.Subject; sub != nil {
		if nameID := sub.NameID; nameID != nil {
			claims.Subject = nameID.Value
		}
	}

	claims.Attributes = map[string][]string{}

	for _, attributeStatement := range assertion.AttributeStatements {
		for _, attr := range attributeStatement.Attributes {
			claimName := attr.FriendlyName
			if claimName == "" {
				claimName = attr.Name
			}
			for _, value := range attr.Values {
				claims.Attributes[claimName] = append(claims.Attributes[claimName], value.Value)
			}
		}
	}

	// add SessionIndex to claims Attributes
	for _, authnStatement := range assertion.AuthnStatements {
		claims.Attributes[claimNameSessionIndex] = append(claims.Attributes[claimNameSessionIndex],
			authnStatement.SessionIndex)
	}

	return claims, nil
}

// Encode returns a serialized version of the Session.
//
// The provided session must be a JWTSessionClaims, otherwise this
// function will panic.
func (c JWTSessionCodec) Encode(s Session) (string, error) {
	claims := s.(JWTSessionClaims) // this will panic if you pass the wrong kind of session

	token := jwt.NewWithClaims(c.SigningMethod, claims)
	signedString, err := token.SignedString(c.Key)
	if err != nil {
		return "", err
	}

	return signedString, nil
}

// Decode parses the serialized session that may have been returned by Encode
// and returns a Session.
func (c JWTSessionCodec) Decode(signed string) (Session, error) {
	parser := jwt.Parser{
		ValidMethods: []string{c.SigningMethod.Alg()},
	}
	claims := JWTSessionClaims{}
	_, err := parser.ParseWithClaims(signed, &claims, func(*jwt.Token) (interface{}, error) {
		return c.Key.Public(), nil
	})
	// TODO(ross): check for errors due to bad time and return ErrNoSession
	if err != nil {
		return nil, err
	}
	if !claims.VerifyAudience(c.Audience, true) {
		return nil, fmt.Errorf("expected audience %q, got %q", c.Audience, claims.Audience)
	}
	if !claims.VerifyIssuer(c.Issuer, true) {
		return nil, fmt.Errorf("expected issuer %q, got %q", c.Issuer, claims.Issuer)
	}
	if claims.SAMLSession != true {
		return nil, errors.New("expected saml-session")
	}
	return claims, nil
}

// JWTSessionClaims represents the JWT claims in the encoded session
type JWTSessionClaims struct {
	jwt.StandardClaims
	Attributes  Attributes `json:"attr"`
	SAMLSession bool       `json:"saml-session"`
}

var _ Session = JWTSessionClaims{}

// GetAttributes implements SessionWithAttributes. It returns the SAMl attributes.
func (c JWTSessionClaims) GetAttributes() Attributes {
	return c.Attributes
}

// Attributes is a map of attributes provided in the SAML assertion
type Attributes map[string][]string

// Get returns the first attribute named `key` or an empty string if
// no such attributes is present.
func (a Attributes) Get(key string) string {
	if a == nil {
		return ""
	}
	v := a[key]
	if len(v) == 0 {
		return ""
	}
	return v[0]
}
<|endoftext|>


<commit_before>package yenc

import (
	"bufio"
	"bytes"
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	"log"
	"strconv"
)

const (
	keywordLine = "=y"
	headerLine  = "begin"
	partLine    = "part"
	trailerLine = "end"

	byteOffset    byte = 42
	specialOffset byte = 64
)

var (
	keywordBytes = []byte(keywordLine)
	headerBytes  = []byte(headerLine)
	partBytes    = []byte(partLine)
	trailerBytes = []byte(trailerLine)
)

//Error constants
var (
	ErrBadCRC    = fmt.Errorf("CRC check error")
	ErrWrongSize = fmt.Errorf("size check error")
)

//Reader implements the io.Reader methods for an underlying YENC
//document/stream. It additionally exposes some of the metadata that may be
//useful for consumers.
type Reader struct {
	br         *bufio.Reader
	begun, eof bool

	Length          int
	CRC             hash.Hash32
	Headers, Footer *Header
}

//NewReader returns a reader from an input reader.
func NewReader(r io.Reader) *Reader {
	return &Reader{
		br:  bufio.NewReader(r),
		CRC: crc32.New(crc32.IEEETable),
	}
}

func (d *Reader) Read(p []byte) (bytesRead int, err error) {
	defer func() {
		d.Length += bytesRead
	}()

	if d.eof {
		return
	}

	var n int
	n, err = d.br.Read(p)

	if err != nil && err != io.EOF {
		return
	}

	lp := len(p)

	var offset int
	var b byte

	//i points at current byte. i-offset is where the current byte should go.
readLoop:
	for i := 0; i < n; i++ {
		b = p[i]
		switch b {
		case '\r':
			if lp < i+1 {
				return
			}

			if p[i+1] == '\n' {
				//Skip next byte
				i++
				//Set insert position 2 back
				offset += 2
				//Skip this byte
				continue readLoop
			}
			break
		case escape:
			if len(p) < i+1 {
				log.Fatal("Ooops")
			}

			if p[i+1] == 'y' {
				var len int
				len, err = d.checkKeywordLine(p[i:])
				if err != nil {
					return
				}

				//Set offset len back
				offset += len
				//Skip all len bytes
				i += len
				continue readLoop
			}

			//Read next byte
			i++
			b = p[i]

			b -= specialOffset
		}

		if !d.begun {
			continue readLoop
		}

		p[i-offset] = b - byteOffset
		d.CRC.Write(p[bytesRead : bytesRead+1])
		bytesRead++
	}

	return
}

func (d *Reader) checkKeywordLine(bs []byte) (n int, err error) {
	if beginsWith(bs, headerBytes) || beginsWith(bs, partBytes) {
		d.begun = true

		var h *Header
		h, n = ReadYENCHeader(bs)
		d.Headers = h
		return
	}

	if beginsWith(bs, trailerBytes) {
		d.eof = true

		if n, err = d.checkTrailer(bs); err != nil {
			return
		}

		if err == nil {
			err = io.EOF
		}
	}

	return
}

func beginsWith(l, c []byte) bool {
	return len(l) >= len(c) && bytes.Equal(c, l[:len(c)])
}

func (d *Reader) checkTrailer(l []byte) (int, error) {
	f, n := ReadYENCHeader(l)

	d.Footer = f
	preCrc := d.Footer.Get("pcrc32")

	if preCrc == "" {
		return n, nil
	}

	i, err := strconv.ParseUint(preCrc, 16, 0)
	if err != nil {
		return n, fmt.Errorf("error parsing uint: %v", err)
	}

	length, err := strconv.Atoi(d.Footer.Get("size"))

	if err != nil && length != d.Length {
		return n, ErrWrongSize
	}

	sum := d.CRC.Sum32()
	if sum != uint32(i) {
		return n, ErrBadCRC
	}

	return n, nil
}
<commit_msg>Update crc for faster write<commit_after>package yenc

import (
	"bufio"
	"bytes"
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	"strconv"
)

const (
	keywordLine = "=y"
	headerLine  = "begin"
	partLine    = "part"
	trailerLine = "end"

	byteOffset    byte = 42
	specialOffset byte = 64
)

var (
	keywordBytes = []byte(keywordLine)
	headerBytes  = []byte(headerLine)
	partBytes    = []byte(partLine)
	trailerBytes = []byte(trailerLine)
)

//Error constants
var (
	ErrBadCRC    = fmt.Errorf("CRC check error")
	ErrWrongSize = fmt.Errorf("size check error")
)

//Reader implements the io.Reader methods for an underlying YENC
//document/stream. It additionally exposes some of the metadata that may be
//useful for consumers.
type Reader struct {
	br         *bufio.Reader
	begun, eof bool

	Length          int
	CRC             hash.Hash32
	Headers, Footer *Header
}

//NewReader returns a reader from an input reader.
func NewReader(r io.Reader) *Reader {
	return &Reader{
		br:  bufio.NewReader(r),
		CRC: crc32.New(crc32.IEEETable),
	}
}

func (d *Reader) Read(p []byte) (bytesRead int, err error) {
	defer func() {
		d.Length += bytesRead
	}()

	if d.eof {
		return
	}

	var n int
	n, err = d.br.Read(p)

	if err != nil && err != io.EOF {
		return
	}

	lp := len(p)

	var offset int
	var b byte

	//i points at current byte. i-offset is where the current byte should go.
readLoop:
	for i := 0; i < n; i++ {
		b = p[i]
		switch b {
		case '\r':
			if lp < i+1 {
				return
			}

			if p[i+1] == '\n' {
				//Skip next byte
				i++
				//Set insert position 2 back
				offset += 2
				//Skip this byte
				continue readLoop
			}
		case escape:
			if lp < i+2 {
				return
			}
			if p[i+1] == 'y' {
				var len int
				len, err = d.checkKeywordLine(p[i:])
				if err != nil {
					return
				}

				//Set offset len back
				offset += len
				//Skip all len bytes
				i += len
				continue readLoop
			}

			//Read next byte
			i++
			b = p[i]

			b -= specialOffset
		}

		if !d.begun {
			continue readLoop
		}

		p[i-offset] = b - byteOffset
		d.CRC.Write(p[:bytesRead+1])
		bytesRead++
	}

	return
}

func (d *Reader) checkKeywordLine(bs []byte) (n int, err error) {
	if beginsWith(bs, headerBytes) || beginsWith(bs, partBytes) {
		d.begun = true

		var h *Header
		h, n = ReadYENCHeader(bs)
		d.Headers = h
		return
	}

	if beginsWith(bs, trailerBytes) {
		d.eof = true

		if n, err = d.checkTrailer(bs); err != nil {
			return
		}

		if err == nil {
			err = io.EOF
		}
	}

	return
}

func beginsWith(l, c []byte) bool {
	return len(l) >= len(c) && bytes.Equal(c, l[:len(c)])
}

func (d *Reader) checkTrailer(l []byte) (int, error) {
	f, n := ReadYENCHeader(l)

	d.Footer = f
	preCrc := d.Footer.Get("pcrc32")

	if preCrc == "" {
		return n, nil
	}

	i, err := strconv.ParseUint(preCrc, 16, 0)
	if err != nil {
		return n, fmt.Errorf("error parsing uint: %v", err)
	}

	length, err := strconv.Atoi(d.Footer.Get("size"))

	if err != nil && length != d.Length {
		return n, ErrWrongSize
	}

	sum := d.CRC.Sum32()
	if sum != uint32(i) {
		return n, ErrBadCRC
	}

	return n, nil
}
<|endoftext|>


<commit_before>package brotli

import (
	"errors"
	"io"
)

type decodeError int

func (err decodeError) Error() string {
	return "brotli: " + string(decoderErrorString(int(err)))
}

var errExcessiveInput = errors.New("brotli: excessive input")
var errInvalidState = errors.New("brotli: invalid state")
var errReaderClosed = errors.New("brotli: Reader is closed")

// readBufSize is a "good" buffer size that avoids excessive round-trips
// between C and Go but doesn't waste too much memory on buffering.
// It is arbitrarily chosen to be equal to the constant used in io.Copy.
const readBufSize = 32 * 1024

// NewReader initializes new Reader instance.
func NewReader(src io.Reader) *Reader {
	r := new(Reader)
	decoderStateInit(r)
	r.src = src
	r.buf = make([]byte, readBufSize)
	return r
}

func (r *Reader) Read(p []byte) (n int, err error) {
	if !decoderHasMoreOutput(r) && len(r.in) == 0 {
		m, readErr := r.src.Read(r.buf)
		if m == 0 {
			// If readErr is `nil`, we just proxy underlying stream behavior.
			return 0, readErr
		}
		r.in = r.buf[:m]
	}

	if len(p) == 0 {
		return 0, nil
	}

	for {
		var written uint
		in_len := uint(len(r.in))
		out_len := uint(len(p))
		in_remaining := in_len
		out_remaining := out_len
		result := decoderDecompressStream(r, &in_remaining, &r.in, &out_remaining, &p)
		written = out_len - out_remaining
		n = int(written)

		switch result {
		case decoderResultSuccess:
			if len(r.in) > 0 {
				return n, errExcessiveInput
			}
			return n, nil
		case decoderResultError:
			return n, decodeError(decoderGetErrorCode(r))
		case decoderResultNeedsMoreOutput:
			if n == 0 {
				return 0, io.ErrShortBuffer
			}
			return n, nil
		case decoderNeedsMoreInput:
		}

		if len(r.in) != 0 {
			return 0, errInvalidState
		}

		// Calling r.src.Read may block. Don't block if we have data to return.
		if n > 0 {
			return n, nil
		}

		// Top off the buffer.
		encN, err := r.src.Read(r.buf)
		if encN == 0 {
			// Not enough data to complete decoding.
			if err == io.EOF {
				return 0, io.ErrUnexpectedEOF
			}
			return 0, err
		}
		r.in = r.buf[:encN]
	}
}
<commit_msg>Removed unused error<commit_after>package brotli

import (
	"errors"
	"io"
)

type decodeError int

func (err decodeError) Error() string {
	return "brotli: " + string(decoderErrorString(int(err)))
}

var errExcessiveInput = errors.New("brotli: excessive input")
var errInvalidState = errors.New("brotli: invalid state")

// readBufSize is a "good" buffer size that avoids excessive round-trips
// between C and Go but doesn't waste too much memory on buffering.
// It is arbitrarily chosen to be equal to the constant used in io.Copy.
const readBufSize = 32 * 1024

// NewReader initializes new Reader instance.
func NewReader(src io.Reader) *Reader {
	r := new(Reader)
	decoderStateInit(r)
	r.src = src
	r.buf = make([]byte, readBufSize)
	return r
}

func (r *Reader) Read(p []byte) (n int, err error) {
	if !decoderHasMoreOutput(r) && len(r.in) == 0 {
		m, readErr := r.src.Read(r.buf)
		if m == 0 {
			// If readErr is `nil`, we just proxy underlying stream behavior.
			return 0, readErr
		}
		r.in = r.buf[:m]
	}

	if len(p) == 0 {
		return 0, nil
	}

	for {
		var written uint
		in_len := uint(len(r.in))
		out_len := uint(len(p))
		in_remaining := in_len
		out_remaining := out_len
		result := decoderDecompressStream(r, &in_remaining, &r.in, &out_remaining, &p)
		written = out_len - out_remaining
		n = int(written)

		switch result {
		case decoderResultSuccess:
			if len(r.in) > 0 {
				return n, errExcessiveInput
			}
			return n, nil
		case decoderResultError:
			return n, decodeError(decoderGetErrorCode(r))
		case decoderResultNeedsMoreOutput:
			if n == 0 {
				return 0, io.ErrShortBuffer
			}
			return n, nil
		case decoderNeedsMoreInput:
		}

		if len(r.in) != 0 {
			return 0, errInvalidState
		}

		// Calling r.src.Read may block. Don't block if we have data to return.
		if n > 0 {
			return n, nil
		}

		// Top off the buffer.
		encN, err := r.src.Read(r.buf)
		if encN == 0 {
			// Not enough data to complete decoding.
			if err == io.EOF {
				return 0, io.ErrUnexpectedEOF
			}
			return 0, err
		}
		r.in = r.buf[:encN]
	}
}
<|endoftext|>


<commit_before>// Package vcfgo implements a Reader and Writer for variant call format.
// It eases reading, filtering modifying VCF's even if they are not to spec.
// Example:
//  f, _ := os.Open("examples/test.auto_dom.no_parents.vcf")
//  rdr, err := vcfgo.NewReader(f)
//  if err != nil {
//  	panic(err)
//  }
//  for {
//  	variant := rdr.Read()
//  	if variant == nil {
//  		break
//  	}
//  	fmt.Printf("%s\t%d\t%s\t%s\n", variant.Chromosome, variant.Pos, variant.Ref, variant.Alt)
//  	fmt.Printf("%s", variant.Info["DP"].(int) > 10)
//  	sample := variant.Samples[0]
//  	// we can get the PL field as a list (-1 is default in case of missing value)
//  	fmt.Println("%s", variant.GetGenotypeField(sample, "PL", -1))
//  	_ = sample.DP
//  }
//  fmt.Fprintln(os.Stderr, rdr.Error())
package vcfgo

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"unsafe"

	"github.com/brentp/irelate/interfaces"
)

// used for the quality score which is 0 to 255, but allows "."
const MISSING_VAL = 256

// Reader holds information about the current line number (for errors) and
// The VCF header that indicates the structure of records.
type Reader struct {
	buf         *bufio.Reader
	Header      *Header
	verr        *VCFError
	LineNumber  int64
	lazySamples bool
	r           io.Reader
}

func NewWithHeader(r io.Reader, h *Header, lazySamples bool) (*Reader, error) {
	buf := bufio.NewReaderSize(r, 32768/8)
	var verr = NewVCFError()
	return &Reader{buf, h, verr, 1, lazySamples, r}, nil
}

// NewReader returns a Reader.
// If lazySamples is true, then the user will have to call Reader.ParseSamples()
// in order to access simple info.
func NewReader(r io.Reader, lazySamples bool) (*Reader, error) {
	buffered := bufio.NewReaderSize(r, 32768/8)

	var verr = NewVCFError()

	var LineNumber int64
	h := NewHeader()

	for {

		LineNumber++
		line, err := buffered.ReadString('\n')
		if err != nil && err != io.EOF {
			verr.Add(err, LineNumber)
		}
		if len(line) > 1 && line[len(line)-1] == '\n' {
			line = line[:len(line)-1]
		}

		if LineNumber == 1 {
			v, err := parseHeaderFileVersion(line)
			verr.Add(err, LineNumber)
			h.FileFormat = v

		} else if strings.HasPrefix(line, "##FORMAT") {
			format, err := parseHeaderFormat(line)
			verr.Add(err, LineNumber)
			if format != nil {
				h.SampleFormats[format.Id] = format
			}

		} else if strings.HasPrefix(line, "##INFO") {
			info, err := parseHeaderInfo(line)
			verr.Add(err, LineNumber)
			if info != nil {
				h.Infos[info.Id] = info
			}

		} else if strings.HasPrefix(line, "##FILTER") {
			filter, err := parseHeaderFilter(line)
			verr.Add(err, LineNumber)
			if filter != nil && len(filter) == 2 {
				h.Filters[filter[0]] = filter[1]
			}

		} else if strings.HasPrefix(line, "##contig") {
			contig, err := parseHeaderContig(line)
			verr.Add(err, LineNumber)
			if contig != nil {
				if _, ok := contig["ID"]; ok {
					h.Contigs = append(h.Contigs, contig)
				} else {
					verr.Add(fmt.Errorf("bad contig: %v", line), LineNumber)
				}
			}
		} else if strings.HasPrefix(line, "##SAMPLE") {
			sample, err := parseHeaderSample(line)
			verr.Add(err, LineNumber)
			if sample != "" {
				h.Samples[sample] = line
			} else {
				verr.Add(fmt.Errorf("bad sample: %v", line), LineNumber)
			}
		} else if strings.HasPrefix(line, "##PEDIGREE") {
			h.Pedigrees = append(h.Pedigrees, line)
		} else if strings.HasPrefix(line, "##") {
			kv, err := parseHeaderExtraKV(line)
			verr.Add(err, LineNumber)

			if kv != nil && len(kv) == 2 {
				h.Extras = append(h.Extras, line)
			}

		} else if strings.HasPrefix(line, "#CHROM") {
			var err error
			h.SampleNames, err = parseSampleLine(line)
			verr.Add(err, LineNumber)
			//h.Validate(verr)
			break

		} else {
			e := fmt.Errorf("unexpected header line: %s", line)
			return nil, e
		}
	}
	reader := &Reader{buffered, h, verr, LineNumber, lazySamples, r}
	return reader, reader.Error()
}

// Read returns a pointer to a Variant. Upon reading the caller is assumed
// to check Reader.Err()
func (vr *Reader) Read() interfaces.IVariant {

	line, err := vr.buf.ReadBytes('\n')
	if err != nil {
		if len(line) == 0 && err == io.EOF {
			return nil
		} else if err != io.EOF {
			vr.verr.Add(err, vr.LineNumber)
		}
	}

	vr.LineNumber++
	if line[len(line)-1] == '\n' {
		line = line[:len(line)-1]
	}
	fields := bytes.SplitN(line, []byte{'\t'}, 10)

	return vr.Parse(fields)
}

func unsafeString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

func (vr *Reader) Parse(fields [][]byte) interfaces.IVariant {

	pos, err := strconv.ParseUint(unsafeString(fields[1]), 10, 64)
	vr.verr.Add(err, vr.LineNumber)

	var qual float64
	if len(fields[5]) == 1 && fields[5][0] == '.' {
		qual = MISSING_VAL
	} else {
		qual, err = strconv.ParseFloat(unsafeString(fields[5]), 32)
	}

	vr.verr.Add(err, vr.LineNumber)

	v := &Variant{Chromosome: string(fields[0]), Pos: pos, Id_: string(fields[2]), Reference: string(fields[3]), Alternate: strings.Split(string(fields[4]), ","), Quality: float32(qual),
		Filter: string(fields[6]), Header: vr.Header}

	if len(fields) > 8 {
		v.Format = strings.Split(string(fields[8]), ":")
		if len(fields) > 9 {
			v.sampleString = string(fields[9])
		}
		if !vr.lazySamples {
			vr.Header.ParseSamples(v)
		}
	}
	v.LineNumber = vr.LineNumber

	v.Info_ = NewInfoByte(fields[7], vr.Header)
	vr.verr.Add(err, vr.LineNumber)
	return v
}

// Force parsing of the sample fields.
func (h *Header) ParseSamples(v *Variant) error {
	if v.Format == nil || v.sampleString == "" || v.Samples != nil {
		return nil
	}
	var errors []error
	v.Samples = make([]*SampleGenotype, len(h.SampleNames))

	for i, sample := range strings.Split(v.sampleString, "\t") {
		var geno *SampleGenotype
		geno, errors = h.parseSample(v.Format, sample)

		v.Samples[i] = geno
	}
	v.sampleString = ""
	if len(errors) > 0 {
		return errors[0]
	}
	return nil
}

// Add a INFO field to the header.
func (vr *Reader) AddInfoToHeader(id string, num string, stype string, desc string) {
	h := vr.Header
	h.Infos[id] = &Info{Id: id, Number: num, Type: stype, Description: desc}
}

// Error() aggregates the multiple errors that can occur into a single object.
func (vr *Reader) Error() error {
	if vr.verr.IsEmpty() {
		return nil
	}
	return vr.verr
}

// Clear empties the cache of errors.
func (vr *Reader) Clear() {
	vr.verr.Clear()
}
<commit_msg>make vcfgo.Reader an io.ReadCloser<commit_after>// Package vcfgo implements a Reader and Writer for variant call format.
// It eases reading, filtering modifying VCF's even if they are not to spec.
// Example:
//  f, _ := os.Open("examples/test.auto_dom.no_parents.vcf")
//  rdr, err := vcfgo.NewReader(f)
//  if err != nil {
//  	panic(err)
//  }
//  for {
//  	variant := rdr.Read()
//  	if variant == nil {
//  		break
//  	}
//  	fmt.Printf("%s\t%d\t%s\t%s\n", variant.Chromosome, variant.Pos, variant.Ref, variant.Alt)
//  	fmt.Printf("%s", variant.Info["DP"].(int) > 10)
//  	sample := variant.Samples[0]
//  	// we can get the PL field as a list (-1 is default in case of missing value)
//  	fmt.Println("%s", variant.GetGenotypeField(sample, "PL", -1))
//  	_ = sample.DP
//  }
//  fmt.Fprintln(os.Stderr, rdr.Error())
package vcfgo

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"unsafe"

	"github.com/brentp/irelate/interfaces"
)

// used for the quality score which is 0 to 255, but allows "."
const MISSING_VAL = 256

// Reader holds information about the current line number (for errors) and
// The VCF header that indicates the structure of records.
type Reader struct {
	buf         *bufio.Reader
	Header      *Header
	verr        *VCFError
	LineNumber  int64
	lazySamples bool
	r           io.Reader
}

func NewWithHeader(r io.Reader, h *Header, lazySamples bool) (*Reader, error) {
	buf := bufio.NewReaderSize(r, 32768/8)
	var verr = NewVCFError()
	return &Reader{buf, h, verr, 1, lazySamples, r}, nil
}

// NewReader returns a Reader.
// If lazySamples is true, then the user will have to call Reader.ParseSamples()
// in order to access simple info.
func NewReader(r io.Reader, lazySamples bool) (*Reader, error) {
	buffered := bufio.NewReaderSize(r, 32768/8)

	var verr = NewVCFError()

	var LineNumber int64
	h := NewHeader()

	for {

		LineNumber++
		line, err := buffered.ReadString('\n')
		if err != nil && err != io.EOF {
			verr.Add(err, LineNumber)
		}
		if len(line) > 1 && line[len(line)-1] == '\n' {
			line = line[:len(line)-1]
		}

		if LineNumber == 1 {
			v, err := parseHeaderFileVersion(line)
			verr.Add(err, LineNumber)
			h.FileFormat = v

		} else if strings.HasPrefix(line, "##FORMAT") {
			format, err := parseHeaderFormat(line)
			verr.Add(err, LineNumber)
			if format != nil {
				h.SampleFormats[format.Id] = format
			}

		} else if strings.HasPrefix(line, "##INFO") {
			info, err := parseHeaderInfo(line)
			verr.Add(err, LineNumber)
			if info != nil {
				h.Infos[info.Id] = info
			}

		} else if strings.HasPrefix(line, "##FILTER") {
			filter, err := parseHeaderFilter(line)
			verr.Add(err, LineNumber)
			if filter != nil && len(filter) == 2 {
				h.Filters[filter[0]] = filter[1]
			}

		} else if strings.HasPrefix(line, "##contig") {
			contig, err := parseHeaderContig(line)
			verr.Add(err, LineNumber)
			if contig != nil {
				if _, ok := contig["ID"]; ok {
					h.Contigs = append(h.Contigs, contig)
				} else {
					verr.Add(fmt.Errorf("bad contig: %v", line), LineNumber)
				}
			}
		} else if strings.HasPrefix(line, "##SAMPLE") {
			sample, err := parseHeaderSample(line)
			verr.Add(err, LineNumber)
			if sample != "" {
				h.Samples[sample] = line
			} else {
				verr.Add(fmt.Errorf("bad sample: %v", line), LineNumber)
			}
		} else if strings.HasPrefix(line, "##PEDIGREE") {
			h.Pedigrees = append(h.Pedigrees, line)
		} else if strings.HasPrefix(line, "##") {
			kv, err := parseHeaderExtraKV(line)
			verr.Add(err, LineNumber)

			if kv != nil && len(kv) == 2 {
				h.Extras = append(h.Extras, line)
			}

		} else if strings.HasPrefix(line, "#CHROM") {
			var err error
			h.SampleNames, err = parseSampleLine(line)
			verr.Add(err, LineNumber)
			//h.Validate(verr)
			break

		} else {
			e := fmt.Errorf("unexpected header line: %s", line)
			return nil, e
		}
	}
	reader := &Reader{buffered, h, verr, LineNumber, lazySamples, r}
	return reader, reader.Error()
}

// Read returns a pointer to a Variant. Upon reading the caller is assumed
// to check Reader.Err()
func (vr *Reader) Read() interfaces.IVariant {

	line, err := vr.buf.ReadBytes('\n')
	if err != nil {
		if len(line) == 0 && err == io.EOF {
			return nil
		} else if err != io.EOF {
			vr.verr.Add(err, vr.LineNumber)
		}
	}

	vr.LineNumber++
	if line[len(line)-1] == '\n' {
		line = line[:len(line)-1]
	}
	fields := bytes.SplitN(line, []byte{'\t'}, 10)

	return vr.Parse(fields)
}

func unsafeString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

func (vr *Reader) Parse(fields [][]byte) interfaces.IVariant {

	pos, err := strconv.ParseUint(unsafeString(fields[1]), 10, 64)
	vr.verr.Add(err, vr.LineNumber)

	var qual float64
	if len(fields[5]) == 1 && fields[5][0] == '.' {
		qual = MISSING_VAL
	} else {
		qual, err = strconv.ParseFloat(unsafeString(fields[5]), 32)
	}

	vr.verr.Add(err, vr.LineNumber)

	v := &Variant{Chromosome: string(fields[0]), Pos: pos, Id_: string(fields[2]), Reference: string(fields[3]), Alternate: strings.Split(string(fields[4]), ","), Quality: float32(qual),
		Filter: string(fields[6]), Header: vr.Header}

	if len(fields) > 8 {
		v.Format = strings.Split(string(fields[8]), ":")
		if len(fields) > 9 {
			v.sampleString = string(fields[9])
		}
		if !vr.lazySamples {
			vr.Header.ParseSamples(v)
		}
	}
	v.LineNumber = vr.LineNumber

	v.Info_ = NewInfoByte(fields[7], vr.Header)
	vr.verr.Add(err, vr.LineNumber)
	return v
}

// Force parsing of the sample fields.
func (h *Header) ParseSamples(v *Variant) error {
	if v.Format == nil || v.sampleString == "" || v.Samples != nil {
		return nil
	}
	var errors []error
	v.Samples = make([]*SampleGenotype, len(h.SampleNames))

	for i, sample := range strings.Split(v.sampleString, "\t") {
		var geno *SampleGenotype
		geno, errors = h.parseSample(v.Format, sample)

		v.Samples[i] = geno
	}
	v.sampleString = ""
	if len(errors) > 0 {
		return errors[0]
	}
	return nil
}

// Add a INFO field to the header.
func (vr *Reader) AddInfoToHeader(id string, num string, stype string, desc string) {
	h := vr.Header
	h.Infos[id] = &Info{Id: id, Number: num, Type: stype, Description: desc}
}

// Error() aggregates the multiple errors that can occur into a single object.
func (vr *Reader) Error() error {
	if vr.verr.IsEmpty() {
		return nil
	}
	return vr.verr
}

// Clear empties the cache of errors.
func (vr *Reader) Clear() {
	vr.verr.Clear()
}

func (vr *Reader) Close() error {
	if rc, ok := vr.r.(io.ReadCloser); ok {
		return rc.Close()
	}
	return nil
}
<|endoftext|>


<commit_before>package csvutil
/*
*  File: reader.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat May 28 23:53:36 PDT 2011
*  Description: CSV reader library.
*
*   This file is part of csvutil.
*
*   csvutil is free software: you can redistribute it and/or modify
*   it under the terms of the GNU Lesser Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   csvutil is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU Lesser Public License for more details.
*
*   You should have received a copy of the GNU Lesser Public License
*   along with csvutil.  If not, see <http://www.gnu.org/licenses/>.
*/
import (
	"io"
	"bufio"
	"strings"
	"os"
)

//  A reader object for CSV data utilizing the bufio package.
type Reader struct {
	Sep int "Field separator character."
	Trim bool "Remove excess whitespace from field values."
	Cutset string "Set of characters to trim."
    LastRow Row "The last row read by the Reader."
	r io.Reader "Base reader object."
	br *bufio.Reader "For reading lines."
    bufSize int "Initial size of internal line buffers."
}

//  A simple row structure for rows read by a csvutil.Reader that
//  encapsulates any read error enountered along with any data read
//  prior to encountering an error.
type Row struct {
	Fields []string "CSV row field data"
	Error os.Error "Error encountered reading"
}

func mkrow(fields []string, err os.Error) Row {
	var r Row
	r.Fields = fields
	r.Error = err
	return r
}

//  An object for iterating over the rows of a Reader.
//      rit = reader.RowIterStarted()
//      for r := range reader.RowsChan {
//          if r.Error != nil {
//              rit.Break()
//              panic(r.Error)
//          }
//          var fields []string = r.Fields
//          if !fieldsOk(fields) {
//              rit.Break()
//              break
//          }
//          // Process the desired entries of "fields".
//          rit.Next()
//      }
//  This itererator is safe to break out of. For iterators meant for
//  parsing an entire stream, see the ReaderRowIteratorAuto type.
type ReaderRowIterator struct {
    stopped bool
    RowsChan <-chan Row
    control chan<- bool
}

//  A ReaderRowIteratorAuto is meant for reading until encountering the
//  end of the data stream corresponding to a Reader's underlying
//  io.Reader.
//      rit = reader.RowIterAuto()
//      for r := range reader.RowsChan {
//          if r.Error != nil {
//              panic(r.Error)
//          }
//          var fields []string = r.Fields
//          // Process the desired entries of "fields".
//      }
//  This iteration using a range statement as above, it is not safe to
//  break out of the loop. This generally causes the 'loss' of at least
//  one row.
//
//  For iterating rows in a way such that the iteration can be stopped
//  safely, use ReaderRowIterator objects instead.
type ReaderRowIteratorAuto struct {
    stopped bool
    RowsChan <-chan Row
}

//  Tell the iterator to get another row from the Reader.
func (csvri *ReaderRowIterator) Next() {
    if csvri.stopped {
        panic("stopped")
    }
    csvri.control <- true
}

//  Tell the iterator to stop fetching rows and exit its goroutine.
//  Calling the (*ReaderRowIterator) Break() method is not necessary,
//  but to avoid doing so will cause the iterating goroutine to sleep
//  for the duration of the program.
func (csvri *ReaderRowIterator) Break() {
    if csvri.stopped {
        return
    }
    close(csvri.control)
    csvri.stopped = true
}

//  Create a new reader object.
func NewReader(r io.Reader) *Reader {
	var csvr *Reader = new(Reader).Reset()
	csvr.r = r
	csvr.br = bufio.NewReader(r)
    csvr.bufSize = 80
	return csvr
}

//  Create a new reader with a buffer of a specified size.
func NewReaderSize(r io.Reader, size int) *Reader {
	var csvr *Reader = new(Reader).Reset()
	csvr.r = r
	var err os.Error
	csvr.br, err = bufio.NewReaderSize(r, size)
	if err != nil { panic(err) }
    csvr.bufSize = size
	return csvr
}

// Create a new row iterator and return it.
func (csvr *Reader) RowIter() (*ReaderRowIterator) {
    ri := new(ReaderRowIterator)
    throughChan := make(chan Row)
    controlChan := make (chan bool)
    ri.RowsChan = throughChan
    ri.control = controlChan
	var read_rows = func (r chan<- Row, c <-chan bool) {
        defer func() {
            if x:=recover(); x!=nil {
                /* Do nothing. */
            }
        } ()
		for true {
            cont, ok := <-c
            if !ok || !cont {
                break
            }
            csvr.LastRow = Row{Fields:nil, Error:nil}
			var row Row = csvr.ReadRow()
			if row.Fields == nil {
				if row.Error == os.EOF {
					break
				} else {
					panic(row.Error)
				}
			}
            csvr.LastRow = row
			r <- row
		}
		close(r)
	}
	go read_rows(throughChan, controlChan)
	return ri
}
//  For convenience, return a new ReaderRowIterator rit that has
//  already already been the target of (*ReaderRowIterator) Next().
func (csvr *Reader) RowIterStarted() (rit *ReaderRowIterator) {
    rit = csvr.RowIter()
    rit.Next()
    return rit
}

// Create a new ReaderRowIteratorAuto object and return it.
func (csvr *Reader) RowIterAuto() (*ReaderRowIteratorAuto) {
    ri := new(ReaderRowIteratorAuto)
    throughChan := make(chan Row)
    ri.RowsChan = throughChan
	var read_rows = func (r chan<- Row) {
        defer func() {
            if x:=recover(); x!=nil {
                /* Do nothing. */
            }
        } ()
		for true {
            csvr.LastRow = Row{Fields:nil, Error:nil}
			var row Row = csvr.ReadRow()
			if row.Fields == nil {
				if row.Error == os.EOF {
					break
				} else {
					panic(row.Error)
				}
			}
            csvr.LastRow = row
			r <- row
		}
		close(r)
	}
	go read_rows(throughChan)
	return ri
}

//  Read up to a new line and return a slice of string slices
func (csvr *Reader) ReadRow() Row {
	/* Read one row of the CSV and and return an array of the fields. */
    var(
        r Row
        line, readLine, ln []byte
        err os.Error
        isPrefix bool
    )
	r = Row{Fields:nil, Error:nil}
    csvr.LastRow = r
    isPrefix = true
    for isPrefix {
        readLine, isPrefix, err = csvr.br.ReadLine()
	    r.Fields = nil
	    r.Error = err
	    if err == os.EOF { return r }
	    if err != nil { return r }
	    if isPrefix {
            readLen := len(readLine)
            if line == nil {
                line = make([]byte, 0, 2*readLen)
            }
            ln = make([]byte, readLen)
            copy(ln, readLine)
            line = append(line, ln...)
        } else {
            // isPrefix is false here. The loop will break next iteration.
            if line == nil {
                line = readLine
            }
        }
    }
	r.Fields = strings.FieldsFunc(
			string(line),
			func (c int) bool { return c == csvr.Sep } )
	if csvr.Trim {
		for i:=0 ; i<len(r.Fields) ; i++ {
			r.Fields[i] = strings.Trim(r.Fields[i], csvr.Cutset)
		}
	}
    csvr.LastRow = r
	return r
}

//  Read rows into a preallocated buffer. Any error encountered is
//  returned. Returns the number of rows read in a single value return
//  context any errors encountered (including os.EOF).
func (csvr *Reader) ReadRows(rbuf [][]string) (int, os.Error) {
    var(
        err os.Error
        numRead int = 0
        n int = len(rbuf)
    )
    for i:=0 ; i<n ; i++ {
        r := csvr.ReadRow()
        numRead++
        if r.Error != nil {
            err = r.Error
            if r.Fields != nil {
                rbuf[i] = r.Fields
            }
            break
        }
        rbuf[i] = r.Fields
    }
    return numRead, err
}

//  Convenience methor to read at most n rows from csvr. Simple allocates
//  a row slice rs and calls csvr.ReadRows(rs). Returns the actual number
//  of rows read and any error that occurred (and halted reading).
func (csvr *Reader) ReadNRows(n int) (int, os.Error) {
    rows := make([][]string, n)
    return csvr.ReadRows(rows)
}

//  Reads any remaining rows of CSV data in the underlying io.Reader.
//  Uses resizing when a preallocated buffer of rows fills. Up to 16
//  rows can be read without any doubling occuring.
func (csvr *Reader) RemainingRows() (rows [][]string, err os.Error) {
    return csvr.RemainingRowsSize(16)
}

//  Like csvr.RemainingRows(), but allows specification of the initial
//  row buffer capacity.
func (csvr *Reader) RemainingRowsSize(size int) (rows [][]string, err os.Error) {
    err = nil
    var rbuf [][]string = make([][]string, 0, size)
    rit := csvr.RowIterAuto()
    for r := range rit.RowsChan {
        /*
        if cap(rbuf) == len(rbuf) {
            newbuf := make([][]string, len(rbuf), 2*len(rbuf))
            copy(rbuf,newbuf)
            rbuf = newbuf
        }
        */
        if r.Error != nil {
            err = r.Error
            if r.Fields != nil {
                rbuf = append(rbuf, r.Fields)
            }
            break
        }
        rbuf = append(rbuf, r.Fields)
    }
    return rbuf, err
}

//  A function routine for setting all the configuration variables of a
//  csvutil.Reader in a single line.
func (csvr *Reader) Configure(sep int, trim bool, cutset string) *Reader {
	csvr.Sep = sep
	csvr.Trim = trim
	csvr.Cutset = cutset
	return csvr
}

//  Reset a Reader's configuration to the defaults. This is mostly meant
//  for internal use but is safe for general use.
func (csvr *Reader) Reset() *Reader {
	return csvr.Configure(DEFAULT_SEP, DEFAULT_TRIM, DEFAULT_CUTSET)
}

/* Comply with the reader interface. */
/*
func (csvr*Reader) Read(b []byte) (n int, err os.Error) {
	return csvr.r.Read(b)
}
*/
<commit_msg>Testing out iteration with no deferring.<commit_after>package csvutil
/*
*  File: reader.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat May 28 23:53:36 PDT 2011
*  Description: CSV reader library.
*
*   This file is part of csvutil.
*
*   csvutil is free software: you can redistribute it and/or modify
*   it under the terms of the GNU Lesser Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   csvutil is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU Lesser Public License for more details.
*
*   You should have received a copy of the GNU Lesser Public License
*   along with csvutil.  If not, see <http://www.gnu.org/licenses/>.
*/
import (
	"io"
	"bufio"
	"strings"
	"os"
)

//  A reader object for CSV data utilizing the bufio package.
type Reader struct {
	Sep int "Field separator character."
	Trim bool "Remove excess whitespace from field values."
	Cutset string "Set of characters to trim."
    LastRow Row "The last row read by the Reader."
	r io.Reader "Base reader object."
	br *bufio.Reader "For reading lines."
    bufSize int "Initial size of internal line buffers."
}

//  A simple row structure for rows read by a csvutil.Reader that
//  encapsulates any read error enountered along with any data read
//  prior to encountering an error.
type Row struct {
	Fields []string "CSV row field data"
	Error os.Error "Error encountered reading"
}

func mkrow(fields []string, err os.Error) Row {
	var r Row
	r.Fields = fields
	r.Error = err
	return r
}

//  An object for iterating over the rows of a Reader.
//      rit = reader.RowIterStarted()
//      for r := range reader.RowsChan {
//          if r.Error != nil {
//              rit.Break()
//              panic(r.Error)
//          }
//          var fields []string = r.Fields
//          if !fieldsOk(fields) {
//              rit.Break()
//              break
//          }
//          // Process the desired entries of "fields".
//          rit.Next()
//      }
//  This itererator is safe to break out of. For iterators meant for
//  parsing an entire stream, see the ReaderRowIteratorAuto type.
type ReaderRowIterator struct {
    stopped bool
    RowsChan <-chan Row
    control chan<- bool
}

//  A ReaderRowIteratorAuto is meant for reading until encountering the
//  end of the data stream corresponding to a Reader's underlying
//  io.Reader.
//      rit = reader.RowIterAuto()
//      for r := range reader.RowsChan {
//          if r.Error != nil {
//              panic(r.Error)
//          }
//          var fields []string = r.Fields
//          // Process the desired entries of "fields".
//      }
//  This iteration using a range statement as above, it is not safe to
//  break out of the loop. This generally causes the 'loss' of at least
//  one row.
//
//  For iterating rows in a way such that the iteration can be stopped
//  safely, use ReaderRowIterator objects instead.
type ReaderRowIteratorAuto struct {
    stopped bool
    RowsChan <-chan Row
}

//  Tell the iterator to get another row from the Reader.
func (csvri *ReaderRowIterator) Next() {
    if csvri.stopped {
        panic("stopped")
    }
    csvri.control <- true
}

//  Tell the iterator to stop fetching rows and exit its goroutine.
//  Calling the (*ReaderRowIterator) Break() method is not necessary,
//  but to avoid doing so will cause the iterating goroutine to sleep
//  for the duration of the program.
func (csvri *ReaderRowIterator) Break() {
    if csvri.stopped {
        return
    }
    close(csvri.control)
    csvri.stopped = true
}

//  Create a new reader object.
func NewReader(r io.Reader) *Reader {
	var csvr *Reader = new(Reader).Reset()
	csvr.r = r
	csvr.br = bufio.NewReader(r)
    csvr.bufSize = 80
	return csvr
}

//  Create a new reader with a buffer of a specified size.
func NewReaderSize(r io.Reader, size int) *Reader {
	var csvr *Reader = new(Reader).Reset()
	csvr.r = r
	var err os.Error
	csvr.br, err = bufio.NewReaderSize(r, size)
	if err != nil { panic(err) }
    csvr.bufSize = size
	return csvr
}

// Create a new row iterator and return it.
func (csvr *Reader) RowIter() (*ReaderRowIterator) {
    ri := new(ReaderRowIterator)
    throughChan := make(chan Row)
    controlChan := make (chan bool)
    ri.RowsChan = throughChan
    ri.control = controlChan
	var read_rows = func (r chan<- Row, c <-chan bool) {
        /* Deferring may be unnecessary (and undesired) now.
            defer func() {
                x:=recover()
                if x !=nil {
                }
            } ()
        */
		for true {
            cont, ok := <-c
            if !ok || !cont {
                break
            }
            csvr.LastRow = Row{Fields:nil, Error:nil}
			var row Row = csvr.ReadRow()
			if row.Fields == nil {
				if row.Error == os.EOF {
					break
				} else {
					panic(row.Error)
				}
			}
            csvr.LastRow = row
			r <- row
		}
		close(r)
	}
	go read_rows(throughChan, controlChan)
	return ri
}
//  For convenience, return a new ReaderRowIterator rit that has
//  already already been the target of (*ReaderRowIterator) Next().
func (csvr *Reader) RowIterStarted() (rit *ReaderRowIterator) {
    rit = csvr.RowIter()
    rit.Next()
    return rit
}

// Create a new ReaderRowIteratorAuto object and return it.
func (csvr *Reader) RowIterAuto() (*ReaderRowIteratorAuto) {
    ri := new(ReaderRowIteratorAuto)
    throughChan := make(chan Row)
    ri.RowsChan = throughChan
	var read_rows = func (r chan<- Row) {
        defer func() {
            if x:=recover(); x!=nil {
                /* Do nothing. */
            }
        } ()
		for true {
            csvr.LastRow = Row{Fields:nil, Error:nil}
			var row Row = csvr.ReadRow()
			if row.Fields == nil {
				if row.Error == os.EOF {
					break
				} else {
					panic(row.Error)
				}
			}
            csvr.LastRow = row
			r <- row
		}
		close(r)
	}
	go read_rows(throughChan)
	return ri
}

//  Read up to a new line and return a slice of string slices
func (csvr *Reader) ReadRow() Row {
	/* Read one row of the CSV and and return an array of the fields. */
    var(
        r Row
        line, readLine, ln []byte
        err os.Error
        isPrefix bool
    )
	r = Row{Fields:nil, Error:nil}
    csvr.LastRow = r
    isPrefix = true
    for isPrefix {
        readLine, isPrefix, err = csvr.br.ReadLine()
	    r.Fields = nil
	    r.Error = err
	    if err == os.EOF { return r }
	    if err != nil { return r }
	    if isPrefix {
            readLen := len(readLine)
            if line == nil {
                line = make([]byte, 0, 2*readLen)
            }
            ln = make([]byte, readLen)
            copy(ln, readLine)
            line = append(line, ln...)
        } else {
            // isPrefix is false here. The loop will break next iteration.
            if line == nil {
                line = readLine
            }
        }
    }
	r.Fields = strings.FieldsFunc(
			string(line),
			func (c int) bool { return c == csvr.Sep } )
	if csvr.Trim {
		for i:=0 ; i<len(r.Fields) ; i++ {
			r.Fields[i] = strings.Trim(r.Fields[i], csvr.Cutset)
		}
	}
    csvr.LastRow = r
	return r
}

//  Read rows into a preallocated buffer. Any error encountered is
//  returned. Returns the number of rows read in a single value return
//  context any errors encountered (including os.EOF).
func (csvr *Reader) ReadRows(rbuf [][]string) (int, os.Error) {
    var(
        err os.Error
        numRead int = 0
        n int = len(rbuf)
    )
    for i:=0 ; i<n ; i++ {
        r := csvr.ReadRow()
        numRead++
        if r.Error != nil {
            err = r.Error
            if r.Fields != nil {
                rbuf[i] = r.Fields
            }
            break
        }
        rbuf[i] = r.Fields
    }
    return numRead, err
}

//  Convenience methor to read at most n rows from csvr. Simple allocates
//  a row slice rs and calls csvr.ReadRows(rs). Returns the actual number
//  of rows read and any error that occurred (and halted reading).
func (csvr *Reader) ReadNRows(n int) (int, os.Error) {
    rows := make([][]string, n)
    return csvr.ReadRows(rows)
}

//  Reads any remaining rows of CSV data in the underlying io.Reader.
//  Uses resizing when a preallocated buffer of rows fills. Up to 16
//  rows can be read without any doubling occuring.
func (csvr *Reader) RemainingRows() (rows [][]string, err os.Error) {
    return csvr.RemainingRowsSize(16)
}

//  Like csvr.RemainingRows(), but allows specification of the initial
//  row buffer capacity.
func (csvr *Reader) RemainingRowsSize(size int) (rows [][]string, err os.Error) {
    err = nil
    var rbuf [][]string = make([][]string, 0, size)
    rit := csvr.RowIterAuto()
    for r := range rit.RowsChan {
        /*
        if cap(rbuf) == len(rbuf) {
            newbuf := make([][]string, len(rbuf), 2*len(rbuf))
            copy(rbuf,newbuf)
            rbuf = newbuf
        }
        */
        if r.Error != nil {
            err = r.Error
            if r.Fields != nil {
                rbuf = append(rbuf, r.Fields)
            }
            break
        }
        rbuf = append(rbuf, r.Fields)
    }
    return rbuf, err
}

//  A function routine for setting all the configuration variables of a
//  csvutil.Reader in a single line.
func (csvr *Reader) Configure(sep int, trim bool, cutset string) *Reader {
	csvr.Sep = sep
	csvr.Trim = trim
	csvr.Cutset = cutset
	return csvr
}

//  Reset a Reader's configuration to the defaults. This is mostly meant
//  for internal use but is safe for general use.
func (csvr *Reader) Reset() *Reader {
	return csvr.Configure(DEFAULT_SEP, DEFAULT_TRIM, DEFAULT_CUTSET)
}

/* Comply with the reader interface. */
/*
func (csvr*Reader) Read(b []byte) (n int, err os.Error) {
	return csvr.r.Read(b)
}
*/
<|endoftext|>


<commit_before>package peco

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sync"
	"time"
)

type BufferReader struct {
	*Ctx
	input io.ReadCloser
}

func (b *BufferReader) Loop() {
	defer b.ReleaseWaitGroup()
	defer func() { recover() }() // ignore errors

	ch := make(chan string, 10)

	// scanner.Scan() blocks until the next read or error. But we want to
	// exit immediately, so we move it out to its own goroutine
	go func() {
		defer func() { recover() }()
		defer func() { close(ch) }()
		scanner := bufio.NewScanner(b.input)
		for scanner.Scan() {
			ch <- scanner.Text()
		}
	}()

	m := &sync.Mutex{}
	var refresh *time.Timer

	loop := true
	for loop {
		select {
		case <-b.LoopCh():
			loop = false
		case line, ok := <-ch:
			if !ok {
				loop = false
				continue
			}

			if line != "" {
				b.lines = append(b.lines, NewNoMatch(line, b.enableSep))
				if b.IsBufferOverflowing() {
					b.lines = b.lines[1:]
				}
			}

			m.Lock()
			if refresh == nil {
				refresh = time.AfterFunc(100*time.Millisecond, func() {
					if !b.ExecQuery() {
						b.DrawMatches(b.lines)
					}
					m.Lock()
					refresh = nil
					m.Unlock()
				})
			}
			m.Unlock()
		}
	}

	b.input.Close()

	// Out of the reader loop. If at this point we have no buffer,
	// that means we have no buffer, so we should quit.
	if len(b.lines) == 0 {
		b.ExitWith(1)
		fmt.Fprintf(os.Stderr, "No buffer to work with was available")
	}
}
<commit_msg>Protect modification on b.lines<commit_after>package peco

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sync"
	"time"
)

type BufferReader struct {
	*Ctx
	input io.ReadCloser
}

func (b *BufferReader) Loop() {
	defer b.ReleaseWaitGroup()
	defer func() { recover() }() // ignore errors

	ch := make(chan string, 10)

	// scanner.Scan() blocks until the next read or error. But we want to
	// exit immediately, so we move it out to its own goroutine
	go func() {
		defer func() { recover() }()
		defer func() { close(ch) }()
		scanner := bufio.NewScanner(b.input)
		for scanner.Scan() {
			ch <- scanner.Text()
		}
	}()

	m := &sync.Mutex{}
	var refresh *time.Timer

	loop := true
	for loop {
		select {
		case <-b.LoopCh():
			loop = false
		case line, ok := <-ch:
			if !ok {
				loop = false
				continue
			}

			if line != "" {
				m.Lock()
				b.lines = append(b.lines, NewNoMatch(line, b.enableSep))
				if b.IsBufferOverflowing() {
					b.lines = b.lines[1:]
				}
				m.Unlock()
			}

			m.Lock()
			if refresh == nil {
				refresh = time.AfterFunc(100*time.Millisecond, func() {
					if !b.ExecQuery() {
						b.DrawMatches(b.lines)
					}
					m.Lock()
					refresh = nil
					m.Unlock()
				})
			}
			m.Unlock()
		}
	}

	b.input.Close()

	// Out of the reader loop. If at this point we have no buffer,
	// that means we have no buffer, so we should quit.
	if len(b.lines) == 0 {
		b.ExitWith(1)
		fmt.Fprintf(os.Stderr, "No buffer to work with was available")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strconv"
	"time"
)

func main() {
	if len(os.Args) >= 2 {
		seconds, _ := strconv.Atoi(os.Args[1])
		time.Sleep(time.Duration(seconds) * time.Second)
	}
}
<commit_msg>sleep: parse durations<commit_after>package main

import (
	"log"
	"os"
	"strconv"
	"time"
)

func main() {
	log.SetPrefix("sleep: ")
	log.SetFlags(0)
	if len(os.Args) > 1 {
		var dur time.Duration
		seconds, err := strconv.Atoi(os.Args[1])
		if err != nil {
			if dur, err = time.ParseDuration(os.Args[1]); err != nil {
				log.Fatal(err)
			}
		} else {
			dur = time.Duration(seconds) * time.Second
		}
		time.Sleep(dur)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"io/ioutil"
	"log"
	"os/exec"
	"strings"

	"github.com/mdlayher/wavepipe/transcode"
)

// transcodeManager manages active file transcodes, their caching, etc, and communicates back
// and forth with the manager goroutine
func transcodeManager(transcodeKillChan chan struct{}) {
	log.Println("transcode: starting...")

	// Perform setup routines for ffmpeg transcoding
	go ffmpegSetup()

	// Trigger events via channel
	for {
		select {
		// Stop transcode manager
		case <-transcodeKillChan:
			// Inform manager that shutdown is complete
			log.Println("transcode: stopped!")
			transcodeKillChan <- struct{}{}
			return
		}
	}
}

// ffmpegSetup performs setup routines for ffmpeg transcoding
func ffmpegSetup() {
	// Disable transcoding until ffmpeg is available
	transcode.Enabled = false

	// Verify that ffmpeg is available for transcoding
	path, err := exec.LookPath("ffmpeg")
	if err != nil {
		log.Println("transcode: cannot find ffmpeg, transcoding will be disabled")
		return
	}

	// Set ffmpeg location, enable transcoding
	log.Println("transcode: found ffmpeg:", path)
	transcode.Enabled = true
	transcode.FFmpegPath = path

	// Check for codecs which wavepipe uses that ffmpeg is able to use
	ffmpeg := exec.Command(path, "-loglevel", "quiet", "-codecs")
	stdout, err := ffmpeg.StdoutPipe()

	// Start ffmpeg to retrieve its codecs, wait for it to finish
	err2 := ffmpeg.Start()
	codecs, err3 := ioutil.ReadAll(stdout)
	defer stdout.Close()
	err4 := ffmpeg.Wait()

	// Check errors
	if err != nil || err2 != nil || err3 != nil || err4 != nil {
		log.Println("transcode: could not detect ffmpeg codecs, transcoding will be disabled")
		return
	}

	// Check for MP3 transcoding codec
	codecStr := string(codecs)
	if strings.Contains(codecStr, transcode.FFMpegMP3Codec) {
		log.Println("transcode: found", transcode.FFMpegMP3Codec, ", enabling MP3 transcoding")
		transcode.CodecSet.Add("MP3")
	} else {
		log.Println("transcode: could not find", transcode.FFMpegMP3Codec, ", disabling MP3 transcoding")
	}

	// Check for OGG transcoding codec
	if strings.Contains(codecStr, transcode.FFMpegOGGCodec) {
		log.Println("transcode: found", transcode.FFMpegOGGCodec, ", enabling OGG transcoding")
		transcode.CodecSet.Add("OGG")
	} else {
		log.Println("transcode: could not find", transcode.FFMpegOGGCodec, ", disabling OGG transcoding")
	}
}
<commit_msg>Fix typos, add Ogg Opus detection in transcode manager<commit_after>package core

import (
	"io/ioutil"
	"log"
	"os/exec"
	"strings"

	"github.com/mdlayher/wavepipe/transcode"
)

// transcodeManager manages active file transcodes, their caching, etc, and communicates back
// and forth with the manager goroutine
func transcodeManager(transcodeKillChan chan struct{}) {
	log.Println("transcode: starting...")

	// Perform setup routines for ffmpeg transcoding
	go ffmpegSetup()

	// Trigger events via channel
	for {
		select {
		// Stop transcode manager
		case <-transcodeKillChan:
			// Inform manager that shutdown is complete
			log.Println("transcode: stopped!")
			transcodeKillChan <- struct{}{}
			return
		}
	}
}

// ffmpegSetup performs setup routines for ffmpeg transcoding
func ffmpegSetup() {
	// Disable transcoding until ffmpeg is available
	transcode.Enabled = false

	// Verify that ffmpeg is available for transcoding
	path, err := exec.LookPath("ffmpeg")
	if err != nil {
		log.Println("transcode: cannot find ffmpeg, transcoding will be disabled")
		return
	}

	// Set ffmpeg location, enable transcoding
	log.Println("transcode: found ffmpeg:", path)
	transcode.Enabled = true
	transcode.FFmpegPath = path

	// Check for codecs which wavepipe uses that ffmpeg is able to use
	ffmpeg := exec.Command(path, "-loglevel", "quiet", "-codecs")
	stdout, err := ffmpeg.StdoutPipe()

	// Start ffmpeg to retrieve its codecs, wait for it to finish
	err2 := ffmpeg.Start()
	codecs, err3 := ioutil.ReadAll(stdout)
	defer stdout.Close()
	err4 := ffmpeg.Wait()

	// Check errors
	if err != nil || err2 != nil || err3 != nil || err4 != nil {
		log.Println("transcode: could not detect ffmpeg codecs, transcoding will be disabled")
		return
	}

	// Check for MP3 transcoding codec
	codecStr := string(codecs)
	if strings.Contains(codecStr, transcode.FFmpegMP3Codec) {
		log.Println("transcode: found", transcode.FFmpegMP3Codec, ", enabling MP3 transcoding")
		transcode.CodecSet.Add("MP3")
	} else {
		log.Println("transcode: could not find", transcode.FFmpegMP3Codec, ", disabling MP3 transcoding")
	}

	// Check for OGG transcoding codec
	if strings.Contains(codecStr, transcode.FFmpegOGGCodec) {
		log.Println("transcode: found", transcode.FFmpegOGGCodec, ", enabling OGG transcoding")
		transcode.CodecSet.Add("OGG")
	} else {
		log.Println("transcode: could not find", transcode.FFmpegOGGCodec, ", disabling OGG transcoding")
	}

	// Check for OPUS transcoding codec
	if strings.Contains(codecStr, transcode.FFmpegOPUSCodec) {
		log.Println("transcode: found", transcode.FFmpegOPUSCodec, ", enabling OPUS transcoding")
		transcode.CodecSet.Add("OPUS")
	} else {
		log.Println("transcode: could not find", transcode.FFmpegOPUSCodec, ", disabling OPUS transcoding")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"github.com/ziutek/mymysql/autorc"
	"io"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

// Message format (lines ended by CR or CRLF):
// FROM                                - symbol of source (<=16B)
// PHONE1[=DSTID1] PHONE2[=DSTID2] ... - list of phone numbers and dstIds
// Lines that contain optional parameters, one parameter per line: NAME or
// NAME VALUE. Implemented parameters:
// report        - report required
// delede        - delete message after sending (wait for reports, if required)
//               - empty line
// Message body
// .             - '.' as first and only character in line

// You can use optional dstIds to link recipients with your other data in db.

// Input represents source of messages
type Input struct {
	smsd                           *SMSd
	db                             *autorc.Conn
	knownSrc                       []string
	proto, addr                    string
	ln                             net.Listener
	outboxInsert, recipientsInsert autorc.Stmt
	stop                           bool
}

func NewInput(smsd *SMSd, proto, addr string, db *autorc.Conn, src []string) *Input {
	in := new(Input)
	in.smsd = smsd
	in.db = db
	in.db.Register(setNames)
	in.db.Register(createOutbox)
	in.db.Register(createRecipients)
	in.proto = proto
	in.addr = addr
	in.knownSrc = src
	return in
}

const outboxInsert = `INSERT
	` + outboxTable + `
SET
	time=?,
	src=?,
	report=?,
	del=?,
	body=?
`

const recipientsInsert = `INSERT ` + recipientsTable + ` SET
	msgId=?,
	number=?,
	dstId=?
`

func (in *Input) handle(c net.Conn) {
	defer c.Close()

	if !prepareOnce(in.db, &in.outboxInsert, outboxInsert) {
		return
	}
	if !prepareOnce(in.db, &in.recipientsInsert, recipientsInsert) {
		return
	}
	r := bufio.NewReader(c)
	from, ok := readLine(r)
	if !ok {
		return
	}
	i := 0
	for i < len(in.knownSrc) && in.knownSrc[i] != from {
		i++
	}
	if i == len(in.knownSrc) {
		log.Println("Unknown source:", from)
		time.Sleep(5 * time.Second)
		io.WriteString(c, "Unknown source\n")
		return
	}
	tels, ok := readLine(r)
	if !ok {
		return
	}
	// Read options until first empty line
	var del, report bool
	for {
		l, ok := readLine(r)
		if !ok {
			return
		}
		if l == "" {
			break
		}
		switch l {
		case "report":
			report = true
		case "delete":
			del = true
		}
	}
	// Read a message body
	var body []byte
	var prevIsPrefix bool
	for {
		buf, isPrefix, err := r.ReadLine()
		if err != nil {
			log.Print("Can't read message body: ", err)
			return
		}
		if !isPrefix && !prevIsPrefix && len(buf) == 1 && buf[0] == '.' {
			break
		}
		body = append(body, '\n')
		body = append(body, buf...)
		prevIsPrefix = isPrefix
	}
	// Insert message into Outbox
	_, res, err := in.outboxInsert.Exec(time.Now(), from, report, del, body[1:])
	if err != nil {
		log.Printf("Can't insert message from %s into Outbox: %s", from, err)
		// Send error response, ignore errors
		io.WriteString(c, "DB error (can't insert message)\n")
		return
	}
	msgId := uint32(res.InsertId())
	// Save recipients for this message
	for _, dst := range strings.Split(tels, " ") {
		d := strings.SplitN(dst, "=", 2)
		num := d[0]
		if !checkNumber(num) {
			log.Printf("Bad phone number: '%s' for message #%d.", num, msgId)
			// Send error response, ignore errors
			io.WriteString(c, "Bad phone number\n")
			continue
		}
		var dstId uint64
		if len(d) == 2 {
			dstId, err = strconv.ParseUint(d[1], 0, 32)
			if err != nil {
				dstId = 0
				log.Printf("Bad DstId=`%s` for number %s: %s", d[1], num, err)
				// Send error response, ignore errors
				io.WriteString(c, "Bad DstId\n")
			}
		}
		_, _, err = in.recipientsInsert.Exec(msgId, num, uint32(dstId))
		if err != nil {
			log.Printf("Can't insert phone number %s into Recipients: %s", num, err)
			// Send error response, ignore errors
			io.WriteString(c, "DB error (can't insert phone number)\n")
		}
	}
	// Send OK as response, ignore errors
	io.WriteString(c, "OK\n")

	// Inform SMSd about new message
	in.smsd.NewMsg()
}

func (in *Input) loop() {
	for {
		c, err := in.ln.Accept()
		if err != nil {
			if in.stop {
				return
			}
			log.Print("Can't accept connection: ", err)
			if e, ok := err.(net.Error); !ok || !e.Temporary() {
				return
			}
		}
		go in.handle(c)
	}
}

func (in *Input) Start() {
	var err error
	if in.proto == "unix" {
		os.Remove(in.addr)
	}
	in.ln, err = net.Listen(in.proto, in.addr)
	if err != nil {
		log.Printf("Can't listen on %s: %s", in.addr, err)
		os.Exit(1)
	}
	if in.proto == "unix" {
		err = os.Chmod(in.addr, 0666)
		if err != nil {
			log.Printf("Can't chmod on unix socket %s: %s", in.addr, err)
			os.Exit(1)
		}
	}
	log.Println("Listen on:", in.proto, in.addr)
	in.stop = false
	go in.loop()
	return
}

func (in *Input) Stop() {
	in.stop = true
	if err := in.ln.Close(); err != nil {
		log.Println("Can't close listen socket:", err)
	}
}

func (in *Input) String() string {
	return in.proto + ":" + in.addr
}
<commit_msg>Fix typo in description of message format.<commit_after>package main

import (
	"bufio"
	"github.com/ziutek/mymysql/autorc"
	"io"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

// Message format (lines ended by CR or CRLF):
// FROM                                - symbol of source (<=16B)
// PHONE1[=DSTID1] PHONE2[=DSTID2] ... - list of phone numbers and dstIds
// Lines that contain optional parameters, one parameter per line: NAME or
// NAME VALUE. Implemented parameters:
// report        - report required
// delete        - delete message after sending (wait for reports, if required)
//               - empty line
// Message body
// .             - '.' as first and only character in line

// You can use optional dstIds to link recipients with your other data in db.

// Input represents source of messages
type Input struct {
	smsd                           *SMSd
	db                             *autorc.Conn
	knownSrc                       []string
	proto, addr                    string
	ln                             net.Listener
	outboxInsert, recipientsInsert autorc.Stmt
	stop                           bool
}

func NewInput(smsd *SMSd, proto, addr string, db *autorc.Conn, src []string) *Input {
	in := new(Input)
	in.smsd = smsd
	in.db = db
	in.db.Register(setNames)
	in.db.Register(createOutbox)
	in.db.Register(createRecipients)
	in.proto = proto
	in.addr = addr
	in.knownSrc = src
	return in
}

const outboxInsert = `INSERT
	` + outboxTable + `
SET
	time=?,
	src=?,
	report=?,
	del=?,
	body=?
`

const recipientsInsert = `INSERT ` + recipientsTable + ` SET
	msgId=?,
	number=?,
	dstId=?
`

func (in *Input) handle(c net.Conn) {
	defer c.Close()

	if !prepareOnce(in.db, &in.outboxInsert, outboxInsert) {
		return
	}
	if !prepareOnce(in.db, &in.recipientsInsert, recipientsInsert) {
		return
	}
	r := bufio.NewReader(c)
	from, ok := readLine(r)
	if !ok {
		return
	}
	i := 0
	for i < len(in.knownSrc) && in.knownSrc[i] != from {
		i++
	}
	if i == len(in.knownSrc) {
		log.Println("Unknown source:", from)
		time.Sleep(5 * time.Second)
		io.WriteString(c, "Unknown source\n")
		return
	}
	tels, ok := readLine(r)
	if !ok {
		return
	}
	// Read options until first empty line
	var del, report bool
	for {
		l, ok := readLine(r)
		if !ok {
			return
		}
		if l == "" {
			break
		}
		switch l {
		case "report":
			report = true
		case "delete":
			del = true
		}
	}
	// Read a message body
	var body []byte
	var prevIsPrefix bool
	for {
		buf, isPrefix, err := r.ReadLine()
		if err != nil {
			log.Print("Can't read message body: ", err)
			return
		}
		if !isPrefix && !prevIsPrefix && len(buf) == 1 && buf[0] == '.' {
			break
		}
		body = append(body, '\n')
		body = append(body, buf...)
		prevIsPrefix = isPrefix
	}
	// Insert message into Outbox
	_, res, err := in.outboxInsert.Exec(time.Now(), from, report, del, body[1:])
	if err != nil {
		log.Printf("Can't insert message from %s into Outbox: %s", from, err)
		// Send error response, ignore errors
		io.WriteString(c, "DB error (can't insert message)\n")
		return
	}
	msgId := uint32(res.InsertId())
	// Save recipients for this message
	for _, dst := range strings.Split(tels, " ") {
		d := strings.SplitN(dst, "=", 2)
		num := d[0]
		if !checkNumber(num) {
			log.Printf("Bad phone number: '%s' for message #%d.", num, msgId)
			// Send error response, ignore errors
			io.WriteString(c, "Bad phone number\n")
			continue
		}
		var dstId uint64
		if len(d) == 2 {
			dstId, err = strconv.ParseUint(d[1], 0, 32)
			if err != nil {
				dstId = 0
				log.Printf("Bad DstId=`%s` for number %s: %s", d[1], num, err)
				// Send error response, ignore errors
				io.WriteString(c, "Bad DstId\n")
			}
		}
		_, _, err = in.recipientsInsert.Exec(msgId, num, uint32(dstId))
		if err != nil {
			log.Printf("Can't insert phone number %s into Recipients: %s", num, err)
			// Send error response, ignore errors
			io.WriteString(c, "DB error (can't insert phone number)\n")
		}
	}
	// Send OK as response, ignore errors
	io.WriteString(c, "OK\n")

	// Inform SMSd about new message
	in.smsd.NewMsg()
}

func (in *Input) loop() {
	for {
		c, err := in.ln.Accept()
		if err != nil {
			if in.stop {
				return
			}
			log.Print("Can't accept connection: ", err)
			if e, ok := err.(net.Error); !ok || !e.Temporary() {
				return
			}
		}
		go in.handle(c)
	}
}

func (in *Input) Start() {
	var err error
	if in.proto == "unix" {
		os.Remove(in.addr)
	}
	in.ln, err = net.Listen(in.proto, in.addr)
	if err != nil {
		log.Printf("Can't listen on %s: %s", in.addr, err)
		os.Exit(1)
	}
	if in.proto == "unix" {
		err = os.Chmod(in.addr, 0666)
		if err != nil {
			log.Printf("Can't chmod on unix socket %s: %s", in.addr, err)
			os.Exit(1)
		}
	}
	log.Println("Listen on:", in.proto, in.addr)
	in.stop = false
	go in.loop()
	return
}

func (in *Input) Stop() {
	in.stop = true
	if err := in.ln.Close(); err != nil {
		log.Println("Can't close listen socket:", err)
	}
}

func (in *Input) String() string {
	return in.proto + ":" + in.addr
}
<|endoftext|>