<commit_before>package torrent

import (
	"errors"
	"fmt"
	"net"

	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/torrent/internal/announcer"
	"github.com/cenkalti/rain/torrent/internal/handshaker/incominghandshaker"
	"github.com/cenkalti/rain/torrent/internal/handshaker/outgoinghandshaker"
	"github.com/cenkalti/rain/torrent/internal/infodownloader"
	"github.com/cenkalti/rain/torrent/internal/peer"
	"github.com/cenkalti/rain/torrent/internal/peerconn"
	"github.com/cenkalti/rain/torrent/internal/peerprotocol"
	"github.com/cenkalti/rain/torrent/internal/piecedownloader"
	"github.com/cenkalti/rain/torrent/internal/tracker/trackermanager"
)

var errClosed = errors.New("torrent is closed")

func (t *Torrent) close() {
	// Stop if running.
	t.stop(errClosed)

	// Maybe we are in "Stopping" state. Close "stopped" event announcer.
	if t.stoppedEventAnnouncer != nil {
		t.stoppedEventAnnouncer.Close()
	}

	// Close open tracker connections.
	for _, tr := range t.trackersInstances {
		trackermanager.DefaultTrackerManager.Release(tr)
	}
}

// Torrent event loop
func (t *Torrent) run() {
	for {
		select {
		case doneC := <-t.closeC:
			t.close()
			close(doneC)
			return
		case <-t.startCommandC:
			t.start()
		case <-t.stopCommandC:
			t.stop(nil)
		case <-t.announcersStoppedC:
			t.stoppedEventAnnouncer = nil
			t.errC <- t.lastError
			t.errC = nil
			t.portC = nil
			t.log.Info("torrent has stopped")
		case cmd := <-t.notifyErrorCommandC:
			cmd.errCC <- t.errC
		case cmd := <-t.notifyListenCommandC:
			cmd.portCC <- t.portC
		case req := <-t.statsCommandC:
			req.Response <- t.stats()
		case req := <-t.trackersCommandC:
			req.Response <- t.getTrackers()
		case req := <-t.peersCommandC:
			req.Response <- t.getPeers()
		case <-t.allocatorProgressC:
			// TODO handle allocation progress
		case al := <-t.allocatorResultC:
			t.handleAllocationDone(al)
		case <-t.verifierProgressC:
			// TODO handle verification progress
		case ve := <-t.verifierResultC:
			t.handleVerificationDone(ve)
		case addrs := <-t.addrsFromTrackers:
			t.handleNewPeers(addrs, "tracker")
		case addrs := <-t.addPeersCommandC:
			t.handleNewPeers(addrs, "manual")
		case addrs := <-t.dhtPeersC:
			t.handleNewPeers(addrs, "dht")
		case conn := <-t.incomingConnC:
			if len(t.incomingHandshakers)+len(t.incomingPeers) >= t.config.MaxPeerAccept {
				t.log.Debugln("peer limit reached, rejecting peer", conn.RemoteAddr().String())
				conn.Close()
				break
			}
			ip := conn.RemoteAddr().(*net.TCPAddr).IP.String()
			if _, ok := t.connectedPeerIPs[ip]; ok {
				t.log.Debugln("received duplicate connection from same IP: ", conn.RemoteAddr().String())
				conn.Close()
				break
			}
			h := incominghandshaker.New(conn)
			t.incomingHandshakers[h] = struct{}{}
			t.connectedPeerIPs[ip] = struct{}{}
			go h.Run(t.peerID, t.getSKey, t.checkInfoHash, t.incomingHandshakerResultC, t.config.PeerHandshakeTimeout, ourExtensions, t.config.ForceIncomingEncryption)
		case req := <-t.announcerRequestC:
			tr := t.announcerFields()
			// TODO set bytes uploaded/downloaded
			select {
			case req.Response <- announcer.Response{Torrent: tr}:
			case <-req.Cancel:
			}
		case pw := <-t.pieceWriterResultC:
			pw.Piece.Writing = false
			delete(t.pieceWriters, pw)
			if pw.Error != nil {
				t.stop(pw.Error)
				break
			}
			pw.Piece.Done = true
			if t.bitfield.Test(pw.Piece.Index) {
				panic("already have the piece")
			}
			t.bitfield.Set(pw.Piece.Index)
			if t.resume != nil {
				err := t.resume.WriteBitfield(t.bitfield.Bytes())
				if err != nil {
					err = fmt.Errorf("cannot write bitfield to resume db: %s", err)
					t.log.Errorln(err)
					t.stop(err)
					break
				}
			}
			t.checkCompletion()
			// Tell everyone that we have this piece
			for pe := range t.peers {
				msg := peerprotocol.HaveMessage{Index: pw.Piece.Index}
				pe.SendMessage(msg)
				t.updateInterestedState(pe)
			}
		case pe := <-t.peerSnubbedC:
			// Mark slow peer as snubbed and don't select that peer in piece picker
			pe.Snubbed = true
			t.peersSnubbed[pe] = struct{}{}
			if pd, ok := t.pieceDownloaders[pe]; ok {
				t.pieceDownloadersSnubbed[pe] = pd
				t.piecePicker.HandleSnubbed(pe, pd.Piece.Index)
				t.startPieceDownloaders()
			} else if id, ok := t.infoDownloaders[pe]; ok {
				t.infoDownloadersSnubbed[pe] = id
				t.startInfoDownloaders()
			}
		case <-t.unchokeTimerC:
			t.tickUnchoke()
		case <-t.optimisticUnchokeTimerC:
			t.tickOptimisticUnchoke()
		case ih := <-t.incomingHandshakerResultC:
			delete(t.incomingHandshakers, ih)
			if ih.Error != nil {
				delete(t.connectedPeerIPs, ih.Conn.RemoteAddr().(*net.TCPAddr).IP.String())
				break
			}
			log := logger.New("peer <- " + ih.Conn.RemoteAddr().String())
			pe := peerconn.New(ih.Conn, ih.PeerID, ih.Extensions, log, t.config.PieceTimeout, t.config.PeerReadBufferSize)
			t.startPeer(pe, t.incomingPeers)
		case oh := <-t.outgoingHandshakerResultC:
			delete(t.outgoingHandshakers, oh)
			if oh.Error != nil {
				delete(t.connectedPeerIPs, oh.Addr.IP.String())
				t.dialAddresses()
				break
			}
			log := logger.New("peer -> " + oh.Conn.RemoteAddr().String())
			pe := peerconn.New(oh.Conn, oh.PeerID, oh.Extensions, log, t.config.PieceTimeout, t.config.PeerReadBufferSize)
			t.startPeer(pe, t.outgoingPeers)
		case pe := <-t.peerDisconnectedC:
			t.closePeer(pe)
		case pm := <-t.messages:
			t.handlePeerMessage(pm)
		}
	}
}

func (t *Torrent) closePeer(pe *peer.Peer) {
	pe.Close()
	if pd, ok := t.pieceDownloaders[pe]; ok {
		t.closePieceDownloader(pd)
	}
	if id, ok := t.infoDownloaders[pe]; ok {
		t.closeInfoDownloader(id)
	}
	delete(t.peers, pe)
	delete(t.incomingPeers, pe)
	delete(t.outgoingPeers, pe)
	delete(t.peersSnubbed, pe)
	delete(t.peerIDs, pe.ID())
	delete(t.connectedPeerIPs, pe.Conn.IP())
	if t.piecePicker != nil {
		t.piecePicker.HandleDisconnect(pe)
	}
	t.pexDropPeer(pe.Addr())
	t.dialAddresses()
}

func (t *Torrent) closePieceDownloader(pd *piecedownloader.PieceDownloader) {
	delete(t.pieceDownloaders, pd.Peer)
	delete(t.pieceDownloadersSnubbed, pd.Peer)
	delete(t.pieceDownloadersChoked, pd.Peer)
	t.piecePicker.HandleCancelDownload(pd.Peer, pd.Piece.Index)
	pd.Peer.Downloading = false
}

func (t *Torrent) closeInfoDownloader(id *infodownloader.InfoDownloader) {
	delete(t.infoDownloaders, id.Peer)
	delete(t.infoDownloadersSnubbed, id.Peer)
}

func (t *Torrent) handleNewPeers(addrs []*net.TCPAddr, source string) {
	t.log.Debugf("received %d peers from %s", len(addrs), source)
	t.setNeedMorePeers(false)
	if !t.completed {
		t.addrList.Push(addrs, t.port)
		t.dialAddresses()
	}
}

func (t *Torrent) dialAddresses() {
	if t.completed {
		return
	}
	for len(t.outgoingPeers)+len(t.outgoingHandshakers) < t.config.MaxPeerDial {
		addr := t.addrList.Pop()
		if addr == nil {
			t.setNeedMorePeers(true)
			break
		}
		ip := addr.IP.String()
		if _, ok := t.connectedPeerIPs[ip]; ok {
			continue
		}
		h := outgoinghandshaker.New(addr)
		t.outgoingHandshakers[h] = struct{}{}
		t.connectedPeerIPs[ip] = struct{}{}
		go h.Run(t.config.PeerConnectTimeout, t.config.PeerHandshakeTimeout, t.peerID, t.infoHash, t.outgoingHandshakerResultC, ourExtensions, t.config.DisableOutgoingEncryption, t.config.ForceOutgoingEncryption)
	}
}

func (t *Torrent) setNeedMorePeers(val bool) {
	for _, an := range t.announcers {
		an.NeedMorePeers(val)
	}
	if t.dhtAnnouncer != nil {
		t.dhtAnnouncer.NeedMorePeers(val)
	}
}

// Process messages received while we don't have metadata yet.
func (t *Torrent) processQueuedMessages() {
	for pe := range t.peers {
		for _, msg := range pe.Messages {
			pm := peer.Message{Peer: pe, Message: msg}
			t.handlePeerMessage(pm)
		}
	}
}

func (t *Torrent) startPeer(p *peerconn.Conn, peers map[*peer.Peer]struct{}) {
	t.pexAddPeer(p.Addr())
	_, ok := t.peerIDs[p.ID()]
	if ok {
		p.Logger().Errorln("peer with same id already connected:", p.ID())
		p.CloseConn()
		t.pexDropPeer(p.Addr())
		t.dialAddresses()
		return
	}
	t.peerIDs[p.ID()] = struct{}{}

	pe := peer.New(p)
	t.peers[pe] = struct{}{}
	peers[pe] = struct{}{}
	go pe.Run(t.messages, t.peerDisconnectedC)

	t.sendFirstMessage(pe)
	if len(t.peers) <= 4 {
		t.unchokePeer(pe)
	}
}

func (t *Torrent) pexAddPeer(addr *net.TCPAddr) {
	for pe := range t.peers {
		if pe.PEX != nil {
			pe.PEX.Add(addr)
		}
	}
}

func (t *Torrent) pexDropPeer(addr *net.TCPAddr) {
	for pe := range t.peers {
		if pe.PEX != nil {
			pe.PEX.Drop(addr)
		}
	}
}

func (t *Torrent) sendFirstMessage(p *peer.Peer) {
	bf := t.bitfield
	if p.FastExtension && bf != nil && bf.All() {
		msg := peerprotocol.HaveAllMessage{}
		p.SendMessage(msg)
	} else if p.FastExtension && (bf == nil || bf != nil && bf.Count() == 0) {
		msg := peerprotocol.HaveNoneMessage{}
		p.SendMessage(msg)
	} else if bf != nil {
		bitfieldData := make([]byte, len(bf.Bytes()))
		copy(bitfieldData, bf.Bytes())
		msg := peerprotocol.BitfieldMessage{Data: bitfieldData}
		p.SendMessage(msg)
	}
	var metadataSize uint32
	if t.info != nil {
		metadataSize = t.info.InfoSize
	}
	extHandshakeMsg := peerprotocol.NewExtensionHandshake(metadataSize)
	msg := peerprotocol.ExtensionMessage{
		ExtendedMessageID: peerprotocol.ExtensionIDHandshake,
		Payload:           extHandshakeMsg,
	}
	p.SendMessage(msg)
}

func (t *Torrent) chokePeer(pe *peer.Peer) {
	if !pe.AmChoking {
		pe.AmChoking = true
		msg := peerprotocol.ChokeMessage{}
		pe.SendMessage(msg)
	}
}

func (t *Torrent) unchokePeer(pe *peer.Peer) {
	if pe.AmChoking {
		pe.AmChoking = false
		msg := peerprotocol.UnchokeMessage{}
		pe.SendMessage(msg)
	}
}

func (t *Torrent) checkCompletion() {
	if t.completed {
		return
	}
	if t.bitfield.All() {
		t.log.Info("download completed")
		t.completed = true
		close(t.completeC)
		for h := range t.outgoingHandshakers {
			h.Close()
		}
		t.outgoingHandshakers = make(map[*outgoinghandshaker.OutgoingHandshaker]struct{})
		for pe := range t.peers {
			if !pe.PeerInterested {
				t.closePeer(pe)
			}
		}
		t.addrList.Reset()
	}
}
<commit_msg>add todo<commit_after>package torrent

import (
	"errors"
	"fmt"
	"net"

	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/torrent/internal/announcer"
	"github.com/cenkalti/rain/torrent/internal/handshaker/incominghandshaker"
	"github.com/cenkalti/rain/torrent/internal/handshaker/outgoinghandshaker"
	"github.com/cenkalti/rain/torrent/internal/infodownloader"
	"github.com/cenkalti/rain/torrent/internal/peer"
	"github.com/cenkalti/rain/torrent/internal/peerconn"
	"github.com/cenkalti/rain/torrent/internal/peerprotocol"
	"github.com/cenkalti/rain/torrent/internal/piecedownloader"
	"github.com/cenkalti/rain/torrent/internal/tracker/trackermanager"
)

var errClosed = errors.New("torrent is closed")

func (t *Torrent) close() {
	// Stop if running.
	t.stop(errClosed)

	// Maybe we are in "Stopping" state. Close "stopped" event announcer.
	if t.stoppedEventAnnouncer != nil {
		t.stoppedEventAnnouncer.Close()
	}

	// Close open tracker connections.
	for _, tr := range t.trackersInstances {
		trackermanager.DefaultTrackerManager.Release(tr)
	}
}

// Torrent event loop
func (t *Torrent) run() {
	for {
		select {
		case doneC := <-t.closeC:
			t.close()
			close(doneC)
			return
		case <-t.startCommandC:
			t.start()
		case <-t.stopCommandC:
			t.stop(nil)
		case <-t.announcersStoppedC:
			t.stoppedEventAnnouncer = nil
			t.errC <- t.lastError
			t.errC = nil
			t.portC = nil
			t.log.Info("torrent has stopped")
		case cmd := <-t.notifyErrorCommandC:
			cmd.errCC <- t.errC
		case cmd := <-t.notifyListenCommandC:
			cmd.portCC <- t.portC
		case req := <-t.statsCommandC:
			req.Response <- t.stats()
		case req := <-t.trackersCommandC:
			req.Response <- t.getTrackers()
		case req := <-t.peersCommandC:
			req.Response <- t.getPeers()
		case <-t.allocatorProgressC:
			// TODO handle allocation progress
		case al := <-t.allocatorResultC:
			t.handleAllocationDone(al)
		case <-t.verifierProgressC:
			// TODO handle verification progress
		case ve := <-t.verifierResultC:
			t.handleVerificationDone(ve)
		case addrs := <-t.addrsFromTrackers:
			t.handleNewPeers(addrs, "tracker")
		case addrs := <-t.addPeersCommandC:
			t.handleNewPeers(addrs, "manual")
		case addrs := <-t.dhtPeersC:
			t.handleNewPeers(addrs, "dht")
		case conn := <-t.incomingConnC:
			if len(t.incomingHandshakers)+len(t.incomingPeers) >= t.config.MaxPeerAccept {
				t.log.Debugln("peer limit reached, rejecting peer", conn.RemoteAddr().String())
				conn.Close()
				break
			}
			ip := conn.RemoteAddr().(*net.TCPAddr).IP.String()
			if _, ok := t.connectedPeerIPs[ip]; ok {
				t.log.Debugln("received duplicate connection from same IP: ", conn.RemoteAddr().String())
				conn.Close()
				break
			}
			h := incominghandshaker.New(conn)
			t.incomingHandshakers[h] = struct{}{}
			t.connectedPeerIPs[ip] = struct{}{}
			go h.Run(t.peerID, t.getSKey, t.checkInfoHash, t.incomingHandshakerResultC, t.config.PeerHandshakeTimeout, ourExtensions, t.config.ForceIncomingEncryption)
		case req := <-t.announcerRequestC:
			tr := t.announcerFields()
			// TODO set bytes uploaded/downloaded
			select {
			case req.Response <- announcer.Response{Torrent: tr}:
			case <-req.Cancel:
			}
		case pw := <-t.pieceWriterResultC:
			pw.Piece.Writing = false
			delete(t.pieceWriters, pw)
			if pw.Error != nil {
				t.stop(pw.Error)
				break
			}
			pw.Piece.Done = true
			if t.bitfield.Test(pw.Piece.Index) {
				panic("already have the piece")
			}
			t.bitfield.Set(pw.Piece.Index)
			if t.resume != nil {
				err := t.resume.WriteBitfield(t.bitfield.Bytes())
				if err != nil {
					err = fmt.Errorf("cannot write bitfield to resume db: %s", err)
					t.log.Errorln(err)
					t.stop(err)
					break
				}
			}
			t.checkCompletion()
			// Tell everyone that we have this piece
			for pe := range t.peers {
				// TODO skip peers having the piece
				msg := peerprotocol.HaveMessage{Index: pw.Piece.Index}
				pe.SendMessage(msg)
				t.updateInterestedState(pe)
			}
		case pe := <-t.peerSnubbedC:
			// Mark slow peer as snubbed and don't select that peer in piece picker
			pe.Snubbed = true
			t.peersSnubbed[pe] = struct{}{}
			if pd, ok := t.pieceDownloaders[pe]; ok {
				t.pieceDownloadersSnubbed[pe] = pd
				t.piecePicker.HandleSnubbed(pe, pd.Piece.Index)
				t.startPieceDownloaders()
			} else if id, ok := t.infoDownloaders[pe]; ok {
				t.infoDownloadersSnubbed[pe] = id
				t.startInfoDownloaders()
			}
		case <-t.unchokeTimerC:
			t.tickUnchoke()
		case <-t.optimisticUnchokeTimerC:
			t.tickOptimisticUnchoke()
		case ih := <-t.incomingHandshakerResultC:
			delete(t.incomingHandshakers, ih)
			if ih.Error != nil {
				delete(t.connectedPeerIPs, ih.Conn.RemoteAddr().(*net.TCPAddr).IP.String())
				break
			}
			log := logger.New("peer <- " + ih.Conn.RemoteAddr().String())
			pe := peerconn.New(ih.Conn, ih.PeerID, ih.Extensions, log, t.config.PieceTimeout, t.config.PeerReadBufferSize)
			t.startPeer(pe, t.incomingPeers)
		case oh := <-t.outgoingHandshakerResultC:
			delete(t.outgoingHandshakers, oh)
			if oh.Error != nil {
				delete(t.connectedPeerIPs, oh.Addr.IP.String())
				t.dialAddresses()
				break
			}
			log := logger.New("peer -> " + oh.Conn.RemoteAddr().String())
			pe := peerconn.New(oh.Conn, oh.PeerID, oh.Extensions, log, t.config.PieceTimeout, t.config.PeerReadBufferSize)
			t.startPeer(pe, t.outgoingPeers)
		case pe := <-t.peerDisconnectedC:
			t.closePeer(pe)
		case pm := <-t.messages:
			t.handlePeerMessage(pm)
		}
	}
}

func (t *Torrent) closePeer(pe *peer.Peer) {
	pe.Close()
	if pd, ok := t.pieceDownloaders[pe]; ok {
		t.closePieceDownloader(pd)
	}
	if id, ok := t.infoDownloaders[pe]; ok {
		t.closeInfoDownloader(id)
	}
	delete(t.peers, pe)
	delete(t.incomingPeers, pe)
	delete(t.outgoingPeers, pe)
	delete(t.peersSnubbed, pe)
	delete(t.peerIDs, pe.ID())
	delete(t.connectedPeerIPs, pe.Conn.IP())
	if t.piecePicker != nil {
		t.piecePicker.HandleDisconnect(pe)
	}
	t.pexDropPeer(pe.Addr())
	t.dialAddresses()
}

func (t *Torrent) closePieceDownloader(pd *piecedownloader.PieceDownloader) {
	delete(t.pieceDownloaders, pd.Peer)
	delete(t.pieceDownloadersSnubbed, pd.Peer)
	delete(t.pieceDownloadersChoked, pd.Peer)
	t.piecePicker.HandleCancelDownload(pd.Peer, pd.Piece.Index)
	pd.Peer.Downloading = false
}

func (t *Torrent) closeInfoDownloader(id *infodownloader.InfoDownloader) {
	delete(t.infoDownloaders, id.Peer)
	delete(t.infoDownloadersSnubbed, id.Peer)
}

func (t *Torrent) handleNewPeers(addrs []*net.TCPAddr, source string) {
	t.log.Debugf("received %d peers from %s", len(addrs), source)
	t.setNeedMorePeers(false)
	if !t.completed {
		t.addrList.Push(addrs, t.port)
		t.dialAddresses()
	}
}

func (t *Torrent) dialAddresses() {
	if t.completed {
		return
	}
	for len(t.outgoingPeers)+len(t.outgoingHandshakers) < t.config.MaxPeerDial {
		addr := t.addrList.Pop()
		if addr == nil {
			t.setNeedMorePeers(true)
			break
		}
		ip := addr.IP.String()
		if _, ok := t.connectedPeerIPs[ip]; ok {
			continue
		}
		h := outgoinghandshaker.New(addr)
		t.outgoingHandshakers[h] = struct{}{}
		t.connectedPeerIPs[ip] = struct{}{}
		go h.Run(t.config.PeerConnectTimeout, t.config.PeerHandshakeTimeout, t.peerID, t.infoHash, t.outgoingHandshakerResultC, ourExtensions, t.config.DisableOutgoingEncryption, t.config.ForceOutgoingEncryption)
	}
}

func (t *Torrent) setNeedMorePeers(val bool) {
	for _, an := range t.announcers {
		an.NeedMorePeers(val)
	}
	if t.dhtAnnouncer != nil {
		t.dhtAnnouncer.NeedMorePeers(val)
	}
}

// Process messages received while we don't have metadata yet.
func (t *Torrent) processQueuedMessages() {
	for pe := range t.peers {
		for _, msg := range pe.Messages {
			pm := peer.Message{Peer: pe, Message: msg}
			t.handlePeerMessage(pm)
		}
	}
}

func (t *Torrent) startPeer(p *peerconn.Conn, peers map[*peer.Peer]struct{}) {
	t.pexAddPeer(p.Addr())
	_, ok := t.peerIDs[p.ID()]
	if ok {
		p.Logger().Errorln("peer with same id already connected:", p.ID())
		p.CloseConn()
		t.pexDropPeer(p.Addr())
		t.dialAddresses()
		return
	}
	t.peerIDs[p.ID()] = struct{}{}

	pe := peer.New(p)
	t.peers[pe] = struct{}{}
	peers[pe] = struct{}{}
	go pe.Run(t.messages, t.peerDisconnectedC)

	t.sendFirstMessage(pe)
	if len(t.peers) <= 4 {
		t.unchokePeer(pe)
	}
}

func (t *Torrent) pexAddPeer(addr *net.TCPAddr) {
	for pe := range t.peers {
		if pe.PEX != nil {
			pe.PEX.Add(addr)
		}
	}
}

func (t *Torrent) pexDropPeer(addr *net.TCPAddr) {
	for pe := range t.peers {
		if pe.PEX != nil {
			pe.PEX.Drop(addr)
		}
	}
}

func (t *Torrent) sendFirstMessage(p *peer.Peer) {
	bf := t.bitfield
	if p.FastExtension && bf != nil && bf.All() {
		msg := peerprotocol.HaveAllMessage{}
		p.SendMessage(msg)
	} else if p.FastExtension && (bf == nil || bf != nil && bf.Count() == 0) {
		msg := peerprotocol.HaveNoneMessage{}
		p.SendMessage(msg)
	} else if bf != nil {
		bitfieldData := make([]byte, len(bf.Bytes()))
		copy(bitfieldData, bf.Bytes())
		msg := peerprotocol.BitfieldMessage{Data: bitfieldData}
		p.SendMessage(msg)
	}
	var metadataSize uint32
	if t.info != nil {
		metadataSize = t.info.InfoSize
	}
	extHandshakeMsg := peerprotocol.NewExtensionHandshake(metadataSize)
	msg := peerprotocol.ExtensionMessage{
		ExtendedMessageID: peerprotocol.ExtensionIDHandshake,
		Payload:           extHandshakeMsg,
	}
	p.SendMessage(msg)
}

func (t *Torrent) chokePeer(pe *peer.Peer) {
	if !pe.AmChoking {
		pe.AmChoking = true
		msg := peerprotocol.ChokeMessage{}
		pe.SendMessage(msg)
	}
}

func (t *Torrent) unchokePeer(pe *peer.Peer) {
	if pe.AmChoking {
		pe.AmChoking = false
		msg := peerprotocol.UnchokeMessage{}
		pe.SendMessage(msg)
	}
}

func (t *Torrent) checkCompletion() {
	if t.completed {
		return
	}
	if t.bitfield.All() {
		t.log.Info("download completed")
		t.completed = true
		close(t.completeC)
		for h := range t.outgoingHandshakers {
			h.Close()
		}
		t.outgoingHandshakers = make(map[*outgoinghandshaker.OutgoingHandshaker]struct{})
		for pe := range t.peers {
			if !pe.PeerInterested {
				t.closePeer(pe)
			}
		}
		t.addrList.Reset()
	}
}
<|endoftext|>


<commit_before>package toml

// Struct field handling is adapted from code in encoding/json:
//
// Copyright 2010 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.

import (
	"reflect"
	"sort"
	"sync"
)

// A field represents a single field found in a struct.
type field struct {
	name  string
	tag   bool
	index []int
	typ   reflect.Type
}

// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from toml tag", then
// breaking ties with index sequence.
type byName []field

func (x byName) Len() int { return len(x) }

func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

func (x byName) Less(i, j int) bool {
	if x[i].name != x[j].name {
		return x[i].name < x[j].name
	}
	if len(x[i].index) != len(x[j].index) {
		return len(x[i].index) < len(x[j].index)
	}
	if x[i].tag != x[j].tag {
		return x[i].tag
	}
	return byIndex(x).Less(i, j)
}

// byIndex sorts field by index sequence.
type byIndex []field

func (x byIndex) Len() int { return len(x) }

func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

func (x byIndex) Less(i, j int) bool {
	for k, xik := range x[i].index {
		if k >= len(x[j].index) {
			return false
		}
		if xik != x[j].index[k] {
			return xik < x[j].index[k]
		}
	}
	return len(x[i].index) < len(x[j].index)
}

// typeFields returns a list of fields that TOML should recognize for the given
// type. The algorithm is breadth-first search over the set of structs to
// include - the top struct and then any reachable anonymous structs.
func typeFields(t reflect.Type) []field {
	// Anonymous fields to explore at the current level and the next.
	current := []field{}
	next := []field{{typ: t}}

	// Count of queued names for current level and the next.
	count := map[reflect.Type]int{}
	nextCount := map[reflect.Type]int{}

	// Types already visited at an earlier level.
	visited := map[reflect.Type]bool{}

	// Fields found.
	var fields []field

	for len(next) > 0 {
		current, next = next, current[:0]
		count, nextCount = nextCount, map[reflect.Type]int{}

		for _, f := range current {
			if visited[f.typ] {
				continue
			}
			visited[f.typ] = true

			// Scan f.typ for fields to include.
			for i := 0; i < f.typ.NumField(); i++ {
				sf := f.typ.Field(i)
				if sf.PkgPath != "" { // unexported
					continue
				}
				name := sf.Tag.Get("toml")
				if name == "-" {
					continue
				}
				index := make([]int, len(f.index)+1)
				copy(index, f.index)
				index[len(f.index)] = i

				ft := sf.Type
				if ft.Name() == "" && ft.Kind() == reflect.Ptr {
					// Follow pointer.
					ft = ft.Elem()
				}

				// Record found field and index sequence.
				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
					tagged := name != ""
					if name == "" {
						name = sf.Name
					}
					fields = append(fields, field{name, tagged, index, ft})
					if count[f.typ] > 1 {
						// If there were multiple instances, add a second,
						// so that the annihilation code will see a duplicate.
						// It only cares about the distinction between 1 or 2,
						// so don't bother generating any more copies.
						fields = append(fields, fields[len(fields)-1])
					}
					continue
				}

				// Record new anonymous struct to explore in next round.
				nextCount[ft]++
				if nextCount[ft] == 1 {
					f := field{name: ft.Name(), index: index, typ: ft}
					next = append(next, f)
				}
			}
		}
	}

	sort.Sort(byName(fields))

	// Delete all fields that are hidden by the Go rules for embedded fields,
	// except that fields with TOML tags are promoted.

	// The fields are sorted in primary order of name, secondary order
	// of field index length. Loop over names; for each name, delete
	// hidden fields by choosing the one dominant field that survives.
	out := fields[:0]
	for advance, i := 0, 0; i < len(fields); i += advance {
		// One iteration per name.
		// Find the sequence of fields with the name of this first field.
		fi := fields[i]
		name := fi.name
		for advance = 1; i+advance < len(fields); advance++ {
			fj := fields[i+advance]
			if fj.name != name {
				break
			}
		}
		if advance == 1 { // Only one field with this name
			out = append(out, fi)
			continue
		}
		dominant, ok := dominantField(fields[i : i+advance])
		if ok {
			out = append(out, dominant)
		}
	}

	fields = out
	sort.Sort(byIndex(fields))

	return fields
}

// dominantField looks through the fields, all of which are known to
// have the same name, to find the single field that dominates the
// others using Go's embedding rules, modified by the presence of
// TOML tags. If there are multiple top-level fields, the boolean
// will be false: This condition is an error in Go and we skip all
// the fields.
func dominantField(fields []field) (field, bool) {
	// The fields are sorted in increasing index-length order. The winner
	// must therefore be one with the shortest index length. Drop all
	// longer entries, which is easy: just truncate the slice.
	length := len(fields[0].index)
	tagged := -1 // Index of first tagged field.
	for i, f := range fields {
		if len(f.index) > length {
			fields = fields[:i]
			break
		}
		if f.tag {
			if tagged >= 0 {
				// Multiple tagged fields at the same level: conflict.
				// Return no field.
				return field{}, false
			}
			tagged = i
		}
	}
	if tagged >= 0 {
		return fields[tagged], true
	}
	// All remaining fields have the same length. If there's more than one,
	// we have a conflict (two fields named "X" at the same level) and we
	// return no field.
	if len(fields) > 1 {
		return field{}, false
	}
	return fields[0], true
}

var fieldCache struct {
	sync.RWMutex
	m map[reflect.Type][]field
}

// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
	fieldCache.RLock()
	f := fieldCache.m[t]
	fieldCache.RUnlock()
	if f != nil {
		return f
	}

	// Compute fields without lock.
	// Might duplicate effort but won't hold other computations back.
	f = typeFields(t)
	if f == nil {
		f = []field{}
	}

	fieldCache.Lock()
	if fieldCache.m == nil {
		fieldCache.m = map[reflect.Type][]field{}
	}
	fieldCache.m[t] = f
	fieldCache.Unlock()
	return f
}
<commit_msg>Document representation of a field in code from `encoding/json`.<commit_after>package toml

// Struct field handling is adapted from code in encoding/json:
//
// Copyright 2010 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.

import (
	"reflect"
	"sort"
	"sync"
)

// A field represents a single field found in a struct.
type field struct {
	name  string       // the name of the field (`toml` tag included)
	tag   bool         // whether field has a `toml` tag
	index []int        // represents the depth of an anonymous field
	typ   reflect.Type // the type of the field
}

// byName sorts field by name, breaking ties with depth,
// then breaking ties with "name came from toml tag", then
// breaking ties with index sequence.
type byName []field

func (x byName) Len() int { return len(x) }

func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

func (x byName) Less(i, j int) bool {
	if x[i].name != x[j].name {
		return x[i].name < x[j].name
	}
	if len(x[i].index) != len(x[j].index) {
		return len(x[i].index) < len(x[j].index)
	}
	if x[i].tag != x[j].tag {
		return x[i].tag
	}
	return byIndex(x).Less(i, j)
}

// byIndex sorts field by index sequence.
type byIndex []field

func (x byIndex) Len() int { return len(x) }

func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

func (x byIndex) Less(i, j int) bool {
	for k, xik := range x[i].index {
		if k >= len(x[j].index) {
			return false
		}
		if xik != x[j].index[k] {
			return xik < x[j].index[k]
		}
	}
	return len(x[i].index) < len(x[j].index)
}

// typeFields returns a list of fields that TOML should recognize for the given
// type. The algorithm is breadth-first search over the set of structs to
// include - the top struct and then any reachable anonymous structs.
func typeFields(t reflect.Type) []field {
	// Anonymous fields to explore at the current level and the next.
	current := []field{}
	next := []field{{typ: t}}

	// Count of queued names for current level and the next.
	count := map[reflect.Type]int{}
	nextCount := map[reflect.Type]int{}

	// Types already visited at an earlier level.
	visited := map[reflect.Type]bool{}

	// Fields found.
	var fields []field

	for len(next) > 0 {
		current, next = next, current[:0]
		count, nextCount = nextCount, map[reflect.Type]int{}

		for _, f := range current {
			if visited[f.typ] {
				continue
			}
			visited[f.typ] = true

			// Scan f.typ for fields to include.
			for i := 0; i < f.typ.NumField(); i++ {
				sf := f.typ.Field(i)
				if sf.PkgPath != "" { // unexported
					continue
				}
				name := sf.Tag.Get("toml")
				if name == "-" {
					continue
				}
				index := make([]int, len(f.index)+1)
				copy(index, f.index)
				index[len(f.index)] = i

				ft := sf.Type
				if ft.Name() == "" && ft.Kind() == reflect.Ptr {
					// Follow pointer.
					ft = ft.Elem()
				}

				// Record found field and index sequence.
				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
					tagged := name != ""
					if name == "" {
						name = sf.Name
					}
					fields = append(fields, field{name, tagged, index, ft})
					if count[f.typ] > 1 {
						// If there were multiple instances, add a second,
						// so that the annihilation code will see a duplicate.
						// It only cares about the distinction between 1 or 2,
						// so don't bother generating any more copies.
						fields = append(fields, fields[len(fields)-1])
					}
					continue
				}

				// Record new anonymous struct to explore in next round.
				nextCount[ft]++
				if nextCount[ft] == 1 {
					f := field{name: ft.Name(), index: index, typ: ft}
					next = append(next, f)
				}
			}
		}
	}

	sort.Sort(byName(fields))

	// Delete all fields that are hidden by the Go rules for embedded fields,
	// except that fields with TOML tags are promoted.

	// The fields are sorted in primary order of name, secondary order
	// of field index length. Loop over names; for each name, delete
	// hidden fields by choosing the one dominant field that survives.
	out := fields[:0]
	for advance, i := 0, 0; i < len(fields); i += advance {
		// One iteration per name.
		// Find the sequence of fields with the name of this first field.
		fi := fields[i]
		name := fi.name
		for advance = 1; i+advance < len(fields); advance++ {
			fj := fields[i+advance]
			if fj.name != name {
				break
			}
		}
		if advance == 1 { // Only one field with this name
			out = append(out, fi)
			continue
		}
		dominant, ok := dominantField(fields[i : i+advance])
		if ok {
			out = append(out, dominant)
		}
	}

	fields = out
	sort.Sort(byIndex(fields))

	return fields
}

// dominantField looks through the fields, all of which are known to
// have the same name, to find the single field that dominates the
// others using Go's embedding rules, modified by the presence of
// TOML tags. If there are multiple top-level fields, the boolean
// will be false: This condition is an error in Go and we skip all
// the fields.
func dominantField(fields []field) (field, bool) {
	// The fields are sorted in increasing index-length order. The winner
	// must therefore be one with the shortest index length. Drop all
	// longer entries, which is easy: just truncate the slice.
	length := len(fields[0].index)
	tagged := -1 // Index of first tagged field.
	for i, f := range fields {
		if len(f.index) > length {
			fields = fields[:i]
			break
		}
		if f.tag {
			if tagged >= 0 {
				// Multiple tagged fields at the same level: conflict.
				// Return no field.
				return field{}, false
			}
			tagged = i
		}
	}
	if tagged >= 0 {
		return fields[tagged], true
	}
	// All remaining fields have the same length. If there's more than one,
	// we have a conflict (two fields named "X" at the same level) and we
	// return no field.
	if len(fields) > 1 {
		return field{}, false
	}
	return fields[0], true
}

var fieldCache struct {
	sync.RWMutex
	m map[reflect.Type][]field
}

// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
	fieldCache.RLock()
	f := fieldCache.m[t]
	fieldCache.RUnlock()
	if f != nil {
		return f
	}

	// Compute fields without lock.
	// Might duplicate effort but won't hold other computations back.
	f = typeFields(t)
	if f == nil {
		f = []field{}
	}

	fieldCache.Lock()
	if fieldCache.m == nil {
		fieldCache.m = map[reflect.Type][]field{}
	}
	fieldCache.m[t] = f
	fieldCache.Unlock()
	return f
}
<|endoftext|>


<commit_before>package funcgo

// see http://learnyouahaskell.com/types-and-typeclasses

// Eq is the equality typeclass: (Eq a) => a -> a -> Bool
type Eq interface {
	Eq(Eq) bool
}

// Ord is the Ordering typeclass: (Ord a) => a -> a -> Bool
type Ord interface {
	Before(Ord) bool
}

// Show is the typeclass for converting a type to a string (same as fmt.Stringer): (Show a) => a -> string
type Show interface {
	Show() string
}

// Read is the typeclass for converting a string into an instance of Read: (Read a) => string -> Read
type Read interface {
	Read(string) (Read, error)
}

// Integral is the typeclass for representing an integer type
type Integral interface {
	Int() int64
}

// IntegralFunctor is the typeclass for iterating over a container of Integral types, applying a function on each of them, and returning the results.
//
// All implementations of this interface must adhere to the following rules:
//
//	1. f.Map(func(i Integral) { return i }) == f
//	2. f.Map(funcA(funcB(param))) == f.Map(funcA).Map(funcB)
type IntegralFunctor interface {
	Map(func(Integral) Integral) IntegralFunctor
}

// Floating is the typeclass for representing a floating type
type Floating interface {
	Float() float64
}
<commit_msg>adding some usage docs<commit_after>package funcgo

// see http://learnyouahaskell.com/types-and-typeclasses

// Each of the typeclasses herein are "adapters" for existing types. Other languages (Haskell, Scala) automatically convert existing types for use with these adapters, but in Go we have to do things more manually. Here's how:
//
// 1. create an implementation of one of the type classes
//
//	type intEq int
//
//	func (i intEq) Eq(e Eq) bool {
//		i2, ok := e.(int)
//		if !ok {
//			return false
//		}
//		return i == i2
//	}
//
// 2. wrap your value in the implementation
//
//	intEq(1).Eq(intEq(2))

// Eq is the equality typeclass: (Eq a) => a -> a -> Bool
type Eq interface {
	Eq(Eq) bool
}

// Ord is the Ordering typeclass: (Ord a) => a -> a -> Bool
type Ord interface {
	Before(Ord) bool
}

// Show is the typeclass for converting a type to a string (same as fmt.Stringer): (Show a) => a -> string
type Show interface {
	Show() string
}

// Read is the typeclass for converting a string into an instance of Read: (Read a) => string -> Read
type Read interface {
	Read(string) (Read, error)
}

// Integral is the typeclass for representing an integer type
type Integral interface {
	Int() int64
}

// IntegralFunctor is the typeclass for iterating over a container of Integral types, applying a function on each of them, and returning the results.
//
// All implementations of this interface must adhere to the following rules:
//
//	1. f.Map(func(i Integral) { return i }) == f
//	2. f.Map(funcA(funcB(param))) == f.Map(funcA).Map(funcB)
type IntegralFunctor interface {
	Map(func(Integral) Integral) IntegralFunctor
}

// Floating is the typeclass for representing a floating type
type Floating interface {
	Float() float64
}
<|endoftext|>


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

// Package types defines common types.
package types

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
)

// Bytes20Size is the size of a 20-byte long byte array.
const Bytes20Size = 20

// Bytes20 is a 20-byte long byte array.
type Bytes20 [Bytes20Size]byte

// NewBytes20FromString creates a Bytes20 from a hex encoded string.
func NewBytes20FromString(src string) (*Bytes20, error) {
	var b Bytes20
	if err := b.Unstring(src); err != nil {
		return nil, err
	}
	return &b, nil
}

// String returns a hex encoded string.
func (b *Bytes20) String() string {
	return hex.EncodeToString(b[:])
}

// Unstring sets the value from a hex encoded string.
func (b *Bytes20) Unstring(src string) error {
	buf, err := hex.DecodeString(src)
	if err != nil {
		return err
	}
	if n := len(buf); n != Bytes20Size {
		return fmt.Errorf("invalid Bytes20 size got %d want %d", n, Bytes20Size)
	}

	copy(b[:], buf)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (b *Bytes20) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.String())
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (b *Bytes20) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	return b.Unstring(s)
}

// Reverse reverses the bytes order.
func (b *Bytes20) Reverse(rb *ReversedBytes20) {
	for i, v := range b {
		rb[Bytes20Size-i-1] = v
	}
}

// ReversedBytes20 is a 20-byte long byte reversed array.
// While the bytes are reversed, the hex encoded strings are not.
type ReversedBytes20 [Bytes20Size]byte

// NewReversedBytes20FromString creates a ReversedBytes20 from a hex encoded string.
func NewReversedBytes20FromString(src string) (*ReversedBytes20, error) {
	b, err := NewBytes20FromString(src)
	if err != nil {
		return nil, err
	}
	var rb ReversedBytes20
	b.Reverse(&rb)
	return &rb, nil
}

// String returns a hex encoded string.
func (rb *ReversedBytes20) String() string {
	var b Bytes20
	rb.Reverse(&b)
	return b.String()
}

// Unstring sets the value from a hex encoded string.
func (rb *ReversedBytes20) Unstring(src string) error {
	b, err := NewBytes20FromString(src)
	if err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (rb *ReversedBytes20) MarshalJSON() ([]byte, error) {
	var b Bytes20
	rb.Reverse(&b)
	return b.MarshalJSON()
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (rb *ReversedBytes20) UnmarshalJSON(data []byte) error {
	var b Bytes20
	if err := json.Unmarshal(data, &b); err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// Reverse reverses the bytes order.
func (rb *ReversedBytes20) Reverse(b *Bytes20) {
	for i, v := range rb {
		b[Bytes20Size-i-1] = v
	}
}

// Bytes32Size is the size of a 32-byte long byte array.
const Bytes32Size = 32

// Bytes32 is a 32-byte long byte array.
type Bytes32 [Bytes32Size]byte

// NewBytes32FromString creates a Bytes32 from a hex encoded string.
func NewBytes32FromString(src string) (*Bytes32, error) {
	var b Bytes32
	if err := b.Unstring(src); err != nil {
		return nil, err
	}
	return &b, nil
}

// String returns a hex encoded string.
func (b *Bytes32) String() string {
	return hex.EncodeToString(b[:])
}

// Unstring sets the value from a hex encoded string.
func (b *Bytes32) Unstring(src string) error {
	buf, err := hex.DecodeString(src)
	if err != nil {
		return err
	}
	if n := len(buf); n != Bytes32Size {
		return fmt.Errorf("invalid Bytes32 size got %d want %d", n, Bytes32Size)
	}

	copy(b[:], buf)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (b *Bytes32) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.String())
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (b *Bytes32) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	return b.Unstring(s)
}

// Reverse reverses the bytes order.
func (b *Bytes32) Reverse(rb *ReversedBytes32) {
	for i, v := range b {
		rb[Bytes32Size-i-1] = v
	}
}

// ReversedBytes32 is a 32-byte long byte reversed array.
// While the bytes are reversed, the hex encoded strings are not.
type ReversedBytes32 [Bytes32Size]byte

// NewReversedBytes32FromString creates a ReversedBytes32 from a hex encoded string.
func NewReversedBytes32FromString(src string) (*ReversedBytes32, error) {
	b, err := NewBytes32FromString(src)
	if err != nil {
		return nil, err
	}
	var rb ReversedBytes32
	b.Reverse(&rb)
	return &rb, nil
}

// String returns a hex encoded string.
func (rb *ReversedBytes32) String() string {
	var b Bytes32
	rb.Reverse(&b)
	return b.String()
}

// Unstring sets the value from a hex encoded string.
func (rb *ReversedBytes32) Unstring(src string) error {
	b, err := NewBytes32FromString(src)
	if err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (rb *ReversedBytes32) MarshalJSON() ([]byte, error) {
	var b Bytes32
	rb.Reverse(&b)
	return b.MarshalJSON()
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (rb *ReversedBytes32) UnmarshalJSON(data []byte) error {
	var b Bytes32
	if err := json.Unmarshal(data, &b); err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// Reverse reverses the bytes order.
func (rb *ReversedBytes32) Reverse(b *Bytes32) {
	for i, v := range rb {
		b[Bytes32Size-i-1] = v
	}
}
<commit_msg>Optimize types reverse functions<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package types defines common types.
package types

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
)

// Bytes20Size is the size of a 20-byte long byte array.
const Bytes20Size = 20

// Bytes20 is a 20-byte long byte array.
type Bytes20 [Bytes20Size]byte

// NewBytes20FromString creates a Bytes20 from a hex encoded string.
func NewBytes20FromString(src string) (*Bytes20, error) {
	var b Bytes20
	if err := b.Unstring(src); err != nil {
		return nil, err
	}
	return &b, nil
}

// String returns a hex encoded string.
func (b *Bytes20) String() string {
	return hex.EncodeToString(b[:])
}

// Unstring sets the value from a hex encoded string.
func (b *Bytes20) Unstring(src string) error {
	buf, err := hex.DecodeString(src)
	if err != nil {
		return err
	}
	if n := len(buf); n != Bytes20Size {
		return fmt.Errorf("invalid Bytes20 size got %d want %d", n, Bytes20Size)
	}

	copy(b[:], buf)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (b *Bytes20) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.String())
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (b *Bytes20) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	return b.Unstring(s)
}

// Reverse reverses the bytes order.
func (b *Bytes20) Reverse(rb *ReversedBytes20) {
	i := Bytes20Size - 1
	for _, v := range b {
		rb[i] = v
		i--
	}
}

// ReversedBytes20 is a 20-byte long byte reversed array.
// While the bytes are reversed, the hex encoded strings are not.
type ReversedBytes20 [Bytes20Size]byte

// NewReversedBytes20FromString creates a ReversedBytes20 from a hex encoded string.
func NewReversedBytes20FromString(src string) (*ReversedBytes20, error) {
	b, err := NewBytes20FromString(src)
	if err != nil {
		return nil, err
	}
	var rb ReversedBytes20
	b.Reverse(&rb)
	return &rb, nil
}

// String returns a hex encoded string.
func (rb *ReversedBytes20) String() string {
	var b Bytes20
	rb.Reverse(&b)
	return b.String()
}

// Unstring sets the value from a hex encoded string.
func (rb *ReversedBytes20) Unstring(src string) error {
	b, err := NewBytes20FromString(src)
	if err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (rb *ReversedBytes20) MarshalJSON() ([]byte, error) {
	var b Bytes20
	rb.Reverse(&b)
	return b.MarshalJSON()
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (rb *ReversedBytes20) UnmarshalJSON(data []byte) error {
	var b Bytes20
	if err := json.Unmarshal(data, &b); err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// Reverse reverses the bytes order.
func (rb *ReversedBytes20) Reverse(b *Bytes20) {
	i := Bytes20Size - 1
	for _, v := range rb {
		b[i] = v
		i--
	}
}

// Bytes32Size is the size of a 32-byte long byte array.
const Bytes32Size = 32

// Bytes32 is a 32-byte long byte array.
type Bytes32 [Bytes32Size]byte

// NewBytes32FromString creates a Bytes32 from a hex encoded string.
func NewBytes32FromString(src string) (*Bytes32, error) {
	var b Bytes32
	if err := b.Unstring(src); err != nil {
		return nil, err
	}
	return &b, nil
}

// String returns a hex encoded string.
func (b *Bytes32) String() string {
	return hex.EncodeToString(b[:])
}

// Unstring sets the value from a hex encoded string.
func (b *Bytes32) Unstring(src string) error {
	buf, err := hex.DecodeString(src)
	if err != nil {
		return err
	}
	if n := len(buf); n != Bytes32Size {
		return fmt.Errorf("invalid Bytes32 size got %d want %d", n, Bytes32Size)
	}

	copy(b[:], buf)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (b *Bytes32) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.String())
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (b *Bytes32) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	return b.Unstring(s)
}

// Reverse reverses the bytes order.
func (b *Bytes32) Reverse(rb *ReversedBytes32) {
	for i, v := range b {
		rb[Bytes32Size-i-1] = v
	}
}

// ReversedBytes32 is a 32-byte long byte reversed array.
// While the bytes are reversed, the hex encoded strings are not.
type ReversedBytes32 [Bytes32Size]byte

// NewReversedBytes32FromString creates a ReversedBytes32 from a hex encoded string.
func NewReversedBytes32FromString(src string) (*ReversedBytes32, error) {
	b, err := NewBytes32FromString(src)
	if err != nil {
		return nil, err
	}
	var rb ReversedBytes32
	b.Reverse(&rb)
	return &rb, nil
}

// String returns a hex encoded string.
func (rb *ReversedBytes32) String() string {
	var b Bytes32
	rb.Reverse(&b)
	return b.String()
}

// Unstring sets the value from a hex encoded string.
func (rb *ReversedBytes32) Unstring(src string) error {
	b, err := NewBytes32FromString(src)
	if err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON.
func (rb *ReversedBytes32) MarshalJSON() ([]byte, error) {
	var b Bytes32
	rb.Reverse(&b)
	return b.MarshalJSON()
}

// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON.
func (rb *ReversedBytes32) UnmarshalJSON(data []byte) error {
	var b Bytes32
	if err := json.Unmarshal(data, &b); err != nil {
		return err
	}
	b.Reverse(rb)
	return nil
}

// Reverse reverses the bytes order.
func (rb *ReversedBytes32) Reverse(b *Bytes32) {
	for i, v := range rb {
		b[Bytes32Size-i-1] = v
	}
}
<|endoftext|>


<commit_before><commit_msg>userCurrent for unsupported GOOS<commit_after><|endoftext|>


<commit_before><commit_msg>use sub-task to check getIpfromCIDR<commit_after><|endoftext|>


<commit_before><commit_msg>Test for CopyFile<commit_after><|endoftext|>


<commit_before>package github

import (
	"github.com/stretchr/gomniauth/common"
	"github.com/stretchr/gomniauth/oauth2"
	"github.com/stretchr/stew/objects"
	"net/http"
)

const (
	githubDefaultScope    string = "user"
	githubName            string = "github"
	githubAuthURL         string = "https://github.com/login/oauth/authorize"
	githubTokenURL        string = "https://github.com/login/oauth/access_token"
	githubEndpointProfile string = "https://api.github.com/user"
)

// GithubProvider implements the Provider interface and provides Github
// OAuth2 communication capabilities.
type GithubProvider struct {
	config         *common.Config
	tripperFactory common.TripperFactory
}

func New(clientId, clientSecret, redirectUrl string) *GithubProvider {

	p := new(GithubProvider)
	p.config = &common.Config{objects.M(
		oauth2.OAuth2KeyAuthURL, githubAuthURL,
		oauth2.OAuth2KeyTokenURL, githubTokenURL,
		oauth2.OAuth2KeyClientID, clientId,
		oauth2.OAuth2KeySecret, clientSecret,
		oauth2.OAuth2KeyRedirectUrl, redirectUrl,
		oauth2.OAuth2KeyScope, githubDefaultScope,
		oauth2.OAuth2KeyAccessType, oauth2.OAuth2AccessTypeOnline,
		oauth2.OAuth2KeyApprovalPrompt, oauth2.OAuth2ApprovalPromptAuto)}
	return p
}

// TripperFactory gets an OAuth2TripperFactory
func (provider *GithubProvider) TripperFactory() common.TripperFactory {

	if provider.tripperFactory == nil {
		provider.tripperFactory = new(oauth2.OAuth2TripperFactory)
	}

	return provider.tripperFactory
}

// Name is the unique name for this provider.
func (provider *GithubProvider) Name() string {
	return githubName
}

// GetBeginAuthURL gets the URL that the client must visit in order
// to begin the authentication process.
func (provider *GithubProvider) GetBeginAuthURL(state *common.State) (string, error) {
	return oauth2.GetBeginAuthURLWithBase(provider.config.GetString(oauth2.OAuth2KeyAuthURL), state, provider.config)
}

// Get makes an authenticated request and returns the data in the
// response as a data map.
func (provider *GithubProvider) Get(creds *common.Credentials, endpoint string) (objects.Map, error) {
	return oauth2.Get(provider, creds, endpoint)
}

// GetUser uses the specified common.Credentials to access the users profile
// from the remote provider, and builds the appropriate User object.
func (provider *GithubProvider) GetUser(creds *common.Credentials) (common.User, error) {

	profileData, err := provider.Get(creds, githubEndpointProfile)

	if err != nil {
		return nil, err
	}

	// build user
	user := NewUser(profileData, creds, provider)

	return user, nil
}

// CompleteAuth takes a map of arguments that are used to
// complete the authorisation process, completes it, and returns
// the appropriate Credentials.
func (provider *GithubProvider) CompleteAuth(data objects.Map) (*common.Credentials, error) {
	return oauth2.CompleteAuth(provider.TripperFactory(), data, provider.config, provider)
}

// GetClient returns an authenticated http.Client that can be used to make requests to
// protected Github resources
func (provider *GithubProvider) GetClient(creds *common.Credentials) (*http.Client, error) {
	return oauth2.GetClient(provider.TripperFactory(), creds, provider)
}
<commit_msg>Add response type to github provider<commit_after>package github

import (
	"github.com/stretchr/gomniauth/common"
	"github.com/stretchr/gomniauth/oauth2"
	"github.com/stretchr/stew/objects"
	"net/http"
)

const (
	githubDefaultScope    string = "user"
	githubName            string = "github"
	githubAuthURL         string = "https://github.com/login/oauth/authorize"
	githubTokenURL        string = "https://github.com/login/oauth/access_token"
	githubEndpointProfile string = "https://api.github.com/user"
)

// GithubProvider implements the Provider interface and provides Github
// OAuth2 communication capabilities.
type GithubProvider struct {
	config         *common.Config
	tripperFactory common.TripperFactory
}

func New(clientId, clientSecret, redirectUrl string) *GithubProvider {

	p := new(GithubProvider)
	p.config = &common.Config{objects.M(
		oauth2.OAuth2KeyAuthURL, githubAuthURL,
		oauth2.OAuth2KeyTokenURL, githubTokenURL,
		oauth2.OAuth2KeyClientID, clientId,
		oauth2.OAuth2KeySecret, clientSecret,
		oauth2.OAuth2KeyRedirectUrl, redirectUrl,
		oauth2.OAuth2KeyScope, githubDefaultScope,
		oauth2.OAuth2KeyAccessType, oauth2.OAuth2AccessTypeOnline,
		oauth2.OAuth2KeyApprovalPrompt, oauth2.OAuth2ApprovalPromptAuto,
		oauth2.OAuth2KeyResponseType, oauth2.OAuth2KeyCode)}
	return p
}

// TripperFactory gets an OAuth2TripperFactory
func (provider *GithubProvider) TripperFactory() common.TripperFactory {

	if provider.tripperFactory == nil {
		provider.tripperFactory = new(oauth2.OAuth2TripperFactory)
	}

	return provider.tripperFactory
}

// Name is the unique name for this provider.
func (provider *GithubProvider) Name() string {
	return githubName
}

// GetBeginAuthURL gets the URL that the client must visit in order
// to begin the authentication process.
func (provider *GithubProvider) GetBeginAuthURL(state *common.State) (string, error) {
	return oauth2.GetBeginAuthURLWithBase(provider.config.GetString(oauth2.OAuth2KeyAuthURL), state, provider.config)
}

// Get makes an authenticated request and returns the data in the
// response as a data map.
func (provider *GithubProvider) Get(creds *common.Credentials, endpoint string) (objects.Map, error) {
	return oauth2.Get(provider, creds, endpoint)
}

// GetUser uses the specified common.Credentials to access the users profile
// from the remote provider, and builds the appropriate User object.
func (provider *GithubProvider) GetUser(creds *common.Credentials) (common.User, error) {

	profileData, err := provider.Get(creds, githubEndpointProfile)

	if err != nil {
		return nil, err
	}

	// build user
	user := NewUser(profileData, creds, provider)

	return user, nil
}

// CompleteAuth takes a map of arguments that are used to
// complete the authorisation process, completes it, and returns
// the appropriate Credentials.
func (provider *GithubProvider) CompleteAuth(data objects.Map) (*common.Credentials, error) {
	return oauth2.CompleteAuth(provider.TripperFactory(), data, provider.config, provider)
}

// GetClient returns an authenticated http.Client that can be used to make requests to
// protected Github resources
func (provider *GithubProvider) GetClient(creds *common.Credentials) (*http.Client, error) {
	return oauth2.GetClient(provider.TripperFactory(), creds, provider)
}
<|endoftext|>


<commit_before>package dokodemo

//go:generate errorgen

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/session"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/features/policy"
	"v2ray.com/core/features/routing"
	"v2ray.com/core/transport/internet"
)

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		d := new(DokodemoDoor)
		err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
			return d.Init(config.(*Config), pm)
		})
		return d, err
	}))
}

type DokodemoDoor struct {
	policyManager policy.Manager
	config        *Config
	address       net.Address
	port          net.Port
}

// Init initializes the DokodemoDoor instance with necessary parameters.
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager) error {
	if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
		return newError("no network specified")
	}
	d.config = config
	d.address = config.GetPredefinedAddress()
	d.port = net.Port(config.Port)
	d.policyManager = pm

	return nil
}

// Network implements proxy.Inbound.
func (d *DokodemoDoor) Network() []net.Network {
	if len(d.config.Networks) > 0 {
		return d.config.Networks
	}

	return d.config.NetworkList.Network
}

func (d *DokodemoDoor) policy() policy.Session {
	config := d.config
	p := d.policyManager.ForLevel(config.UserLevel)
	if config.Timeout > 0 && config.UserLevel == 0 {
		p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
	}
	return p
}

type hasHandshakeAddress interface {
	HandshakeAddress() net.Address
}

// Process implements proxy.Inbound.
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
	newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
	dest := net.Destination{
		Network: network,
		Address: d.address,
		Port:    d.port,
	}

	destinationOverridden := false
	if d.config.FollowRedirect {
		if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
			dest = outbound.Target
			destinationOverridden = true
		} else if handshake, ok := conn.(hasHandshakeAddress); ok {
			addr := handshake.HandshakeAddress()
			if addr != nil {
				dest.Address = addr
				destinationOverridden = true
			}
		}
	}
	if !dest.IsValid() || dest.Address == nil {
		return newError("unable to get destination")
	}

	plcy := d.policy()
	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)

	ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
	link, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return newError("failed to dispatch request").Base(err)
	}

	requestDone := func() error {
		defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)

		reader := buf.NewReader(conn)
		if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
			return newError("failed to transport request").Base(err)
		}

		return nil
	}

	var tConn net.Conn
	responseDone := func() error {
		defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)

		var writer buf.Writer
		if network == net.Network_TCP {
			writer = buf.NewWriter(conn)
		} else {
			//if we are in TPROXY mode, use linux's udp forging functionality
			if !destinationOverridden {
				writer = &buf.SequentialWriter{Writer: conn}
			} else {
				sockopt := &internet.SocketConfig{
					Tproxy: internet.SocketConfig_TProxy,
				}
				if dest.Address.Family().IsIP() {
					sockopt.BindAddress = dest.Address.IP()
					sockopt.BindPort = uint32(dest.Port)
				}
				var err error
				tConn, err = internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
				if err != nil {
					return err
				}
				writer = &buf.SequentialWriter{Writer: tConn}
				tReader := buf.NewReader(tConn)
				go func() {
					defer tConn.Close()
					defer common.Close(link.Writer)
					if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
						newError("failed to transport request (TPROXY conn)").Base(err).WriteToLog()
					}
				}()
			}
		}

		defer func() {
			if tConn != nil {
				tConn.Close()
			}
		}()
		if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
			return newError("failed to transport response").Base(err)
		}

		return nil
	}

	if err := task.Run(ctx, task.OnSuccess(requestDone, task.Close(link.Writer)), responseDone); err != nil {
		common.Interrupt(link.Reader)
		common.Interrupt(link.Writer)
		if tConn != nil {
			tConn.Close()
		}
		return newError("connection ends").Base(err)
	}

	return nil
}
<commit_msg>refactor tproxy handling in dokodemo<commit_after>package dokodemo

//go:generate errorgen

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/session"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/features/policy"
	"v2ray.com/core/features/routing"
	"v2ray.com/core/transport/internet"
)

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		d := new(DokodemoDoor)
		err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
			return d.Init(config.(*Config), pm)
		})
		return d, err
	}))
}

type DokodemoDoor struct {
	policyManager policy.Manager
	config        *Config
	address       net.Address
	port          net.Port
}

// Init initializes the DokodemoDoor instance with necessary parameters.
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager) error {
	if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
		return newError("no network specified")
	}
	d.config = config
	d.address = config.GetPredefinedAddress()
	d.port = net.Port(config.Port)
	d.policyManager = pm

	return nil
}

// Network implements proxy.Inbound.
func (d *DokodemoDoor) Network() []net.Network {
	if len(d.config.Networks) > 0 {
		return d.config.Networks
	}

	return d.config.NetworkList.Network
}

func (d *DokodemoDoor) policy() policy.Session {
	config := d.config
	p := d.policyManager.ForLevel(config.UserLevel)
	if config.Timeout > 0 && config.UserLevel == 0 {
		p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
	}
	return p
}

type hasHandshakeAddress interface {
	HandshakeAddress() net.Address
}

// Process implements proxy.Inbound.
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
	newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
	dest := net.Destination{
		Network: network,
		Address: d.address,
		Port:    d.port,
	}

	destinationOverridden := false
	if d.config.FollowRedirect {
		if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
			dest = outbound.Target
			destinationOverridden = true
		} else if handshake, ok := conn.(hasHandshakeAddress); ok {
			addr := handshake.HandshakeAddress()
			if addr != nil {
				dest.Address = addr
				destinationOverridden = true
			}
		}
	}
	if !dest.IsValid() || dest.Address == nil {
		return newError("unable to get destination")
	}

	plcy := d.policy()
	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)

	ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
	link, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return newError("failed to dispatch request").Base(err)
	}

	requestDone := func() error {
		defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)

		reader := buf.NewReader(conn)
		if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
			return newError("failed to transport request").Base(err)
		}

		return nil
	}

	tproxyRequest := func() error {
		return nil
	}

	var writer buf.Writer
	if network == net.Network_TCP {
		writer = buf.NewWriter(conn)
	} else {
		//if we are in TPROXY mode, use linux's udp forging functionality
		if !destinationOverridden {
			writer = &buf.SequentialWriter{Writer: conn}
		} else {
			sockopt := &internet.SocketConfig{
				Tproxy: internet.SocketConfig_TProxy,
			}
			if dest.Address.Family().IsIP() {
				sockopt.BindAddress = dest.Address.IP()
				sockopt.BindPort = uint32(dest.Port)
			}
			tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
			if err != nil {
				return err
			}
			defer tConn.Close()

			writer = &buf.SequentialWriter{Writer: tConn}
			tReader := buf.NewReader(tConn)
			tproxyRequest = func() error {
				if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
					return newError("failed to transport request (TPROXY conn)").Base(err)
				}
				return nil
			}
		}
	}

	responseDone := func() error {
		defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)

		if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
			return newError("failed to transport response").Base(err)
		}
		return nil
	}

	if err := task.Run(ctx, task.OnSuccess(requestDone, task.Close(link.Writer)), responseDone, tproxyRequest); err != nil {
		common.Interrupt(link.Reader)
		common.Interrupt(link.Writer)
		return newError("connection ends").Base(err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/cloudfoundry/cli/plugin"
	"github.com/krujos/usagereport-plugin/apihelper"
	"github.com/krujos/usagereport-plugin/models"
)

//UsageReportCmd the plugin
type UsageReportCmd struct {
	apiHelper apihelper.CFAPIHelper
}

// contains CLI flag values
type flagVal struct {
	OrgName string
	Format  string
}

func ParseFlags(args []string) flagVal {
	flagSet := flag.NewFlagSet(args[0], flag.ContinueOnError)

	// Create flags
	orgName := flagSet.String("o", "", "-o orgName")
	format := flagSet.String("f", "format", "-f <csv> / -f <json>")

	err := flagSet.Parse(args[1:])
	if err != nil {

	}

	return flagVal{
		OrgName: string(*orgName),
		Format:  string(*format),
	}
}

//GetMetadata returns metatada
func (cmd *UsageReportCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "usage-report",
		Version: plugin.VersionType{
			Major: 1,
			Minor: 4,
			Build: 1,
		},
		Commands: []plugin.Command{
			{
				Name:     "usage-report",
				HelpText: "Report AI and memory usage for orgs and spaces",
				UsageDetails: plugin.Usage{
					Usage: "cf usage-report [-o orgName] [-f <csv>] [-f <json>]",
					Options: map[string]string{
						"o": "organization",
						"f": "format",
					},
				},
			},
		},
	}
}

//UsageReportCommand doer
func (cmd *UsageReportCmd) UsageReportCommand(args []string) {
	flagVals := ParseFlags(args)

	var orgs []models.Org
	var err error
	var report models.Report

	if flagVals.OrgName != "" {
		org, err := cmd.getOrg(flagVals.OrgName)
		if nil != err {
			fmt.Println(err)
			os.Exit(1)
		}
		orgs = append(orgs, org)
	} else {
		orgs, err = cmd.getOrgs()
		if nil != err {
			fmt.Println(err)
			os.Exit(1)
		}
	}

	report.Orgs = orgs

	if flagVals.Format == "csv" {
		fmt.Println(report.CSV())
	} else 	if flagVals.Format == "json" {
		fmt.Println(report.JSON())
	} else {
		fmt.Println(report.String())
	}
}

func (cmd *UsageReportCmd) getOrgs() ([]models.Org, error) {
	rawOrgs, err := cmd.apiHelper.GetOrgs()
	if nil != err {
		return nil, err
	}

	var orgs = []models.Org{}

	for _, o := range rawOrgs {
		orgDetails, err := cmd.getOrgDetails(o)
		if err != nil {
			return nil, err
		}
		orgs = append(orgs, orgDetails)
	}
	return orgs, nil
}

func (cmd *UsageReportCmd) getOrg(name string) (models.Org, error) {
	rawOrg, err := cmd.apiHelper.GetOrg(name)
	if nil != err {
		return models.Org{}, err
	}

	return cmd.getOrgDetails(rawOrg)
}

func (cmd *UsageReportCmd) getOrgDetails(o apihelper.Organization) (models.Org, error) {
	usage, err := cmd.apiHelper.GetOrgMemoryUsage(o)
	if nil != err {
		return models.Org{}, err
	}
	quota, err := cmd.apiHelper.GetQuotaMemoryLimit(o.QuotaURL)
	if nil != err {
		return models.Org{}, err
	}
	spaces, err := cmd.getSpaces(o.SpacesURL)
	if nil != err {
		return models.Org{}, err
	}

	return models.Org{
		Name:        o.Name,
		MemoryQuota: int(quota),
		MemoryUsage: int(usage),
		Spaces:      spaces,
	}, nil
}

func (cmd *UsageReportCmd) getSpaces(spaceURL string) ([]models.Space, error) {
	rawSpaces, err := cmd.apiHelper.GetOrgSpaces(spaceURL)
	if nil != err {
		return nil, err
	}
	var spaces = []models.Space{}
	for _, s := range rawSpaces {
		apps, err := cmd.getApps(s.AppsURL)
		if nil != err {
			return nil, err
		}

		var quota apihelper.Quota
		quota.RAM = -1;
		quota.Name = "none";
		if s.SpaceQuotaURL != "" {
			quota, err = cmd.apiHelper.GetQuotaPlan(s.SpaceQuotaURL)
			if nil != err {
				return nil, err
			}
		}

		var usage = cmd.getAllotedMem(apps)
		spaces = append(spaces,
			models.Space{
				Apps: apps,
				Name: s.Name,
				MemoryQuota: int(quota.RAM),
				QuotaPlan: quota.Name,
				MemoryUsage: int(usage),
			},
		)
	}
	return spaces, nil
}

func (cmd *UsageReportCmd) getApps(appsURL string) ([]models.App, error) {
	rawApps, err := cmd.apiHelper.GetSpaceApps(appsURL)
	if nil != err {
		return nil, err
	}
	var apps = []models.App{}
	for _, a := range rawApps {
		apps = append(apps, models.App{
			Name:      a.Name,
			Instances: int(a.Instances),
			Ram:       int(a.RAM),
			Running:   a.Running,
		})
	}
	return apps, nil
}

//Run runs the plugin
func (cmd *UsageReportCmd) Run(cli plugin.CliConnection, args []string) {
	if args[0] == "usage-report" {
		cmd.apiHelper = apihelper.New(cli)
		cmd.UsageReportCommand(args)
	}
}

func main() {
	plugin.Start(new(UsageReportCmd))
}

func (cmd *UsageReportCmd) getAllotedMem(apps []models.App) (int) {
	var memUsed = 0
	for _, a := range apps {
		memUsed += int(a.Instances * a.Ram)
	}
	return memUsed
}<commit_msg>corrected default value of quotaplan<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/cloudfoundry/cli/plugin"
	"github.com/krujos/usagereport-plugin/apihelper"
	"github.com/krujos/usagereport-plugin/models"
)

//UsageReportCmd the plugin
type UsageReportCmd struct {
	apiHelper apihelper.CFAPIHelper
}

// contains CLI flag values
type flagVal struct {
	OrgName string
	Format  string
}

func ParseFlags(args []string) flagVal {
	flagSet := flag.NewFlagSet(args[0], flag.ContinueOnError)

	// Create flags
	orgName := flagSet.String("o", "", "-o orgName")
	format := flagSet.String("f", "format", "-f <csv> / -f <json>")

	err := flagSet.Parse(args[1:])
	if err != nil {

	}

	return flagVal{
		OrgName: string(*orgName),
		Format:  string(*format),
	}
}

//GetMetadata returns metatada
func (cmd *UsageReportCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "usage-report",
		Version: plugin.VersionType{
			Major: 1,
			Minor: 4,
			Build: 1,
		},
		Commands: []plugin.Command{
			{
				Name:     "usage-report",
				HelpText: "Report AI and memory usage for orgs and spaces",
				UsageDetails: plugin.Usage{
					Usage: "cf usage-report [-o orgName] [-f <csv>] [-f <json>]",
					Options: map[string]string{
						"o": "organization",
						"f": "format",
					},
				},
			},
		},
	}
}

//UsageReportCommand doer
func (cmd *UsageReportCmd) UsageReportCommand(args []string) {
	flagVals := ParseFlags(args)

	var orgs []models.Org
	var err error
	var report models.Report

	if flagVals.OrgName != "" {
		org, err := cmd.getOrg(flagVals.OrgName)
		if nil != err {
			fmt.Println(err)
			os.Exit(1)
		}
		orgs = append(orgs, org)
	} else {
		orgs, err = cmd.getOrgs()
		if nil != err {
			fmt.Println(err)
			os.Exit(1)
		}
	}

	report.Orgs = orgs

	if flagVals.Format == "csv" {
		fmt.Println(report.CSV())
	} else 	if flagVals.Format == "json" {
		fmt.Println(report.JSON())
	} else {
		fmt.Println(report.String())
	}
}

func (cmd *UsageReportCmd) getOrgs() ([]models.Org, error) {
	rawOrgs, err := cmd.apiHelper.GetOrgs()
	if nil != err {
		return nil, err
	}

	var orgs = []models.Org{}

	for _, o := range rawOrgs {
		orgDetails, err := cmd.getOrgDetails(o)
		if err != nil {
			return nil, err
		}
		orgs = append(orgs, orgDetails)
	}
	return orgs, nil
}

func (cmd *UsageReportCmd) getOrg(name string) (models.Org, error) {
	rawOrg, err := cmd.apiHelper.GetOrg(name)
	if nil != err {
		return models.Org{}, err
	}

	return cmd.getOrgDetails(rawOrg)
}

func (cmd *UsageReportCmd) getOrgDetails(o apihelper.Organization) (models.Org, error) {
	usage, err := cmd.apiHelper.GetOrgMemoryUsage(o)
	if nil != err {
		return models.Org{}, err
	}
	quota, err := cmd.apiHelper.GetQuotaMemoryLimit(o.QuotaURL)
	if nil != err {
		return models.Org{}, err
	}
	spaces, err := cmd.getSpaces(o.SpacesURL)
	if nil != err {
		return models.Org{}, err
	}

	return models.Org{
		Name:        o.Name,
		MemoryQuota: int(quota),
		MemoryUsage: int(usage),
		Spaces:      spaces,
	}, nil
}

func (cmd *UsageReportCmd) getSpaces(spaceURL string) ([]models.Space, error) {
	rawSpaces, err := cmd.apiHelper.GetOrgSpaces(spaceURL)
	if nil != err {
		return nil, err
	}
	var spaces = []models.Space{}
	for _, s := range rawSpaces {
		apps, err := cmd.getApps(s.AppsURL)
		if nil != err {
			return nil, err
		}

		var quota apihelper.Quota
		quota.RAM = -1;
		quota.Name = "";
		if s.SpaceQuotaURL != "" {
			quota, err = cmd.apiHelper.GetQuotaPlan(s.SpaceQuotaURL)
			if nil != err {
				return nil, err
			}
		}

		var usage = cmd.getAllotedMem(apps)
		spaces = append(spaces,
			models.Space{
				Apps: apps,
				Name: s.Name,
				MemoryQuota: int(quota.RAM),
				QuotaPlan: quota.Name,
				MemoryUsage: int(usage),
			},
		)
	}
	return spaces, nil
}

func (cmd *UsageReportCmd) getApps(appsURL string) ([]models.App, error) {
	rawApps, err := cmd.apiHelper.GetSpaceApps(appsURL)
	if nil != err {
		return nil, err
	}
	var apps = []models.App{}
	for _, a := range rawApps {
		apps = append(apps, models.App{
			Name:      a.Name,
			Instances: int(a.Instances),
			Ram:       int(a.RAM),
			Running:   a.Running,
		})
	}
	return apps, nil
}

//Run runs the plugin
func (cmd *UsageReportCmd) Run(cli plugin.CliConnection, args []string) {
	if args[0] == "usage-report" {
		cmd.apiHelper = apihelper.New(cli)
		cmd.UsageReportCommand(args)
	}
}

func main() {
	plugin.Start(new(UsageReportCmd))
}

func (cmd *UsageReportCmd) getAllotedMem(apps []models.App) (int) {
	var memUsed = 0
	for _, a := range apps {
		memUsed += int(a.Instances * a.Ram)
	}
	return memUsed
}<|endoftext|>


<commit_before>/* this is blockchain technology.  Well, except without the blocks.
Really it's header chain technology.
The blocks themselves don't really make a chain.  Just the headers do.
*/

package uspv

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"math/big"
	"os"

	"github.com/adiabat/btcd/blockchain"

	"github.com/adiabat/btcd/wire"
	"github.com/mit-dci/lit/coinparam"
)

// checkProofOfWork verifies the header hashes into something
// lower than specified by the 4-byte bits field.
func checkProofOfWork(header wire.BlockHeader, p *coinparam.Params) bool {

	target := blockchain.CompactToBig(header.Bits)

	// The target must more than 0.  Why can you even encode negative...
	if target.Sign() <= 0 {
		log.Printf("block target %064x is neagtive(??)\n", target.Bytes())
		return false
	}
	// The target must be less than the maximum allowed (difficulty 1)
	if target.Cmp(p.PowLimit) > 0 {
		log.Printf("block target %064x is "+
			"higher than max of %064x", target, p.PowLimit.Bytes())
		return false
	}

	// The header hash must be less than the claimed target in the header.
	var buf bytes.Buffer
	_ = wire.WriteBlockHeader(&buf, 0, &header)

	blockHash := p.PoWFunction(buf.Bytes())

	hashNum := new(big.Int)

	hashNum = blockchain.HashToBig(&blockHash)
	if hashNum.Cmp(target) > 0 {
		log.Printf("block hash %064x is higher than "+
			"required target of %064x", hashNum, target)
		return false
	}
	return true
}

// GetHeaderAtHeight gives back a header at the specified height
func (s *SPVCon) GetHeaderAtHeight(h int32) (*wire.BlockHeader, error) {
	s.headerMutex.Lock()
	defer s.headerMutex.Unlock()

	// height is reduced by startHeight
	h = h - s.Param.StartHeight

	// seek to that header
	_, err := s.headerFile.Seek(int64(80*h), os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	hdr := new(wire.BlockHeader)
	err = hdr.Deserialize(s.headerFile)
	if err != nil {
		return nil, err
	}

	return hdr, nil
}

// GetHeaderAtHeight gives back a header at the specified height
func (s *SPVCon) GetHeaderTipHeight() int32 {
	s.headerMutex.Lock() // start header file ops
	defer s.headerMutex.Unlock()
	info, err := s.headerFile.Stat()
	if err != nil {
		log.Printf("Header file error: %s", err.Error())
		return 0
	}
	headerFileSize := info.Size()
	if headerFileSize == 0 || headerFileSize%80 != 0 { // header file broken
		// try to fix it!
		s.headerFile.Truncate(headerFileSize - (headerFileSize % 80))
		log.Printf("ERROR: Header file not a multiple of 80 bytes. Truncating")
	}
	// subtract 1 as we want the start of the tip offset, not the end
	return int32(headerFileSize/80) + s.Param.StartHeight - 1
}

// FindHeader will try to find where the header you give it is.
// it runs backwards to find it and gives up after 1000 headers
func FindHeader(r io.ReadSeeker, hdr wire.BlockHeader) (int32, error) {

	var cur wire.BlockHeader

	for tries := 1; tries < 2200; tries++ {
		offset, err := r.Seek(int64(-80*tries), os.SEEK_END)
		if err != nil {
			return -1, err
		}

		//	for blkhash.IsEqual(&target) {
		err = cur.Deserialize(r)
		if err != nil {
			return -1, err
		}
		curhash := cur.BlockHash()

		//		fmt.Printf("try %d %s\n", tries, curhash.String())

		if hdr.PrevBlock.IsEqual(&curhash) {
			return int32(offset / 80), nil
		}
	}

	return 0, nil
}

// CheckHeaderChain takes in the headers message and sees if they all validate.
// This function also needs read access to the previous headers.
// Does not deal with re-orgs; assumes new headers link to tip
// returns true if *all* headers are cool, false if there is any problem
// Note we don't know what the height is, just the relative height.
// returnin nil means it worked
// returns an int32 usually 0, but if there's a reorg, shows what height to
// reorg back to before adding on the headers
func CheckHeaderChain(
	r io.ReadSeeker, inHeaders []*wire.BlockHeader,
	p *coinparam.Params) (int32, error) {

	// make sure we actually got new headers
	if len(inHeaders) < 1 {
		return 0, fmt.Errorf(
			"CheckHeaderChain: headers message doesn't have any headers.")
	}

	// first, look through all the incoming headers to make sure
	// they're at least self-consistent.  Do this before even
	// checking that they link to anything; it's all in-ram and quick
	for i, hdr := range inHeaders {
		// check they link to each other
		// That whole 'blockchain' thing.
		if i > 1 {
			hash := inHeaders[i-1].BlockHash()
			if !hdr.PrevBlock.IsEqual(&hash) {
				return 0, fmt.Errorf(
					"headers %d and %d in header message don't link", i, i-1)
			}
		}
		// check if there's a valid proof of work.  That whole "Bitcoin" thing.
		if !checkProofOfWork(*hdr, p) {
			return 0, fmt.Errorf("header %d in message has bad proof of work", i)
		}

		// check that header version is non-negative (fork detect)
		if hdr.Version < 0 {
			return 0, fmt.Errorf(
				"header %d in message has negative version (hard fork?)", i)
		}

	}
	// incoming header message is internally consistent, now check that it
	// links with what we have on disk

	epochLength := int32(p.TargetTimespan / p.TargetTimePerBlock)

	// seek to start of last header
	pos, err := r.Seek(-80, os.SEEK_END)
	if err != nil {
		return 0, err
	}
	log.Printf("header file position: %d\n", pos)
	if pos%80 != 0 {
		return 0, fmt.Errorf(
			"CheckHeaderChain: Header file not a multiple of 80 bytes.")
	}

	// we know incoming height; it's startheight + all the headers on disk + 1
	height := int32(pos/80) + p.StartHeight + 1

	// see if we don't have enough & load em all.
	var numheaders int32 // number of headers to read

	// load only last epoch if there are a lot on disk
	if pos > int64(80*(epochLength+1)) {
		_, err = r.Seek(int64(-80*(epochLength+1)), os.SEEK_END)
		numheaders = epochLength + 1
	} else { // otherwise load everything, start at byte 0
		_, err = r.Seek(0, os.SEEK_SET)
		numheaders = height - p.StartHeight
	}
	if err != nil { // seems like it will always be ok here..?
		return 0, err
	}

	// weird off-by-1 stuff here; makes numheaders, incluing the 0th
	oldHeaders := make([]*wire.BlockHeader, numheaders)
	log.Printf("made %d header slice\n", len(oldHeaders))
	// load a bunch of headers from disk into ram
	for i, _ := range oldHeaders {
		// read from file at current offset
		oldHeaders[i] = new(wire.BlockHeader)
		err = oldHeaders[i].Deserialize(r)
		if err != nil {
			log.Printf("CheckHeaderChain ran out of file at oldheader %d\n", i)
			return 0, err
		}
	}

	tiphash := oldHeaders[len(oldHeaders)-1].BlockHash()

	var attachHeight int32
	// make sure the first header in the message points to our on-disk tip
	if !inHeaders[0].PrevBlock.IsEqual(&tiphash) {

		// find where it points to

		attachHeight, err = FindHeader(r, *inHeaders[0])
		if err != nil {
			return 0, fmt.Errorf(
				"CheckHeaderChain: header message doesn't attach to tip or anywhere.")
		}

		log.Printf("Header %s attaches at height %d\n",
			inHeaders[0].BlockHash().String(), attachHeight)

		// TODO check for more work here instead of length.  This is wrong...
		// if we've been given insufficient headers, don't reorg, but
		// ask for more headers.
		if attachHeight+int32(len(inHeaders)) < height {
			return -1, fmt.Errorf(
				"reorg message up to height %d, but have up to %d",
				attachHeight+int32(len(inHeaders)), height-1)
		}

		log.Printf("reorg from height %d to %d",
			height-1, attachHeight+int32(len(inHeaders)))

		// reorg is go, snip to attach height
		reorgDepth := height - attachHeight
		oldHeaders = oldHeaders[:numheaders-reorgDepth]
	}

	prevHeaders := oldHeaders

	// check difficulty adjustments in the new headers
	// since we call this many times, append each time
	for i, hdr := range inHeaders {
		// build slice of "previous" headers
		prevHeaders = append(prevHeaders, inHeaders[i])
		rightBits, err := p.DiffCalcFunction(prevHeaders, height+int32(i), p)
		if err != nil {
			return 0, fmt.Errorf("Error calculating Block %d %s difficuly. %s",
				int(height)+i, hdr.BlockHash().String(), err.Error())
		}

		if hdr.Bits != rightBits {
			return 0, fmt.Errorf("Block %d %s incorrect difficuly.  Read %x, expect %x",
				int(height)+i, hdr.BlockHash().String(), hdr.Bits, rightBits)
		}
	}

	return attachHeight, nil
}

func CheckHeader(r io.ReadSeeker, height, startheight int32, p *coinparam.Params) bool {
	// startHeight is the height the file starts at
	// header start must be 0 mod 2106
	var err error
	var cur, prev wire.BlockHeader
	// don't try to verfy the genesis block.  That way madness lies.
	if height == 0 {
		return true
	}

	offsetHeight := height - startheight
	// initial load of headers

	// load previous and current.

	// seek to n-1 header
	_, err = r.Seek(int64(80*(offsetHeight-1)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	// read in n-1
	err = prev.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	// seek to curHeight header and read in
	_, err = r.Seek(int64(80*(offsetHeight)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	err = cur.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	// get hash of n-1 header
	prevHash := prev.BlockHash()
	// check if headers link together.  That whole 'blockchain' thing.
	if prevHash.IsEqual(&cur.PrevBlock) == false {
		log.Printf("Headers %d and %d don't link.\n",
			height-1, height)
		log.Printf("%s - %s",
			prev.BlockHash().String(), cur.BlockHash().String())
		return false
	}

	// Check that the difficulty bits are correct
	if offsetHeight > 0 && height >= p.AssumeDiffBefore {
		//		rightBits, err := p.DiffCalcFunction(r, height, startheight, p)
		rightBits, err := p.DiffCalcFunction(nil, height, p)
		if err != nil {
			log.Printf("Error calculating Block %d %s difficuly. %s\n",
				height, cur.BlockHash().String(), err.Error())
			return false
		}

		if cur.Bits != rightBits {
			log.Printf("Block %d %s incorrect difficuly.  Read %x, expect %x\n",
				height, cur.BlockHash().String(), cur.Bits, rightBits)
			return false
		}
	}

	// check if there's a valid proof of work.  That whole "Bitcoin" thing.
	if !checkProofOfWork(cur, p) {
		log.Printf("Block %d Bad proof of work.\n", height)
		return false
	}

	// Check for checkpoints
	for _, checkpoint := range p.Checkpoints {
		if checkpoint.Height == height {
			if *checkpoint.Hash != cur.BlockHash() {
				log.Printf("Block %d is not a valid checkpoint", height)
				return false
			}
			break
		}
	}

	// Not entirely sure why I need to do this, but otherwise the tip block
	// can go missing
	_, err = r.Seek(int64(80*(offsetHeight)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	err = cur.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	return true // it must have worked if there's no errors and got to the end.
}

/* checkrange verifies a range of headers.  it checks their proof of work,
difficulty adjustments, and that they all link in to each other properly.
This is the only blockchain technology in the whole code base.
Returns false if anything bad happens.  Returns true if the range checks
out with no errors. */
func CheckRange(r io.ReadSeeker, first, last, startHeight int32, p *coinparam.Params) bool {
	for i := first; i <= last; i++ {
		if !CheckHeader(r, i, startHeight, p) {
			return false
		}
	}
	return true // all good.
}
<commit_msg>make reorgs work with startHeight param<commit_after>/* this is blockchain technology.  Well, except without the blocks.
Really it's header chain technology.
The blocks themselves don't really make a chain.  Just the headers do.
*/

package uspv

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"math/big"
	"os"

	"github.com/adiabat/btcd/blockchain"

	"github.com/adiabat/btcd/wire"
	"github.com/mit-dci/lit/coinparam"
)

// checkProofOfWork verifies the header hashes into something
// lower than specified by the 4-byte bits field.
func checkProofOfWork(header wire.BlockHeader, p *coinparam.Params) bool {

	target := blockchain.CompactToBig(header.Bits)

	// The target must more than 0.  Why can you even encode negative...
	if target.Sign() <= 0 {
		log.Printf("block target %064x is neagtive(??)\n", target.Bytes())
		return false
	}
	// The target must be less than the maximum allowed (difficulty 1)
	if target.Cmp(p.PowLimit) > 0 {
		log.Printf("block target %064x is "+
			"higher than max of %064x", target, p.PowLimit.Bytes())
		return false
	}

	// The header hash must be less than the claimed target in the header.
	var buf bytes.Buffer
	_ = wire.WriteBlockHeader(&buf, 0, &header)

	blockHash := p.PoWFunction(buf.Bytes())

	hashNum := new(big.Int)

	hashNum = blockchain.HashToBig(&blockHash)
	if hashNum.Cmp(target) > 0 {
		log.Printf("block hash %064x is higher than "+
			"required target of %064x", hashNum, target)
		return false
	}
	return true
}

// GetHeaderAtHeight gives back a header at the specified height
func (s *SPVCon) GetHeaderAtHeight(h int32) (*wire.BlockHeader, error) {
	s.headerMutex.Lock()
	defer s.headerMutex.Unlock()

	// height is reduced by startHeight
	h = h - s.Param.StartHeight

	// seek to that header
	_, err := s.headerFile.Seek(int64(80*h), os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	hdr := new(wire.BlockHeader)
	err = hdr.Deserialize(s.headerFile)
	if err != nil {
		return nil, err
	}

	return hdr, nil
}

// GetHeaderAtHeight gives back a header at the specified height
func (s *SPVCon) GetHeaderTipHeight() int32 {
	s.headerMutex.Lock() // start header file ops
	defer s.headerMutex.Unlock()
	info, err := s.headerFile.Stat()
	if err != nil {
		log.Printf("Header file error: %s", err.Error())
		return 0
	}
	headerFileSize := info.Size()
	if headerFileSize == 0 || headerFileSize%80 != 0 { // header file broken
		// try to fix it!
		s.headerFile.Truncate(headerFileSize - (headerFileSize % 80))
		log.Printf("ERROR: Header file not a multiple of 80 bytes. Truncating")
	}
	// subtract 1 as we want the start of the tip offset, not the end
	return int32(headerFileSize/80) + s.Param.StartHeight - 1
}

// FindHeader will try to find where the header you give it is.
// it runs backwards to find it and gives up after 1000 headers
func FindHeader(r io.ReadSeeker, hdr wire.BlockHeader) (int32, error) {

	var cur wire.BlockHeader

	for tries := 1; tries < 2200; tries++ {
		offset, err := r.Seek(int64(-80*tries), os.SEEK_END)
		if err != nil {
			return -1, err
		}

		//	for blkhash.IsEqual(&target) {
		err = cur.Deserialize(r)
		if err != nil {
			return -1, err
		}
		curhash := cur.BlockHash()

		//		fmt.Printf("try %d %s\n", tries, curhash.String())

		if hdr.PrevBlock.IsEqual(&curhash) {
			return int32(offset / 80), nil
		}
	}

	return 0, nil
}

// CheckHeaderChain takes in the headers message and sees if they all validate.
// This function also needs read access to the previous headers.
// Does not deal with re-orgs; assumes new headers link to tip
// returns true if *all* headers are cool, false if there is any problem
// Note we don't know what the height is, just the relative height.
// returnin nil means it worked
// returns an int32 usually 0, but if there's a reorg, shows what height to
// reorg back to before adding on the headers
func CheckHeaderChain(
	r io.ReadSeeker, inHeaders []*wire.BlockHeader,
	p *coinparam.Params) (int32, error) {

	// make sure we actually got new headers
	if len(inHeaders) < 1 {
		return 0, fmt.Errorf(
			"CheckHeaderChain: headers message doesn't have any headers.")
	}

	// first, look through all the incoming headers to make sure
	// they're at least self-consistent.  Do this before even
	// checking that they link to anything; it's all in-ram and quick
	for i, hdr := range inHeaders {
		// check they link to each other
		// That whole 'blockchain' thing.
		if i > 1 {
			hash := inHeaders[i-1].BlockHash()
			if !hdr.PrevBlock.IsEqual(&hash) {
				return 0, fmt.Errorf(
					"headers %d and %d in header message don't link", i, i-1)
			}
		}
		// check if there's a valid proof of work.  That whole "Bitcoin" thing.
		if !checkProofOfWork(*hdr, p) {
			return 0, fmt.Errorf("header %d in message has bad proof of work", i)
		}

		// check that header version is non-negative (fork detect)
		if hdr.Version < 0 {
			return 0, fmt.Errorf(
				"header %d in message has negative version (hard fork?)", i)
		}

	}
	// incoming header message is internally consistent, now check that it
	// links with what we have on disk

	epochLength := int32(p.TargetTimespan / p.TargetTimePerBlock)

	// seek to start of last header
	pos, err := r.Seek(-80, os.SEEK_END)
	if err != nil {
		return 0, err
	}
	log.Printf("header file position: %d\n", pos)
	if pos%80 != 0 {
		return 0, fmt.Errorf(
			"CheckHeaderChain: Header file not a multiple of 80 bytes.")
	}

	// we know incoming height; it's startheight + all the headers on disk + 1
	height := int32(pos/80) + p.StartHeight + 1

	// see if we don't have enough & load em all.
	var numheaders int32 // number of headers to read

	// load only last epoch if there are a lot on disk
	if pos > int64(80*(epochLength+1)) {
		_, err = r.Seek(int64(-80*(epochLength+1)), os.SEEK_END)
		numheaders = epochLength + 1
	} else { // otherwise load everything, start at byte 0
		_, err = r.Seek(0, os.SEEK_SET)
		numheaders = height - p.StartHeight
	}
	if err != nil { // seems like it will always be ok here..?
		return 0, err
	}

	// weird off-by-1 stuff here; makes numheaders, incluing the 0th
	oldHeaders := make([]*wire.BlockHeader, numheaders)
	log.Printf("made %d header slice\n", len(oldHeaders))
	// load a bunch of headers from disk into ram
	for i, _ := range oldHeaders {
		// read from file at current offset
		oldHeaders[i] = new(wire.BlockHeader)
		err = oldHeaders[i].Deserialize(r)
		if err != nil {
			log.Printf("CheckHeaderChain ran out of file at oldheader %d\n", i)
			return 0, err
		}
	}

	tiphash := oldHeaders[len(oldHeaders)-1].BlockHash()

	var attachHeight int32
	// make sure the first header in the message points to our on-disk tip
	if !inHeaders[0].PrevBlock.IsEqual(&tiphash) {

		// find where it points to

		attachHeight, err = FindHeader(r, *inHeaders[0])
		if err != nil {
			return 0, fmt.Errorf(
				"CheckHeaderChain: header message doesn't attach to tip or anywhere.")
		}

		// adjust attachHeight by adding the startheight
		attachHeight += p.StartHeight

		log.Printf("Header %s attaches at height %d\n",
			inHeaders[0].BlockHash().String(), attachHeight)

		// TODO check for more work here instead of length.  This is wrong...
		// if we've been given insufficient headers, don't reorg, but
		// ask for more headers.
		if attachHeight+int32(len(inHeaders)) < height {
			return -1, fmt.Errorf(
				"reorg message up to height %d, but have up to %d",
				attachHeight+int32(len(inHeaders)), height-1)
		}

		log.Printf("reorg from height %d to %d",
			height-1, attachHeight+int32(len(inHeaders)))

		// reorg is go, snip to attach height
		reorgDepth := height - attachHeight
		oldHeaders = oldHeaders[:numheaders-reorgDepth]
	}

	prevHeaders := oldHeaders

	// check difficulty adjustments in the new headers
	// since we call this many times, append each time
	for i, hdr := range inHeaders {
		// build slice of "previous" headers
		prevHeaders = append(prevHeaders, inHeaders[i])
		rightBits, err := p.DiffCalcFunction(prevHeaders, height+int32(i), p)
		if err != nil {
			return 0, fmt.Errorf("Error calculating Block %d %s difficuly. %s",
				int(height)+i, hdr.BlockHash().String(), err.Error())
		}

		if hdr.Bits != rightBits {
			return 0, fmt.Errorf("Block %d %s incorrect difficuly.  Read %x, expect %x",
				int(height)+i, hdr.BlockHash().String(), hdr.Bits, rightBits)
		}
	}

	return attachHeight, nil
}

func CheckHeader(r io.ReadSeeker, height, startheight int32, p *coinparam.Params) bool {
	// startHeight is the height the file starts at
	// header start must be 0 mod 2106
	var err error
	var cur, prev wire.BlockHeader
	// don't try to verfy the genesis block.  That way madness lies.
	if height == 0 {
		return true
	}

	offsetHeight := height - startheight
	// initial load of headers

	// load previous and current.

	// seek to n-1 header
	_, err = r.Seek(int64(80*(offsetHeight-1)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	// read in n-1
	err = prev.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	// seek to curHeight header and read in
	_, err = r.Seek(int64(80*(offsetHeight)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	err = cur.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	// get hash of n-1 header
	prevHash := prev.BlockHash()
	// check if headers link together.  That whole 'blockchain' thing.
	if prevHash.IsEqual(&cur.PrevBlock) == false {
		log.Printf("Headers %d and %d don't link.\n",
			height-1, height)
		log.Printf("%s - %s",
			prev.BlockHash().String(), cur.BlockHash().String())
		return false
	}

	// Check that the difficulty bits are correct
	if offsetHeight > 0 && height >= p.AssumeDiffBefore {
		//		rightBits, err := p.DiffCalcFunction(r, height, startheight, p)
		rightBits, err := p.DiffCalcFunction(nil, height, p)
		if err != nil {
			log.Printf("Error calculating Block %d %s difficuly. %s\n",
				height, cur.BlockHash().String(), err.Error())
			return false
		}

		if cur.Bits != rightBits {
			log.Printf("Block %d %s incorrect difficuly.  Read %x, expect %x\n",
				height, cur.BlockHash().String(), cur.Bits, rightBits)
			return false
		}
	}

	// check if there's a valid proof of work.  That whole "Bitcoin" thing.
	if !checkProofOfWork(cur, p) {
		log.Printf("Block %d Bad proof of work.\n", height)
		return false
	}

	// Check for checkpoints
	for _, checkpoint := range p.Checkpoints {
		if checkpoint.Height == height {
			if *checkpoint.Hash != cur.BlockHash() {
				log.Printf("Block %d is not a valid checkpoint", height)
				return false
			}
			break
		}
	}

	// Not entirely sure why I need to do this, but otherwise the tip block
	// can go missing
	_, err = r.Seek(int64(80*(offsetHeight)), os.SEEK_SET)
	if err != nil {
		log.Printf(err.Error())
		return false
	}
	err = cur.Deserialize(r)
	if err != nil {
		log.Printf(err.Error())
		return false
	}

	return true // it must have worked if there's no errors and got to the end.
}

/* checkrange verifies a range of headers.  it checks their proof of work,
difficulty adjustments, and that they all link in to each other properly.
This is the only blockchain technology in the whole code base.
Returns false if anything bad happens.  Returns true if the range checks
out with no errors. */
func CheckRange(r io.ReadSeeker, first, last, startHeight int32, p *coinparam.Params) bool {
	for i := first; i <= last; i++ {
		if !CheckHeader(r, i, startHeight, p) {
			return false
		}
	}
	return true // all good.
}
<|endoftext|>