<commit_before>package server

import (
	"log"
	"net/rpc"
	"sync"
	"time"

	"github.com/mateusbraga/freestore/pkg/comm"
	"github.com/mateusbraga/freestore/pkg/consensus"
	"github.com/mateusbraga/freestore/pkg/view"
)

const LEADER_PROCESS_POSITION int = 0

var (
	viewGenerators   []viewGeneratorInstance
	viewGeneratorsMu sync.Mutex
)

type viewGeneratorInstance struct {
	AssociatedView *view.View //Id
	jobChan        chan interface{}
}

func getOrCreateViewGenerator(associatedView *view.View, initialSeq ViewSeq) viewGeneratorInstance {
	viewGeneratorsMu.Lock()
	defer viewGeneratorsMu.Unlock()

	for _, vgi := range viewGenerators {
		if vgi.AssociatedView.Equal(associatedView) {
			return vgi
		}
	}

	//TODO this is temporary, remove this after getting the data
	if startReconfigurationTime.Sub(time.Now()) > 20*time.Second {
		startReconfigurationTime = time.Now()
	}

	// view generator does not exist. Create it.
	vgi := viewGeneratorInstance{}
	vgi.AssociatedView = associatedView
	vgi.jobChan = make(chan interface{}, CHANNEL_DEFAULT_SIZE)
	viewGenerators = append(viewGenerators, vgi)

	workerSeq := initialSeq
	if workerSeq == nil {
		workerSeq = getInitialViewSeq()
	}
	go viewGeneratorWorker(vgi, workerSeq)

	return vgi
}

func viewGeneratorWorker(vgi viewGeneratorInstance, initialSeq ViewSeq) {
	log.Printf("Starting new viewGeneratorWorker with initialSeq: %v\n", initialSeq)

	associatedView := vgi.AssociatedView
	jobChan := vgi.jobChan

	var lastProposedSeq ViewSeq
	var lastConvergedSeq ViewSeq
	var viewSeqQuorumCounter viewSeqQuorumCounterType
	var seqConvQuorumCounter seqConvQuorumCounterType

	countViewSeq := func(viewSeqMsg ViewSeqMsg) {
		if viewSeqQuorumCounter.count(&viewSeqMsg, associatedView.QuorumSize()) {
			newConvergedSeq := viewSeqMsg.ProposedSeq

			log.Printf("sending newConvergedSeq: %v\n", newConvergedSeq)
			lastConvergedSeq = newConvergedSeq

			seqConvMsg := SeqConvMsg{}
			seqConvMsg.AssociatedView = associatedView
			seqConvMsg.Seq = newConvergedSeq

			// Send seq-conv to all
			go broadcastViewSequenceConv(associatedView, seqConvMsg)
		}
	}

	if len(initialSeq) != 0 {
		// Send viewSeqMsg to all
		viewSeqMsg := ViewSeqMsg{}
		viewSeqMsg.ProposedSeq = initialSeq
		viewSeqMsg.LastConvergedSeq = nil
		viewSeqMsg.AssociatedView = associatedView
		viewSeqMsg.Sender = thisProcess

		go broadcastViewSequence(associatedView, viewSeqMsg)
		countViewSeq(viewSeqMsg)

		lastProposedSeq = initialSeq
	}

	for {
		job := <-jobChan
		switch jobPointer := job.(type) {
		case ViewSeqMsg:
			receivedViewSeqMsg := jobPointer
			log.Println("received ViewSeqMsg:", receivedViewSeqMsg)

			var newProposeSeq ViewSeq

			hasChanges := false
			hasConflict := false

		OuterLoop:
			for _, v := range receivedViewSeqMsg.ProposedSeq {
				if lastProposedSeq.HasView(v) {
					continue
				}

				log.Printf("New view discovered: %v\n", v)
				hasChanges = true

				// check if v conflicts with any view from lastProposedSeq
				for _, v2 := range lastProposedSeq {
					if v.LessUpdatedThan(v2) && v2.LessUpdatedThan(v) {
						log.Printf("Has conflict between %v and %v!\n", v, v2)
						hasConflict = true
						break OuterLoop
					}
				}
			}

			if hasChanges {
				if hasConflict {
					// set lastConvergedSeq to the one with the most updated view
					receivedLastConvergedSeqMostUpdatedView := receivedViewSeqMsg.LastConvergedSeq.GetMostUpdatedView()
					thisProcessLastConvergedSeqMostUpdatedView := lastConvergedSeq.GetMostUpdatedView()
					if thisProcessLastConvergedSeqMostUpdatedView.LessUpdatedThan(receivedLastConvergedSeqMostUpdatedView) {
						lastConvergedSeq = receivedViewSeqMsg.LastConvergedSeq
					}

					oldMostUpdated := lastProposedSeq.GetMostUpdatedView()
					receivedMostUpdated := receivedViewSeqMsg.ProposedSeq.GetMostUpdatedView()

					updates := append(oldMostUpdated.GetUpdates(), receivedMostUpdated.GetUpdates()...)
					auxView := view.NewWithUpdates(updates...)

					newProposeSeq = lastConvergedSeq.Append(auxView)
				} else {
					newProposeSeq = lastProposedSeq.Append(receivedViewSeqMsg.ProposedSeq...)
				}
				log.Println("sending newProposeSeq:", newProposeSeq)

				viewSeqMsg := ViewSeqMsg{}
				viewSeqMsg.Sender = thisProcess
				viewSeqMsg.AssociatedView = associatedView
				viewSeqMsg.ProposedSeq = newProposeSeq
				viewSeqMsg.LastConvergedSeq = lastConvergedSeq

				go broadcastViewSequence(associatedView, viewSeqMsg)
				countViewSeq(viewSeqMsg)

				lastProposedSeq = newProposeSeq
			}

			// Quorum check
			countViewSeq(receivedViewSeqMsg)

		case *SeqConv:
			receivedSeqConvMsg := jobPointer
			log.Println("received SeqConvMsg:", receivedSeqConvMsg)

			// Quorum check
			if seqConvQuorumCounter.count(receivedSeqConvMsg, associatedView.QuorumSize()) {
				generatedViewSeqChan <- generatedViewSeq{ViewSeq: receivedSeqConvMsg.Seq, AssociatedView: associatedView}
			}
		default:
			log.Fatalln("Something is wrong with the switch statement")
		}

	}
}

// assertOnlyUpdatedViews exits the program if any view from seq is less updated than view.
func assertOnlyUpdatedViews(baseView *view.View, seq ViewSeq) {
	for _, loopView := range seq {
		if loopView.LessUpdatedThan(baseView) {
			log.Fatalf("BUG! Found an old view in view sequence %v: %v\n", seq, loopView)
		}
	}
}

// we can change seq
func generateViewSequenceWithoutConsensus(associatedView *view.View, seq ViewSeq) {
	assertOnlyUpdatedViews(associatedView, seq)

	_ = getOrCreateViewGenerator(associatedView, seq)
}

func generateViewSequenceWithConsensus(associatedView *view.View, seq ViewSeq) {
	assertOnlyUpdatedViews(associatedView, seq)

	if associatedView.GetProcessPosition(thisProcess) == LEADER_PROCESS_POSITION {
		consensus.Propose(associatedView, thisProcess, &seq)
	}
	log.Println("Waiting for consensus resolution")
	value := <-consensus.GetConsensusResultChan(associatedView)

	//TODO this is temporary, remove this after getting the data
	if startReconfigurationTime.Sub(time.Now()) > 20*time.Second {
		startReconfigurationTime = consensus.GetConsensusStartTime(associatedView)
		log.Println("starttime :", startReconfigurationTime)
	}

	result, ok := value.(*ViewSeq)
	if !ok {
		log.Fatalf("FATAL: consensus on generateViewSequenceWithConsensus got %T %v\n", value, value)
	}
	log.Println("Consensus result received")

	generatedViewSeqChan <- generatedViewSeq{*result, associatedView}
}

type viewSeqQuorumCounterType struct {
	list    []*ViewSeqMsg
	counter []int
}

func (quorumCounter *viewSeqQuorumCounterType) count(newViewSeqMsg *ViewSeqMsg, quorumSize int) bool {
	for i, _ := range quorumCounter.list {
		if quorumCounter.list[i].SameButDifferentSender(*newViewSeqMsg) {
			quorumCounter.counter[i]++

			return quorumCounter.counter[i] == quorumSize
		}
	}

	quorumCounter.list = append(quorumCounter.list, newViewSeqMsg)
	quorumCounter.counter = append(quorumCounter.counter, 1)

	return (1 == quorumSize)
}

type seqConvQuorumCounterType struct {
	list    []*SeqConv
	counter []int
}

func (quorumCounter *seqConvQuorumCounterType) count(newSeqConv *SeqConv, quorumSize int) bool {
	for i, _ := range quorumCounter.list {
		if quorumCounter.list[i].Equal(*newSeqConv) {
			quorumCounter.counter[i]++

			return quorumCounter.counter[i] == quorumSize
		}
	}

	quorumCounter.list = append(quorumCounter.list, newSeqConv)
	quorumCounter.counter = append(quorumCounter.counter, 1)

	return (1 == quorumSize)
}

// -------- REQUESTS -----------
type SeqConv struct {
	Seq ViewSeq
}

type SeqConvMsg struct {
	AssociatedView *view.View
	SeqConv
}

func (seqConv SeqConv) Equal(seqConv2 SeqConv) bool {
	if len(seqConv.Seq) != len(seqConv2.Seq) {
		return false
	}
	for i, _ := range seqConv.Seq {
		if !seqConv.Seq[i].Equal(seqConv2.Seq[i]) {
			return false
		}
	}
	return true
}

type ViewSeqMsg struct {
	Sender           view.Process
	AssociatedView   *view.View
	ProposedSeq      ViewSeq
	LastConvergedSeq ViewSeq
}

func (thisViewSeqMsg ViewSeqMsg) SameButDifferentSender(otherViewSeqMsg ViewSeqMsg) bool {
	if thisViewSeqMsg.Sender == otherViewSeqMsg.Sender {
		return false
	}

	if !thisViewSeqMsg.AssociatedView.Equal(otherViewSeqMsg.AssociatedView) {
		return false
	}

	if !thisViewSeqMsg.ProposedSeq.Equal(otherViewSeqMsg.ProposedSeq) {
		return false
	}

	if !thisViewSeqMsg.LastConvergedSeq.Equal(otherViewSeqMsg.LastConvergedSeq) {
		return false
	}

	return true
}

type ViewGeneratorRequest int

func (r *ViewGeneratorRequest) ProposeSeqView(arg ViewSeqMsg, reply *struct{}) error {
	vgi := getOrCreateViewGenerator(arg.AssociatedView, nil)
	vgi.jobChan <- arg

	return nil
}

func (r *ViewGeneratorRequest) SeqConv(arg SeqConvMsg, reply *struct{}) error {
	vgi := getOrCreateViewGenerator(arg.AssociatedView, nil)
	vgi.jobChan <- &arg.SeqConv

	return nil
}

func init() {
	rpc.Register(new(ViewGeneratorRequest))
}

// -------- Broadcast functions -----------
func broadcastViewSequence(destinationView *view.View, viewSeqMsg ViewSeqMsg) {
	destinationViewWithoutThisProcess := destinationView.NewCopyWithUpdates(view.Update{Type: view.Leave, Process: thisProcess})
	comm.BroadcastRPCRequest(destinationViewWithoutThisProcess, "ViewGeneratorRequest.ProposeSeqView", viewSeqMsg)
}

func broadcastViewSequenceConv(destinationView *view.View, seqConvMsg SeqConvMsg) {
	comm.BroadcastRPCRequest(destinationView, "ViewGeneratorRequest.SeqConv", seqConvMsg)
}
<commit_msg>Do not change startReconfigurationTime every time<commit_after>package server

import (
	"log"
	"net/rpc"
	"sync"
	"time"

	"github.com/mateusbraga/freestore/pkg/comm"
	"github.com/mateusbraga/freestore/pkg/consensus"
	"github.com/mateusbraga/freestore/pkg/view"
)

const LEADER_PROCESS_POSITION int = 0

var (
	viewGenerators   []viewGeneratorInstance
	viewGeneratorsMu sync.Mutex
)

type viewGeneratorInstance struct {
	AssociatedView *view.View //Id
	jobChan        chan interface{}
}

func getOrCreateViewGenerator(associatedView *view.View, initialSeq ViewSeq) viewGeneratorInstance {
	viewGeneratorsMu.Lock()
	defer viewGeneratorsMu.Unlock()

	for _, vgi := range viewGenerators {
		if vgi.AssociatedView.Equal(associatedView) {
			return vgi
		}
	}

	//TODO this is temporary, remove this after getting the data
	if startReconfigurationTime.IsZero() || startReconfigurationTime.Sub(time.Now()) > 20*time.Second {
		startReconfigurationTime = time.Now()
	}

	// view generator does not exist. Create it.
	vgi := viewGeneratorInstance{}
	vgi.AssociatedView = associatedView
	vgi.jobChan = make(chan interface{}, CHANNEL_DEFAULT_SIZE)
	viewGenerators = append(viewGenerators, vgi)

	workerSeq := initialSeq
	if workerSeq == nil {
		workerSeq = getInitialViewSeq()
	}
	go viewGeneratorWorker(vgi, workerSeq)

	return vgi
}

func viewGeneratorWorker(vgi viewGeneratorInstance, initialSeq ViewSeq) {
	log.Printf("Starting new viewGeneratorWorker with initialSeq: %v\n", initialSeq)

	associatedView := vgi.AssociatedView
	jobChan := vgi.jobChan

	var lastProposedSeq ViewSeq
	var lastConvergedSeq ViewSeq
	var viewSeqQuorumCounter viewSeqQuorumCounterType
	var seqConvQuorumCounter seqConvQuorumCounterType

	countViewSeq := func(viewSeqMsg ViewSeqMsg) {
		if viewSeqQuorumCounter.count(&viewSeqMsg, associatedView.QuorumSize()) {
			newConvergedSeq := viewSeqMsg.ProposedSeq

			log.Printf("sending newConvergedSeq: %v\n", newConvergedSeq)
			lastConvergedSeq = newConvergedSeq

			seqConvMsg := SeqConvMsg{}
			seqConvMsg.AssociatedView = associatedView
			seqConvMsg.Seq = newConvergedSeq

			// Send seq-conv to all
			go broadcastViewSequenceConv(associatedView, seqConvMsg)
		}
	}

	if len(initialSeq) != 0 {
		// Send viewSeqMsg to all
		viewSeqMsg := ViewSeqMsg{}
		viewSeqMsg.ProposedSeq = initialSeq
		viewSeqMsg.LastConvergedSeq = nil
		viewSeqMsg.AssociatedView = associatedView
		viewSeqMsg.Sender = thisProcess

		go broadcastViewSequence(associatedView, viewSeqMsg)
		countViewSeq(viewSeqMsg)

		lastProposedSeq = initialSeq
	}

	for {
		job := <-jobChan
		switch jobPointer := job.(type) {
		case ViewSeqMsg:
			receivedViewSeqMsg := jobPointer
			log.Println("received ViewSeqMsg:", receivedViewSeqMsg)

			var newProposeSeq ViewSeq

			hasChanges := false
			hasConflict := false

		OuterLoop:
			for _, v := range receivedViewSeqMsg.ProposedSeq {
				if lastProposedSeq.HasView(v) {
					continue
				}

				log.Printf("New view discovered: %v\n", v)
				hasChanges = true

				// check if v conflicts with any view from lastProposedSeq
				for _, v2 := range lastProposedSeq {
					if v.LessUpdatedThan(v2) && v2.LessUpdatedThan(v) {
						log.Printf("Has conflict between %v and %v!\n", v, v2)
						hasConflict = true
						break OuterLoop
					}
				}
			}

			if hasChanges {
				if hasConflict {
					// set lastConvergedSeq to the one with the most updated view
					receivedLastConvergedSeqMostUpdatedView := receivedViewSeqMsg.LastConvergedSeq.GetMostUpdatedView()
					thisProcessLastConvergedSeqMostUpdatedView := lastConvergedSeq.GetMostUpdatedView()
					if thisProcessLastConvergedSeqMostUpdatedView.LessUpdatedThan(receivedLastConvergedSeqMostUpdatedView) {
						lastConvergedSeq = receivedViewSeqMsg.LastConvergedSeq
					}

					oldMostUpdated := lastProposedSeq.GetMostUpdatedView()
					receivedMostUpdated := receivedViewSeqMsg.ProposedSeq.GetMostUpdatedView()

					updates := append(oldMostUpdated.GetUpdates(), receivedMostUpdated.GetUpdates()...)
					auxView := view.NewWithUpdates(updates...)

					newProposeSeq = lastConvergedSeq.Append(auxView)
				} else {
					newProposeSeq = lastProposedSeq.Append(receivedViewSeqMsg.ProposedSeq...)
				}
				log.Println("sending newProposeSeq:", newProposeSeq)

				viewSeqMsg := ViewSeqMsg{}
				viewSeqMsg.Sender = thisProcess
				viewSeqMsg.AssociatedView = associatedView
				viewSeqMsg.ProposedSeq = newProposeSeq
				viewSeqMsg.LastConvergedSeq = lastConvergedSeq

				go broadcastViewSequence(associatedView, viewSeqMsg)
				countViewSeq(viewSeqMsg)

				lastProposedSeq = newProposeSeq
			}

			// Quorum check
			countViewSeq(receivedViewSeqMsg)

		case *SeqConv:
			receivedSeqConvMsg := jobPointer
			log.Println("received SeqConvMsg:", receivedSeqConvMsg)

			// Quorum check
			if seqConvQuorumCounter.count(receivedSeqConvMsg, associatedView.QuorumSize()) {
				generatedViewSeqChan <- generatedViewSeq{ViewSeq: receivedSeqConvMsg.Seq, AssociatedView: associatedView}
			}
		default:
			log.Fatalln("Something is wrong with the switch statement")
		}

	}
}

// assertOnlyUpdatedViews exits the program if any view from seq is less updated than view.
func assertOnlyUpdatedViews(baseView *view.View, seq ViewSeq) {
	for _, loopView := range seq {
		if loopView.LessUpdatedThan(baseView) {
			log.Fatalf("BUG! Found an old view in view sequence %v: %v\n", seq, loopView)
		}
	}
}

// we can change seq
func generateViewSequenceWithoutConsensus(associatedView *view.View, seq ViewSeq) {
	assertOnlyUpdatedViews(associatedView, seq)

	_ = getOrCreateViewGenerator(associatedView, seq)
}

func generateViewSequenceWithConsensus(associatedView *view.View, seq ViewSeq) {
	assertOnlyUpdatedViews(associatedView, seq)

	if associatedView.GetProcessPosition(thisProcess) == LEADER_PROCESS_POSITION {
		consensus.Propose(associatedView, thisProcess, &seq)
	}
	log.Println("Waiting for consensus resolution")
	value := <-consensus.GetConsensusResultChan(associatedView)

	//TODO this is temporary, remove this after getting the data
	if startReconfigurationTime.IsZero() || startReconfigurationTime.Sub(time.Now()) > 20*time.Second {
		startReconfigurationTime = consensus.GetConsensusStartTime(associatedView)
		log.Println("starttime :", startReconfigurationTime)
	}

	result, ok := value.(*ViewSeq)
	if !ok {
		log.Fatalf("FATAL: consensus on generateViewSequenceWithConsensus got %T %v\n", value, value)
	}
	log.Println("Consensus result received")

	generatedViewSeqChan <- generatedViewSeq{*result, associatedView}
}

type viewSeqQuorumCounterType struct {
	list    []*ViewSeqMsg
	counter []int
}

func (quorumCounter *viewSeqQuorumCounterType) count(newViewSeqMsg *ViewSeqMsg, quorumSize int) bool {
	for i, _ := range quorumCounter.list {
		if quorumCounter.list[i].SameButDifferentSender(*newViewSeqMsg) {
			quorumCounter.counter[i]++

			return quorumCounter.counter[i] == quorumSize
		}
	}

	quorumCounter.list = append(quorumCounter.list, newViewSeqMsg)
	quorumCounter.counter = append(quorumCounter.counter, 1)

	return (1 == quorumSize)
}

type seqConvQuorumCounterType struct {
	list    []*SeqConv
	counter []int
}

func (quorumCounter *seqConvQuorumCounterType) count(newSeqConv *SeqConv, quorumSize int) bool {
	for i, _ := range quorumCounter.list {
		if quorumCounter.list[i].Equal(*newSeqConv) {
			quorumCounter.counter[i]++

			return quorumCounter.counter[i] == quorumSize
		}
	}

	quorumCounter.list = append(quorumCounter.list, newSeqConv)
	quorumCounter.counter = append(quorumCounter.counter, 1)

	return (1 == quorumSize)
}

// -------- REQUESTS -----------
type SeqConv struct {
	Seq ViewSeq
}

type SeqConvMsg struct {
	AssociatedView *view.View
	SeqConv
}

func (seqConv SeqConv) Equal(seqConv2 SeqConv) bool {
	if len(seqConv.Seq) != len(seqConv2.Seq) {
		return false
	}
	for i, _ := range seqConv.Seq {
		if !seqConv.Seq[i].Equal(seqConv2.Seq[i]) {
			return false
		}
	}
	return true
}

type ViewSeqMsg struct {
	Sender           view.Process
	AssociatedView   *view.View
	ProposedSeq      ViewSeq
	LastConvergedSeq ViewSeq
}

func (thisViewSeqMsg ViewSeqMsg) SameButDifferentSender(otherViewSeqMsg ViewSeqMsg) bool {
	if thisViewSeqMsg.Sender == otherViewSeqMsg.Sender {
		return false
	}

	if !thisViewSeqMsg.AssociatedView.Equal(otherViewSeqMsg.AssociatedView) {
		return false
	}

	if !thisViewSeqMsg.ProposedSeq.Equal(otherViewSeqMsg.ProposedSeq) {
		return false
	}

	if !thisViewSeqMsg.LastConvergedSeq.Equal(otherViewSeqMsg.LastConvergedSeq) {
		return false
	}

	return true
}

type ViewGeneratorRequest int

func (r *ViewGeneratorRequest) ProposeSeqView(arg ViewSeqMsg, reply *struct{}) error {
	vgi := getOrCreateViewGenerator(arg.AssociatedView, nil)
	vgi.jobChan <- arg

	return nil
}

func (r *ViewGeneratorRequest) SeqConv(arg SeqConvMsg, reply *struct{}) error {
	vgi := getOrCreateViewGenerator(arg.AssociatedView, nil)
	vgi.jobChan <- &arg.SeqConv

	return nil
}

func init() {
	rpc.Register(new(ViewGeneratorRequest))
}

// -------- Broadcast functions -----------
func broadcastViewSequence(destinationView *view.View, viewSeqMsg ViewSeqMsg) {
	destinationViewWithoutThisProcess := destinationView.NewCopyWithUpdates(view.Update{Type: view.Leave, Process: thisProcess})
	comm.BroadcastRPCRequest(destinationViewWithoutThisProcess, "ViewGeneratorRequest.ProposeSeqView", viewSeqMsg)
}

func broadcastViewSequenceConv(destinationView *view.View, seqConvMsg SeqConvMsg) {
	comm.BroadcastRPCRequest(destinationView, "ViewGeneratorRequest.SeqConv", seqConvMsg)
}
<|endoftext|>


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

/*
Package net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
		}
		go handleConnection(conn)
	}
*/
package net

// TODO(rsc):
//	support for raw ethernet sockets

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

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	// Any blocked Read or Write operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	//
	// A deadline is an absolute time after which I/O operations
	// fail with a timeout (see type Error) instead of
	// blocking. The deadline applies to all future I/O, not just
	// the immediately following call to Read or Write.
	//
	// An idle timeout can be implemented by repeatedly extending
	// the deadline after successful Read or Write calls.
	//
	// A zero value for t means I/O operations will not time out.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

type conn struct {
	fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface.

// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Read(b)
}

// Write implements the Conn Write method.
func (c *conn) Write(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Write(b)
}

// Close closes the connection.
func (c *conn) Close() error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.Close()
}

// LocalAddr returns the local network address.
func (c *conn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr returns the remote network address.
func (c *conn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *conn) SetDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setDeadline(t)
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *conn) SetReadDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setReadDeadline(t)
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *conn) SetWriteDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setWriteDeadline(t)
}

// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
func (c *conn) SetReadBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadBuffer(c.fd, bytes)
}

// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
func (c *conn) SetWriteBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteBuffer(c.fd, bytes)
}

// File sets the underlying os.File to blocking mode and returns a copy.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
//
// The returned os.File's file descriptor is different from the connection's.
// Attempting to change properties of the original using this duplicate
// may or may not have the desired effect.
func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
//
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

var listenerBacklog = maxListenerBacklog()

// A Listener is a generic network listener for stream-oriented protocols.
//
// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	// Any blocked Accept operations will be unblocked and return errors.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

// Various errors contained in OpError.
var (
	// For connection setup and write operations.
	errMissingAddress = errors.New("missing address")

	// For both read and write operations.
	errTimeout          error = &timeoutError{}
	errClosing                = errors.New("use of closed network connection")
	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
)

// OpError is the error type usually returned by functions in the net
// package. It describes the operation, network type, and address of
// an error.
type OpError struct {
	// Op is the operation which caused the error, such as
	// "read" or "write".
	Op string

	// Net is the network type on which this error occurred,
	// such as "tcp" or "udp6".
	Net string

	// Addr is the network address on which this error occurred.
	Addr Addr

	// Err is the error that occurred during the operation.
	Err error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

var noDeadline = time.Time{}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

type InvalidAddrError string

func (e InvalidAddrError) Error() string   { return string(e) }
func (e InvalidAddrError) Timeout() bool   { return false }
func (e InvalidAddrError) Temporary() bool { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

type writerOnly struct {
	io.Writer
}

// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
// applicable.
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
	// Use wrapper to hide existing r.ReadFrom from io.Copy.
	return io.Copy(writerOnly{w}, r)
}

// Limit the number of concurrent cgo-using goroutines, because
// each will block an entire operating system thread. The usual culprit
// is resolving many DNS names in separate goroutines but the DNS
// server is not responding. Then the many lookups each use a different
// thread, and the system or the program runs out of threads.

var threadLimit = make(chan struct{}, 500)

// Using send for acquire is fine here because we are not using this
// to protect any memory. All we care about is the number of goroutines
// making calls at a time.

func acquireThread() {
	threadLimit <- struct{}{}
}

func releaseThread() {
	<-threadLimit
}
<commit_msg>net: update TDDO<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
		}
		go handleConnection(conn)
	}
*/
package net

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

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	// Any blocked Read or Write operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	//
	// A deadline is an absolute time after which I/O operations
	// fail with a timeout (see type Error) instead of
	// blocking. The deadline applies to all future I/O, not just
	// the immediately following call to Read or Write.
	//
	// An idle timeout can be implemented by repeatedly extending
	// the deadline after successful Read or Write calls.
	//
	// A zero value for t means I/O operations will not time out.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

type conn struct {
	fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Implementation of the Conn interface.

// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Read(b)
}

// Write implements the Conn Write method.
func (c *conn) Write(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	return c.fd.Write(b)
}

// Close closes the connection.
func (c *conn) Close() error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.Close()
}

// LocalAddr returns the local network address.
func (c *conn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr returns the remote network address.
func (c *conn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *conn) SetDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setDeadline(t)
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *conn) SetReadDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setReadDeadline(t)
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *conn) SetWriteDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return c.fd.setWriteDeadline(t)
}

// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
func (c *conn) SetReadBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setReadBuffer(c.fd, bytes)
}

// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
func (c *conn) SetWriteBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	return setWriteBuffer(c.fd, bytes)
}

// File sets the underlying os.File to blocking mode and returns a copy.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
//
// The returned os.File's file descriptor is different from the connection's.
// Attempting to change properties of the original using this duplicate
// may or may not have the desired effect.
func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
//
// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

var listenerBacklog = maxListenerBacklog()

// A Listener is a generic network listener for stream-oriented protocols.
//
// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	// Any blocked Accept operations will be unblocked and return errors.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

// Various errors contained in OpError.
var (
	// For connection setup and write operations.
	errMissingAddress = errors.New("missing address")

	// For both read and write operations.
	errTimeout          error = &timeoutError{}
	errClosing                = errors.New("use of closed network connection")
	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
)

// OpError is the error type usually returned by functions in the net
// package. It describes the operation, network type, and address of
// an error.
type OpError struct {
	// Op is the operation which caused the error, such as
	// "read" or "write".
	Op string

	// Net is the network type on which this error occurred,
	// such as "tcp" or "udp6".
	Net string

	// Addr is the network address on which this error occurred.
	Addr Addr

	// Err is the error that occurred during the operation.
	Err error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

var noDeadline = time.Time{}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

type InvalidAddrError string

func (e InvalidAddrError) Error() string   { return string(e) }
func (e InvalidAddrError) Timeout() bool   { return false }
func (e InvalidAddrError) Temporary() bool { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

type writerOnly struct {
	io.Writer
}

// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
// applicable.
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
	// Use wrapper to hide existing r.ReadFrom from io.Copy.
	return io.Copy(writerOnly{w}, r)
}

// Limit the number of concurrent cgo-using goroutines, because
// each will block an entire operating system thread. The usual culprit
// is resolving many DNS names in separate goroutines but the DNS
// server is not responding. Then the many lookups each use a different
// thread, and the system or the program runs out of threads.

var threadLimit = make(chan struct{}, 500)

// Using send for acquire is fine here because we are not using this
// to protect any memory. All we care about is the number of goroutines
// making calls at a time.

func acquireThread() {
	threadLimit <- struct{}{}
}

func releaseThread() {
	<-threadLimit
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/NebulousLabs/Sia-Block-Explorer/api"
)

// A structure to store any state of the server. Should remain
// relatively unpopulated, mostly constants which will eventually be
// broken off
type ExploreServer struct {
	// The explorer must know where to send the API calls
	siad *api.ApiLink

	// Used to store the server muxer
	serveMux *http.ServeMux
}

// writeJSON writes the object to the ResponseWriter. If the encoding fails, an
// error is written instead.
func writeJSON(w http.ResponseWriter, obj interface{}) {
	if json.NewEncoder(w).Encode(obj) != nil {
		http.Error(w, "Failed to encode response", http.StatusInternalServerError)
	}
}

func (srv *ExploreServer) overviewPage(w http.ResponseWriter, r *http.Request) {
	// First query the local instance of siad for the status
	explorerState, err := srv.siad.ExplorerState()
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	blocklist, err := srv.siad.GetBlockData(0, explorerState.Height)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	// Attempt to make a page out of it
	page, err := parseOverview(overviewRoot{
		Explorer: explorerState,
		Blocks: blocklist,
	})
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	w.Write(page)
}

// Handles the root page being requested. Is responsible for
// differentiating between api calls and pages
func (srv *ExploreServer) rootHandler(w http.ResponseWriter, r *http.Request) {

	if (strings.Contains(r.URL.Path, ".")) {
		srv.serveMux.ServeHTTP(w, r)
	} else {
		srv.overviewPage(w, r)
	}
}

// TODO: parse port as a command line option

func main() {
	// Initilize the server
	var srv = &ExploreServer{
		siad: api.New("9000"),
		serveMux: http.NewServeMux(),
	}

	srv.serveMux.Handle("/", http.FileServer(http.Dir("./webroot/")))
	http.HandleFunc("/", srv.rootHandler)
	http.ListenAndServe(":9003", nil)
	fmt.Println("Done serving")
}
<commit_msg>Add Command line flags for port numbers<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"strings"

	"github.com/NebulousLabs/Sia-Block-Explorer/api"
)

// A structure to store any state of the server. Should remain
// relatively unpopulated, mostly constants which will eventually be
// broken off
type ExploreServer struct {
	// The explorer must know where to send the API calls
	siad *api.ApiLink

	// Used to store the server muxer
	serveMux *http.ServeMux
}

// writeJSON writes the object to the ResponseWriter. If the encoding fails, an
// error is written instead.
func writeJSON(w http.ResponseWriter, obj interface{}) {
	if json.NewEncoder(w).Encode(obj) != nil {
		http.Error(w, "Failed to encode response", http.StatusInternalServerError)
	}
}

func (srv *ExploreServer) overviewPage(w http.ResponseWriter, r *http.Request) {
	// First query the local instance of siad for the status
	explorerState, err := srv.siad.ExplorerState()
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	blocklist, err := srv.siad.GetBlockData(0, explorerState.Height)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	// Attempt to make a page out of it
	page, err := parseOverview(overviewRoot{
		Explorer: explorerState,
		Blocks: blocklist,
	})
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	w.Write(page)
}

// Handles the root page being requested. Is responsible for
// differentiating between api calls and pages
func (srv *ExploreServer) rootHandler(w http.ResponseWriter, r *http.Request) {
	if (strings.Contains(r.URL.Path, ".")) {
		srv.serveMux.ServeHTTP(w, r)
	} else {
		srv.overviewPage(w, r)
	}
}

// TODO: parse port as a command line option

func main() {
	// Parse command line flags
	apiPort := flag.String("a", "9980", "Api port")
	hostPort := flag.String("p", "9983", "HTTP host port")
	flag.Parse()

	// Initilize the server
	var srv = &ExploreServer{
		siad: api.New(*apiPort),
		serveMux: http.NewServeMux(),
	}

	srv.serveMux.Handle("/", http.FileServer(http.Dir("./webroot/")))
	http.HandleFunc("/", srv.rootHandler)
	http.ListenAndServe(":"+*hostPort, nil)
	fmt.Println("Done serving")
}
<|endoftext|>


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

// +build ignore

package main

import (
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/plt"
)

func main() {

	// load graph data from FLOW file
	g := graph.ReadGraphTable("../graph/data/SiouxFalls.flow", false)

	// compute paths
	g.ShortestPaths("FW")

	// print shortest path from 0 to 20
	io.Pf("dist from = %v\n", g.Path(0, 20))
	io.Pf("must be: [0, 2, 11, 12, 23, 20]\n")

	// data for drawing: ids of vertices along columns in plot grid
	columns := [][]int{
		{0, 2, 11, 12},
		{3, 10, 13, 22, 23},
		{4, 8, 9, 14, 21, 20},
		{1, 5, 7, 15, 16, 18, 19},
		{6, 17},
	}

	// data for drawing: y-coordinates of vertices in plot
	Y := [][]float64{
		{7, 6, 4, 0},          // col0
		{6, 4, 2, 1, 0},       // col1
		{6, 5, 4, 2, 1, 0},    // col2
		{7, 6, 5, 4, 3, 2, 0}, // col3
		{5, 4},                // col4
	}

	// data for drawing: set vertices in graph structure
	scalex := 1.8
	scaley := 1.3
	nv := 24
	g.Verts = make([][]float64, nv)
	for j, col := range columns {
		x := float64(j) * scalex
		for i, vid := range col {
			g.Verts[vid] = []float64{x, Y[j][i] * scaley}
		}
	}

	// data for drawing: set vertex labels
	vlabels := make(map[int]string)
	for i := 0; i < nv; i++ {
		vlabels[i] = io.Sf("%d", i)
	}

	// data for drawing: set edge labels
	ne := 76
	elabels := make(map[int]string)
	for i := 0; i < ne; i++ {
		elabels[i] = io.Sf("%d", i)
	}

	// plot
	plt.Reset(true, &plt.A{WidthPt: 500, Dpi: 150, Prop: 1.1})
	g.Draw(vlabels, elabels, 0, 0, 0, nil, nil, nil, nil)
	plt.Equal()
	plt.AxisOff()
	plt.Save("/tmp/gosl/graph", "graph_siouxfalls01")
}
<commit_msg>Fix example<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/plt"
)

func main() {

	// load graph data from FLOW file
	g := graph.ReadGraphTable("../graph/data/SiouxFalls.flow", false)

	// compute paths
	g.ShortestPaths("FW")

	// print shortest path from 0 to 20
	io.Pf("dist from = %v\n", g.Path(0, 20))
	io.Pf("must be: [0, 2, 11, 12, 23, 20]\n")

	// data for drawing: ids of vertices along columns in plot grid
	columns := [][]int{
		{0, 2, 11, 12},
		{3, 10, 13, 22, 23},
		{4, 8, 9, 14, 21, 20},
		{1, 5, 7, 15, 16, 18, 19},
		{6, 17},
	}

	// data for drawing: y-coordinates of vertices in plot
	Y := [][]float64{
		{7, 6, 4, 0},          // col0
		{6, 4, 2, 1, 0},       // col1
		{6, 5, 4, 2, 1, 0},    // col2
		{7, 6, 5, 4, 3, 2, 0}, // col3
		{5, 4},                // col4
	}

	// data for drawing: set vertices in graph structure
	scalex := 1.8
	scaley := 1.3
	nv := 24
	g.Verts = make([][]float64, nv)
	for j, col := range columns {
		x := float64(j) * scalex
		for i, vid := range col {
			g.Verts[vid] = []float64{x, Y[j][i] * scaley}
		}
	}

	// plotter
	p := graph.Plotter{G: g}

	// data for drawing: set vertex labels
	p.VertsLabels = make(map[int]string)
	for i := 0; i < nv; i++ {
		p.VertsLabels[i] = io.Sf("%d", i)
	}

	// data for drawing: set edge labels
	ne := 76
	p.EdgesLabels = make(map[int]string)
	for i := 0; i < ne; i++ {
		p.EdgesLabels[i] = io.Sf("%d", i)
	}

	// plot
	plt.Reset(true, &plt.A{WidthPt: 500, Dpi: 150, Prop: 1.1})
	p.Draw()
	plt.Equal()
	plt.AxisOff()
	plt.Save("/tmp/gosl/graph", "graph_siouxfalls01")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
  "github.com/stretchr/testify/assert"
)

func TestSizeOfTileConvert(t *testing.T) {

	testMatrix := [][]int{
		{0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0},
		{1, 1, 0, 1, 1},
		{0, 0, 0, 3, 3},
		{2, 0, 0, 3, 3}}

	expectedsize := 5
	expectedsize2 := 5
	amap := TileConvert(testMatrix)
	actualsizeamap := len(amap[0])
	actualsizeamap2 := len(amap)

	if expectedsize != actualsizeamap {
		t.Errorf("Expected %d, but got %d", expectedsize, actualsizeamap)
	}

	if expectedsize != actualsizeamap2 {
		t.Errorf("Expected %d, but got %d", expectedsize2, actualsizeamap)
	}

	testMatrix2 := [][]int{
		{0, 0},
		{0, 0},
		{1, 1}}

	expectedinnersize := 2
	expectedoutersize := 3
	amap2 := TileConvert(testMatrix2)
	actualinnersize := len(amap2[0])
	actualoutersize := len(amap2)

	if expectedinnersize != actualinnersize {
		t.Errorf("Expected %d, but got %d", expectedinnersize, actualinnersize)
	}

	if expectedoutersize != actualoutersize {
		t.Errorf("Expected %d, but got %d", expectedoutersize, actualoutersize)
	}
}

func TestTileConvert(t *testing.T) {
	//0 = floor, 1 = wall, 2 = door, 3 = outofbounds
	testMatrix := [][]int{
		{0, 1},
		{2, 3}}

	amap := TileConvert(testMatrix)
	actualtile := (amap[0][0]) //floor
	//x = row 0, y = column 0

  //test, expected, actual, errormessage
  assert.Equal(t, false, actualtile.wall, "Expected a floor but this is a wall")
  assert.Equal(t, false, actualtile.door, "Expected a floor but this is a door")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a floor, but this is a outofbounds")

  actualtile = amap[0][1] //wall

  assert.Equal(t, true, actualtile.wall, "Expected a wall, but this is not a wall" )
  assert.Equal(t, false, actualtile.door, "Expected a wall, but this is a door")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a wall, but this is a outofbounds")
  if actualtile.outOfBounds != false && actualtile.door != false && actualtile.wall == false {
		t.Errorf("Expected a wall, but this is a floor")
	}

	actualtile = amap[1][0] //door
  assert.Equal(t, true, actualtile.door, "Expected a door, but this is not a door" )
  assert.Equal(t, false, actualtile.wall, "Expected a door, but this is a wall")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a door, but this is a outofbounds")
	if actualtile.outOfBounds != false && actualtile.wall != false && actualtile.door == false {
		t.Errorf("Expected a door, but this is a floor")
	}

	actualtile = amap[1][1] //out of bounds
  assert.Equal(t, true, actualtile.outOfBounds, "Expected a outofbounds, but this is not a outofbounds" )
  assert.Equal(t, false, actualtile.wall, "Expected a outofbounds, but this is a wall")
  assert.Equal(t, false, actualtile.door, "Expected a outofbounds, but this is a door")
  if actualtile.door != false && actualtile.wall != false && actualtile.outOfBounds == false {
		t.Errorf("Expected outofbounds, but this is a floor")
	}
}

func TestNeighbouringtiles(t *testing.T) {

	//0 = floor, 1 = wall, 2 = door, 3 = outofbounds
	testMatrix := [][]int{
		{0, 1},
		{2, 3}}

	amap := TileConvert(testMatrix)
	firsttile := amap[0][0] //0
	actualNorth := firsttile.neighborNorth
	actualEast := firsttile.neighborEast
	actualSouth := firsttile.neighborSouth
	actualWest := firsttile.neighborWest

	expectedEast := &amap[0][1]
	expectedSouth := &amap[1][0]

  //test, expected, actual, errormessage
  assert.Equal(t, ((*tile)(nil)), actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, expectedEast, actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, expectedSouth, actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, ((*tile)(nil)), actualWest, "Neighbor to the west is wrong")

  testMatrix2 := [][]int{
		{0, 1},
		{2, 3},
		{0, 0}}

	amap2 := TileConvert(testMatrix2)
	lasttile := amap2[2][1] //0 last tile
	actualNorth = lasttile.neighborNorth
	actualEast = lasttile.neighborEast
	actualSouth = lasttile.neighborSouth
	actualWest = lasttile.neighborWest

	expectedNorth2 := &amap2[1][1]
	expectedWest2 := &amap2[2][0]

  assert.Equal(t, expectedNorth2, actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, ((*tile)(nil)), actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, ((*tile)(nil)), actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, expectedWest2, actualWest, "Neighbor to the west is wrong")

	testMatrix3 := [][]int{
		{0, 1, 0},
		{2, 3, 0},
		{0, 0, 0}}

	amap3 := TileConvert(testMatrix3)
	lasttile = amap3[1][1] //3, middle tile
	actualNorth = lasttile.neighborNorth
	actualEast = lasttile.neighborEast
	actualSouth = lasttile.neighborSouth
	actualWest = lasttile.neighborWest

	expectedNorth3 := &amap3[0][1]
	expectedEast3 := &amap3[1][2]
	expectedSouth3 := &amap3[2][1]
	expectedWest3 := &amap3[1][0]

  //test, expected, actual, errormessage
  assert.Equal(t, expectedNorth3, actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, expectedEast3, actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, expectedSouth3, actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, expectedWest3, actualWest, "Neighbor to the west is wrong")
}

func TestAMovement(t *testing.T) {

  testMatrix := [][]int{
		{0, 0, 0, 0},
		{0, 0, 0, 0},
		{0, 0, 0, 0},
    {0, 0, 2, 0}}

    /*
    Initial people placement
    {0, X, 0, 0 },
		{0, 0, 0, X },
		{X, 0, 0, 0 },
    {0, 0, 2, 0}}
    */

  testmap := TileConvert(testMatrix)
  peoplecordinates := [][]int{
    {0,1},
    {2,0},
    {1,3}}

    peoplearray:= PeopleInit(testmap, peoplecordinates)

   //these test needs affection when we make people into threads

   fmt.Println("Inital people placement")
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][1].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][0].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][3].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("One step")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][1].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Two steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][2].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Three steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[3][2].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[2][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Four steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[1][2].occupied, "People1 is in the wrong tile")
   assert.NotEqual(t, peoplearray[1], testmap[3][2].occupied, "People2 is still in the map")
   assert.Equal(t, peoplearray[2], testmap[3][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Five steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[2][2].occupied, "People1 is in the wrong tile")
   assert.NotEqual(t, peoplearray[2], testmap[3][2].occupied, "People3 is still in the map")
   fmt.Println("\n")

   fmt.Println("Six steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[3][2].occupied, "People1 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Seven steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.NotEqual(t, peoplearray[0], testmap[3][2].occupied, "People1 is still in the map")
   fmt.Println("\n")
}

/*
func TestFireSpread(t* testing.T) {

  testMatrix := [][]int{
    {0, 1, 0},
    {2, 3, 0},
    {0, 0, 0}}

    amap := TileConvert(testMatrix);

    SetFire(&amap[1][1]);

    for i := 0; i < 100; i++{
      FireSpread(amap)
      fmt.Println(amap[1][1].heat)
      //assert.Equal(t, i, amap[1][1].fireLevel-1, "They should be equal")
      //fmt.Println("\n")
      //printTileMap(amap)
    }
  }
*/

func printTile(thisTile tile) {
	if thisTile.wall {
		fmt.Print("[Wall(")
	} else if thisTile.door {
		fmt.Print("[Door(")
	} else if thisTile.outOfBounds {
		fmt.Print("[Out(")
	} else {
		fmt.Print("[Floor(")
	}
  if thisTile.occupied != nil {
	fmt.Print("X")
}
	//fmt.Print(" Heat: ")
	//fmt.Print(thisTile.heat)
	fmt.Print(")] ")
}

func printTileMap(inMap [][]tile) {
	mapXSize := len(inMap)
	mapYSize := len(inMap[0])

	for x := 0; x < mapXSize; x++ {
		for y := 0; y < mapYSize; y++ {
			printTile(inMap[x][y])
		}
		fmt.Print("\n")
	}
}

func printNeighbors(atile tile) {
	if atile.neighborNorth != nil {
		fmt.Print("North: ")
		printTile(*(atile.neighborNorth))
		fmt.Print("\n")
	} else {
		fmt.Print("North: nil\n")
	}
	if atile.neighborWest != nil {
		fmt.Print("West: ")
		printTile(*(atile.neighborWest))
		fmt.Print("\n")
	} else {
		fmt.Print("West: nil\n")
	}
	if atile.neighborEast != nil {
		fmt.Print("East: ")
		printTile(*(atile.neighborEast))
		fmt.Print("\n")
	} else {
		fmt.Print("East: nil\n")
	}
	if atile.neighborSouth != nil {
		fmt.Print("South: ")
		printTile(*(atile.neighborSouth))
		fmt.Print("\n")
	} else {
		fmt.Print("South: nil\n")
	}
}

/*
func main() {
	testMatrix := [][]int{
		{0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0},
		{1, 1, 0, 1, 1},
		{0, 0, 0, 3, 3}}

		amap := TileConvert(testMatrix)
		printTileMap(amap)
		fmt.Print("\n")
		printNeighbors(amap[0][0])

		//fire testing
		SetFire(&(amap[2][2]))
		printTileMap(amap)

		for i := 0; i < 100; i++{
			FireSpread(amap)
			fmt.Println("\n")
			printTileMap(amap)
		}
	}
*/
<commit_msg>firespreadtest<commit_after>package main

import (
	"fmt"
	"testing"
  "github.com/stretchr/testify/assert"
)

func TestSizeOfTileConvert(t *testing.T) {

	testMatrix := [][]int{
		{0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0},
		{1, 1, 0, 1, 1},
		{0, 0, 0, 3, 3},
		{2, 0, 0, 3, 3}}

	expectedsize := 5
	expectedsize2 := 5
	amap := TileConvert(testMatrix)
	actualsizeamap := len(amap[0])
	actualsizeamap2 := len(amap)

	if expectedsize != actualsizeamap {
		t.Errorf("Expected %d, but got %d", expectedsize, actualsizeamap)
	}

	if expectedsize != actualsizeamap2 {
		t.Errorf("Expected %d, but got %d", expectedsize2, actualsizeamap)
	}

	testMatrix2 := [][]int{
		{0, 0},
		{0, 0},
		{1, 1}}

	expectedinnersize := 2
	expectedoutersize := 3
	amap2 := TileConvert(testMatrix2)
	actualinnersize := len(amap2[0])
	actualoutersize := len(amap2)

	if expectedinnersize != actualinnersize {
		t.Errorf("Expected %d, but got %d", expectedinnersize, actualinnersize)
	}

	if expectedoutersize != actualoutersize {
		t.Errorf("Expected %d, but got %d", expectedoutersize, actualoutersize)
	}
}

func TestTileConvert(t *testing.T) {
	//0 = floor, 1 = wall, 2 = door, 3 = outofbounds
	testMatrix := [][]int{
		{0, 1},
		{2, 3}}

	amap := TileConvert(testMatrix)
	actualtile := (amap[0][0]) //floor
	//x = row 0, y = column 0

  //test, expected, actual, errormessage
  assert.Equal(t, false, actualtile.wall, "Expected a floor but this is a wall")
  assert.Equal(t, false, actualtile.door, "Expected a floor but this is a door")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a floor, but this is a outofbounds")

  actualtile = amap[0][1] //wall

  assert.Equal(t, true, actualtile.wall, "Expected a wall, but this is not a wall" )
  assert.Equal(t, false, actualtile.door, "Expected a wall, but this is a door")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a wall, but this is a outofbounds")
  if actualtile.outOfBounds != false && actualtile.door != false && actualtile.wall == false {
		t.Errorf("Expected a wall, but this is a floor")
	}

	actualtile = amap[1][0] //door
  assert.Equal(t, true, actualtile.door, "Expected a door, but this is not a door" )
  assert.Equal(t, false, actualtile.wall, "Expected a door, but this is a wall")
  assert.Equal(t, false, actualtile.outOfBounds, "Expected a door, but this is a outofbounds")
	if actualtile.outOfBounds != false && actualtile.wall != false && actualtile.door == false {
		t.Errorf("Expected a door, but this is a floor")
	}

	actualtile = amap[1][1] //out of bounds
  assert.Equal(t, true, actualtile.outOfBounds, "Expected a outofbounds, but this is not a outofbounds" )
  assert.Equal(t, false, actualtile.wall, "Expected a outofbounds, but this is a wall")
  assert.Equal(t, false, actualtile.door, "Expected a outofbounds, but this is a door")
  if actualtile.door != false && actualtile.wall != false && actualtile.outOfBounds == false {
		t.Errorf("Expected outofbounds, but this is a floor")
	}
}

func TestNeighbouringtiles(t *testing.T) {

	//0 = floor, 1 = wall, 2 = door, 3 = outofbounds
	testMatrix := [][]int{
		{0, 1},
		{2, 3}}

	amap := TileConvert(testMatrix)
	firsttile := amap[0][0] //0
	actualNorth := firsttile.neighborNorth
	actualEast := firsttile.neighborEast
	actualSouth := firsttile.neighborSouth
	actualWest := firsttile.neighborWest

	expectedEast := &amap[0][1]
	expectedSouth := &amap[1][0]

  //test, expected, actual, errormessage
  assert.Equal(t, ((*tile)(nil)), actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, expectedEast, actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, expectedSouth, actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, ((*tile)(nil)), actualWest, "Neighbor to the west is wrong")

  testMatrix2 := [][]int{
		{0, 1},
		{2, 3},
		{0, 0}}

	amap2 := TileConvert(testMatrix2)
	lasttile := amap2[2][1] //0 last tile
	actualNorth = lasttile.neighborNorth
	actualEast = lasttile.neighborEast
	actualSouth = lasttile.neighborSouth
	actualWest = lasttile.neighborWest

	expectedNorth2 := &amap2[1][1]
	expectedWest2 := &amap2[2][0]

  assert.Equal(t, expectedNorth2, actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, ((*tile)(nil)), actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, ((*tile)(nil)), actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, expectedWest2, actualWest, "Neighbor to the west is wrong")

	testMatrix3 := [][]int{
		{0, 1, 0},
		{2, 3, 0},
		{0, 0, 0}}

	amap3 := TileConvert(testMatrix3)
	lasttile = amap3[1][1] //3, middle tile
	actualNorth = lasttile.neighborNorth
	actualEast = lasttile.neighborEast
	actualSouth = lasttile.neighborSouth
	actualWest = lasttile.neighborWest

	expectedNorth3 := &amap3[0][1]
	expectedEast3 := &amap3[1][2]
	expectedSouth3 := &amap3[2][1]
	expectedWest3 := &amap3[1][0]

  //test, expected, actual, errormessage
  assert.Equal(t, expectedNorth3, actualNorth, "Neighbor to the north is wrong")
  assert.Equal(t, expectedEast3, actualEast, "Neigbor to the east is wrong")
  assert.Equal(t, expectedSouth3, actualSouth, "Neigbor to the south is wrong")
  assert.Equal(t, expectedWest3, actualWest, "Neighbor to the west is wrong")
}

func TestAMovement(t *testing.T) {

  testMatrix := [][]int{
		{0, 0, 0, 0},
		{0, 0, 0, 0},
		{0, 0, 0, 0},
    {0, 0, 2, 0}}

    /*
    Initial people placement
    {0, X, 0, 0 },
		{0, 0, 0, X },
		{X, 0, 0, 0 },
    {0, 0, 2, 0}}
    */

  testmap := TileConvert(testMatrix)
  peoplecordinates := [][]int{
    {0,1},
    {2,0},
    {1,3}}

    peoplearray:= PeopleInit(testmap, peoplecordinates)

   //these test needs affection when we make people into threads

   fmt.Println("Inital people placement")
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][1].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][0].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][3].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("One step")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][1].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Two steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[2][2].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[1][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Three steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[0][2].occupied, "People1 is in the wrong tile")
   assert.Equal(t, peoplearray[1], testmap[3][2].occupied, "People2 is in the wrong tile")
   assert.Equal(t, peoplearray[2], testmap[2][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Four steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[1][2].occupied, "People1 is in the wrong tile")
   assert.NotEqual(t, peoplearray[1], testmap[3][2].occupied, "People2 is still in the map")
   assert.Equal(t, peoplearray[2], testmap[3][2].occupied, "People3 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Five steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[2][2].occupied, "People1 is in the wrong tile")
   assert.NotEqual(t, peoplearray[2], testmap[3][2].occupied, "People3 is still in the map")
   fmt.Println("\n")

   fmt.Println("Six steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.Equal(t, peoplearray[0], testmap[3][2].occupied, "People1 is in the wrong tile")
   fmt.Println("\n")

   fmt.Println("Seven steps")
   Run(testmap, peoplearray)
   printTileMap(testmap)
   assert.NotEqual(t, peoplearray[0], testmap[3][2].occupied, "People1 is still in the map")
   fmt.Println("\n")
}

func TestFireSpread(t* testing.T) {

  testMatrix := [][]int{
    {0, 1, 0},
    {2, 3, 0},
    {0, 0, 0}}

    amap := TileConvert(testMatrix);

    SetFire(&amap[1][1]);

    for i := 1; i < 100; i++{
      FireSpread(amap)
    }
    assert.Equal(t, 3, amap[0][1].fireLevel, "The fire has not spread properly")
    assert.Equal(t, 3, amap[1][2].fireLevel, "The fire has not spread properly")
    assert.Equal(t, 3, amap[2][1].fireLevel, "The fire has not spread properly")
    assert.Equal(t, 3, amap[1][0].fireLevel, "The fire has not spread properly")

  }

  func printTile(thisTile tile) {
	if thisTile.wall {
		fmt.Print("[Wall(")
	} else if thisTile.door {
		fmt.Print("[Door(")
	} else if thisTile.outOfBounds {
		fmt.Print("[Out(")
	} else {
		fmt.Print("[Floor(")
	}
  if thisTile.occupied != nil {
	fmt.Print("X")
}
	//fmt.Print(" Heat: ")
	//fmt.Print(thisTile.heat)
	fmt.Print(")] ")
}

func printTileMap(inMap [][]tile) {
	mapXSize := len(inMap)
	mapYSize := len(inMap[0])

	for x := 0; x < mapXSize; x++ {
		for y := 0; y < mapYSize; y++ {
			printTile(inMap[x][y])
		}
		fmt.Print("\n")
	}
}

func printNeighbors(atile tile) {
	if atile.neighborNorth != nil {
		fmt.Print("North: ")
		printTile(*(atile.neighborNorth))
		fmt.Print("\n")
	} else {
		fmt.Print("North: nil\n")
	}
	if atile.neighborWest != nil {
		fmt.Print("West: ")
		printTile(*(atile.neighborWest))
		fmt.Print("\n")
	} else {
		fmt.Print("West: nil\n")
	}
	if atile.neighborEast != nil {
		fmt.Print("East: ")
		printTile(*(atile.neighborEast))
		fmt.Print("\n")
	} else {
		fmt.Print("East: nil\n")
	}
	if atile.neighborSouth != nil {
		fmt.Print("South: ")
		printTile(*(atile.neighborSouth))
		fmt.Print("\n")
	} else {
		fmt.Print("South: nil\n")
	}
}

/*
func main() {
	testMatrix := [][]int{
		{0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0},
		{1, 1, 0, 1, 1},
		{0, 0, 0, 3, 3}}

		amap := TileConvert(testMatrix)
		printTileMap(amap)
		fmt.Print("\n")
		printNeighbors(amap[0][0])

		//fire testing
		SetFire(&(amap[2][2]))
		printTileMap(amap)

		for i := 0; i < 100; i++{
			FireSpread(amap)
			fmt.Println("\n")
			printTileMap(amap)
		}
	}
*/
<|endoftext|>


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

package inspect

import (
	"bytes"
	"context"
	"strings"
	"testing"

	"cloud.google.com/go/bigquery"
	"cloud.google.com/go/datastore"
	"cloud.google.com/go/storage"
	"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
	"github.com/gofrs/uuid"
)

const (
	topicName        = "dlp-inspect-test-topic-"
	subscriptionName = "dlp-inspect-test-sub-"

	ssnFileName = "fake_ssn.txt"
	bucketName  = "golang-samples-dlp-test"
)

func TestInspectDatastore(t *testing.T) {
	tc := testutil.EndToEndTest(t)
	writeTestDatastoreFiles(t, tc.ProjectID)
	tests := []struct {
		kind string
		want string
	}{
		{
			kind: "SSNTask",
			want: "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.kind, func(t *testing.T) {
			t.Parallel()
			u := uuid.Must(uuid.NewV4()).String()[:8]
			buf := new(bytes.Buffer)
			if err := inspectDatastore(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, tc.ProjectID, "", test.kind); err != nil {
				t.Errorf("inspectDatastore(%s) got err: %v", test.kind, err)
			}
			if got := buf.String(); !strings.Contains(got, test.want) {
				t.Errorf("inspectDatastore(%s) = %q, want %q substring", test.kind, got, test.want)
			}
		})
	}
}

type SSNTask struct {
	Description string
}

type BoringTask struct {
	Description string
}

func writeTestDatastoreFiles(t *testing.T, projectID string) {
	t.Helper()
	ctx := context.Background()
	client, err := datastore.NewClient(ctx, projectID)
	if err != nil {
		t.Fatalf("datastore.NewClient: %v", err)
	}
	kind := "SSNTask"
	name := "ssntask1"
	ssnKey := datastore.NameKey(kind, name, nil)
	task := SSNTask{
		Description: "My SSN is 111222333",
	}
	if _, err := client.Put(ctx, ssnKey, &task); err != nil {
		t.Fatalf("Failed to save task: %v", err)
	}
}

func TestInspectGCS(t *testing.T) {
	tc := testutil.SystemTest(t)
	writeTestGCSFiles(t, tc.ProjectID)
	tests := []struct {
		fileName string
		want     string
	}{
		{
			fileName: ssnFileName,
			want:     "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.fileName, func(t *testing.T) {
			t.Parallel()
			u := uuid.Must(uuid.NewV4()).String()[:8]
			buf := new(bytes.Buffer)
			if err := inspectGCSFile(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, bucketName, test.fileName); err != nil {
				t.Errorf("inspectGCSFile(%s) got err: %v", test.fileName, err)
			}
			if got := buf.String(); !strings.Contains(got, test.want) {
				t.Errorf("inspectGCSFile(%s) = %q, want %q substring", test.fileName, got, test.want)
			}
		})
	}
}

func writeTestGCSFiles(t *testing.T, projectID string) {
	t.Helper()
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		t.Fatalf("storage.NewClient: %v", err)
	}
	bucket := client.Bucket(bucketName)
	_, err = bucket.Attrs(ctx)
	if err != nil {
		switch err {
		case storage.ErrObjectNotExist:
			if err := bucket.Create(ctx, projectID, nil); err != nil {
				t.Fatalf("bucket.Create: %v", err)
			}
		default:
			t.Fatalf("error getting bucket attrs: %v", err)
		}
	}
	if err := writeObject(ctx, bucket, ssnFileName, "My SSN is 111222333"); err != nil {
		t.Fatalf("writeObject: %v", err)
	}
}

func writeObject(ctx context.Context, bucket *storage.BucketHandle, fileName, content string) error {
	obj := bucket.Object(fileName)
	_, err := obj.Attrs(ctx)
	if err != nil {
		switch err {
		case storage.ErrObjectNotExist:
			w := obj.NewWriter(ctx)
			w.Write([]byte(content))
			if err := w.Close(); err != nil {
				return err
			}
		default:
			return err
		}
	}
	return nil
}

func TestInspectString(t *testing.T) {
	tc := testutil.SystemTest(t)
	buf := new(bytes.Buffer)

	if err := inspectString(buf, tc.ProjectID, "I'm Gary and my email is gary@example.com"); err != nil {
		t.Errorf("TestInspectFile: %v", err)
	}

	got := buf.String()
	if want := "Info type: EMAIL_ADDRESS"; !strings.Contains(got, want) {
		t.Errorf("inspectString got %q, want %q", got, want)
	}
}

func TestInspectTextFile(t *testing.T) {
	tc := testutil.SystemTest(t)
	buf := new(bytes.Buffer)

	if err := inspectTextFile(buf, tc.ProjectID, "testdata/test.txt"); err != nil {
		t.Errorf("TestInspectTextFile: %v", err)
	}

	got := buf.String()
	if want := "Info type: PHONE_NUMBER"; !strings.Contains(got, want) {
		t.Errorf("inspectTextFile got %q, want %q", got, want)
	}
	if want := "Info type: EMAIL_ADDRESS"; !strings.Contains(got, want) {
		t.Errorf("inspectTextFile got %q, want %q", got, want)
	}
}

type Item struct {
	Description string
}

const (
	harmfulTable = "harmful"
	bqDatasetID  = "golang_samples_dlp"
)

func mustCreateBigqueryTestFiles(t *testing.T, projectID, datasetID string) {
	t.Helper()

	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		t.Fatalf("bigquery.NewClient: %v", err)
	}
	defer client.Close()
	d := client.Dataset(datasetID)
	if _, err := d.Metadata(ctx); err != nil {
		if err := d.Create(ctx, &bigquery.DatasetMetadata{}); err != nil {
			t.Fatalf("Create: %v", err)
		}
	}
	schema, err := bigquery.InferSchema(Item{})
	if err != nil {
		t.Fatalf("InferSchema: %v", err)
	}
	if err := uploadBigQuery(ctx, d, schema, harmfulTable, "My SSN is 111222333"); err != nil {
		t.Fatalf("uploadBigQuery: %v", err)
	}
}

func uploadBigQuery(ctx context.Context, d *bigquery.Dataset, schema bigquery.Schema, table, content string) error {
	t := d.Table(table)
	if _, err := t.Metadata(ctx); err == nil {
		return nil
	}
	if err := t.Create(ctx, &bigquery.TableMetadata{Schema: schema}); err != nil {
		return err
	}
	source := bigquery.NewReaderSource(strings.NewReader(content))
	l := t.LoaderFrom(source)
	job, err := l.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	return status.Err()
}

func TestInspectBigquery(t *testing.T) {
	tc := testutil.EndToEndTest(t)

	mustCreateBigqueryTestFiles(t, tc.ProjectID, bqDatasetID)

	tests := []struct {
		table string
		want  string
	}{
		{
			table: harmfulTable,
			want:  "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.table, func(t *testing.T) {
			t.Parallel()
			u := uuid.Must(uuid.NewV4()).String()[:8]
			buf := new(bytes.Buffer)
			if err := inspectBigquery(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, tc.ProjectID, bqDatasetID, test.table); err != nil {
				t.Errorf("inspectBigquery(%s) got err: %v", test.table, err)
			}
			if got := buf.String(); !strings.Contains(got, test.want) {
				t.Errorf("inspectBigquery(%s) = %q, want %q substring", test.table, got, test.want)
			}
		})
	}
}
<commit_msg>test(dlp): add retries (#1996)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package inspect

import (
	"bytes"
	"context"
	"strings"
	"testing"
	"time"

	"cloud.google.com/go/bigquery"
	"cloud.google.com/go/datastore"
	"cloud.google.com/go/storage"
	"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
	"github.com/gofrs/uuid"
)

const (
	topicName        = "dlp-inspect-test-topic-"
	subscriptionName = "dlp-inspect-test-sub-"

	ssnFileName = "fake_ssn.txt"
	bucketName  = "golang-samples-dlp-test"
)

func TestInspectDatastore(t *testing.T) {
	tc := testutil.EndToEndTest(t)
	writeTestDatastoreFiles(t, tc.ProjectID)
	tests := []struct {
		kind string
		want string
	}{
		{
			kind: "SSNTask",
			want: "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.kind, func(t *testing.T) {
			t.Parallel()
			testutil.Retry(t, 5, 15*time.Second, func(r *testutil.R) {
				u := uuid.Must(uuid.NewV4()).String()[:8]
				buf := new(bytes.Buffer)
				if err := inspectDatastore(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, tc.ProjectID, "", test.kind); err != nil {
					r.Errorf("inspectDatastore(%s) got err: %v", test.kind, err)
					return
				}
				if got := buf.String(); !strings.Contains(got, test.want) {
					r.Errorf("inspectDatastore(%s) = %q, want %q substring", test.kind, got, test.want)
				}
			})
		})
	}
}

type SSNTask struct {
	Description string
}

func writeTestDatastoreFiles(t *testing.T, projectID string) {
	t.Helper()
	ctx := context.Background()
	client, err := datastore.NewClient(ctx, projectID)
	if err != nil {
		t.Fatalf("datastore.NewClient: %v", err)
	}
	kind := "SSNTask"
	name := "ssntask1"
	ssnKey := datastore.NameKey(kind, name, nil)
	task := SSNTask{
		Description: "My SSN is 111222333",
	}
	if _, err := client.Put(ctx, ssnKey, &task); err != nil {
		t.Fatalf("Failed to save task: %v", err)
	}
}

func TestInspectGCS(t *testing.T) {
	tc := testutil.SystemTest(t)
	writeTestGCSFiles(t, tc.ProjectID)
	tests := []struct {
		fileName string
		want     string
	}{
		{
			fileName: ssnFileName,
			want:     "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.fileName, func(t *testing.T) {
			t.Parallel()
			testutil.Retry(t, 5, 15*time.Second, func(r *testutil.R) {
				u := uuid.Must(uuid.NewV4()).String()[:8]
				buf := new(bytes.Buffer)
				if err := inspectGCSFile(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, bucketName, test.fileName); err != nil {
					r.Errorf("inspectGCSFile(%s) got err: %v", test.fileName, err)
					return
				}
				if got := buf.String(); !strings.Contains(got, test.want) {
					r.Errorf("inspectGCSFile(%s) = %q, want %q substring", test.fileName, got, test.want)
				}
			})
		})
	}
}

func writeTestGCSFiles(t *testing.T, projectID string) {
	t.Helper()
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		t.Fatalf("storage.NewClient: %v", err)
	}
	bucket := client.Bucket(bucketName)
	_, err = bucket.Attrs(ctx)
	if err != nil {
		switch err {
		case storage.ErrObjectNotExist:
			if err := bucket.Create(ctx, projectID, nil); err != nil {
				t.Fatalf("bucket.Create: %v", err)
			}
		default:
			t.Fatalf("error getting bucket attrs: %v", err)
		}
	}
	if err := writeObject(ctx, bucket, ssnFileName, "My SSN is 111222333"); err != nil {
		t.Fatalf("writeObject: %v", err)
	}
}

func writeObject(ctx context.Context, bucket *storage.BucketHandle, fileName, content string) error {
	obj := bucket.Object(fileName)
	_, err := obj.Attrs(ctx)
	if err != nil {
		switch err {
		case storage.ErrObjectNotExist:
			w := obj.NewWriter(ctx)
			w.Write([]byte(content))
			if err := w.Close(); err != nil {
				return err
			}
		default:
			return err
		}
	}
	return nil
}

func TestInspectString(t *testing.T) {
	tc := testutil.SystemTest(t)
	buf := new(bytes.Buffer)

	if err := inspectString(buf, tc.ProjectID, "I'm Gary and my email is gary@example.com"); err != nil {
		t.Errorf("TestInspectFile: %v", err)
	}

	got := buf.String()
	if want := "Info type: EMAIL_ADDRESS"; !strings.Contains(got, want) {
		t.Errorf("inspectString got %q, want %q", got, want)
	}
}

func TestInspectTextFile(t *testing.T) {
	tc := testutil.SystemTest(t)
	buf := new(bytes.Buffer)

	if err := inspectTextFile(buf, tc.ProjectID, "testdata/test.txt"); err != nil {
		t.Errorf("TestInspectTextFile: %v", err)
	}

	got := buf.String()
	if want := "Info type: PHONE_NUMBER"; !strings.Contains(got, want) {
		t.Errorf("inspectTextFile got %q, want %q", got, want)
	}
	if want := "Info type: EMAIL_ADDRESS"; !strings.Contains(got, want) {
		t.Errorf("inspectTextFile got %q, want %q", got, want)
	}
}

type Item struct {
	Description string
}

const (
	harmfulTable = "harmful"
	bqDatasetID  = "golang_samples_dlp"
)

func mustCreateBigqueryTestFiles(t *testing.T, projectID, datasetID string) {
	t.Helper()

	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		t.Fatalf("bigquery.NewClient: %v", err)
	}
	defer client.Close()
	d := client.Dataset(datasetID)
	if _, err := d.Metadata(ctx); err != nil {
		if err := d.Create(ctx, &bigquery.DatasetMetadata{}); err != nil {
			t.Fatalf("Create: %v", err)
		}
	}
	schema, err := bigquery.InferSchema(Item{})
	if err != nil {
		t.Fatalf("InferSchema: %v", err)
	}
	if err := uploadBigQuery(ctx, d, schema, harmfulTable, "My SSN is 111222333"); err != nil {
		t.Fatalf("uploadBigQuery: %v", err)
	}
}

func uploadBigQuery(ctx context.Context, d *bigquery.Dataset, schema bigquery.Schema, table, content string) error {
	t := d.Table(table)
	if _, err := t.Metadata(ctx); err == nil {
		return nil
	}
	if err := t.Create(ctx, &bigquery.TableMetadata{Schema: schema}); err != nil {
		return err
	}
	source := bigquery.NewReaderSource(strings.NewReader(content))
	l := t.LoaderFrom(source)
	job, err := l.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	return status.Err()
}

func TestInspectBigquery(t *testing.T) {
	tc := testutil.EndToEndTest(t)

	mustCreateBigqueryTestFiles(t, tc.ProjectID, bqDatasetID)

	tests := []struct {
		table string
		want  string
	}{
		{
			table: harmfulTable,
			want:  "Created job",
		},
	}
	for _, test := range tests {
		t.Run(test.table, func(t *testing.T) {
			t.Parallel()
			u := uuid.Must(uuid.NewV4()).String()[:8]
			buf := new(bytes.Buffer)
			if err := inspectBigquery(buf, tc.ProjectID, []string{"US_SOCIAL_SECURITY_NUMBER"}, []string{}, []string{}, topicName+u, subscriptionName+u, tc.ProjectID, bqDatasetID, test.table); err != nil {
				t.Errorf("inspectBigquery(%s) got err: %v", test.table, err)
			}
			if got := buf.String(); !strings.Contains(got, test.want) {
				t.Errorf("inspectBigquery(%s) = %q, want %q substring", test.table, got, test.want)
			}
		})
	}
}
<|endoftext|>