<commit_before>package quad

import (
	"fmt"

	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

// 1. Input Application Phase - User Defined
//
// The input phase takes the user input and applies
// it to the entities movement state. This enables the
// broad phase to estimate where collisions might take
// place if the movement is valid.
// The narrow phase should revert any changes to the movement
// state that cannot happen because of collisions.
type InputPhaseHandler interface {
	ApplyInputsIn(Chunk, stime.Time) Chunk
}

// Convenience type so input phase handlers can be written
// as closures or as functions.
type InputPhaseHandlerFn func(Chunk, stime.Time) Chunk

func (f InputPhaseHandlerFn) ApplyInputsIn(c Chunk, t stime.Time) Chunk {
	return f(c, t)
}

// 2. Broad Phase - Internal
//
// The broad phase is only concerned with the bounds
// of all the entities potential futures. For this
// reason it will be and internal implementation.
// The broad phase will need to happen while recursively
// descending and ascending through the tree. It will be
// where chunks of interest are created based on the
// potential future overlapping bounds of the entities.
// The chunks of interest will then be passed into the
// user supplied narrow phase handler.

// 3. Narrow Phase - User Defined
//
// The narrow phase resolves any collisions that the
// broad phase identified by the bounds of the potential
// future state of the entity. The broad phase has grouped
// this chunk together, such that, there is no possible way
// any of these entities can interact with any entities that
// are not included in this chunk. The narrow phase should
// return a chunk.... Honestly I don't know what it should
// return and I need to stop thinking about it for now and
// just shut the fuck up and write the fucking code.
type NarrowPhaseHandler interface {
	ResolveCollisions(Chunk, stime.Time) Chunk
}

func RunPhasesOn(q Quad, inputPhase InputPhaseHandler, narrowPhase NarrowPhaseHandler, now stime.Time) Quad {
	q, _ = q.runInputPhase(inputPhase, now)
	q, chunksToSolve := q.runBroadPhase(now)
	q = q.runNarrowPhase(narrowPhase, chunksToSolve, now)

	return q
}

func RunInputPhaseOn(q Quad, inputPhase InputPhaseHandler, now stime.Time) (Quad, []entity.Entity) {
	return q.runInputPhase(inputPhase, now)
}

func RunBroadPhaseOn(q Quad, now stime.Time) (quad Quad, chunksOfInterest []Chunk) {
	return q.runBroadPhase(now)
}

func RunNarrowPhaseOn(q Quad, chunksToSolve []Chunk, narrowPhase NarrowPhaseHandler, now stime.Time) []Chunk {
	return nil
}

func (q quadNode) runInputPhase(p InputPhaseHandler, at stime.Time) (Quad, []entity.Entity) {
	// TODO Implement this method more efficiently
	// It may use a lot of memory because of all the
	// slice creation/appending/copying.
	var outOfBounds []entity.Entity

	// TODO Implement concurrently
	// For each child, recursively descend and run input phase
	for i, quad := range q.children {
		quad, oobc := quad.runInputPhase(p, at)
		q.children[i] = quad
		outOfBounds = append(outOfBounds, oobc...)
	}

	// Use a var of the interface value
	// This enables us to use Insert() method functionally
	var quad Quad = q

	// For each entity that was out of bounds for a child
	// check if it is still within our own bounds.
	for i, e := range outOfBounds {
		if quad.Bounds().Contains(e.Cell()) {
			quad = quad.Insert(e)
			outOfBounds = append(outOfBounds[:i], outOfBounds[i+1:]...)
		}
	}

	return quad, outOfBounds
}

func (q quadLeaf) runInputPhase(p InputPhaseHandler, now stime.Time) (Quad, []entity.Entity) {
	chunk := p.ApplyInputsIn(q.Chunk(), now)

	// Use a var of the interface value
	// This enables us to use Remove() method functionally
	var quad Quad = q
	var outOfBounds []entity.Entity

	for _, e := range chunk.Entities {
		if !quad.Bounds().Contains(e.Cell()) {
			quad = quad.Remove(e)
			outOfBounds = append(outOfBounds, e)
		}
	}

	return quad, outOfBounds
}

func (q quadNode) runBroadPhase(now stime.Time) (quad Quad, chunksOfActivity []Chunk) {
	var chunks []Chunk

	for i, cq := range q.children {
		cq, chunksOfActivity := cq.runBroadPhase(now)
		q.children[i] = cq
		chunks = append(chunks, chunksOfActivity...)
	}

	return q, chunks
}

func (q quadLeaf) runBroadPhase(stime.Time) (quad Quad, chunksOfActivity []Chunk) {
	// A map of the chunks generated thus far
	chunkIndex := make(map[entity.Entity]*Chunk, len(q.entities))
	chunkPtrs := make([]*Chunk, 0, len(q.entities))

	for _, e1 := range q.entities {
		for _, e2 := range q.entities {
			if e1 == e2 {
				continue
			}

			if !e1.Bounds().Overlaps(e2.Bounds()) {
				continue
			}

			// We have 2 entities with overlapping bounds.
			// Are either of them indexed in the chunks map?
			e1c, e1cExists := chunkIndex[e1]
			e2c, e2cExists := chunkIndex[e2]

			switch {

			case (e1cExists && !e2cExists):
				// e1 exists in a chunk already
				// add e2 to that chunk
				e1c.Entities = append(e1c.Entities, e2)

				// set e2's chunk to e1's chunk in the chunks index.
				chunkIndex[e2] = e1c

			case (!e1cExists && e2cExists):
				// e2 exists in a chunk already
				// add e1 to that chunk
				e2c.Entities = append(e2c.Entities, e1)

				// set e1's chunk to e1's chunk in the index
				chunkIndex[e1] = e2c
			case !e1cExists && !e2cExists:
				// neither e1 or e2 have been assigned to a chunk
				// create a new chunk with containing e1 and e2
				ch := &Chunk{Entities: []entity.Entity{e1, e2}}

				// set e1 and e2's chunk in the index
				chunkIndex[e1] = ch
				chunkIndex[e2] = ch

				// add chunk into the array of chunks
				chunkPtrs = append(chunkPtrs, ch)

			case (e1cExists && e2cExists) && (e1c != e2c):
				// both entities exist in chunks
				// but those chunks are different

				// merge the chunks
				e1c.Entities = append(e1c.Entities, e2c.Entities...)
				chunkIndex[e2] = e1c

			case (e1cExists && e2cExists) && (e1c == e2c):
			// both entities exist in the same chunk already.
			// do nothing

			default:
				panic(fmt.Sprintf(`unexpected index state during broad phase
e1c = %v
e2c = %v
`, e1c, e2c))
			}
		}
	}

	chunks := make([]Chunk, 0, len(chunkPtrs))
	for _, cptr := range chunkPtrs {
		chunks = append(chunks, *cptr)
	}

	return q, chunks
}

func (q quadNode) runNarrowPhase(narrowPhase NarrowPhaseHandler, chunksToSolve []Chunk, now stime.Time) Quad {
	return q
}

func (q quadLeaf) runNarrowPhase(narrowPhase NarrowPhaseHandler, chunksToSolve []Chunk, now stime.Time) Quad {
	return q
}
<commit_msg>2 things that must be implemented on the broad phase<commit_after>package quad

import (
	"fmt"

	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

// 1. Input Application Phase - User Defined
//
// The input phase takes the user input and applies
// it to the entities movement state. This enables the
// broad phase to estimate where collisions might take
// place if the movement is valid.
// The narrow phase should revert any changes to the movement
// state that cannot happen because of collisions.
type InputPhaseHandler interface {
	ApplyInputsIn(Chunk, stime.Time) Chunk
}

// Convenience type so input phase handlers can be written
// as closures or as functions.
type InputPhaseHandlerFn func(Chunk, stime.Time) Chunk

func (f InputPhaseHandlerFn) ApplyInputsIn(c Chunk, t stime.Time) Chunk {
	return f(c, t)
}

// 2. Broad Phase - Internal
//
// The broad phase is only concerned with the bounds
// of all the entities potential futures. For this
// reason it will be and internal implementation.
// The broad phase will need to happen while recursively
// descending and ascending through the tree. It will be
// where chunks of interest are created based on the
// potential future overlapping bounds of the entities.
// The chunks of interest will then be passed into the
// user supplied narrow phase handler.

// 3. Narrow Phase - User Defined
//
// The narrow phase resolves any collisions that the
// broad phase identified by the bounds of the potential
// future state of the entity. The broad phase has grouped
// this chunk together, such that, there is no possible way
// any of these entities can interact with any entities that
// are not included in this chunk. The narrow phase should
// return a chunk.... Honestly I don't know what it should
// return and I need to stop thinking about it for now and
// just shut the fuck up and write the fucking code.
type NarrowPhaseHandler interface {
	ResolveCollisions(Chunk, stime.Time) Chunk
}

func RunPhasesOn(q Quad, inputPhase InputPhaseHandler, narrowPhase NarrowPhaseHandler, now stime.Time) Quad {
	q, _ = q.runInputPhase(inputPhase, now)
	q, chunksToSolve := q.runBroadPhase(now)
	q = q.runNarrowPhase(narrowPhase, chunksToSolve, now)

	return q
}

func RunInputPhaseOn(q Quad, inputPhase InputPhaseHandler, now stime.Time) (Quad, []entity.Entity) {
	return q.runInputPhase(inputPhase, now)
}

func RunBroadPhaseOn(q Quad, now stime.Time) (quad Quad, chunksOfInterest []Chunk) {
	return q.runBroadPhase(now)
}

func RunNarrowPhaseOn(q Quad, chunksToSolve []Chunk, narrowPhase NarrowPhaseHandler, now stime.Time) []Chunk {
	return nil
}

func (q quadNode) runInputPhase(p InputPhaseHandler, at stime.Time) (Quad, []entity.Entity) {
	// TODO Implement this method more efficiently
	// It may use a lot of memory because of all the
	// slice creation/appending/copying.
	var outOfBounds []entity.Entity

	// TODO Implement concurrently
	// For each child, recursively descend and run input phase
	for i, quad := range q.children {
		quad, oobc := quad.runInputPhase(p, at)
		q.children[i] = quad
		outOfBounds = append(outOfBounds, oobc...)
	}

	// Use a var of the interface value
	// This enables us to use Insert() method functionally
	var quad Quad = q

	// For each entity that was out of bounds for a child
	// check if it is still within our own bounds.
	for i, e := range outOfBounds {
		if quad.Bounds().Contains(e.Cell()) {
			quad = quad.Insert(e)
			outOfBounds = append(outOfBounds[:i], outOfBounds[i+1:]...)
		}
	}

	return quad, outOfBounds
}

func (q quadLeaf) runInputPhase(p InputPhaseHandler, now stime.Time) (Quad, []entity.Entity) {
	chunk := p.ApplyInputsIn(q.Chunk(), now)

	// Use a var of the interface value
	// This enables us to use Remove() method functionally
	var quad Quad = q
	var outOfBounds []entity.Entity

	for _, e := range chunk.Entities {
		if !quad.Bounds().Contains(e.Cell()) {
			quad = quad.Remove(e)
			outOfBounds = append(outOfBounds, e)
		}
	}

	return quad, outOfBounds
}

func (q quadNode) runBroadPhase(now stime.Time) (quad Quad, chunksOfActivity []Chunk) {
	var chunks []Chunk

	for i, cq := range q.children {
		cq, chunksOfActivity := cq.runBroadPhase(now)
		q.children[i] = cq
		chunks = append(chunks, chunksOfActivity...)
	}

	// TODO Join chunks that are overlapping

	return q, chunks
}

func (q quadLeaf) runBroadPhase(stime.Time) (quad Quad, chunksOfActivity []Chunk) {
	// A map of the chunks generated thus far
	chunkIndex := make(map[entity.Entity]*Chunk, len(q.entities))
	chunkPtrs := make([]*Chunk, 0, len(q.entities))

	for _, e1 := range q.entities {
		for _, e2 := range q.entities {
			if e1 == e2 {
				continue
			}

			if !e1.Bounds().Overlaps(e2.Bounds()) {
				continue
			}

			// We have 2 entities with overlapping bounds.
			// Are either of them indexed in the chunks map?
			e1c, e1cExists := chunkIndex[e1]
			e2c, e2cExists := chunkIndex[e2]

			switch {

			case (e1cExists && !e2cExists):
				// e1 exists in a chunk already
				// add e2 to that chunk
				e1c.Entities = append(e1c.Entities, e2)

				// set e2's chunk to e1's chunk in the chunks index.
				chunkIndex[e2] = e1c

			case (!e1cExists && e2cExists):
				// e2 exists in a chunk already
				// add e1 to that chunk
				e2c.Entities = append(e2c.Entities, e1)

				// set e1's chunk to e1's chunk in the index
				chunkIndex[e1] = e2c
			case !e1cExists && !e2cExists:
				// neither e1 or e2 have been assigned to a chunk
				// create a new chunk with containing e1 and e2
				ch := &Chunk{Entities: []entity.Entity{e1, e2}}

				// set e1 and e2's chunk in the index
				chunkIndex[e1] = ch
				chunkIndex[e2] = ch

				// add chunk into the array of chunks
				chunkPtrs = append(chunkPtrs, ch)

			case (e1cExists && e2cExists) && (e1c != e2c):
				// both entities exist in chunks
				// but those chunks are different

				// merge the chunks
				e1c.Entities = append(e1c.Entities, e2c.Entities...)
				chunkIndex[e2] = e1c

			case (e1cExists && e2cExists) && (e1c == e2c):
			// both entities exist in the same chunk already.
			// do nothing

			default:
				panic(fmt.Sprintf(`unexpected index state during broad phase
e1c = %v
e2c = %v
`, e1c, e2c))
			}
		}
	}

	chunks := make([]Chunk, 0, len(chunkPtrs))
	for _, cptr := range chunkPtrs {
		chunks = append(chunks, *cptr)
	}

	// TODO Combine bounds of all entities to from bounds for each chunk

	return q, chunks
}

func (q quadNode) runNarrowPhase(narrowPhase NarrowPhaseHandler, chunksToSolve []Chunk, now stime.Time) Quad {
	return q
}

func (q quadLeaf) runNarrowPhase(narrowPhase NarrowPhaseHandler, chunksToSolve []Chunk, now stime.Time) Quad {
	return q
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/kardianos/service"
	"github.com/lukamicoder/ini-parser"
	"log"
	"math/rand"
	"net"
	"os"
	"regexp"
	"strings"
	"time"
)

var (
	interval = 3600
	services []DdnsService
	logger service.Logger

	regex = regexp.MustCompile("(?m)[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}")
)

var urls = []string{
	"myipinfo.net",
	"myip.dnsomatic.com",
	"icanhazip.com",
	"checkip.dyndns.org",
	"www.myipnumber.com",
	"checkmyip.com",
	"myexternalip.com",
	"www.ipchicken.com",
	"ipecho.net/plain",
	"bot.whatismyipaddress.com",
	"ipv4.ipogre.com",
	"smart-ip.net/myip",
	"checkip.amazonaws.com",
	"www.checkip.org",
}

type program struct {
	exit chan struct {}
}

func (p *program) Start(s service.Service) error {
	p.exit = make(chan struct {})
	go p.run()
	return nil
}

func (p *program) run() error {
	update()
	ticker := time.NewTicker(time.Duration(interval) * time.Second)

	for {
		select {
		case <-ticker.C:
			update()
		case <-p.exit:
			ticker.Stop()
			return nil
		}
	}
}

func (p *program) Stop(s service.Service) error {
	logger.Info("Stopping service...")
	close(p.exit)
	return nil
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	svcConfig := &service.Config{
		Name:        "ddns-client",
		DisplayName: "DDNS Client",
		Description: "Dynamic DNS Client.",
	}

	prg := &program{}
	s, err := service.New(prg, svcConfig)
	if err != nil {
		log.Fatal(err)
	}

	logger, err = s.Logger(nil)
	if err != nil {
		log.Fatal(err)
	}

	err = loadConfig()
	if err != nil {
		log.Fatal(err)
	}

	if len(os.Args) > 1 {
		err := service.Control(s, os.Args[1])
		if err != nil {
			log.Printf("Valid actions: %q\n", service.ControlAction)
			log.Fatal(err)
		}

		return
	}

	err = s.Run()
	if err != nil {
		logger.Error(err)
	}
}

func loadConfig() error {
	var config iniparser.Config

	if err := config.LoadFile("./config.ini"); err != nil {
		return err
	}

	sections := config.GetSections()
	if len(sections) < 2 {
		return errors.New("No services found in config file.\n")
	}

	for _, section := range sections {
		var err error
		var name = section.Name

		if name == "settings" {
			if interval, err = config.GetInt(name, "interval"); err != nil {
				logger.Errorf("%s - %s", name, err)
			}
			continue
		}

		t, err := config.GetString(name, "type")
		if err != nil {
			logger.Error(err)
			continue
		}
		switch strings.ToLower(t) {
		case "namecheap":
			service := new(nameCheapService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "noip":
		case "no-ip":
			service := new(noIPService)
			service.Name = name
			service.Domain, err = config.GetString(name, "domain")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			_, err := net.LookupHost(service.getDomain())
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			service.UserName, err = config.GetString(name, "username")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			service.Password, err = config.GetString(name, "password")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "changeip":
			service := new(changeIPService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "duckdns":
			service := new(duckDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "freedns":
			service := new(freeDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "system-ns":
		case "systemns":
			service := new(systemNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ipdns":
			service := new(ipDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "dynu":
			service := new(dynuService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ydns":
			service := new(yDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ddnss.de":
		case "ddnssde":
			service := new(ddnssdeService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		}
	}

	if len(services) < 1 {
		return errors.New("No valid services found in config file.")
	}

	return nil
}

func update() {
	var currentIP net.IP
	if currentIP = getExternalIP(); currentIP == nil {
		return
	}

	for _, service := range services {
		addr, err := net.LookupHost(service.getDomain())
		if err != nil {
			logger.Errorf("%s - %s", service.getDomain(), err)
			continue
		}
		if len(addr) == 0 || addr[0] == "" {
			logger.Errorf("%s - Unable to get IP address", service.getDomain())
			continue
		}

		registeredIP := addr[0]

		if currentIP.String() == registeredIP {
			logger.Infof("%s - No update is necessary", service.getDomain())
		} else {
			err := service.updateIP()
			if err == nil {
				logger.Infof("%s - Successfully updated from %s to %s", service.getDomain(), registeredIP, currentIP.String())
			} else {
				logger.Errorf("%s - %s", service.getDomain(), err)
			}
		}
	}
}

func getExternalIP() net.IP {
	var currentIP net.IP
	for _, i := range rand.Perm(len(urls)) {
		url := "http://" + urls[i]

		content, err := GetResponse(url, "", "")
		if err != nil {
			logger.Errorf("%s - %s", url, err)
			continue
		}

		ip := regex.FindString(content)

		if currentIP = net.ParseIP(ip); currentIP != nil {
			return currentIP
		}
	}

	return currentIP
}
<commit_msg>Fixed switch.<commit_after>package main

import (
	"errors"
	"github.com/kardianos/service"
	"github.com/lukamicoder/ini-parser"
	"log"
	"math/rand"
	"net"
	"os"
	"regexp"
	"strings"
	"time"
)

var (
	interval = 3600
	services []DdnsService
	logger service.Logger

	regex = regexp.MustCompile("(?m)[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}")
)

var urls = []string{
	"myipinfo.net",
	"myip.dnsomatic.com",
	"icanhazip.com",
	"checkip.dyndns.org",
	"www.myipnumber.com",
	"checkmyip.com",
	"myexternalip.com",
	"www.ipchicken.com",
	"ipecho.net/plain",
	"bot.whatismyipaddress.com",
	"ipv4.ipogre.com",
	"smart-ip.net/myip",
	"checkip.amazonaws.com",
	"www.checkip.org",
}

type program struct {
	exit chan struct {}
}

func (p *program) Start(s service.Service) error {
	p.exit = make(chan struct {})
	go p.run()
	return nil
}

func (p *program) run() error {
	update()
	ticker := time.NewTicker(time.Duration(interval) * time.Second)

	for {
		select {
		case <-ticker.C:
			update()
		case <-p.exit:
			ticker.Stop()
			return nil
		}
	}
}

func (p *program) Stop(s service.Service) error {
	logger.Info("Stopping service...")
	close(p.exit)
	return nil
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	svcConfig := &service.Config{
		Name:        "ddns-client",
		DisplayName: "DDNS Client",
		Description: "Dynamic DNS Client.",
	}

	prg := &program{}
	s, err := service.New(prg, svcConfig)
	if err != nil {
		log.Fatal(err)
	}

	logger, err = s.Logger(nil)
	if err != nil {
		log.Fatal(err)
	}

	err = loadConfig()
	if err != nil {
		log.Fatal(err)
	}

	if len(os.Args) > 1 {
		err := service.Control(s, os.Args[1])
		if err != nil {
			log.Printf("Valid actions: %q\n", service.ControlAction)
			log.Fatal(err)
		}

		return
	}

	err = s.Run()
	if err != nil {
		logger.Error(err)
	}
}

func loadConfig() error {
	var config iniparser.Config

	if err := config.LoadFile("./config.ini"); err != nil {
		return err
	}

	sections := config.GetSections()
	if len(sections) < 2 {
		return errors.New("No services found in config file.\n")
	}

	for _, section := range sections {
		var err error
		var name = section.Name

		if name == "settings" {
			if interval, err = config.GetInt(name, "interval"); err != nil {
				logger.Errorf("%s - %s", name, err)
			}
			continue
		}

		t, err := config.GetString(name, "type")
		if err != nil {
			logger.Error(err)
			continue
		}
		switch strings.ToLower(t) {
		case "namecheap":
			service := new(nameCheapService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "noip", "no-ip":
			service := new(noIPService)
			service.Name = name
			service.Domain, err = config.GetString(name, "domain")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			_, err := net.LookupHost(service.getDomain())
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			service.UserName, err = config.GetString(name, "username")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			service.Password, err = config.GetString(name, "password")
			if err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "changeip":
			service := new(changeIPService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "duckdns":
			service := new(duckDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "freedns":
			service := new(freeDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "system-ns", "systemns":
			service := new(systemNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Token, err = config.GetString(name, "token"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ipdns":
			service := new(ipDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "dynu":
			service := new(dynuService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ydns":
			service := new(yDNSService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		case "ddnss.de", "ddnssde":
			service := new(ddnssdeService)
			service.Name = name
			if service.Domain, err = config.GetString(name, "domain"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if _, err := net.LookupHost(service.getDomain()); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.UserName, err = config.GetString(name, "username"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			if service.Password, err = config.GetString(name, "password"); err != nil {
				logger.Errorf("%s - %s", name, err)
				continue
			}
			services = append(services, service)
		}
	}

	if len(services) < 1 {
		return errors.New("No valid services found in config file.")
	}

	return nil
}

func update() {
	var currentIP net.IP
	if currentIP = getExternalIP(); currentIP == nil {
		return
	}

	for _, service := range services {
		addr, err := net.LookupHost(service.getDomain())
		if err != nil {
			logger.Errorf("%s - %s", service.getDomain(), err)
			continue
		}
		if len(addr) == 0 || addr[0] == "" {
			logger.Errorf("%s - Unable to get IP address", service.getDomain())
			continue
		}

		registeredIP := addr[0]

		if currentIP.String() == registeredIP {
			logger.Infof("%s - No update is necessary", service.getDomain())
		} else {
			err := service.updateIP()
			if err == nil {
				logger.Infof("%s - Successfully updated from %s to %s", service.getDomain(), registeredIP, currentIP.String())
			} else {
				logger.Errorf("%s - %s", service.getDomain(), err)
			}
		}
	}
}

func getExternalIP() net.IP {
	var currentIP net.IP
	for _, i := range rand.Perm(len(urls)) {
		url := "http://" + urls[i]

		content, err := GetResponse(url, "", "")
		if err != nil {
			logger.Errorf("%s - %s", url, err)
			continue
		}

		ip := regex.FindString(content)

		if currentIP = net.ParseIP(ip); currentIP != nil {
			return currentIP
		}
	}

	return currentIP
}
<|endoftext|>


<commit_before>package queue

import (
	"fmt"
	"testing"

	"github.com/garyburd/redigo/redis"
)

var testRedis = "redis://localhost:6379"

func TestPartitions(t *testing.T) {
	Partitions([]string{testRedis})
	_, err := redisPool[0].conn.Do("PING")
	if err != nil {
		t.Error("SetRedisPool items are not set correctly")
	}
}

func TestAddTask(t *testing.T) {
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_0")
	AddTask(4, "test")
	r, e := redisdb.Do("RPOP", "WAREHOUSE_0")
	s, e := redis.String(r, e)
	if s != "4;test" {
		t.Error("Task is stored incorrectly: ", s)
	}
}

func TestQueuesInPartision(t *testing.T) {
	QueuesInPartision(5)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_4")
	AddTask(4, "test")
	r, e := redisdb.Do("RPOP", "WAREHOUSE_4")
	s, e := redis.String(r, e)
	if s != "4;test" {
		t.Error("Task is stored incorrectly: ", s)
	}

}

func TestAnalysePool(t *testing.T) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_0")
	AddTask(1, "start")
	AddTask(2, "start")
	AddTask(1, "stop")
	AddTask(2, "stop")
	a := analyse
	AnalysePool(1, 2, true, a)
	r, e := redisdb.Do("LLEN", "WAREHOUSE_0")
	s, e := redis.Int64(r, e)
	if s != 0 {
		t.Error("Queue is not empty after processing tasks: ", s)
	}

}

func BenchmarkAddTask(b *testing.B) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	for i := 0; i < b.N; i++ {
		AddTask(i, "stop")
	}
}

func BenchmarkRemoveTask(b *testing.B) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	for i := 0; i < b.N; i++ {
		removeTask(redisdb, "WAREHOUSE_0")
	}
}

// This will act both as test and example in documentation
func ExampleAnalysePool() {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	AddTask(1, "start")
	AddTask(2, "start")
	AddTask(1, "stop")
	AddTask(2, "stop")
	a := analyse
	AnalysePool(1, 2, true, a)
	// Output:
	// 1 start
	// 2 start
	// 1 stop
	// 2 stop

}

func analyse(id int, msg_channel chan string, success chan bool, next chan bool) {
	for {
		select {
		case msg := <-msg_channel:
			fmt.Println(id, msg)
			if msg == "stop" {
				<-next
				success <- true
				return
			}
		}
	}
}
<commit_msg>now example show will look like a complete app. Add addTask part is a very simple part, focus is ont analyze<commit_after>package queue

import (
	"fmt"
	"testing"

	"github.com/garyburd/redigo/redis"
)

var testRedis = "redis://localhost:6379"

func TestPartitions(t *testing.T) {
	Partitions([]string{testRedis})
	_, err := redisPool[0].conn.Do("PING")
	if err != nil {
		t.Error("SetRedisPool items are not set correctly")
	}
}

func TestAddTask(t *testing.T) {
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_0")
	AddTask(4, "test")
	r, e := redisdb.Do("RPOP", "WAREHOUSE_0")
	s, e := redis.String(r, e)
	if s != "4;test" {
		t.Error("Task is stored incorrectly: ", s)
	}
}

func TestQueuesInPartision(t *testing.T) {
	QueuesInPartision(5)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_4")
	AddTask(4, "test")
	r, e := redisdb.Do("RPOP", "WAREHOUSE_4")
	s, e := redis.String(r, e)
	if s != "4;test" {
		t.Error("Task is stored incorrectly: ", s)
	}

}

func TestAnalysePool(t *testing.T) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	redisdb.Do("DEL", "WAREHOUSE_0")
	AddTask(1, "start")
	AddTask(2, "start")
	AddTask(1, "stop")
	AddTask(2, "stop")
	analyzer := func(id int, msg_channel chan string, success chan bool, next chan bool) {
		for {
			select {
			case msg := <-msg_channel:
				if msg == "stop" {
					<-next
					success <- true
					return
				}
			}
		}
	}
	AnalysePool(1, 2, true, analyzer)
	r, e := redisdb.Do("LLEN", "WAREHOUSE_0")
	s, e := redis.Int64(r, e)
	if s != 0 {
		t.Error("Queue is not empty after processing tasks: ", s)
	}

}

func BenchmarkAddTask(b *testing.B) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	for i := 0; i < b.N; i++ {
		AddTask(i, "stop")
	}
}

func BenchmarkRemoveTask(b *testing.B) {
	QueuesInPartision(1)
	Partitions([]string{testRedis})
	redisdb := redisPool[0].conn
	for i := 0; i < b.N; i++ {
		removeTask(redisdb, "WAREHOUSE_0")
	}
}

// This will act both as test and example in documentation
func ExampleAnalysePool() {
	QueuesInPartision(1)
	Partitions([]string{"redis://localhost:6379"})
	AddTask(1, "start")
	AddTask(2, "start")
	AddTask(1, "stop")
	AddTask(2, "stop")
	analyzer := func(id int, msg_channel chan string, success chan bool, next chan bool) {
		for {
			select {
			case msg := <-msg_channel:
				fmt.Println(id, msg)
				if msg == "stop" {
					<-next
					success <- true
					return
				}
			}
		}
	}
	AnalysePool(1, 2, true, analyzer)
	// Output:
	// 1 start
	// 2 start
	// 1 stop
	// 2 stop

}
<|endoftext|>


<commit_before>// +build go1.5,cgo

/*
Package plugin exports the functions required to write collectd plugins in Go.

This package provides the abstraction necessary to write plugins for collectd
in Go, compile them into a shared object and let the daemon load and use them.

Example plugin

To understand how this module is being used, please consider the following
example:

  package main

  import (
          "fmt"
          "time"

          "collectd.org/api"
          "collectd.org/plugin"
  )

  type examplePlugin struct{}

  func (examplePlugin) Read() error {
          vl := &api.ValueList{
                  Identifier: api.Identifier{
                          Host:   "example.com",
                          Plugin: "goplug",
                          Type:   "gauge",
                  },
                  Time:     time.Now(),
                  Interval: 10 * time.Second,
                  Values:   []api.Value{api.Gauge(42)},
                  DSNames:  []string{"value"},
          }
          if err := plugin.Write(vl); err != nil {
                  return fmt.Errorf("plugin.Write: %w", err)
          }

          return nil
  }

  func init() {
          plugin.RegisterRead("example", examplePlugin{})
  }

  func main() {} // ignored

The first step when writing a new plugin with this package, is to create a new
"main" package. Even though it has to have a main() function to make cgo happy,
the main() function is ignored. Instead, put your startup code into the init()
function which essentially takes on the same role as the module_register()
function in C based plugins.

Then, define a type which implements the Reader interface by implementing the
"Read() error" function. In the example above, this type is called
ExamplePlugin. Create an instance of this type and pass it to RegisterRead() in
the init() function.

Build flags

To compile your plugin, set up the CGO_CPPFLAGS environment variable and call
"go build" with the following options:

  export COLLECTD_SRC="/path/to/collectd"
  export CGO_CPPFLAGS="-I${COLLECTD_SRC}/src/daemon -I${COLLECTD_SRC}/src"
  go build -buildmode=c-shared -o example.so
*/
package plugin // import "collectd.org/plugin"

// #cgo CPPFLAGS: -DHAVE_CONFIG_H
// #cgo LDFLAGS: -ldl
// #include <stdlib.h>
// #include <dlfcn.h>
// #include "plugin.h"
//
// int dispatch_values_wrapper (value_list_t const *vl);
// int register_read_wrapper (char const *group, char const *name,
//     plugin_read_cb callback,
//     cdtime_t interval,
//     user_data_t *ud);
//
// data_source_t *ds_dsrc(data_set_t const *ds, size_t i);
//
// void value_list_add_counter (value_list_t *, counter_t);
// void value_list_add_derive  (value_list_t *, derive_t);
// void value_list_add_gauge   (value_list_t *, gauge_t);
// counter_t value_list_get_counter (value_list_t *, size_t);
// derive_t  value_list_get_derive  (value_list_t *, size_t);
// gauge_t   value_list_get_gauge   (value_list_t *, size_t);
//
// int wrap_read_callback(user_data_t *);
//
// int register_write_wrapper (char const *, plugin_write_cb, user_data_t *);
// int wrap_write_callback(data_set_t *, value_list_t *, user_data_t *);
//
// int register_shutdown_wrapper (char *, plugin_shutdown_cb);
// int wrap_shutdown_callback(void);
import "C"

import (
	"context"
	"fmt"
	"unsafe"

	"collectd.org/api"
	"collectd.org/cdtime"
)

var (
	ctx = context.Background()
)

// Reader defines the interface for read callbacks, i.e. Go functions that are
// called periodically from the collectd daemon.
type Reader interface {
	Read() error
}

func strcpy(dst []C.char, src string) {
	byteStr := []byte(src)
	cStr := make([]C.char, len(byteStr)+1)

	for i, b := range byteStr {
		cStr[i] = C.char(b)
	}
	cStr[len(cStr)-1] = C.char(0)

	copy(dst, cStr)
}

func newValueListT(vl *api.ValueList) (*C.value_list_t, error) {
	ret := &C.value_list_t{}

	strcpy(ret.host[:], vl.Host)
	strcpy(ret.plugin[:], vl.Plugin)
	strcpy(ret.plugin_instance[:], vl.PluginInstance)
	strcpy(ret._type[:], vl.Type)
	strcpy(ret.type_instance[:], vl.TypeInstance)
	ret.interval = C.cdtime_t(cdtime.NewDuration(vl.Interval))
	ret.time = C.cdtime_t(cdtime.New(vl.Time))

	for _, v := range vl.Values {
		switch v := v.(type) {
		case api.Counter:
			if _, err := C.value_list_add_counter(ret, C.counter_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_counter: %w", err)
			}
		case api.Derive:
			if _, err := C.value_list_add_derive(ret, C.derive_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_derive: %w", err)
			}
		case api.Gauge:
			if _, err := C.value_list_add_gauge(ret, C.gauge_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_gauge: %w", err)
			}
		default:
			return nil, fmt.Errorf("not yet supported: %T", v)
		}
	}

	return ret, nil
}

// Writer implements the api.Write interface.
type Writer struct{}

// Write implements the api.Writer interface for the collectd daemon.
func (Writer) Write(_ context.Context, vl *api.ValueList) error {
	return Write(vl)
}

// Write converts a ValueList and calls the plugin_dispatch_values() function
// of the collectd daemon.
func Write(vl *api.ValueList) error {
	vlt, err := newValueListT(vl)
	if err != nil {
		return err
	}
	defer C.free(unsafe.Pointer(vlt.values))

	status, err := C.dispatch_values_wrapper(vlt)
	if err != nil {
		return fmt.Errorf("dispatch_values failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("dispatch_values failed with status %d", status)
	}

	return nil
}

// readFuncs holds references to all read callbacks, so the garbage collector
// doesn't get any funny ideas.
var readFuncs = make(map[string]Reader)

// RegisterRead registers a new read function with the daemon which is called
// periodically.
func RegisterRead(name string, r Reader) error {
	cGroup := C.CString("golang")
	defer C.free(unsafe.Pointer(cGroup))

	cName := C.CString(name)
	ud := C.user_data_t{
		data:      unsafe.Pointer(cName),
		free_func: nil,
	}

	status, err := C.register_read_wrapper(cGroup, cName,
		C.plugin_read_cb(C.wrap_read_callback),
		C.cdtime_t(0),
		&ud)
	if err != nil {
		return fmt.Errorf("register_read failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("register_read failed with status %d", status)
	}

	readFuncs[name] = r
	return nil
}

//export wrap_read_callback
func wrap_read_callback(ud *C.user_data_t) C.int {
	name := C.GoString((*C.char)(ud.data))
	r, ok := readFuncs[name]
	if !ok {
		return -1
	}

	if err := r.Read(); err != nil {
		Errorf("%s plugin: Read() failed: %v", name, err)
		return -1
	}

	return 0
}

// writeFuncs holds references to all write callbacks, so the garbage collector
// doesn't get any funny ideas.
var writeFuncs = make(map[string]api.Writer)

// RegisterWrite registers a new write function with the daemon which is called
// for every metric collected by collectd.
//
// Please note that multiple threads may call this function concurrently. If
// you're accessing shared resources, such as a memory buffer, you have to
// implement appropriate locking around these accesses.
func RegisterWrite(name string, w api.Writer) error {
	cName := C.CString(name)
	ud := C.user_data_t{
		data:      unsafe.Pointer(cName),
		free_func: nil,
	}

	status, err := C.register_write_wrapper(cName, C.plugin_write_cb(C.wrap_write_callback), &ud)
	if err != nil {
		return fmt.Errorf("register_write failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("register_write failed with status %d", status)
	}

	writeFuncs[name] = w
	return nil
}

//export wrap_write_callback
func wrap_write_callback(ds *C.data_set_t, cvl *C.value_list_t, ud *C.user_data_t) C.int {
	name := C.GoString((*C.char)(ud.data))
	w, ok := writeFuncs[name]
	if !ok {
		return -1
	}

	vl := &api.ValueList{
		Identifier: api.Identifier{
			Host:           C.GoString(&cvl.host[0]),
			Plugin:         C.GoString(&cvl.plugin[0]),
			PluginInstance: C.GoString(&cvl.plugin_instance[0]),
			Type:           C.GoString(&cvl._type[0]),
			TypeInstance:   C.GoString(&cvl.type_instance[0]),
		},
		Time:     cdtime.Time(cvl.time).Time(),
		Interval: cdtime.Time(cvl.interval).Duration(),
	}

	// TODO: Remove 'size_t' cast on 'ds_num' upon 5.7 release.
	for i := C.size_t(0); i < C.size_t(ds.ds_num); i++ {
		dsrc := C.ds_dsrc(ds, i)

		switch dsrc._type {
		case C.DS_TYPE_COUNTER:
			v := C.value_list_get_counter(cvl, i)
			vl.Values = append(vl.Values, api.Counter(v))
		case C.DS_TYPE_DERIVE:
			v := C.value_list_get_derive(cvl, i)
			vl.Values = append(vl.Values, api.Derive(v))
		case C.DS_TYPE_GAUGE:
			v := C.value_list_get_gauge(cvl, i)
			vl.Values = append(vl.Values, api.Gauge(v))
		default:
			Errorf("%s plugin: data source type %d is not supported", name, dsrc._type)
			return -1
		}

		vl.DSNames = append(vl.DSNames, C.GoString(&dsrc.name[0]))
	}

	if err := w.Write(ctx, vl); err != nil {
		Errorf("%s plugin: Write() failed: %v", name, err)
		return -1
	}

	return 0
}

// First declare some types, interfaces, general functions

// Shutter is called to shut down the plugin gracefully.
type Shutter interface {
	Shutdown() error
}

// shutdownFuncs holds references to all shutdown callbacks
var shutdownFuncs = make(map[string]Shutter)

//export wrap_shutdown_callback
func wrap_shutdown_callback() C.int {
	for name, f := range shutdownFuncs {
		if err := f.Shutdown(); err != nil {
			Errorf("%s plugin: Shutdown() failed: %v", name, err)
			return -1
		}
	}
	return 0
}

// RegisterShutdown registers a shutdown function with the daemon which is called
// when the plugin is required to shutdown gracefully.
func RegisterShutdown(name string, s Shutter) error {
	// Only register a callback the first time one is implemented, subsequent
	// callbacks get added to a list and called at the same time
	if len(shutdownFuncs) <= 0 {
		cName := C.CString(name)
		cCallback := C.plugin_shutdown_cb(C.wrap_shutdown_callback)

		status, err := C.register_shutdown_wrapper(cName, cCallback)
		if err != nil {
			Errorf("register_shutdown_wrapper failed with status: %v", status)
			return err
		}
	}
	shutdownFuncs[name] = s
	return nil
}

//export module_register
func module_register() {
}
<commit_msg>Package plugin: Pass a context.Context to callbacks and Write().<commit_after>// +build go1.5,cgo

/*
Package plugin exports the functions required to write collectd plugins in Go.

This package provides the abstraction necessary to write plugins for collectd
in Go, compile them into a shared object and let the daemon load and use them.

Example plugin

To understand how this module is being used, please consider the following
example:

  package main

  import (
          "context"
          "fmt"
          "time"

          "collectd.org/api"
          "collectd.org/plugin"
  )

  type examplePlugin struct{}

  func (examplePlugin) Read(ctx context.Context) error {
          vl := &api.ValueList{
                  Identifier: api.Identifier{
                          Host:   "example.com",
                          Plugin: "goplug",
                          Type:   "gauge",
                  },
                  Time:     time.Now(),
                  Interval: 10 * time.Second,
                  Values:   []api.Value{api.Gauge(42)},
                  DSNames:  []string{"value"},
          }
          if err := plugin.Write(ctx, vl); err != nil {
                  return fmt.Errorf("plugin.Write: %w", err)
          }

          return nil
  }

  func init() {
          plugin.RegisterRead("example", examplePlugin{})
  }

  func main() {} // ignored

The first step when writing a new plugin with this package, is to create a new
"main" package. Even though it has to have a main() function to make cgo happy,
the main() function is ignored. Instead, put your startup code into the init()
function which essentially takes on the same role as the module_register()
function in C based plugins.

Then, define a type which implements the Reader interface by implementing the
"Read() error" function. In the example above, this type is called
"examplePlugin". Create an instance of this type and pass it to RegisterRead()
in the init() function.

Build flags

To compile your plugin, set up the CGO_CPPFLAGS environment variable and call
"go build" with the following options:

  export COLLECTD_SRC="/path/to/collectd"
  export CGO_CPPFLAGS="-I${COLLECTD_SRC}/src/daemon -I${COLLECTD_SRC}/src"
  go build -buildmode=c-shared -o example.so
*/
package plugin // import "collectd.org/plugin"

// #cgo CPPFLAGS: -DHAVE_CONFIG_H
// #cgo LDFLAGS: -ldl
// #include <stdlib.h>
// #include <dlfcn.h>
// #include "plugin.h"
//
// int dispatch_values_wrapper (value_list_t const *vl);
// int register_read_wrapper (char const *group, char const *name,
//     plugin_read_cb callback,
//     cdtime_t interval,
//     user_data_t *ud);
//
// data_source_t *ds_dsrc(data_set_t const *ds, size_t i);
//
// void value_list_add_counter (value_list_t *, counter_t);
// void value_list_add_derive  (value_list_t *, derive_t);
// void value_list_add_gauge   (value_list_t *, gauge_t);
// counter_t value_list_get_counter (value_list_t *, size_t);
// derive_t  value_list_get_derive  (value_list_t *, size_t);
// gauge_t   value_list_get_gauge   (value_list_t *, size_t);
//
// int wrap_read_callback(user_data_t *);
//
// int register_write_wrapper (char const *, plugin_write_cb, user_data_t *);
// int wrap_write_callback(data_set_t *, value_list_t *, user_data_t *);
//
// int register_shutdown_wrapper (char *, plugin_shutdown_cb);
// int wrap_shutdown_callback(void);
import "C"

import (
	"context"
	"fmt"
	"unsafe"

	"collectd.org/api"
	"collectd.org/cdtime"
)

// Reader defines the interface for read callbacks, i.e. Go functions that are
// called periodically from the collectd daemon.
type Reader interface {
	Read(ctx context.Context) error
}

func strcpy(dst []C.char, src string) {
	byteStr := []byte(src)
	cStr := make([]C.char, len(byteStr)+1)

	for i, b := range byteStr {
		cStr[i] = C.char(b)
	}
	cStr[len(cStr)-1] = C.char(0)

	copy(dst, cStr)
}

func newValueListT(vl *api.ValueList) (*C.value_list_t, error) {
	ret := &C.value_list_t{}

	strcpy(ret.host[:], vl.Host)
	strcpy(ret.plugin[:], vl.Plugin)
	strcpy(ret.plugin_instance[:], vl.PluginInstance)
	strcpy(ret._type[:], vl.Type)
	strcpy(ret.type_instance[:], vl.TypeInstance)
	ret.interval = C.cdtime_t(cdtime.NewDuration(vl.Interval))
	ret.time = C.cdtime_t(cdtime.New(vl.Time))

	for _, v := range vl.Values {
		switch v := v.(type) {
		case api.Counter:
			if _, err := C.value_list_add_counter(ret, C.counter_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_counter: %w", err)
			}
		case api.Derive:
			if _, err := C.value_list_add_derive(ret, C.derive_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_derive: %w", err)
			}
		case api.Gauge:
			if _, err := C.value_list_add_gauge(ret, C.gauge_t(v)); err != nil {
				return nil, fmt.Errorf("value_list_add_gauge: %w", err)
			}
		default:
			return nil, fmt.Errorf("not yet supported: %T", v)
		}
	}

	return ret, nil
}

// Writer implements the api.Write interface.
type Writer struct{}

// Write implements the api.Writer interface for the collectd daemon.
func (Writer) Write(ctx context.Context, vl *api.ValueList) error {
	return Write(ctx, vl)
}

// Write converts a ValueList and calls the plugin_dispatch_values() function
// of the collectd daemon.
func Write(ctx context.Context, vl *api.ValueList) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
	}

	vlt, err := newValueListT(vl)
	if err != nil {
		return err
	}
	defer C.free(unsafe.Pointer(vlt.values))

	status, err := C.dispatch_values_wrapper(vlt)
	if err != nil {
		return fmt.Errorf("dispatch_values failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("dispatch_values failed with status %d", status)
	}

	return nil
}

// readFuncs holds references to all read callbacks, so the garbage collector
// doesn't get any funny ideas.
var readFuncs = make(map[string]Reader)

// RegisterRead registers a new read function with the daemon which is called
// periodically.
func RegisterRead(name string, r Reader) error {
	cGroup := C.CString("golang")
	defer C.free(unsafe.Pointer(cGroup))

	cName := C.CString(name)
	ud := C.user_data_t{
		data:      unsafe.Pointer(cName),
		free_func: nil,
	}

	status, err := C.register_read_wrapper(cGroup, cName,
		C.plugin_read_cb(C.wrap_read_callback),
		C.cdtime_t(0),
		&ud)
	if err != nil {
		return fmt.Errorf("register_read failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("register_read failed with status %d", status)
	}

	readFuncs[name] = r
	return nil
}

//export wrap_read_callback
func wrap_read_callback(ud *C.user_data_t) C.int {
	name := C.GoString((*C.char)(ud.data))
	r, ok := readFuncs[name]
	if !ok {
		return -1
	}

	ctx := context.Background()
	if err := r.Read(ctx); err != nil {
		Errorf("%s plugin: Read() failed: %v", name, err)
		return -1
	}

	return 0
}

// writeFuncs holds references to all write callbacks, so the garbage collector
// doesn't get any funny ideas.
var writeFuncs = make(map[string]api.Writer)

// RegisterWrite registers a new write function with the daemon which is called
// for every metric collected by collectd.
//
// Please note that multiple threads may call this function concurrently. If
// you're accessing shared resources, such as a memory buffer, you have to
// implement appropriate locking around these accesses.
func RegisterWrite(name string, w api.Writer) error {
	cName := C.CString(name)
	ud := C.user_data_t{
		data:      unsafe.Pointer(cName),
		free_func: nil,
	}

	status, err := C.register_write_wrapper(cName, C.plugin_write_cb(C.wrap_write_callback), &ud)
	if err != nil {
		return fmt.Errorf("register_write failed: %w", err)
	}
	if status != 0 {
		return fmt.Errorf("register_write failed with status %d", status)
	}

	writeFuncs[name] = w
	return nil
}

//export wrap_write_callback
func wrap_write_callback(ds *C.data_set_t, cvl *C.value_list_t, ud *C.user_data_t) C.int {
	name := C.GoString((*C.char)(ud.data))
	w, ok := writeFuncs[name]
	if !ok {
		return -1
	}

	vl := &api.ValueList{
		Identifier: api.Identifier{
			Host:           C.GoString(&cvl.host[0]),
			Plugin:         C.GoString(&cvl.plugin[0]),
			PluginInstance: C.GoString(&cvl.plugin_instance[0]),
			Type:           C.GoString(&cvl._type[0]),
			TypeInstance:   C.GoString(&cvl.type_instance[0]),
		},
		Time:     cdtime.Time(cvl.time).Time(),
		Interval: cdtime.Time(cvl.interval).Duration(),
	}

	// TODO: Remove 'size_t' cast on 'ds_num' upon 5.7 release.
	for i := C.size_t(0); i < C.size_t(ds.ds_num); i++ {
		dsrc := C.ds_dsrc(ds, i)

		switch dsrc._type {
		case C.DS_TYPE_COUNTER:
			v := C.value_list_get_counter(cvl, i)
			vl.Values = append(vl.Values, api.Counter(v))
		case C.DS_TYPE_DERIVE:
			v := C.value_list_get_derive(cvl, i)
			vl.Values = append(vl.Values, api.Derive(v))
		case C.DS_TYPE_GAUGE:
			v := C.value_list_get_gauge(cvl, i)
			vl.Values = append(vl.Values, api.Gauge(v))
		default:
			Errorf("%s plugin: data source type %d is not supported", name, dsrc._type)
			return -1
		}

		vl.DSNames = append(vl.DSNames, C.GoString(&dsrc.name[0]))
	}

	ctx := context.Background()
	if err := w.Write(ctx, vl); err != nil {
		Errorf("%s plugin: Write() failed: %v", name, err)
		return -1
	}

	return 0
}

// First declare some types, interfaces, general functions

// Shutter is called to shut down the plugin gracefully.
type Shutter interface {
	Shutdown(context.Context) error
}

// shutdownFuncs holds references to all shutdown callbacks
var shutdownFuncs = make(map[string]Shutter)

//export wrap_shutdown_callback
func wrap_shutdown_callback() C.int {
	for name, f := range shutdownFuncs {
		ctx := context.Background()
		if err := f.Shutdown(ctx); err != nil {
			Errorf("%s plugin: Shutdown() failed: %v", name, err)
			return -1
		}
	}
	return 0
}

// RegisterShutdown registers a shutdown function with the daemon which is called
// when the plugin is required to shutdown gracefully.
func RegisterShutdown(name string, s Shutter) error {
	// Only register a callback the first time one is implemented, subsequent
	// callbacks get added to a list and called at the same time
	if len(shutdownFuncs) <= 0 {
		cName := C.CString(name)
		cCallback := C.plugin_shutdown_cb(C.wrap_shutdown_callback)

		status, err := C.register_shutdown_wrapper(cName, cCallback)
		if err != nil {
			Errorf("register_shutdown_wrapper failed with status: %v", status)
			return err
		}
	}
	shutdownFuncs[name] = s
	return nil
}

//export module_register
func module_register() {
}
<|endoftext|>


<commit_before>package fuse

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"

	"github.com/jacobsa/fuse/internal/buffer"
)

var errNoAvail = errors.New("no available fuse devices")
var errNotLoaded = errors.New("osxfusefs is not loaded")

func loadOSXFUSE() error {
	cmd := exec.Command("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs")
	cmd.Dir = "/"
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	return err
}

func openOSXFUSEDev() (dev *os.File, err error) {
	// Try each device name.
	for i := uint64(0); ; i++ {
		path := fmt.Sprintf("/dev/osxfuse%d", i)
		dev, err = os.OpenFile(path, os.O_RDWR, 0000)
		if os.IsNotExist(err) {
			if i == 0 {
				// Not even the first device was found. Fuse must not be loaded.
				err = errNotLoaded
				return
			}

			// Otherwise we've run out of kernel-provided devices
			err = errNoAvail
			return
		}

		if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
			// This device is in use; try the next one.
			continue
		}

		return
	}
}

func callMount(dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
	bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"

	for k, v := range conf.options {
		if strings.Contains(k, ",") || strings.Contains(v, ",") {
			// Silly limitation but the mount helper does not
			// understand any escaping. See TestMountOptionCommaError.
			return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v)
		}
	}
	cmd := exec.Command(
		bin,
		"-o", conf.getOptions(),
		// Tell osxfuse-kext how large our buffer is. It must split
		// writes larger than this into multiple writes.
		//
		// OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
		// this instead.
		"-o", "iosize="+strconv.FormatUint(buffer.MaxWriteSize, 10),
		// refers to fd passed in cmd.ExtraFiles
		"3",
		dir,
	)
	cmd.ExtraFiles = []*os.File{f}
	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
	// TODO this is used for fs typenames etc, let app influence it
	cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_DAEMON_PATH="+bin)
	var buf bytes.Buffer
	cmd.Stdout = &buf
	cmd.Stderr = &buf

	err := cmd.Start()
	if err != nil {
		return err
	}
	go func() {
		err := cmd.Wait()
		if err != nil {
			if buf.Len() > 0 {
				output := buf.Bytes()
				output = bytes.TrimRight(output, "\n")
				msg := err.Error() + ": " + string(output)
				err = errors.New(msg)
			}
		}
		*errp = err
		close(ready)
	}()
	return err
}

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(
	dir string,
	conf *mountConfig,
	ready chan<- error) (dev *os.File, err error) {
	// Open the device.
	dev, err = openOSXFUSEDev()

	// Special case: we may need to explicitly load osxfuse. Load it, then try
	// again.
	if err == errNotLoaded {
		err = loadOSXFUSE()
		if err != nil {
			err = fmt.Errorf("loadOSXFUSE: %v", err)
			return
		}

		dev, err = openOSXFUSEDev()
	}

	// Propagate errors.
	if err != nil {
		err = fmt.Errorf("openOSXFUSEDev: %v", err)
		return
	}

	// Call the mount binary with the device.
	err = callMount(dir, conf, dev, ready)
	if err != nil {
		dev.Close()
		err = fmt.Errorf("callMount: %v", err)
		return
	}

	return
}
<commit_msg>Touched up callMount.<commit_after>package fuse

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"

	"github.com/jacobsa/fuse/internal/buffer"
)

var errNoAvail = errors.New("no available fuse devices")
var errNotLoaded = errors.New("osxfusefs is not loaded")

func loadOSXFUSE() error {
	cmd := exec.Command("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs")
	cmd.Dir = "/"
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	return err
}

func openOSXFUSEDev() (dev *os.File, err error) {
	// Try each device name.
	for i := uint64(0); ; i++ {
		path := fmt.Sprintf("/dev/osxfuse%d", i)
		dev, err = os.OpenFile(path, os.O_RDWR, 0000)
		if os.IsNotExist(err) {
			if i == 0 {
				// Not even the first device was found. Fuse must not be loaded.
				err = errNotLoaded
				return
			}

			// Otherwise we've run out of kernel-provided devices
			err = errNoAvail
			return
		}

		if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
			// This device is in use; try the next one.
			continue
		}

		return
	}
}

func callMount(
	dir string,
	cfg *mountConfig,
	dev *os.File,
	ready chan<- error) (err error) {
	const bin = "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"

	// The mount helper doesn't understand any escaping.
	for k, v := range conf.options {
		if strings.Contains(k, ",") || strings.Contains(v, ",") {
			return fmt.Errorf(
				"mount options cannot contain commas on darwin: %q=%q",
				k,
				v)
		}
	}

	// Call the mount helper, passing in the device file and saving output into a
	// buffer.
	cmd := exec.Command(
		bin,
		"-o", conf.getOptions(),
		// Tell osxfuse-kext how large our buffer is. It must split
		// writes larger than this into multiple writes.
		//
		// OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
		// this instead.
		"-o", "iosize="+strconv.FormatUint(buffer.MaxWriteSize, 10),
		// refers to fd passed in cmd.ExtraFiles
		"3",
		dir,
	)
	cmd.ExtraFiles = []*os.File{dev}
	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
	// TODO this is used for fs typenames etc, let app influence it
	cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_DAEMON_PATH="+bin)

	var buf bytes.Buffer
	cmd.Stdout = &buf
	cmd.Stderr = &buf

	err = cmd.Start()
	if err != nil {
		return
	}

	// In the background, wait for the command to complete.
	go func() {
		err := cmd.Wait()
		if err != nil {
			if buf.Len() > 0 {
				output := buf.Bytes()
				output = bytes.TrimRight(output, "\n")
				err = fmt.Errorf("%v: %s", err, output)
			}
		}

		ready <- err
	}()

	return
}

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(
	dir string,
	conf *mountConfig,
	ready chan<- error) (dev *os.File, err error) {
	// Open the device.
	dev, err = openOSXFUSEDev()

	// Special case: we may need to explicitly load osxfuse. Load it, then try
	// again.
	if err == errNotLoaded {
		err = loadOSXFUSE()
		if err != nil {
			err = fmt.Errorf("loadOSXFUSE: %v", err)
			return
		}

		dev, err = openOSXFUSEDev()
	}

	// Propagate errors.
	if err != nil {
		err = fmt.Errorf("openOSXFUSEDev: %v", err)
		return
	}

	// Call the mount binary with the device.
	err = callMount(dir, conf, dev, ready)
	if err != nil {
		dev.Close()
		err = fmt.Errorf("callMount: %v", err)
		return
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int
var userList []string
var shareList map[string]int
var availableList map[string]int

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "draft"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}

		//step1 : get args
		// user := args[0]
		// amount, _ := strconv.Atoi(args[1])
		// if amount <= 0 {
		// 	return nil, errors.New("errors in args[1],it is negative")
		// }
		fmt.Printf("user is %v and amount is %v", args[0], args[1])

		//step2 : check if the userList[user] exist
		//if exist, then userList[user] += amount
		//if not exists, then userList[user] = amount
		// if shareList[user] == 0 {
		// 	fmt.Printf("the user [%v] does not exit \n", user)
		// 	userList = append(userList, user)
		// 	shareList[user] = amount
		//
		// } else {
		// 	fmt.Printf("the user [%v] exist", user)
		// 	if !GoalReached() {
		// 		shareList[user] += amount
		// 	}
		// }

		// step3: raise amount

		//// TODO: write code for pay
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	default:
		fmt.Println("no function found")
		return nil, errors.New("no function found, recheck your function name")
	}
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	// case "getProjectState":
	// 	fmt.Println("started logging in getProjectState()")
	// 	if len(args) != 0 {
	// 		return nil, errors.New("incorrect args")
	// 	}
	// 	result := projectName + "/"
	// 	result += strconv.Itoa(projectRate) + "/"
	// 	result += strconv.Itoa(projectPeriod) + "/"
	// 	result += strconv.Itoa(projectGoal) + "/"
	// 	result += strconv.Itoa(projectTimes) + "/"
	// 	result += projectBenifary + "/"
	// 	result += projectState + "/"
	// 	result += strconv.FormatFloat(currentPrice, 'E', -1, 64) + "/"
	// 	result += strconv.Itoa(projectSummary) + "/"
	//
	// 	return []byte(result), nil //end of getProjectState
	case "getUserList":
		fmt.Println("started logging in getUserList")
		var result string
		for i, value := range userList {
			result += fmt.Sprintf("userList[%v] is %v ****", strconv.Itoa(i), value)
		}
		return []byte(result), nil
	case "getShareList":
		fmt.Println("started logging in getShareList")
		return nil, nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	default:
		fmt.Println("no function found")
		return nil, errors.New("no function found, recheck your function name")
	}
}

func GoalReached() bool {
	return false
}
<commit_msg>demo7.go<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int
var userList []string
var shareList map[string]int
var availableList map[string]int

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "draft"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}
		fmt.Printf("user is %v and amount is %v", args[0], args[1])
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	}
	return nil, nil
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	case "getUserList":
		fmt.Println("started logging in getUserList")
		var result string
		for i, value := range userList {
			result += fmt.Sprintf("userList[%v] is %v ****", strconv.Itoa(i), value)
		}
		return []byte(result), nil
	case "getShareList":
		fmt.Println("started logging in getShareList")
		return nil, nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package githook

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path"
	"strconv"
	"strings"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
	"github.com/pachyderm/pachyderm/src/server/pkg/ppsdb"
	"github.com/pachyderm/pachyderm/src/server/pkg/util"

	etcd "github.com/coreos/etcd/clientv3"
	logrus "github.com/sirupsen/logrus"
	"golang.org/x/net/context"
	"gopkg.in/go-playground/webhooks.v3"
	"gopkg.in/go-playground/webhooks.v3/github"
)

// GitHookPort specifies the port the server will listen on
const GitHookPort = 999
const apiVersion = "v1"

// gitHookServer serves GetFile requests over HTTP
type gitHookServer struct {
	hook       *github.Webhook
	client     *client.APIClient
	etcdClient *etcd.Client
	pipelines  col.Collection
}

// RunGitHookServer starts the webhook server
func RunGitHookServer(address string, etcdAddress string, etcdPrefix string) error {
	c, err := client.NewFromAddress(address)
	if err != nil {
		return err
	}
	etcdClient, err := etcd.New(etcd.Config{
		Endpoints:   []string{etcdAddress},
		DialOptions: client.EtcdDialOptions(),
	})
	if err != nil {
		return err
	}
	hook := github.New(&github.Config{})
	s := &gitHookServer{
		hook,
		c,
		etcdClient,
		ppsdb.Pipelines(etcdClient, etcdPrefix),
	}

	hook.RegisterEvents(
		func(payload interface{}, header webhooks.Header) {
			if err := s.HandlePush(payload, header); err != nil {
				pl := payload.(github.PushPayload)
				logrus.Infof("github webhook failed to handle push for repo (%v) on branch (%v) with error %v", pl.Repository.Name, path.Base(pl.Ref), err)
			}
		},
		github.PushEvent,
	)
	return webhooks.Run(hook, ":"+strconv.Itoa(GitHookPort), fmt.Sprintf("/%v/handle/push", apiVersion))
}
func matchingBranch(inputBranch string, payloadBranch string) bool {
	if inputBranch == payloadBranch {
		return true
	}
	if inputBranch == "" && payloadBranch == "master" {
		return true
	}
	return false
}

func (s *gitHookServer) findMatchingPipelineInputs(payload github.PushPayload) (pipelines []*pps.PipelineInfo, inputs []*pps.GitInput, err error) {
	payloadBranch := path.Base(payload.Ref)
	pipelines, err = s.client.ListPipeline()
	if err != nil {
		return nil, nil, err
	}
	for _, pipelineInfo := range pipelines {
		pps.VisitInput(pipelineInfo.Input, func(input *pps.Input) {
			if input.Git != nil {
				if input.Git.URL == payload.Repository.CloneURL && matchingBranch(input.Git.Branch, payloadBranch) {
					inputs = append(inputs, input.Git)
				}
			}
		})
	}
	if len(inputs) == 0 {
		return nil, nil, fmt.Errorf("no pipeline inputs corresponding to git URL (%v) on branch (%v) found, perhaps the git input is not set yet on a pipeline", payload.Repository.CloneURL, payloadBranch)
	}
	return pipelines, inputs, nil
}

func (s *gitHookServer) HandlePush(payload interface{}, _ webhooks.Header) (retErr error) {
	pl := payload.(github.PushPayload)
	logrus.Infof("received github push payload for repo (%v) on branch (%v)", pl.Repository.Name, path.Base(pl.Ref))

	raw, err := json.Marshal(pl)
	if err != nil {
		return fmt.Errorf("error marshalling payload (%v): %v", pl, err)
	}
	pipelines, gitInputs, err := s.findMatchingPipelineInputs(pl)
	if err != nil {
		return err
	}
	if pl.Repository.Private {
		for _, pipelineInfo := range pipelines {
			err := util.FailPipeline(context.Background(), s.etcdClient, s.pipelines, pipelineInfo.Pipeline.Name, fmt.Sprintf("unable to clone private github repo (%v)", pl.Repository.CloneURL))
			// err will be handled but first we want to
			// try and fail all relevant pipelines
			if err != nil {
				logrus.Errorf("error marking pipeline %v as failed %v", pipelineInfo.Pipeline.Name, err)
				retErr = err
			}
		}
		return retErr
	}
	triggeredRepos := make(map[string]bool)
	for _, input := range gitInputs {
		repoName := pps.RepoNameFromGitInfo(input.URL, input.Name)
		if triggeredRepos[repoName] {
			// This input is used on multiple pipelines, and we've already
			// committed to this input repo
			continue
		}
		err := s.commitPayload(repoName, input.Branch, raw)
		if err != nil {
			logrus.Errorf("github webhook failed to commit payload to repo (%v) push with error: %v\n", repoName, err)
			retErr = err
			continue
		}
		triggeredRepos[repoName] = true
	}
	return nil
}

func (s *gitHookServer) commitPayload(repoName string, branchName string, rawPayload []byte) (retErr error) {
	commit, err := s.client.StartCommit(repoName, branchName)
	if err != nil {
		return err
	}
	defer func() {
		if retErr != nil {
			err := s.client.DeleteCommit(repoName, commit.ID)
			if err != nil {
				logrus.Errorf("git webhook failed to delete partial commit (%v) on repo (%v)", commit.ID, repoName)
			}
			return
		}
		retErr = s.client.FinishCommit(repoName, commit.ID)
	}()
	if err = s.client.DeleteFile(repoName, commit.ID, "commit.json"); err != nil {
		return err
	}
	if _, err = s.client.PutFile(repoName, commit.ID, "commit.json", bytes.NewReader(rawPayload)); err != nil {
		return err
	}
	return nil
}
<commit_msg>inline this err check<commit_after>package githook

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path"
	"strconv"
	"strings"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pps"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
	"github.com/pachyderm/pachyderm/src/server/pkg/ppsdb"
	"github.com/pachyderm/pachyderm/src/server/pkg/util"

	etcd "github.com/coreos/etcd/clientv3"
	logrus "github.com/sirupsen/logrus"
	"golang.org/x/net/context"
	"gopkg.in/go-playground/webhooks.v3"
	"gopkg.in/go-playground/webhooks.v3/github"
)

// GitHookPort specifies the port the server will listen on
const GitHookPort = 999
const apiVersion = "v1"

// gitHookServer serves GetFile requests over HTTP
type gitHookServer struct {
	hook       *github.Webhook
	client     *client.APIClient
	etcdClient *etcd.Client
	pipelines  col.Collection
}

// RunGitHookServer starts the webhook server
func RunGitHookServer(address string, etcdAddress string, etcdPrefix string) error {
	c, err := client.NewFromAddress(address)
	if err != nil {
		return err
	}
	etcdClient, err := etcd.New(etcd.Config{
		Endpoints:   []string{etcdAddress},
		DialOptions: client.EtcdDialOptions(),
	})
	if err != nil {
		return err
	}
	hook := github.New(&github.Config{})
	s := &gitHookServer{
		hook,
		c,
		etcdClient,
		ppsdb.Pipelines(etcdClient, etcdPrefix),
	}

	hook.RegisterEvents(
		func(payload interface{}, header webhooks.Header) {
			if err := s.HandlePush(payload, header); err != nil {
				pl := payload.(github.PushPayload)
				logrus.Infof("github webhook failed to handle push for repo (%v) on branch (%v) with error %v", pl.Repository.Name, path.Base(pl.Ref), err)
			}
		},
		github.PushEvent,
	)
	return webhooks.Run(hook, ":"+strconv.Itoa(GitHookPort), fmt.Sprintf("/%v/handle/push", apiVersion))
}
func matchingBranch(inputBranch string, payloadBranch string) bool {
	if inputBranch == payloadBranch {
		return true
	}
	if inputBranch == "" && payloadBranch == "master" {
		return true
	}
	return false
}

func (s *gitHookServer) findMatchingPipelineInputs(payload github.PushPayload) (pipelines []*pps.PipelineInfo, inputs []*pps.GitInput, err error) {
	payloadBranch := path.Base(payload.Ref)
	pipelines, err = s.client.ListPipeline()
	if err != nil {
		return nil, nil, err
	}
	for _, pipelineInfo := range pipelines {
		pps.VisitInput(pipelineInfo.Input, func(input *pps.Input) {
			if input.Git != nil {
				if input.Git.URL == payload.Repository.CloneURL && matchingBranch(input.Git.Branch, payloadBranch) {
					inputs = append(inputs, input.Git)
				}
			}
		})
	}
	if len(inputs) == 0 {
		return nil, nil, fmt.Errorf("no pipeline inputs corresponding to git URL (%v) on branch (%v) found, perhaps the git input is not set yet on a pipeline", payload.Repository.CloneURL, payloadBranch)
	}
	return pipelines, inputs, nil
}

func (s *gitHookServer) HandlePush(payload interface{}, _ webhooks.Header) (retErr error) {
	pl := payload.(github.PushPayload)
	logrus.Infof("received github push payload for repo (%v) on branch (%v)", pl.Repository.Name, path.Base(pl.Ref))

	raw, err := json.Marshal(pl)
	if err != nil {
		return fmt.Errorf("error marshalling payload (%v): %v", pl, err)
	}
	pipelines, gitInputs, err := s.findMatchingPipelineInputs(pl)
	if err != nil {
		return err
	}
	if pl.Repository.Private {
		for _, pipelineInfo := range pipelines {
			err := util.FailPipeline(context.Background(), s.etcdClient, s.pipelines, pipelineInfo.Pipeline.Name, fmt.Sprintf("unable to clone private github repo (%v)", pl.Repository.CloneURL))
			// err will be handled but first we want to
			// try and fail all relevant pipelines
			if err != nil {
				logrus.Errorf("error marking pipeline %v as failed %v", pipelineInfo.Pipeline.Name, err)
				retErr = err
			}
		}
		return retErr
	}
	triggeredRepos := make(map[string]bool)
	for _, input := range gitInputs {
		repoName := pps.RepoNameFromGitInfo(input.URL, input.Name)
		if triggeredRepos[repoName] {
			// This input is used on multiple pipelines, and we've already
			// committed to this input repo
			continue
		}
		err := s.commitPayload(repoName, input.Branch, raw)
		if err != nil {
			logrus.Errorf("github webhook failed to commit payload to repo (%v) push with error: %v\n", repoName, err)
			retErr = err
			continue
		}
		triggeredRepos[repoName] = true
	}
	return nil
}

func (s *gitHookServer) commitPayload(repoName string, branchName string, rawPayload []byte) (retErr error) {
	commit, err := s.client.StartCommit(repoName, branchName)
	if err != nil {
		return err
	}
	defer func() {
		if retErr != nil {
			if err := s.client.DeleteCommit(repoName, commit.ID); err != nil {
				logrus.Errorf("git webhook failed to delete partial commit (%v) on repo (%v)", commit.ID, repoName)
			}
			return
		}
		retErr = s.client.FinishCommit(repoName, commit.ID)
	}()
	if err = s.client.DeleteFile(repoName, commit.ID, "commit.json"); err != nil {
		return err
	}
	if _, err = s.client.PutFile(repoName, commit.ID, "commit.json", bytes.NewReader(rawPayload)); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package dnsdb

import (
	"github.com/stretchr/testify/assert"

	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func Test_RDataService_LookupName(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("ns5.dnsmadeeasy.com", nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":1078,"zone_time_first":1374250920,"zone_time_last":1468253883,"rrname":"farsightsecurity.com.","rrtype":"NS","rdata":"ns5.dnsmadeeasy.com."}
{"count":706617,"time_first":1374096380,"time_last":1468334926,"rrname":"farsightsecurity.com.","rrtype":"NS","rdata":"ns5.dnsmadeeasy.com."}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupName("ns5.dnsmadeeasy.com", nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:         Uint64(1078),
			ZoneTimeFirst: NewTimestamp(1374250920),
			ZoneTimeLast:  NewTimestamp(1468253883),
			RRName:        String("farsightsecurity.com."),
			RRType:        String("NS"),
			RData:         String("ns5.dnsmadeeasy.com."),
		},
		RData{
			Count:     Uint64(706617),
			TimeFirst: NewTimestamp(1374096380),
			TimeLast:  NewTimestamp(1468334926),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("NS"),
			RData:     String("ns5.dnsmadeeasy.com."),
		},
	}, actual)
}

func Test_RDataService_LookupIP(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}

func Test_RDataService_LookupIPNet(t *testing.T) {
	// Setup a client
	c := NewClient(nil)
	_, ipnet, _ := net.ParseCIDR("104.244.13.104/29")

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIPNet(*ipnet, nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIPNet(*ipnet, nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}
<commit_msg>Improve coverage<commit_after>package dnsdb

import (
	"github.com/stretchr/testify/assert"

	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func Test_RDataService_LookupName(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupName("ns5.dnsmadeeasy.com", nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":45644,"time_first":1372706073,"time_last":1468330740,"rrname":"fsi.io.","rrtype":"MX","rdata":"10 hq.fsi.io."}
{"count":19304,"time_first":1374098929,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"MX","rdata":"10 hq.fsi.io."}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupName("hq.fsi.io", &RDataLookupNameOptions{
		RRType: "MX",
	})
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:         Uint64(45644),
			ZoneTimeFirst: NewTimestamp(1372706073),
			ZoneTimeLast:  NewTimestamp(1468330740),
			RRName:        String("fsi.io."),
			RRType:        String("MX"),
			RData:         String("10 hq.fsi.io."),
		},
		RData{
			Count:     Uint64(19304),
			TimeFirst: NewTimestamp(1374098929),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("MX"),
			RData:     String("10 hq.fsi.io."),
		},
	}, actual)
}

func Test_RDataService_LookupIP(t *testing.T) {
	// Setup a client
	c := NewClient(nil)

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIP(net.ParseIP("104.244.13.104"), nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}

func Test_RDataService_LookupIPNet(t *testing.T) {
	// Setup a client
	c := NewClient(nil)
	_, ipnet, _ := net.ParseCIDR("104.244.13.104/29")

	// Verify that an error response fails
	errorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Oh No", 500)
	}))
	defer errorServer.Close()
	u, err := url.Parse(errorServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	_, _, err = c.RData.LookupIPNet(*ipnet, nil)
	assert.NotNil(t, err)

	// Verify that it gets and parses a response correctly
	reportServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, `{"count":24,"time_first":1433550785,"time_last":1468312116,"rrname":"www.farsighsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
{"count":9429,"time_first":1427897872,"time_last":1468333042,"rrname":"farsightsecurity.com.","rrtype":"A","rdata":"104.244.13.104"}
`)
	}))
	defer reportServer.Close()
	u, err = url.Parse(reportServer.URL)
	assert.Nil(t, err)
	c.BaseURL = u
	actual, _, err := c.RData.LookupIPNet(*ipnet, nil)
	assert.Nil(t, err)
	assert.Equal(t, []RData{
		RData{
			Count:     Uint64(24),
			TimeFirst: NewTimestamp(1433550785),
			TimeLast:  NewTimestamp(1468312116),
			RRName:    String("www.farsighsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
		RData{
			Count:     Uint64(9429),
			TimeFirst: NewTimestamp(1427897872),
			TimeLast:  NewTimestamp(1468333042),
			RRName:    String("farsightsecurity.com."),
			RRType:    String("A"),
			RData:     String("104.244.13.104"),
		},
	}, actual)
}
<|endoftext|>