<commit_before>// Package flowgraph for scalable asynchronous system development
// https://github.com/vectaport/flowgraph/wiki
package flowgraph

import (
	"github.com/vectaport/fgbase"

	"errors"
	"fmt"
	"log"
)

/*=====================================================================*/

// End of flow
var EOF = errors.New("EOF")

// Hub code
type Code int

// Code constants for NewHub, followed by init type and description
const (
	Retrieve Code = iota // Retriever	retrieve one value with Retriever
	Transmit             // Transmitter	transmit one value with Transmitter
	AllOf                // Transformer	waiting for all sources
	OneOf                // Transformer	waiting for one source
	Array                // []interface{}	produce array of values then EOF
	Const                // interface{}	produce constant values forever
	Sink                 // [Sinker]	consume values forever
	Rdy                  // nil		wait for zeroth source to pass rest
	Pass                 // nil		pass all values
	Steer                // nil		steer rest by zeroth source
	Select               // nil		select rest by zeroth source
	Add                  // nil		add numbers, concat strings, or use Add(interface{})
	Sub                  // nil		subtract numbers or use Sub(interface{})
	Mul                  // nil		multiply numbers or use Mul(interface{})
	Div                  // nil		divide numbers or use Div(interface{})
	Mod                  // nil		modulato numbers or use Mod(interface{})
	And                  // nil		and bool, bit-wise and integers, or use And(interface{})
	Or                   // nil		or bool, bit-wise or integers, or use Or(interface{})
	Not                  // nil		negate bool, invert integers, or use Not(interface{})
	Shift                // ShiftCode	shift integers - LeftShift, RightShift, LeftBarrel, RightBarrel, RightSigned
)

// Shift Code
type ShiftCode int

const (
	LeftShift ShiftCode = iota
	RightShift
	LeftBarrel
	RightBarrel
	RightSigned
)

/*=====================================================================*/

// Transformer transforms a slice of source values into a slice
// of result values with the Transform method. Use Hub.Tracef for tracing.
type Transformer interface {
	Transform(h *Hub, source []interface{}) (result []interface{}, err error)
}

// Retriever retrieves one value using the Retrieve method. Use Hub.Tracef for tracing.
type Retriever interface {
	Retrieve(h *Hub) (result interface{}, err error)
}

// Transmitter transmits one value using a Transmit method. Use Hub.Tracef for tracing.
type Transmitter interface {
	Transmit(h *Hub, source interface{}) (err error)
}

// Sinker consumes wavefronts of values one at a time forever
type Sinker interface {
	Sink(source []interface{})
}

/*=====================================================================*/

// Flowgraph struct for flowgraphs assembled out of hubs and streams
type Flowgraph struct {
	name         string
	hubs         []*Hub
	streams      []*Stream
	nameToHub    map[string]*Hub
	nameToStream map[string]*Stream
}

// New returns a named flowgraph
func New(name string) *Flowgraph {
	nameToHub := make(map[string]*Hub)
	nameToStream := make(map[string]*Stream)
	fg := Flowgraph{name, nil, nil, nameToHub, nameToStream}
	return &fg
}

// Name returns the name of this flowgraph
func (fg *Flowgraph) Name() string {
	return fg.Name()
}

// Hub returns a hub by index
func (fg *Flowgraph) Hub(n int) *Hub {
	return fg.hubs[n]
}

// Stream returns a stream by index
func (fg *Flowgraph) Stream(n int) *Stream {
	return fg.streams[n]
}

// NumHub returns the number of hubs
func (fg *Flowgraph) NumHub() int {
	return len(fg.hubs)
}

// NumStream returns the number of hubs
func (fg *Flowgraph) NumStream() int {
	return len(fg.streams)
}

// NewHub returns a new unconnected hub
func (fg *Flowgraph) NewHub(name string, code Code, init interface{}) *Hub {

	var n fgbase.Node

	switch code {

	// User Supplied Hubs
	case AllOf:
		if _, ok := init.(Transformer); !ok {
			panic(fmt.Sprintf("Hub with AllOf code not given Transformer for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, allOfFire)
	case OneOf:
		if _, ok := init.(Transformer); !ok {
			panic(fmt.Sprintf("Hub with OneOf code not given Transformer for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, oneOfRdy, oneOfFire)
	case Retrieve:
		if _, ok := init.(Retriever); !ok {
			panic(fmt.Sprintf("Hub with Retrieve code not given Retriever for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, retrieveFire)
	case Transmit:
		if _, ok := init.(Transmitter); !ok {
			panic(fmt.Sprintf("Hub with Transmit code not given Transmitter for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, transmitFire)

	// Math Hubs
	case Add:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.AddFire)
	case Sub:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.SubFire)
	case Mul:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.MulFire)
	case Div:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.DivFire)

	// General Purpose Hubs
	case Rdy:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.RdyFire)
	case Array:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.ArrayFire)
	case Const:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.ConstFire)
	case Sink:
		if init != nil {
			if _, ok := init.(Sinker); !ok {
				panic(fmt.Sprintf("Hub with Sink code not given Sinker for init %T(%+v)", init, init))
			}
		}
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil}, nil, nil, fgbase.SinkFire)
	case Steer:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil}, nil, fgbase.SteervRdy, fgbase.SteervFire)
	default:
		log.Panicf("Unexpected Hub code:  %s\n", code)
	}
	if n.Aux == nil {
		n.Aux = init
	}

	h := Hub{&n}
	fg.hubs = append(fg.hubs, &h)
	fg.nameToHub[name] = &h
	return &h
}

// NewStream returns a new unconnected stream
func (fg *Flowgraph) NewStream(name string) *Stream {
	e := fgbase.MakeEdge(name, nil)
	s := Stream{&e}
	fg.streams = append(fg.streams, &s)
	fg.nameToStream[name] = &s
	return &s
}

// FindHub finds a hub by name
func (fg *Flowgraph) FindHub(name string) *Hub {
	return fg.nameToHub[name]
}

// FindStream finds a Stream by name
func (fg *Flowgraph) FindStream(name string) *Stream {
	return fg.nameToStream[name]
}

// Connect connects two hubs via named (string) or indexed (int) ports
func (fg *Flowgraph) Connect(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{}) *Stream {
	return fg.connectInit(upstream, upstreamPort, dnstream, dnstreamPort, nil)
}

// ConnectInit connects two hubs via named (string) or indexed (int) ports
// and sets an initial value for flow
func (fg *Flowgraph) ConnectInit(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{},
	init interface{}) *Stream {
	return fg.connectInit(upstream, upstreamPort, dnstream, dnstreamPort, init)
}

// connectInit connects two hubs via named (string) or indexed (int) ports
// and sets an initial value for flow
func (fg *Flowgraph) connectInit(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{},
	init interface{}) *Stream {

	var us *Stream
	var usok bool
	switch v := upstreamPort.(type) {
	case string:
		us, usok = upstream.FindResult(v)
		if !usok {
			upstream.Panicf("No result port \"%s\" found on Hub \"%s\"\n", v, upstream.Name())
		}
	case int:
		usok = v >= 0 && v < upstream.NumResult()
		if !usok {
			upstream.Panicf("No result port %d found on Hub \"%s\"\n", v, dnstream.Name())
		}
		us = upstream.Result(v)
	default:
		upstream.Panicf("Need string or int to specify port on upstream Hub \"%s\"\n", upstream.Name())
	}

	var ds *Stream
	var dsok bool
	switch v := dnstreamPort.(type) {
	case string:
		ds, dsok = dnstream.FindSource(v)
		if !dsok {
			dnstream.Panicf("No source port \"%s\" found on Hub \"%s\"\n", v, dnstream.Name())
		}
	case int:
		dsok = v >= 0 && v < dnstream.NumSource()
		if !dsok {
			upstream.Panicf("No source port %d found on Hub \"%s\"\n", v, dnstream.Name())
		}
		ds = dnstream.Source(v)
	default:
		dnstream.Panicf("Need string or int to specify port on downstream Hub \"%s\"\n", dnstream.Name())
	}

	if us.base == nil && ds.base == nil {
		s := fg.NewStream("")
		s.Init(init)
		fg.streams = append(fg.streams, s)
		upstream.SetResult(upstreamPort, s)
		dnstream.SetSource(dnstreamPort, s)
		return s
	}
	if us.base == nil {
		upstream.SetResult(upstreamPort, ds)
	} else if ds.base == nil {
		dnstream.SetSource(dnstreamPort, us)
	} else {
		panic("Unexpected two ends to connect but they both are already connected")
	}
	return nil
}

// Run runs the flowgraph
func (fg *Flowgraph) Run() {
	var nodes = make([]*fgbase.Node, len(fg.hubs))
	for i := range nodes {
		nodes[i] = fg.hubs[i].base
	}
	fgbase.RunGraph(nodes)
}

func allOfFire(n *fgbase.Node) error {
	var a []interface{}
	a = make([]interface{}, len(n.Srcs))
	t := n.Aux.(Transformer)
	eofflag := false
	for i, _ := range a {
		a[i] = n.Srcs[i].SrcGet()
		if v, ok := a[i].(error); ok && v.Error() == "EOF" {
			n.Srcs[i].Flow = false
			eofflag = true
		}
	}
	x, _ := t.Transform(&Hub{n}, a)
	for i, _ := range x {
		if eofflag {
			n.Dsts[i].DstPut(EOF)
		} else {
			n.Dsts[i].DstPut(x[i])
		}
	}
	if eofflag {
		return EOF
	} else {
		return nil
	}

}

func oneOfRdy(n *fgbase.Node) bool {
	for _, v := range n.Srcs {
		if v.SrcRdy(n) {
			return true
		}
	}
	return false
}

func oneOfFire(n *fgbase.Node) error {
	var a []interface{}
	a = make([]interface{}, len(n.Srcs))
	t := n.Aux.(Transformer)
	eofflag := false
	for i, _ := range a {
		if n.Srcs[i].SrcRdy(n) {
			a[i] = n.Srcs[i].SrcGet()
			if v, ok := a[i].(error); ok && v.Error() == "EOF" {
				n.Srcs[i].Flow = false
				eofflag = true
			}
			break
		}
	}
	x, _ := t.Transform(&Hub{n}, a)
	for i, _ := range x {
		if eofflag {
			n.Dsts[i].DstPut(EOF)
		} else {
			n.Dsts[i].DstPut(x[i])
		}
	}
	if eofflag {
		return EOF
	} else {
		return nil
	}

}

func retrieveFire(n *fgbase.Node) error {
	retriever := n.Aux.(Retriever)
	v, err := retriever.Retrieve(&Hub{n})
	n.Dsts[0].DstPut(v)
	return err
}

func transmitFire(n *fgbase.Node) error {
	transmitter := n.Aux.(Transmitter)
	err := transmitter.Transmit(&Hub{n}, n.Srcs[0].SrcGet())
	return err
}
<commit_msg>doc owrk<commit_after>// Package flowgraph for scalable asynchronous system development
// https://github.com/vectaport/flowgraph/wiki
package flowgraph

import (
	"github.com/vectaport/fgbase"

	"errors"
	"fmt"
	"log"
)

/*=====================================================================*/

// End of flow
var EOF = errors.New("EOF")

// Hub code
type Code int

// Code constants for NewHub, followed by init type and description
const (
	Retrieve Code = iota // Retriever	retrieve one value with Retriever
	Transmit             // Transmitter	transmit one value with Transmitter
	AllOf                // Transformer	waiting for all sources
	OneOf                // Transformer	waiting for one source
 	Array                // []interface{}	produce array of values then EOF
	Const                // interface{}	produce constant values forever
	Sink                 // [Sinker]	consume values forever
	Rdy                  // nil		wait for zeroth source to pass rest
	Pass                 // nil		pass all values
	Steer                // nil		steer rest by zeroth source
	Select               // nil		select rest by zeroth source
	Add                  // nil		add numbers, concat strings, or use Add(interface{})
	Sub                  // nil		subtract numbers or use Sub(interface{})
	Mul                  // nil		multiply numbers or use Mul(interface{})
	Div                  // nil		divide numbers or use Div(interface{})
	Mod                  // nil		modulato numbers or use Mod(interface{})
	And                  // nil		and bool, bit-wise and integers, or use And(interface{})
	Or                   // nil		or bool, bit-wise or integers, or use Or(interface{})
	Not                  // nil		negate bool, invert integers, or use Not(interface{})
	Shift                // ShiftCode	shift integers - LeftShift, RightShift, LeftBarrel, RightBarrel, RightSigned
)

// Shift Code
type ShiftCode int

const (
	LeftShift ShiftCode = iota
	RightShift
	LeftBarrel
	RightBarrel
	RightSigned
)

/*=====================================================================*/

// Transformer transforms a slice of source values into a slice
// of result values with the Transform method. Use Hub.Tracef for tracing.
type Transformer interface {
	Transform(h *Hub, source []interface{}) (result []interface{}, err error)
}

// Retriever retrieves one value using the Retrieve method. Use Hub.Tracef for tracing.
type Retriever interface {
	Retrieve(h *Hub) (result interface{}, err error)
}

// Transmitter transmits one value using a Transmit method. Use Hub.Tracef for tracing.
type Transmitter interface {
	Transmit(h *Hub, source interface{}) (err error)
}

// Sinker consumes wavefronts of values one at a time forever
type Sinker interface {
	Sink(source []interface{})
}

/*=====================================================================*/

// Flowgraph struct for flowgraphs assembled out of hubs and streams
type Flowgraph struct {
	name         string
	hubs         []*Hub
	streams      []*Stream
	nameToHub    map[string]*Hub
	nameToStream map[string]*Stream
}

// New returns a named flowgraph
func New(name string) *Flowgraph {
	nameToHub := make(map[string]*Hub)
	nameToStream := make(map[string]*Stream)
	fg := Flowgraph{name, nil, nil, nameToHub, nameToStream}
	return &fg
}

// Name returns the name of this flowgraph
func (fg *Flowgraph) Name() string {
	return fg.Name()
}

// Hub returns a hub by index
func (fg *Flowgraph) Hub(n int) *Hub {
	return fg.hubs[n]
}

// Stream returns a stream by index
func (fg *Flowgraph) Stream(n int) *Stream {
	return fg.streams[n]
}

// NumHub returns the number of hubs
func (fg *Flowgraph) NumHub() int {
	return len(fg.hubs)
}

// NumStream returns the number of hubs
func (fg *Flowgraph) NumStream() int {
	return len(fg.streams)
}

// NewHub returns a new unconnected hub
func (fg *Flowgraph) NewHub(name string, code Code, init interface{}) *Hub {

	var n fgbase.Node

	switch code {

	// User Supplied Hubs
	case AllOf:
		if _, ok := init.(Transformer); !ok {
			panic(fmt.Sprintf("Hub with AllOf code not given Transformer for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, allOfFire)
	case OneOf:
		if _, ok := init.(Transformer); !ok {
			panic(fmt.Sprintf("Hub with OneOf code not given Transformer for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, oneOfRdy, oneOfFire)
	case Retrieve:
		if _, ok := init.(Retriever); !ok {
			panic(fmt.Sprintf("Hub with Retrieve code not given Retriever for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, retrieveFire)
	case Transmit:
		if _, ok := init.(Transmitter); !ok {
			panic(fmt.Sprintf("Hub with Transmit code not given Transmitter for init %T(%+v)", init, init))
		}
		n = fgbase.MakeNode(name, nil, nil, nil, transmitFire)

	// Math Hubs
	case Add:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.AddFire)
	case Sub:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.SubFire)
	case Mul:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.MulFire)
	case Div:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil, nil}, []*fgbase.Edge{nil}, nil, fgbase.DivFire)

	// General Purpose Hubs
	case Rdy:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.RdyFire)
	case Array:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.ArrayFire)
	case Const:
		n = fgbase.MakeNode(name, nil, []*fgbase.Edge{nil}, nil, fgbase.ConstFire)
	case Sink:
		if init != nil {
			if _, ok := init.(Sinker); !ok {
				panic(fmt.Sprintf("Hub with Sink code not given Sinker for init %T(%+v)", init, init))
			}
		}
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil}, nil, nil, fgbase.SinkFire)
	case Steer:
		n = fgbase.MakeNode(name, []*fgbase.Edge{nil}, nil, fgbase.SteervRdy, fgbase.SteervFire)
	default:
		log.Panicf("Unexpected Hub code:  %s\n", code)
	}
	if n.Aux == nil {
		n.Aux = init
	}

	h := Hub{&n}
	fg.hubs = append(fg.hubs, &h)
	fg.nameToHub[name] = &h
	return &h
}

// NewStream returns a new unconnected stream
func (fg *Flowgraph) NewStream(name string) *Stream {
	e := fgbase.MakeEdge(name, nil)
	s := Stream{&e}
	fg.streams = append(fg.streams, &s)
	fg.nameToStream[name] = &s
	return &s
}

// FindHub finds a hub by name
func (fg *Flowgraph) FindHub(name string) *Hub {
	return fg.nameToHub[name]
}

// FindStream finds a Stream by name
func (fg *Flowgraph) FindStream(name string) *Stream {
	return fg.nameToStream[name]
}

// Connect connects two hubs via named (string) or indexed (int) ports
func (fg *Flowgraph) Connect(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{}) *Stream {
	return fg.connectInit(upstream, upstreamPort, dnstream, dnstreamPort, nil)
}

// ConnectInit connects two hubs via named (string) or indexed (int) ports
// and sets an initial value for flow
func (fg *Flowgraph) ConnectInit(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{},
	init interface{}) *Stream {
	return fg.connectInit(upstream, upstreamPort, dnstream, dnstreamPort, init)
}

// connectInit connects two hubs via named (string) or indexed (int) ports
// and sets an initial value for flow
func (fg *Flowgraph) connectInit(
	upstream *Hub, upstreamPort interface{},
	dnstream *Hub, dnstreamPort interface{},
	init interface{}) *Stream {

	var us *Stream
	var usok bool
	switch v := upstreamPort.(type) {
	case string:
		us, usok = upstream.FindResult(v)
		if !usok {
			upstream.Panicf("No result port \"%s\" found on Hub \"%s\"\n", v, upstream.Name())
		}
	case int:
		usok = v >= 0 && v < upstream.NumResult()
		if !usok {
			upstream.Panicf("No result port %d found on Hub \"%s\"\n", v, dnstream.Name())
		}
		us = upstream.Result(v)
	default:
		upstream.Panicf("Need string or int to specify port on upstream Hub \"%s\"\n", upstream.Name())
	}

	var ds *Stream
	var dsok bool
	switch v := dnstreamPort.(type) {
	case string:
		ds, dsok = dnstream.FindSource(v)
		if !dsok {
			dnstream.Panicf("No source port \"%s\" found on Hub \"%s\"\n", v, dnstream.Name())
		}
	case int:
		dsok = v >= 0 && v < dnstream.NumSource()
		if !dsok {
			upstream.Panicf("No source port %d found on Hub \"%s\"\n", v, dnstream.Name())
		}
		ds = dnstream.Source(v)
	default:
		dnstream.Panicf("Need string or int to specify port on downstream Hub \"%s\"\n", dnstream.Name())
	}

	if us.base == nil && ds.base == nil {
		s := fg.NewStream("")
		s.Init(init)
		fg.streams = append(fg.streams, s)
		upstream.SetResult(upstreamPort, s)
		dnstream.SetSource(dnstreamPort, s)
		return s
	}
	if us.base == nil {
		upstream.SetResult(upstreamPort, ds)
	} else if ds.base == nil {
		dnstream.SetSource(dnstreamPort, us)
	} else {
		panic("Unexpected two ends to connect but they both are already connected")
	}
	return nil
}

// Run runs the flowgraph
func (fg *Flowgraph) Run() {
	var nodes = make([]*fgbase.Node, len(fg.hubs))
	for i := range nodes {
		nodes[i] = fg.hubs[i].base
	}
	fgbase.RunGraph(nodes)
}

func allOfFire(n *fgbase.Node) error {
	var a []interface{}
	a = make([]interface{}, len(n.Srcs))
	t := n.Aux.(Transformer)
	eofflag := false
	for i, _ := range a {
		a[i] = n.Srcs[i].SrcGet()
		if v, ok := a[i].(error); ok && v.Error() == "EOF" {
			n.Srcs[i].Flow = false
			eofflag = true
		}
	}
	x, _ := t.Transform(&Hub{n}, a)
	for i, _ := range x {
		if eofflag {
			n.Dsts[i].DstPut(EOF)
		} else {
			n.Dsts[i].DstPut(x[i])
		}
	}
	if eofflag {
		return EOF
	} else {
		return nil
	}

}

func oneOfRdy(n *fgbase.Node) bool {
	for _, v := range n.Srcs {
		if v.SrcRdy(n) {
			return true
		}
	}
	return false
}

func oneOfFire(n *fgbase.Node) error {
	var a []interface{}
	a = make([]interface{}, len(n.Srcs))
	t := n.Aux.(Transformer)
	eofflag := false
	for i, _ := range a {
		if n.Srcs[i].SrcRdy(n) {
			a[i] = n.Srcs[i].SrcGet()
			if v, ok := a[i].(error); ok && v.Error() == "EOF" {
				n.Srcs[i].Flow = false
				eofflag = true
			}
			break
		}
	}
	x, _ := t.Transform(&Hub{n}, a)
	for i, _ := range x {
		if eofflag {
			n.Dsts[i].DstPut(EOF)
		} else {
			n.Dsts[i].DstPut(x[i])
		}
	}
	if eofflag {
		return EOF
	} else {
		return nil
	}

}

func retrieveFire(n *fgbase.Node) error {
	retriever := n.Aux.(Retriever)
	v, err := retriever.Retrieve(&Hub{n})
	n.Dsts[0].DstPut(v)
	return err
}

func transmitFire(n *fgbase.Node) error {
	transmitter := n.Aux.(Transmitter)
	err := transmitter.Transmit(&Hub{n}, n.Srcs[0].SrcGet())
	return err
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2010 Seyi Ogunyemi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package fluidinfo

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type readClose struct {
	io.Reader
	io.Closer
}

type badStringError struct {
	what string
	str  string
}

func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

func send(req *http.Request) (resp *http.Response, err error) {
	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":http"
	}
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req)
	if err != nil {
		conn.Close()
		return nil, err
	}
	r := io.Reader(reader)
	if v := resp.Header["Content-Length"]; v != nil {
		n, err := strconv.Atoi(v[0])
		if err != nil {
			return nil, &badStringError{"invalid Content-Length", v[0]}
		}
		v := int64(n)
		r = io.LimitReader(r, v)
	}
	resp.Body = readClose{r, conn}
	return
}

func encodedUsernameAndPassword(user, pwd string) string {
	bb := &bytes.Buffer{}
	encoder := base64.NewEncoder(base64.StdEncoding, bb)
	encoder.Write([]byte(user + ":" + pwd))
	encoder.Close()
	return bb.String()
}

// Naive utility url encode method.  Converts a string map into a query string
//
// Returns a string in the format "?param1=value1&param2=value2"
func UrlEncode(urlmap map[string]string) string {
	url_ := "?"
	var temp []string
	var key, value string
	for key, value = range urlmap {
		temp = append(temp, key+"="+value)
	}
	url_ += strings.Join(temp, "&")
	return url_
}

func authGet(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "GET"
	req.Header = map[string][]string{"Authorization": {"Basic " +
		encodedUsernameAndPassword(user, pwd)}}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Post issues a POST to the specified URL.
//
// Caller should close r.Body when done reading it.
func authPost(url_, user, pwd, client, clientURL, version, agent, bodyType string,
	body io.Reader) (r *http.Response, err error) {
	var req http.Request
	req.Method = "POST"
	req.Body = body.(io.ReadCloser)
	req.Header = map[string][]string{
		"Content-Type":           {bodyType},
		"Transfer-Encoding":      {"chunked"},
		"User-Agent":             {agent},
		"X-Fluidinfo-Client":     {client},
		"X-Fluidinfo-Client-URL": {clientURL},
		"X-Fluidinfo-Version":    {version},
		"Authorization":          {"Basic " + encodedUsernameAndPassword(user, pwd)},
	}

	req.URL, err = url.Parse(url_)
	if err != nil {
		return nil, err
	}

	return send(&req)
}

// Put issues a PUT to the specified URL.
//
// Caller should close r.Body when done reading it.
func authPut(url_, user, pwd, client, clientURL, version, agent, bodyType string,
	body io.Reader) (r *http.Response, err error) {
	var req http.Request
	req.Method = "PUT"
	req.Body = body.(io.ReadCloser)
	if user != "" && pwd != "" {
		req.Header = map[string][]string{
			"Content-Type":           {bodyType},
			"Transfer-Encoding":      {"chunked"},
			"User-Agent":             {agent},
			"X-Fluidinfo-Client":     {client},
			"X-Fluidinfo-Client-URL": {clientURL},
			"X-Fluidinfo-Version":    {version},
			"Authorization":          {"Basic " + encodedUsernameAndPassword(user, pwd)},
		}
	} else {
		req.Header = map[string][]string{
			"Content-Type":           {bodyType},
			"Transfer-Encoding":      {"chunked"},
			"User-Agent":             {agent},
			"X-Fluidinfo-Client":     {client},
			"X-Fluidinfo-Client-URL": {clientURL},
			"X-Fluidinfo-Version":    {version},
		}
	}

	req.URL, err = url.Parse(url_)
	if err != nil {
		return nil, err
	}

	return send(&req)
}

// Delete issues a DELETE to the specified URL.
func authDelete(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "DELETE"
	if user != "" && pwd != "" {
		req.Header = map[string][]string{"Authorization": {"Basic " +
			encodedUsernameAndPassword(user, pwd)}}
	}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Head issues a HEAD to the specified URL.
func authHead(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "HEAD"
	if user != "" && pwd != "" {
		req.Header = map[string][]string{"Authorization": {"Basic " +
			encodedUsernameAndPassword(user, pwd)}}
	}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Do an authenticated Get if we've called Authenticated, otherwise
// just Get it without authentication
func httpGet(url_, user, pwd string) (*http.Response, string, error) {
	var r *http.Response
	var full string = ""
	var err error
	if user != "" && pwd != "" {
		r, err = authGet(url_, user, pwd)
	} else {
		r, err = http.Get(url_)
	}
	return r, full, err
}

// Do an authenticated Post if we've called Authenticated, otherwise
// just Post it without authentication
func httpPost(url_, user, pwd, client, clientURL, version, agent,
	data string) (*http.Response, error) {
	var r *http.Response
	var err error
	body := bytes.NewBufferString(data)
	bodyType := "application/json"
	if user != "" && pwd != "" {
		r, err = authPost(url_, user, pwd, client, clientURL,
			version, agent, bodyType, body)
	} else {
		r, err = http.Post(url_, bodyType, body)
	}
	return r, err
}

// Do an authenticated Put
func httpPut(url_, user, pwd, client, clientURL, version, agent,
	data string) (*http.Response, error) {
	var r *http.Response
	var err error
	body := bytes.NewBufferString(data)
	bodyType := "application/json"
	r, err = authPut(url_, user, pwd, client, clientURL,
		version, agent, bodyType, body)
	return r, err
}

// Do an authenticated Delete
func httpDelete(url_, user, pwd string) (*http.Response, error) {
	var r *http.Response
	var err error
	r, err = authDelete(url_, user, pwd)
	return r, err
}

// Do an authenticated Head
func httpHead(url_, user, pwd string) (*http.Response, error) {
	var r *http.Response
	var err error
	r, err = authHead(url_, user, pwd)
	return r, err
}

const (
	DEFAULT_CLIENT         = "gofluidinfo"
	DEFAULT_CLIENT_URL     = "http://github.com/micrypt/gofluidinfo"
	DEFAULT_CLIENT_VERSION = "0.1"
	DEFAULT_USER_AGENT     = "gofluidinfo"
	ERROR                  = "gofluidinfo Error: "
	WARNING                = "gofluidinfo Warning: "
	DEFAULT_PORT           = 80
	SECURE_PORT            = 443
	UNIX_CREDENTIALS_FILE  = ".fluidinfocredentials"
	// Here's hoping there's a stable Go port to the Windows platform sometime in the future.
	// WINDOWS_CREDENTIALS_FILE    = "fluidinfocredentials.ini"
	RETRY_TIMEOUT          = 5e9 // unlikely the user will choose this
	PRIMITIVE_CONTENT_TYPE = "application/vnd.fluidinfo.value+json"
	HEADER_ERROR           = "X-Fluidinfo-Error-Class"
	HEADER_REQUEST_ID      = "X-Fluidinfo-Request-Id"
	FLUIDINFO_PATH         = "http://fluiddb.fluidinfo.com"
	SANDBOX_PATH           = "http://sandbox.fluidinfo.com"
)

type Client struct {
	Username  string
	Password  string
	URL       string
	Client    string
	ClientURL string
	Version   string
	Agent     string
}

func NewClient(username, password string) *Client {
	return &Client{username, password, SANDBOX_PATH, DEFAULT_CLIENT, DEFAULT_CLIENT_URL, DEFAULT_CLIENT_VERSION, DEFAULT_USER_AGENT}
}

func (self *Client) SetActiveMode() {
	self.URL = FLUIDINFO_PATH
}

func (self *Client) Get(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, _, err = httpGet(url_, self.Username, self.Password)
	return resp, err
}

func (self *Client) Post(url_, data string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpPost(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
	return resp, err
}

func (self *Client) Put(url_, data string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpPut(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
	return resp, err
}

func (self *Client) Delete(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpDelete(url_, self.Username, self.Password)
	return resp, err
}

func (self *Client) Head(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpHead(url_, self.Username, self.Password)
	return resp, err
}
<commit_msg>pkg:fluidinfo: clean up comments.<commit_after>/*
Copyright (c) 2010 Seyi Ogunyemi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package fluidinfo

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type readClose struct {
	io.Reader
	io.Closer
}

type badStringError struct {
	what string
	str  string
}

func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

func send(req *http.Request) (resp *http.Response, err error) {
	addr := req.URL.Host
	if !hasPort(addr) {
		addr += ":http"
	}
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return nil, err
	}
	reader := bufio.NewReader(conn)
	resp, err = http.ReadResponse(reader, req)
	if err != nil {
		conn.Close()
		return nil, err
	}
	r := io.Reader(reader)
	if v := resp.Header["Content-Length"]; v != nil {
		n, err := strconv.Atoi(v[0])
		if err != nil {
			return nil, &badStringError{"invalid Content-Length", v[0]}
		}
		v := int64(n)
		r = io.LimitReader(r, v)
	}
	resp.Body = readClose{r, conn}
	return
}

func encodedUsernameAndPassword(user, pwd string) string {
	bb := &bytes.Buffer{}
	encoder := base64.NewEncoder(base64.StdEncoding, bb)
	encoder.Write([]byte(user + ":" + pwd))
	encoder.Close()
	return bb.String()
}

// Naive utility url encode method.  Converts a string map into a query string and
// returns a string in the format "?param1=value1&param2=value2"
func UrlEncode(urlmap map[string]string) string {
	url_ := "?"
	var temp []string
	var key, value string
	for key, value = range urlmap {
		temp = append(temp, key+"="+value)
	}
	url_ += strings.Join(temp, "&")
	return url_
}

func authGet(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "GET"
	req.Header = map[string][]string{"Authorization": {"Basic " +
		encodedUsernameAndPassword(user, pwd)}}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Post issues a POST to the specified URL.
// Caller should close r.Body when done reading it.
func authPost(url_, user, pwd, client, clientURL, version, agent, bodyType string,
	body io.Reader) (r *http.Response, err error) {
	var req http.Request
	req.Method = "POST"
	req.Body = body.(io.ReadCloser)
	req.Header = map[string][]string{
		"Content-Type":           {bodyType},
		"Transfer-Encoding":      {"chunked"},
		"User-Agent":             {agent},
		"X-Fluidinfo-Client":     {client},
		"X-Fluidinfo-Client-URL": {clientURL},
		"X-Fluidinfo-Version":    {version},
		"Authorization":          {"Basic " + encodedUsernameAndPassword(user, pwd)},
	}

	req.URL, err = url.Parse(url_)
	if err != nil {
		return nil, err
	}

	return send(&req)
}

// Put issues a PUT to the specified URL.
// Caller should close r.Body when done reading it.
func authPut(url_, user, pwd, client, clientURL, version, agent, bodyType string,
	body io.Reader) (r *http.Response, err error) {
	var req http.Request
	req.Method = "PUT"
	req.Body = body.(io.ReadCloser)
	if user != "" && pwd != "" {
		req.Header = map[string][]string{
			"Content-Type":           {bodyType},
			"Transfer-Encoding":      {"chunked"},
			"User-Agent":             {agent},
			"X-Fluidinfo-Client":     {client},
			"X-Fluidinfo-Client-URL": {clientURL},
			"X-Fluidinfo-Version":    {version},
			"Authorization":          {"Basic " + encodedUsernameAndPassword(user, pwd)},
		}
	} else {
		req.Header = map[string][]string{
			"Content-Type":           {bodyType},
			"Transfer-Encoding":      {"chunked"},
			"User-Agent":             {agent},
			"X-Fluidinfo-Client":     {client},
			"X-Fluidinfo-Client-URL": {clientURL},
			"X-Fluidinfo-Version":    {version},
		}
	}

	req.URL, err = url.Parse(url_)
	if err != nil {
		return nil, err
	}

	return send(&req)
}

// Delete issues a DELETE to the specified URL.
func authDelete(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "DELETE"
	if user != "" && pwd != "" {
		req.Header = map[string][]string{"Authorization": {"Basic " +
			encodedUsernameAndPassword(user, pwd)}}
	}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Head issues a HEAD to the specified URL.
func authHead(url_, user, pwd string) (r *http.Response, err error) {
	var req http.Request
	req.Method = "HEAD"
	if user != "" && pwd != "" {
		req.Header = map[string][]string{"Authorization": {"Basic " +
			encodedUsernameAndPassword(user, pwd)}}
	}
	if req.URL, err = url.Parse(url_); err != nil {
		return
	}
	if r, err = send(&req); err != nil {
		return
	}
	return
}

// Do an authenticated Get if we've called Authenticated, otherwise
// just Get it without authentication.
func httpGet(url_, user, pwd string) (*http.Response, string, error) {
	var r *http.Response
	var full string = ""
	var err error
	if user != "" && pwd != "" {
		r, err = authGet(url_, user, pwd)
	} else {
		r, err = http.Get(url_)
	}
	return r, full, err
}

// Do an authenticated Post if we've called Authenticated, otherwise
// just Post it without authentication.
func httpPost(url_, user, pwd, client, clientURL, version, agent,
	data string) (*http.Response, error) {
	var r *http.Response
	var err error
	body := bytes.NewBufferString(data)
	bodyType := "application/json"
	if user != "" && pwd != "" {
		r, err = authPost(url_, user, pwd, client, clientURL,
			version, agent, bodyType, body)
	} else {
		r, err = http.Post(url_, bodyType, body)
	}
	return r, err
}

// Do an authenticated Put.
func httpPut(url_, user, pwd, client, clientURL, version, agent,
	data string) (*http.Response, error) {
	var r *http.Response
	var err error
	body := bytes.NewBufferString(data)
	bodyType := "application/json"
	r, err = authPut(url_, user, pwd, client, clientURL,
		version, agent, bodyType, body)
	return r, err
}

// Do an authenticated Delete.
func httpDelete(url_, user, pwd string) (*http.Response, error) {
	var r *http.Response
	var err error
	r, err = authDelete(url_, user, pwd)
	return r, err
}

// Do an authenticated Head.
func httpHead(url_, user, pwd string) (*http.Response, error) {
	var r *http.Response
	var err error
	r, err = authHead(url_, user, pwd)
	return r, err
}

const (
	DEFAULT_CLIENT           = "gofluidinfo"
	DEFAULT_CLIENT_URL       = "http://github.com/micrypt/gofluidinfo"
	DEFAULT_CLIENT_VERSION   = "0.1"
	DEFAULT_USER_AGENT       = "gofluidinfo"
	ERROR                    = "gofluidinfo Error: "
	WARNING                  = "gofluidinfo Warning: "
	DEFAULT_PORT             = 80
	SECURE_PORT              = 443
	UNIX_CREDENTIALS_FILE    = ".fluidinfocredentials"
	WINDOWS_CREDENTIALS_FILE = "fluidinfocredentials.ini"
	RETRY_TIMEOUT            = 5e9
	PRIMITIVE_CONTENT_TYPE   = "application/vnd.fluidinfo.value+json"
	HEADER_ERROR             = "X-Fluidinfo-Error-Class"
	HEADER_REQUEST_ID        = "X-Fluidinfo-Request-Id"
	FLUIDINFO_PATH           = "http://fluiddb.fluidinfo.com"
	SANDBOX_PATH             = "http://sandbox.fluidinfo.com"
)

type Client struct {
	Username  string
	Password  string
	URL       string
	Client    string
	ClientURL string
	Version   string
	Agent     string
}

func NewClient(username, password string) *Client {
	return &Client{username, password, SANDBOX_PATH, DEFAULT_CLIENT, DEFAULT_CLIENT_URL, DEFAULT_CLIENT_VERSION, DEFAULT_USER_AGENT}
}

func (self *Client) SetActiveMode() {
	self.URL = FLUIDINFO_PATH
}

func (self *Client) Get(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, _, err = httpGet(url_, self.Username, self.Password)
	return resp, err
}

func (self *Client) Post(url_, data string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpPost(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
	return resp, err
}

func (self *Client) Put(url_, data string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpPut(url_, self.Username, self.Password, self.Client, self.ClientURL, self.Version, self.Agent, data)
	return resp, err
}

func (self *Client) Delete(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpDelete(url_, self.Username, self.Password)
	return resp, err
}

func (self *Client) Head(url_ string) (*http.Response, error) {
	url_ = self.URL + url_
	var resp *http.Response
	var err error
	resp, err = httpHead(url_, self.Username, self.Password)
	return resp, err
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net/http"
	"os"
	"runtime"
	"strings"
)

var (
	wguid int = 0
)

// the request worker
type Worker struct {
	wid     int
	client  *http.Client
	request *http.Request
	tpwd    chan string
	pwd     chan string
}

func newRequest(address string) (*http.Request, error) {
	req, err := http.NewRequest("GET", address, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "text/html,application/xhtml+xml,"+
		"application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; widows x86_64) "+
		"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36")
	return req, nil
}

func NewWorker(host string, tpwd, pwd chan string) (*Worker, error) {
	transport := &http.Transport{}
	client := &http.Client{
		Transport: transport,
	}
	req, err := newRequest(host)
	if err != nil {
		return nil, err
	}
	w := &Worker{
		wid:     wguid,
		client:  client,
		request: req,
		tpwd:    tpwd,
		pwd:     pwd,
	}
	wguid += 1
	return w, nil
}

func (w *Worker) Wid() int {
	return w.wid
}

//try http
func (w *Worker) Try() {
	for line := range w.tpwd {
		line = strings.TrimSpace(line)
		w.request.SetBasicAuth("admin", line)
		resp, err := w.client.Do(w.request)
		defer resp.Body.Close()
		if err != nil {
			fmt.Printf("Worker%d try password:%s err:%s\n", w.Wid(), line, err.Error())
			return
		}
		if resp.StatusCode < 400 {
			w.pwd <- line
			return
		}
		fmt.Printf("Worker%d try password:%s code:%d\n", w.Wid(), line, resp.StatusCode)
	}
	close(w.pwd)
}

func scanFile(f *os.File, tpwd chan string) {
	defer f.Close()
	scanner := bufio.NewScanner(f)
	var line string
	for scanner.Scan() {
		line = scanner.Text()
		tpwd <- line
		// fmt.Printf("Scan text:%s\n", line)
	}
	if err := scanner.Err(); err != nil {
		fmt.Printf("Scan error:%s\n", err.Error())
	}
	close(tpwd)
}

func main() {
	maxcpus := runtime.NumCPU()
	tpwd := make(chan string, maxcpus-1)
	pwd := make(chan string, 1)
	filename := "password.txt"
	f, err := os.Open(filename)
	if err != nil {
		fmt.Println(err)
		return
	}
	runtime.GOMAXPROCS(maxcpus)
	go scanFile(f, tpwd)

	for i := 0; i < maxcpus-1; i++ {
		w, err := NewWorker("http://192.168.2.1", tpwd, pwd)
		fmt.Printf("Start worker%d\n", w.Wid())
		if err != nil {
			fmt.Printf("Error:%s\n", err.Error())
			continue
		}
		go w.Try()
	}

	getpwd, ok := <-pwd
	if ok {
		fmt.Printf("Get password:%s\n", getpwd)
	} else {
		fmt.Println("Get nothing")
	}
}
<commit_msg>using fmt instead of log<commit_after>package main

import (
	"bufio"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
)

var (
	wguid int = 0
)

// the request worker
type Worker struct {
	wid     int
	client  *http.Client
	request *http.Request
	tpwd    chan string
	pwd     chan string
}

func newRequest(address string) (*http.Request, error) {
	req, err := http.NewRequest("GET", address, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "text/html,application/xhtml+xml,"+
		"application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; widows x86_64) "+
		"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36")
	return req, nil
}

func NewWorker(host string, tpwd, pwd chan string) (*Worker, error) {
	transport := &http.Transport{}
	client := &http.Client{
		Transport: transport,
	}
	req, err := newRequest(host)
	if err != nil {
		return nil, err
	}
	w := &Worker{
		wid:     wguid,
		client:  client,
		request: req,
		tpwd:    tpwd,
		pwd:     pwd,
	}
	wguid += 1
	return w, nil
}

func (w *Worker) Wid() int {
	return w.wid
}

//try http
func (w *Worker) Try() {
	for line := range w.tpwd {
		line = strings.TrimSpace(line)
		w.request.SetBasicAuth("admin", line)
		resp, err := w.client.Do(w.request)
		defer resp.Body.Close()
		if err != nil {
			log.Printf("Worker%d try password:%s err:%s\n", w.Wid(), line, err.Error())
			return
		}
		if resp.StatusCode < 400 {
			w.pwd <- line
			return
		}
		log.Printf("Worker%d try password:%s code:%d\n", w.Wid(), line, resp.StatusCode)
	}
	close(w.pwd)
}

func scanFile(f *os.File, tpwd chan string) {
	defer f.Close()
	scanner := bufio.NewScanner(f)
	var line string
	for scanner.Scan() {
		line = scanner.Text()
		tpwd <- line
		// log.Printf("Scan text:%s\n", line)
	}
	if err := scanner.Err(); err != nil {
		log.Printf("Scan error:%s\n", err.Error())
	}
	close(tpwd)
}

func main() {
	maxcpus := runtime.NumCPU()
	tpwd := make(chan string, maxcpus-1)
	pwd := make(chan string, 1)
	filename := "password.txt"
	f, err := os.Open(filename)
	if err != nil {
		log.Fatalln(err)
	}
	runtime.GOMAXPROCS(maxcpus)
	go scanFile(f, tpwd)

	for i := 0; i < maxcpus-1; i++ {
		w, err := NewWorker("http://192.168.2.1", tpwd, pwd)
		log.Printf("Start worker%d\n", w.Wid())
		if err != nil {
			log.Printf("Error:%s\n", err.Error())
			continue
		}
		go w.Try()
	}

	getpwd, ok := <-pwd
	if ok {
		log.Printf("Get password:%s\n", getpwd)
	} else {
		log.Println("Get nothing")
	}
}
<|endoftext|>


<commit_before>package easyreq

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"testing"
)

func TestMultipartForm(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) { testData(t, w, r) }
	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := Form{}
	f.Field().Add("Name", "John")
	f.File().Add("File", "test-files/logo.png")

	req, err := f.Request("POST", ts.URL+"/?test=true")
	if err != nil {
		t.Error(err)
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}

	contentType := req.Header.Get("Content-Type")
	if contentType == "application/x-www-form-urlencoded" {
		t.Error(contentType)
	}

	if _, err := f.Do("POST", ts.URL+"/?test=true"); err != nil {
		t.Error(err)
	}
}

func TestSimpleGet(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Query().Get("Name") != "John" {
			t.Error(r.URL)
		}
	}

	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := Form{}
	f.Field().Add("Name", "John")

	req, err := f.Request("GET", ts.URL)
	if err != nil {
		t.Error(err)
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}

}

func TestSimplestGet(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		if len(r.URL.Query()) > 0 {
			t.Error(r.URL)
		}
	}

	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	if _, err := (&Form{}).Do("GET", ts.URL); err != nil {
		t.Error(err)
	}
}

func TestPostForm(t *testing.T) {
	testForm("POST", t, func(r *http.Request) {
		ctype := r.Header.Get("Content-Type")
		if ctype != "application/x-www-form-urlencoded" {
			t.Fatal(ctype)
		}
		if r.Method != "POST" {
			t.Fatal(r.Method)
		}
	})
}

func TestPutForm(t *testing.T) {
	testForm("PUT", t, func(r *http.Request) {
		ctype := r.Header.Get("Content-Type")
		if ctype != "application/x-www-form-urlencoded" {
			t.Fatal(ctype)
		}
		if r.Method != "PUT" {
			t.Fatal(r.Method)
		}
	})
}

func TestGetForm(t *testing.T) {
	testForm("GET", t, func(r *http.Request) {
		if r.Method != "GET" {
			t.Fatal(r.Method)
		}
	})
}

func testForm(verb string, t *testing.T, fn func(*http.Request)) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		fn(r)
		testData(t, w, r)
	}
	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := NewForm(nil, nil)
	f.Field().Add("Name", "John")
	f.Field().Add("Likes", "Ice Cream")
	f.Header().Add("Host", "example.com")

	req, err := f.Request(verb, ts.URL+"/?test=true")
	if err != nil {
		t.Error(err)
	}

	if req.Method != verb {
		t.Log(req.Method)
		t.Fail()
	}

	if req.Header.Get("Host") != "example.com" {
		t.Fail()
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}
}

func testData(t *testing.T, w http.ResponseWriter, r *http.Request) {
	ctype := r.Header.Get("Content-Type")
	m := make(url.Values)

	if strings.Contains(ctype, "json") {
		decoder := json.NewDecoder(r.Body)
		if err := decoder.Decode(&m); err != nil {
			t.Error(err)
		}
	} else if strings.Contains(ctype, "form") {
		if err := r.ParseMultipartForm(10 << 20); err != nil {
			t.Error(err)
		}
		m = r.Form
	} else {
		m = r.URL.Query()
	}

	if r.URL.Query().Get("test") != "true" {
		t.Error(r.URL)
	}

	if len(m["Name"]) == 0 || m["Name"][0] != "John" {
		t.Log(r.URL)
		t.Error(m)
	}

	if strings.Contains(ctype, "multipart") {
		if _, h, err := r.FormFile("File"); err != nil {
			t.Error(err)
		} else if h.Filename != "logo.png" {
			t.Error(h.Filename)
		}
	}
}

func TestFailedCase(t *testing.T) {
	f := Form{}
	f.Field().Add("Name", "John")
	f.File().Add("File", "test-files/logo1.png") //file doesn't exists

	_, err := f.Request("POST", "http://local/")
	if !os.IsNotExist(err) {
		t.Error(err)
	}
}
<commit_msg>Test multipart form and simple form<commit_after>package easyreq

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"testing"
)

func TestMultipartForm(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) { testData(t, w, r) }
	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := Form{}
	f.Field().Add("Name", "John")
	f.File().Add("File", "test-files/logo.png")

	req, err := f.Request("POST", ts.URL+"/?test=true")
	if err != nil {
		t.Error(err)
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}

	contentType := req.Header.Get("Content-Type")
	if contentType == "application/x-www-form-urlencoded" {
		t.Error(contentType)
	}

	if _, err := f.Do("POST", ts.URL+"/?test=true"); err != nil {
		t.Error(err)
	}
}

func TestSimpleGet(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Query().Get("Name") != "John" {
			t.Error(r.URL)
		}
	}

	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := Form{}
	f.Field().Add("Name", "John")

	req, err := f.Request("GET", ts.URL)
	if err != nil {
		t.Error(err)
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}

}

func TestSimplestGet(t *testing.T) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		if len(r.URL.Query()) > 0 {
			t.Error(r.URL)
		}
	}

	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	if _, err := (&Form{}).Do("GET", ts.URL); err != nil {
		t.Error(err)
	}
}

func TestPostForm(t *testing.T) {
	testForm("POST", t, func(r *http.Request) {
		ctype := r.Header.Get("Content-Type")
		if ctype != "application/x-www-form-urlencoded" {
			t.Fatal(ctype)
		}
		if r.Method != "POST" {
			t.Fatal(r.Method)
		}
	})
}

func TestPutForm(t *testing.T) {
	testForm("PUT", t, func(r *http.Request) {
		ctype := r.Header.Get("Content-Type")
		if ctype != "application/x-www-form-urlencoded" {
			t.Fatal(ctype)
		}
		if r.Method != "PUT" {
			t.Fatal(r.Method)
		}
	})
}

func TestGetForm(t *testing.T) {
	testForm("GET", t, func(r *http.Request) {
		if r.Method != "GET" {
			t.Fatal(r.Method)
		}
	})
}

func testForm(verb string, t *testing.T, fn func(*http.Request)) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		fn(r)
		testData(t, w, r)
	}
	ts := httptest.NewServer(http.HandlerFunc(handler))
	defer ts.Close()

	f := NewForm(nil, nil)
	f.Field().Add("Name", "John")
	f.Field().Add("Likes", "Ice Cream")
	f.Header().Add("Host", "example.com")

	req, err := f.Request(verb, ts.URL+"/?test=true")
	if err != nil {
		t.Error(err)
	}

	if req.Method != verb {
		t.Log(req.Method)
		t.Fail()
	}

	if req.Header.Get("Host") != "example.com" {
		t.Fail()
	}

	if _, err := http.DefaultClient.Do(req); err != nil {
		t.Error(err)
	}
}

func testData(t *testing.T, w http.ResponseWriter, r *http.Request) {
	ctype := r.Header.Get("Content-Type")
	m := make(url.Values)

	if strings.Contains(ctype, "json") {
		decoder := json.NewDecoder(r.Body)
		if err := decoder.Decode(&m); err != nil {
			t.Error(err)
		}
	} else if strings.Contains(ctype, "multipart") {
		if err := r.ParseMultipartForm(10 << 20); err != nil {
			t.Error(err)
		}
		m = r.Form
	} else if strings.Contains(ctype, "form") {
		if err := r.ParseForm(); err != nil {
			t.Error(err)
		}
		m = r.Form
	} else {
		m = r.URL.Query()
	}

	if r.URL.Query().Get("test") != "true" {
		t.Error(r.URL)
	}

	if len(m["Name"]) == 0 || m["Name"][0] != "John" {
		t.Log(r.URL)
		t.Error(m)
	}

	if strings.Contains(ctype, "multipart") {
		if _, h, err := r.FormFile("File"); err != nil {
			t.Error(err)
		} else if h.Filename != "logo.png" {
			t.Error(h.Filename)
		}
	}
}

func TestFailedCase(t *testing.T) {
	f := Form{}
	f.Field().Add("Name", "John")
	f.File().Add("File", "test-files/logo1.png") //file doesn't exists

	_, err := f.Request("POST", "http://local/")
	if !os.IsNotExist(err) {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package meritop

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/coreos/go-etcd/etcd"
)

type taskRole int

const (
	roleNone taskRole = iota
	roleParent
	roleChild
)

const (
	DataRequestPrefix string = "/datareq"
	DataRequestTaskID string = "taskID"
	DataRequestReq    string = "req"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID        uint64
	epoch         uint64
	etcdClient    *etcd.Client
	stops         []chan bool
	ln            net.Listener
	addressMap    map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan  chan *dataResponse
	dataCloseChan chan struct{}
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) taskRole {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return roleParent
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return roleChild
		}
	}
	return roleNone
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)
	f.dataCloseChan = make(chan struct{})

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(roleParent, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(roleChild, f.topology.GetChildren(f.epoch))
	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	go f.startHttp()
	go f.dataResponseReceiver()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

func newDataReqHandler(f *framework) http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc(DataRequestPrefix, func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query()
		fromIDStr := q.Get(DataRequestTaskID)
		fromID, err := strconv.ParseUint(fromIDStr, 0, 64)
		if err != nil {
			log.Fatalf("taskID in query couldn't be parsed: %s", fromIDStr)
		}
		req := q.Get(DataRequestReq)
		var serveData func(uint64, string) []byte
		switch f.parentOrChild(fromID) {
		case roleParent:
			serveData = f.task.ServeAsChild
		case roleChild:
			serveData = f.task.ServeAsParent
		default:
			panic("unimplemented")
		}
		d := serveData(fromID, req)

		if _, err := w.Write(d); err != nil {
			log.Printf("response write errored: %v", err)
		}
	})
	return mux
}

// Framework http server for data request.
// Each request will be in the format: "/datareq?taskID=XXX&req=XXX".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHttp() {
	log.Printf("framework: serving http on %s", f.ln.Addr())
	if err := http.Serve(f.ln, newDataReqHandler(f)); err != nil {
		log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

// Framework event loop handles data response for requests sent in DataRequest().
func (f *framework) dataResponseReceiver() {
	for {
		select {
		case dataResp := <-f.dataRespChan:
			switch f.parentOrChild(dataResp.taskID) {
			case roleParent:
				go f.task.ParentDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			case roleChild:
				go f.task.ChildDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			default:
				panic("unimplemented")
			}
		case <-f.dataCloseChan:
			return
		}
	}
}

func (f *framework) stop() {
	close(f.dataCloseChan)
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who taskRole, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case roleParent:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case roleChild:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	u := url.URL{
		Scheme: "http",
		Host:   addr,
		Path:   DataRequestPrefix,
	}
	q := u.Query()
	q.Add(DataRequestTaskID, strconv.FormatUint(f.taskID, 10))
	q.Add(DataRequestReq, req)
	u.RawQuery = q.Encode()
	urlStr := u.String()
	// send request
	// pass the response to the awaiting event loop for data response
	go func(urlStr string) {
		resp, err := http.Get(urlStr)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", urlStr, err)
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(urlStr)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<commit_msg>http handler should return error to client<commit_after>package meritop

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/coreos/go-etcd/etcd"
)

type taskRole int

const (
	roleNone taskRole = iota
	roleParent
	roleChild
)

const (
	DataRequestPrefix string = "/datareq"
	DataRequestTaskID string = "taskID"
	DataRequestReq    string = "req"
)

// This interface is used by application during taskgraph configuration phase.
type Bootstrap interface {
	// These allow application developer to set the task configuration so framework
	// implementation knows which task to invoke at each node.
	SetTaskBuilder(taskBuilder TaskBuilder)

	// This allow the application to specify how tasks are connection at each epoch
	SetTopology(topology Topology)

	// After all the configure is done, driver need to call start so that all
	// nodes will get into the event loop to run the application.
	Start()
}

// Note that framework can decide how update can be done, and how to serve the updatelog.
type BackedUpFramework interface {
	// Ask framework to do update on this update on this task, which consists
	// of one primary and some backup copies.
	Update(taskID uint64, log UpdateLog)
}

type Framework interface {
	// These two are useful for task to inform the framework their status change.
	// metaData has to be really small, since it might be stored in etcd.
	// Flags that parent/child's metadata of the current task is ready.
	FlagParentMetaReady(meta string)
	FlagChildMetaReady(meta string)

	// This allow the task implementation query its neighbors.
	GetTopology() Topology

	// Some task can inform all participating tasks to exit.
	Exit()

	// Some task can inform all participating tasks to new epoch
	SetEpoch(epoch uint64)

	GetLogger() log.Logger

	// Request data from parent or children.
	DataRequest(toID uint64, meta string)

	// This is used to figure out taskid for current node
	GetTaskID() uint64
}

type framework struct {
	// These should be passed by outside world
	name     string
	etcdURLs []string

	// user defined interfaces
	task     Task
	topology Topology

	taskID        uint64
	epoch         uint64
	etcdClient    *etcd.Client
	stops         []chan bool
	ln            net.Listener
	addressMap    map[uint64]string // taskId -> node address. Maybe in etcd later.
	dataRespChan  chan *dataResponse
	dataCloseChan chan struct{}
}

type dataResponse struct {
	taskID uint64
	req    string
	data   []byte
}

func (f *framework) parentOrChild(taskID uint64) taskRole {
	for _, id := range f.topology.GetParents(f.epoch) {
		if taskID == id {
			return roleParent
		}
	}

	for _, id := range f.topology.GetChildren(f.epoch) {
		if taskID == id {
			return roleChild
		}
	}
	return roleNone
}

func (f *framework) start() {
	f.etcdClient = etcd.NewClient(f.etcdURLs)
	f.topology.SetTaskID(f.taskID)
	f.epoch = 0
	f.stops = make([]chan bool, 0)
	f.dataRespChan = make(chan *dataResponse, 100)
	f.dataCloseChan = make(chan struct{})

	// setup etcd watches
	// - create self's parent and child meta flag
	// - watch parents' child meta flag
	// - watch children's parent meta flag
	f.etcdClient.Create(MakeParentMetaPath(f.name, f.GetTaskID()), "", 0)
	f.etcdClient.Create(MakeChildMetaPath(f.name, f.GetTaskID()), "", 0)
	parentStops := f.watchAll(roleParent, f.topology.GetParents(f.epoch))
	childStops := f.watchAll(roleChild, f.topology.GetChildren(f.epoch))
	f.stops = append(f.stops, parentStops...)
	f.stops = append(f.stops, childStops...)

	go f.startHttp()
	go f.dataResponseReceiver()

	// After framework init finished, it should init task.
	f.task.SetEpoch(f.epoch)
	f.task.Init(f.taskID, f, nil)
}

func newDataReqHandler(f *framework) http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc(DataRequestPrefix, func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query()
		fromIDStr := q.Get(DataRequestTaskID)
		fromID, err := strconv.ParseUint(fromIDStr, 0, 64)
		if err != nil {
			http.Error(w, "taskID couldn't be parsed", http.StatusBadRequest)
		}
		req := q.Get(DataRequestReq)
		var serveData func(uint64, string) []byte
		switch f.parentOrChild(fromID) {
		case roleParent:
			serveData = f.task.ServeAsChild
		case roleChild:
			serveData = f.task.ServeAsParent
		default:
			http.Error(w, "taskID isn't a parent or child of this task", http.StatusBadRequest)
		}
		d := serveData(fromID, req)

		if _, err := w.Write(d); err != nil {
			log.Printf("response write errored: %v", err)
		}
	})
	return mux
}

// Framework http server for data request.
// Each request will be in the format: "/datareq?taskID=XXX&req=XXX".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHttp() {
	log.Printf("framework: serving http on %s", f.ln.Addr())
	if err := http.Serve(f.ln, newDataReqHandler(f)); err != nil {
		log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

// Framework event loop handles data response for requests sent in DataRequest().
func (f *framework) dataResponseReceiver() {
	for {
		select {
		case dataResp := <-f.dataRespChan:
			switch f.parentOrChild(dataResp.taskID) {
			case roleParent:
				go f.task.ParentDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			case roleChild:
				go f.task.ChildDataReady(dataResp.taskID, dataResp.req, dataResp.data)
			default:
				panic("unimplemented")
			}
		case <-f.dataCloseChan:
			return
		}
	}
}

func (f *framework) stop() {
	close(f.dataCloseChan)
	for _, c := range f.stops {
		close(c)
	}
}

func (f *framework) FlagParentMetaReady(meta string) {
	f.etcdClient.Set(
		MakeParentMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) FlagChildMetaReady(meta string) {
	f.etcdClient.Set(
		MakeChildMetaPath(f.name, f.GetTaskID()),
		meta,
		0)
}

func (f *framework) SetEpoch(epoch uint64) {
	f.epoch = epoch
}

func (f *framework) watchAll(who taskRole, taskIDs []uint64) []chan bool {
	stops := make([]chan bool, len(taskIDs))

	for i, taskID := range taskIDs {
		receiver := make(chan *etcd.Response, 10)
		stop := make(chan bool, 1)
		stops[i] = stop

		var watchPath string
		var taskCallback func(uint64, string)
		switch who {
		case roleParent:
			// Watch parent's child.
			watchPath = MakeChildMetaPath(f.name, taskID)
			taskCallback = f.task.ParentMetaReady
		case roleChild:
			// Watch child's parent.
			watchPath = MakeParentMetaPath(f.name, taskID)
			taskCallback = f.task.ChildMetaReady
		default:
			panic("unimplemented")
		}

		go f.etcdClient.Watch(watchPath, 0, false, receiver, stop)
		go func(receiver <-chan *etcd.Response, taskID uint64) {
			for {
				resp, ok := <-receiver
				if !ok {
					return
				}
				if resp.Action != "set" {
					continue
				}
				taskCallback(taskID, resp.Node.Value)
			}
		}(receiver, taskID)
	}
	return stops
}

func (f *framework) DataRequest(toID uint64, req string) {
	// getAddressFromTaskID
	addr, ok := f.addressMap[toID]
	if !ok {
		log.Fatalf("ID = %d not found", toID)
		return
	}
	u := url.URL{
		Scheme: "http",
		Host:   addr,
		Path:   DataRequestPrefix,
	}
	q := u.Query()
	q.Add(DataRequestTaskID, strconv.FormatUint(f.taskID, 10))
	q.Add(DataRequestReq, req)
	u.RawQuery = q.Encode()
	urlStr := u.String()
	// send request
	// pass the response to the awaiting event loop for data response
	go func(urlStr string) {
		resp, err := http.Get(urlStr)
		if err != nil {
			log.Fatalf("http.Get(%s) returns error: %v", urlStr, err)
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			log.Fatalf("response code = %d, assume = %d", resp.StatusCode, 200)
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("ioutil.ReadAll(%v) returns error: %v", resp.Body, err)
		}
		dataResp := &dataResponse{
			taskID: toID,
			req:    req,
			data:   data,
		}
		f.dataRespChan <- dataResp
	}(urlStr)
}

func (f *framework) GetTopology() Topology {
	panic("unimplemented")
}

func (f *framework) Exit() {
}

func (f *framework) GetLogger() log.Logger {
	panic("unimplemented")
}

func (f *framework) GetTaskID() uint64 {
	return f.taskID
}
<|endoftext|>


<commit_before>package fullerene

import (
	"time"
)

type Fullerene struct {
	t time.Time
}

func Now() Fullerene {
	return Fullerene{
		t: time.Now(),
	}
}

func (fr Fullerene) Date() (year int, month time.Month, day int) {
	return fr.t.Date()
}

func (fr Fullerene) After(u Fullerene) bool {
	return fr.t.After(u.t)
}

func (fr Fullerene) Before(u Fullerene) bool {
	return fr.t.Before(u.t)
}

func (fr Fullerene) Equal(u Fullerene) bool {
	return fr.t.Equal(u.t)
}

func (fr Fullerene) IsZero() bool {
	return fr.t.IsZero()
}

func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Fullerene {
	return Fullerene{t: time.Date(year, month, day, hour, min, sec, nsec, loc)}
}

func (fr Fullerene) Year() int {
	return fr.t.Year()
}

func (fr Fullerene) Month() time.Month {
	return fr.t.Month()
}

func (fr Fullerene) Day() int {
	return fr.t.Day()
}

func (fr Fullerene) AddDate(years int, months int, days int) Fullerene {
	return Fullerene{t: fr.t.AddDate(years, months, days)}
}

func (fr Fullerene) IsLeapYear() bool {
	y := fr.Year()
	return (y%4 == 0 && (y%100 != 0 || y%400 == 0))
}

func (fr Fullerene) IsLeapDay() bool {
	_, m, d := fr.Date()
	return (m == 2 && d == 29)
}

func (fr Fullerene) IsBirthday(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := fr.Date()           // birthday
	_, mm, dd := targetTime.Date() // check if it is birthday.
	if m == mm && d == dd && !fr.IsLeapDay() {
		// consider leap year.
		return true
	}

	// there are countries which a person get old at the day before leap day, and the day after in a leap year.
	return fr.isBirthdayEx(targetTime, beforeDayIfLeap)
}

func (fr Fullerene) isBirthdayEx(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := targetTime.Date()
	if targetTime.IsLeapYear() {
		return false
	}
	if beforeDayIfLeap && m == 2 && d == 28 {
		return true
	}
	if !beforeDayIfLeap && m == 3 && d == 1 {
		return true
	}
	return false
}

func (fr Fullerene) Age(targetTime Fullerene) int {
	y, m, d := targetTime.Date()
	age := y - fr.Year()
	if m < fr.Month() {
		return age - 1
	}
	if m > fr.Month() {
		return age
	}
	// month of targetTime is equal to birthday.
	if d <= fr.Day() {
		return age
	}
	if d > fr.Day() {
		return age - 1
	}
	return age
}

func (fr Fullerene) CurrentAge() int {
	return fr.Age(Now())
}

func (fr Fullerene) IsHoliday() bool {
	switch fr.t.Weekday() {
	case time.Sunday, time.Saturday:
		return true
	default:
		return false
	}
}

func (fr Fullerene) IsWeekday() bool {
	return !fr.IsHoliday()
}

func (fr *Fullerene) String() string {
	return fr.t.String()
}

func (fr *Fullerene) Format(layout string) string {
	return fr.t.Format(layout)
}
<commit_msg>Add Japanese holiday check on IsHoliday.<commit_after>package fullerene

import (
	"time"
)

type Fullerene struct {
	t time.Time
}

func Now() Fullerene {
	return Fullerene{
		t: time.Now(),
	}
}

func (fr Fullerene) Date() (year int, month time.Month, day int) {
	return fr.t.Date()
}

func (fr Fullerene) After(u Fullerene) bool {
	return fr.t.After(u.t)
}

func (fr Fullerene) Before(u Fullerene) bool {
	return fr.t.Before(u.t)
}

func (fr Fullerene) Equal(u Fullerene) bool {
	return fr.t.Equal(u.t)
}

func (fr Fullerene) IsZero() bool {
	return fr.t.IsZero()
}

func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Fullerene {
	return Fullerene{t: time.Date(year, month, day, hour, min, sec, nsec, loc)}
}

func (fr Fullerene) Year() int {
	return fr.t.Year()
}

func (fr Fullerene) Month() time.Month {
	return fr.t.Month()
}

func (fr Fullerene) Day() int {
	return fr.t.Day()
}

func (fr Fullerene) AddDate(years int, months int, days int) Fullerene {
	return Fullerene{t: fr.t.AddDate(years, months, days)}
}

func (fr Fullerene) IsLeapYear() bool {
	y := fr.Year()
	return (y%4 == 0 && (y%100 != 0 || y%400 == 0))
}

func (fr Fullerene) IsLeapDay() bool {
	_, m, d := fr.Date()
	return (m == 2 && d == 29)
}

func (fr Fullerene) IsBirthday(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := fr.Date()           // birthday
	_, mm, dd := targetTime.Date() // check if it is birthday.
	if m == mm && d == dd && !fr.IsLeapDay() {
		// consider leap year.
		return true
	}

	// there are countries which a person get old at the day before leap day, and the day after in a leap year.
	return fr.isBirthdayEx(targetTime, beforeDayIfLeap)
}

func (fr Fullerene) isBirthdayEx(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := targetTime.Date()
	if targetTime.IsLeapYear() {
		return false
	}
	if beforeDayIfLeap && m == 2 && d == 28 {
		return true
	}
	if !beforeDayIfLeap && m == 3 && d == 1 {
		return true
	}
	return false
}

func (fr Fullerene) Age(targetTime Fullerene) int {
	y, m, d := targetTime.Date()
	age := y - fr.Year()
	if m < fr.Month() {
		return age - 1
	}
	if m > fr.Month() {
		return age
	}
	// month of targetTime is equal to birthday.
	if d <= fr.Day() {
		return age
	}
	if d > fr.Day() {
		return age - 1
	}
	return age
}

func (fr Fullerene) CurrentAge() int {
	return fr.Age(Now())
}

func (fr Fullerene) IsHoliday() bool {
	if fr.t.Location() == loc && fr.IsJapanesePublicHoliday() {
		return true
	}
	switch fr.t.Weekday() {
	case time.Sunday, time.Saturday:
		return true
	default:
		return false
	}
}

func (fr Fullerene) IsJapanesePublicHoliday() bool {
	y1, m1, d1 := fr.Date()
	for _, d := range JapanesePublicHolidays {
		y2, m2, d2 := d.Date()
		if y1 == y2 && m1 == m2 && d1 == d2 {
			return true
		}
	}
	return false
}

func (fr Fullerene) IsWeekday() bool {
	return !fr.IsHoliday()
}

func (fr *Fullerene) String() string {
	return fr.t.String()
}

func (fr *Fullerene) Format(layout string) string {
	return fr.t.Format(layout)
}
<|endoftext|>


<commit_before>package cloudca

import (
	"errors"
	"fmt"
	"github.com/cloud-ca/go-cloudca"
	"github.com/cloud-ca/go-cloudca/api"
	"github.com/cloud-ca/go-cloudca/services/cloudca"
	"github.com/hashicorp/terraform/helper/schema"
	"strconv"
)

func resourceCloudcaLoadBalancerRule() *schema.Resource {
	return &schema.Resource{
		Create: createLbr,
		Read:   readLbr,
		Delete: deleteLbr,
		Update: updateLbr,

		Schema: map[string]*schema.Schema{
			"service_code": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "A cloudca service code",
			},
			"environment_name": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "Name of environment where load balancer rule should be created",
			},
			"name": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the load balancer rule",
			},
			"public_ip_id": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "The public IP to which the rule should be applied",
			},
			"public_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"network_id": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				ForceNew:    true,
				Computed:    true,
				Description: "The network ID to bind to",
			},
			"protocol": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "The protocol that this rule should use (eg. TCP, UDP)",
			},
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "The algorithm used to load balance",
			},
			"public_port": &schema.Schema{
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
				Description: "The port on the public IP",
			},
			"private_port": &schema.Schema{
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
				Description: "The port to which the traffic will be load balanced internally",
			},
			"instance_ids": &schema.Schema{
				Type:        schema.TypeList,
				Optional:    true,
				Description: "List of instance ids that will be load balanced",
				Elem:        &schema.Schema{Type: schema.TypeString},
			},
			"stickiness_method": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The stickiness method",
			},
			"stickiness_params": &schema.Schema{
				Type:        schema.TypeMap,
				Optional:    true,
				Description: "The stickiness policy parameters",
			},
		},
	}
}

func createLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, err := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err != nil {
		return err
	}

	lbr := cloudca.LoadBalancerRule{
		Name:        d.Get("name").(string),
		PublicIpId:  d.Get("public_ip_id").(string),
		NetworkId:   d.Get("network_id").(string),
		Protocol:    d.Get("protocol").(string),
		Algorithm:   d.Get("algorithm").(string),
		PublicPort:  strconv.Itoa(d.Get("public_port").(int)),
		PrivatePort: strconv.Itoa(d.Get("private_port").(int)),
	}

	_, instanceIdsPresent := d.GetOk("instance_ids")

	if instanceIdsPresent {
		var instanceIds []string
		for _, id := range d.Get("instance_ids").([]interface{}) {
			instanceIds = append(instanceIds, id.(string))
		}
		lbr.InstanceIds = instanceIds
	}

	if stickinessMethod, ok := d.GetOk("stickiness_method"); ok {
		lbr.StickinessMethod = stickinessMethod.(string)
	}

	if stickinessParams, ok := d.GetOk("stickiness_params"); ok {
		lbr.StickinessPolicyParameters = getStickinessPolicyParameterMap(stickinessParams.(map[string]interface{}))
	}

	newLbr, err := ccaResources.LoadBalancerRules.Create(lbr)
	if err != nil {
		return err
	}

	d.SetId(newLbr.Id)
	return readLbr(d, meta)
}

func readLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, _ := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	lbr, err := ccaResources.LoadBalancerRules.Get(d.Id())
	if err != nil {
		return handleLbrNotFoundError(err, d)
	}

	d.Set("name", lbr.Name)
	d.Set("public_ip_id", lbr.PublicIpId)
	d.Set("network_id", lbr.NetworkId)
	d.Set("instance_ids", lbr.InstanceIds)
	d.Set("algorithm", lbr.Algorithm)
	d.Set("protocol", lbr.Protocol)
	d.Set("public_port", lbr.PublicPort)
	d.Set("private_port", lbr.PrivatePort)
	d.Set("public_ip", lbr.PublicIp)
	d.Set("stickiness_method", lbr.StickinessMethod)
	d.Set("stickiness_params", lbr.StickinessPolicyParameters)

	return nil
}

func deleteLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, _ := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err := ccaResources.LoadBalancerRules.Delete(d.Id()); err != nil {
		return handleLbrNotFoundError(err, d)
	}
	return nil
}

func updateLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, err := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err != nil {
		return err
	}

	d.Partial(true)

	if d.HasChange("stickiness_method") || d.HasChange("stickiness_params") {
		stickinessMethod := d.Get("stickiness_method")
		if len(stickinessMethod.(string)) > 0 {
			var stickinessPolicyParameters map[string]string
			if stickinessParams, ok := d.GetOk("stickiness_params"); ok {
				stickinessPolicyParameters = getStickinessPolicyParameterMap(stickinessParams.(map[string]interface{}))
			}
			err := ccaResources.LoadBalancerRules.SetLoadBalancerRuleStickinessPolicy(d.Id(), stickinessMethod.(string), stickinessPolicyParameters)
			if err != nil {
				return err
			}
		} else {

			if _, ok := d.GetOk("stickiness_params"); ok {
				return errors.New("Stickiness params should be removed if the stickiness method is removed")
			}
			err := ccaResources.LoadBalancerRules.RemoveLoadBalancerRuleStickinessPolicy(d.Id())
			if err != nil {
				return err
			}
		}
	}

	if d.HasChange("name") || d.HasChange("algorithm") {
		newName := d.Get("name").(string)
		newAlgorithm := d.Get("algorithm").(string)
		_, err := ccaResources.LoadBalancerRules.Update(cloudca.LoadBalancerRule{Id: d.Id(), Name: newName, Algorithm: newAlgorithm})
		if err != nil {
			return err
		}
	}

	if d.HasChange("instance_ids") {
		var instanceIds []string
		for _, id := range d.Get("instance_ids").([]interface{}) {
			instanceIds = append(instanceIds, id.(string))
		}

		instanceErr := ccaResources.LoadBalancerRules.SetLoadBalancerRuleInstances(d.Id(), instanceIds)
		if instanceErr != nil {
			return instanceErr
		}
	}
	d.Partial(false)
	return readLbr(d, meta)
}

func getStickinessPolicyParameterMap(policyMap map[string]interface{}) map[string]string {
	var paramMap = make(map[string]string)
	for k, v := range policyMap {
		paramMap[k] = v.(string)
	}
	return paramMap
}

func handleLbrNotFoundError(err error, d *schema.ResourceData) error {
	if ccaError, ok := err.(api.CcaErrorResponse); ok {
		if ccaError.StatusCode == 404 {
			fmt.Errorf("Load balancer rule with id %s was not found", d.Id())
			d.SetId("")
			return nil
		}
	}

	return err
}
<commit_msg>Changed LBR instance IDs to be a set<commit_after>package cloudca

import (
	"errors"
	"fmt"
	"github.com/cloud-ca/go-cloudca"
	"github.com/cloud-ca/go-cloudca/api"
	"github.com/cloud-ca/go-cloudca/services/cloudca"
	"github.com/hashicorp/terraform/helper/schema"
	"strconv"
)

func resourceCloudcaLoadBalancerRule() *schema.Resource {
	return &schema.Resource{
		Create: createLbr,
		Read:   readLbr,
		Delete: deleteLbr,
		Update: updateLbr,

		Schema: map[string]*schema.Schema{
			"service_code": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "A cloudca service code",
			},
			"environment_name": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "Name of environment where load balancer rule should be created",
			},
			"name": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the load balancer rule",
			},
			"public_ip_id": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "The public IP to which the rule should be applied",
			},
			"public_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"network_id": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				ForceNew:    true,
				Computed:    true,
				Description: "The network ID to bind to",
			},
			"protocol": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				Description: "The protocol that this rule should use (eg. TCP, UDP)",
			},
			"algorithm": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "The algorithm used to load balance",
			},
			"public_port": &schema.Schema{
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
				Description: "The port on the public IP",
			},
			"private_port": &schema.Schema{
				Type:        schema.TypeInt,
				Required:    true,
				ForceNew:    true,
				Description: "The port to which the traffic will be load balanced internally",
			},
			"instance_ids": &schema.Schema{
				Type:        schema.TypeSet,
				Optional:    true,
				Description: "List of instance ids that will be load balanced",
				Elem:        &schema.Schema{Type: schema.TypeString},
			},
			"stickiness_method": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The stickiness method",
			},
			"stickiness_params": &schema.Schema{
				Type:        schema.TypeMap,
				Optional:    true,
				Description: "The stickiness policy parameters",
			},
		},
	}
}

func createLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, err := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err != nil {
		return err
	}

	lbr := cloudca.LoadBalancerRule{
		Name:        d.Get("name").(string),
		PublicIpId:  d.Get("public_ip_id").(string),
		NetworkId:   d.Get("network_id").(string),
		Protocol:    d.Get("protocol").(string),
		Algorithm:   d.Get("algorithm").(string),
		PublicPort:  strconv.Itoa(d.Get("public_port").(int)),
		PrivatePort: strconv.Itoa(d.Get("private_port").(int)),
	}

	_, instanceIdsPresent := d.GetOk("instance_ids")

	if instanceIdsPresent {
		var instanceIds []string
		for _, id := range d.Get("instance_ids").([]interface{}) {
			instanceIds = append(instanceIds, id.(string))
		}
		lbr.InstanceIds = instanceIds
	}

	if stickinessMethod, ok := d.GetOk("stickiness_method"); ok {
		lbr.StickinessMethod = stickinessMethod.(string)
	}

	if stickinessParams, ok := d.GetOk("stickiness_params"); ok {
		lbr.StickinessPolicyParameters = getStickinessPolicyParameterMap(stickinessParams.(map[string]interface{}))
	}

	newLbr, err := ccaResources.LoadBalancerRules.Create(lbr)
	if err != nil {
		return err
	}

	d.SetId(newLbr.Id)
	return readLbr(d, meta)
}

func readLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, _ := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	lbr, err := ccaResources.LoadBalancerRules.Get(d.Id())
	if err != nil {
		return handleLbrNotFoundError(err, d)
	}

	d.Set("name", lbr.Name)
	d.Set("public_ip_id", lbr.PublicIpId)
	d.Set("network_id", lbr.NetworkId)
	d.Set("instance_ids", lbr.InstanceIds)
	d.Set("algorithm", lbr.Algorithm)
	d.Set("protocol", lbr.Protocol)
	d.Set("public_port", lbr.PublicPort)
	d.Set("private_port", lbr.PrivatePort)
	d.Set("public_ip", lbr.PublicIp)
	d.Set("stickiness_method", lbr.StickinessMethod)
	d.Set("stickiness_params", lbr.StickinessPolicyParameters)

	return nil
}

func deleteLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, _ := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err := ccaResources.LoadBalancerRules.Delete(d.Id()); err != nil {
		return handleLbrNotFoundError(err, d)
	}
	return nil
}

func updateLbr(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*cca.CcaClient)
	resources, err := client.GetResources(d.Get("service_code").(string), d.Get("environment_name").(string))
	ccaResources := resources.(cloudca.Resources)

	if err != nil {
		return err
	}

	d.Partial(true)

	if d.HasChange("stickiness_method") || d.HasChange("stickiness_params") {
		stickinessMethod := d.Get("stickiness_method")
		if len(stickinessMethod.(string)) > 0 {
			var stickinessPolicyParameters map[string]string
			if stickinessParams, ok := d.GetOk("stickiness_params"); ok {
				stickinessPolicyParameters = getStickinessPolicyParameterMap(stickinessParams.(map[string]interface{}))
			}
			err := ccaResources.LoadBalancerRules.SetLoadBalancerRuleStickinessPolicy(d.Id(), stickinessMethod.(string), stickinessPolicyParameters)
			if err != nil {
				return err
			}
		} else {

			if _, ok := d.GetOk("stickiness_params"); ok {
				return errors.New("Stickiness params should be removed if the stickiness method is removed")
			}
			err := ccaResources.LoadBalancerRules.RemoveLoadBalancerRuleStickinessPolicy(d.Id())
			if err != nil {
				return err
			}
		}
	}

	if d.HasChange("name") || d.HasChange("algorithm") {
		newName := d.Get("name").(string)
		newAlgorithm := d.Get("algorithm").(string)
		_, err := ccaResources.LoadBalancerRules.Update(cloudca.LoadBalancerRule{Id: d.Id(), Name: newName, Algorithm: newAlgorithm})
		if err != nil {
			return err
		}
	}

	if d.HasChange("instance_ids") {
		var instanceIds []string
		for _, id := range d.Get("instance_ids").([]interface{}) {
			instanceIds = append(instanceIds, id.(string))
		}

		instanceErr := ccaResources.LoadBalancerRules.SetLoadBalancerRuleInstances(d.Id(), instanceIds)
		if instanceErr != nil {
			return instanceErr
		}
	}
	d.Partial(false)
	return readLbr(d, meta)
}

func getStickinessPolicyParameterMap(policyMap map[string]interface{}) map[string]string {
	var paramMap = make(map[string]string)
	for k, v := range policyMap {
		paramMap[k] = v.(string)
	}
	return paramMap
}

func handleLbrNotFoundError(err error, d *schema.ResourceData) error {
	if ccaError, ok := err.(api.CcaErrorResponse); ok {
		if ccaError.StatusCode == 404 {
			fmt.Errorf("Load balancer rule with id %s was not found", d.Id())
			d.SetId("")
			return nil
		}
	}

	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

import (
	"context"

	"github.com/tektoncd/pipeline/pkg/apis/validate"
	"knative.dev/pkg/apis"
)

var _ apis.Validatable = (*ClusterTask)(nil)

func (t *ClusterTask) Validate(ctx context.Context) *apis.FieldError {
	if err := validate.ObjectMetadata(t.GetObjectMeta()); err != nil {
		return err.ViaField("metadata")
	}
	return t.Spec.Validate(ctx)
}
<commit_msg>Enhance v1beta1 validation code for clustertask 🍸<commit_after>/*
Copyright 2020 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

import (
	"context"

	"github.com/tektoncd/pipeline/pkg/apis/validate"
	"knative.dev/pkg/apis"
)

var _ apis.Validatable = (*ClusterTask)(nil)

func (t *ClusterTask) Validate(ctx context.Context) *apis.FieldError {
	errs := validate.ObjectMetadata(t.GetObjectMeta()).ViaField("metadata")
	return errs.Also(t.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec"))
}
<|endoftext|>