<commit_before>// Copyright 2017-2021 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package systems

import (
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"runtime"
	"sort"
	"sync"
	"time"

	"github.com/OWASP/Amass/v3/config"
	"github.com/OWASP/Amass/v3/limits"
	amassnet "github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/caffix/netmap"
	"github.com/caffix/resolve"
	"github.com/caffix/service"
)

// LocalSystem implements a System to be executed within a single process.
type LocalSystem struct {
	Cfg               *config.Config
	pool              resolve.Resolver
	graphs            []*netmap.Graph
	cache             *requests.ASNCache
	done              chan struct{}
	doneAlreadyClosed bool
	addSource         chan service.Service
	allSources        chan chan []service.Service
}

// NewLocalSystem returns an initialized LocalSystem object.
func NewLocalSystem(c *config.Config) (*LocalSystem, error) {
	if err := c.CheckSettings(); err != nil {
		return nil, err
	}

	max := int(float64(limits.GetFileLimit()) * 0.7)

	var pool resolve.Resolver
	if len(c.Resolvers) == 0 {
		pool = publicResolverSetup(c, max)
	} else {
		pool = customResolverSetup(c, max)
	}
	if pool == nil {
		return nil, errors.New("The system was unable to build the pool of resolvers")
	}

	sys := &LocalSystem{
		Cfg:        c,
		pool:       pool,
		cache:      requests.NewASNCache(),
		done:       make(chan struct{}, 2),
		addSource:  make(chan service.Service),
		allSources: make(chan chan []service.Service, 10),
	}

	// Load the ASN information into the cache
	if err := sys.loadCacheData(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}
	// Make sure that the output directory is setup for this local system
	if err := sys.setupOutputDirectory(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}
	// Setup the correct graph database handler
	if err := sys.setupGraphDBs(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}

	go sys.manageDataSources()
	return sys, nil
}

// Config implements the System interface.
func (l *LocalSystem) Config() *config.Config {
	return l.Cfg
}

// Pool implements the System interface.
func (l *LocalSystem) Pool() resolve.Resolver {
	return l.pool
}

// Cache implements the System interface.
func (l *LocalSystem) Cache() *requests.ASNCache {
	return l.cache
}

// AddSource implements the System interface.
func (l *LocalSystem) AddSource(src service.Service) error {
	l.addSource <- src
	return nil
}

// AddAndStart implements the System interface.
func (l *LocalSystem) AddAndStart(srv service.Service) error {
	err := srv.Start()

	if err == nil {
		return l.AddSource(srv)
	}
	return err
}

// DataSources implements the System interface.
func (l *LocalSystem) DataSources() []service.Service {
	ch := make(chan []service.Service, 2)

	l.allSources <- ch
	return <-ch
}

// SetDataSources assigns the data sources that will be used by the system.
func (l *LocalSystem) SetDataSources(sources []service.Service) {
	f := func(src service.Service, ch chan error) { ch <- l.AddAndStart(src) }

	ch := make(chan error, len(sources))
	// Add all the data sources that successfully start to the list
	for _, src := range sources {
		go f(src, ch)
	}

	t := time.NewTimer(5 * time.Second)
	defer t.Stop()
loop:
	for i := 0; i < len(sources); i++ {
		select {
		case <-t.C:
			break loop
		case <-ch:
		}
	}
}

// GraphDatabases implements the System interface.
func (l *LocalSystem) GraphDatabases() []*netmap.Graph {
	return l.graphs
}

// Shutdown implements the System interface.
func (l *LocalSystem) Shutdown() error {
	if l.doneAlreadyClosed {
		return nil
	}
	l.doneAlreadyClosed = true

	var wg sync.WaitGroup
	for _, src := range l.DataSources() {
		wg.Add(1)

		go func(s service.Service, w *sync.WaitGroup) {
			defer w.Done()
			_ = s.Stop()
		}(src, &wg)
	}

	wg.Wait()
	close(l.done)

	for _, g := range l.GraphDatabases() {
		g.Close()
	}

	l.pool.Stop()
	l.cache = nil
	return nil
}

// GetAllSourceNames returns the names of all the available data sources.
func (l *LocalSystem) GetAllSourceNames() []string {
	var names []string

	for _, src := range l.DataSources() {
		names = append(names, src.String())
	}
	return names
}

func (l *LocalSystem) setupOutputDirectory() error {
	path := config.OutputDirectory(l.Cfg.Dir)
	if path == "" {
		return nil
	}

	var err error
	// If the directory does not yet exist, create it
	if err = os.MkdirAll(path, 0755); err != nil {
		return nil
	}

	return nil
}

// Select the graph that will store the System findings.
func (l *LocalSystem) setupGraphDBs() error {
	cfg := l.Config()

	var dbs []*config.Database
	if db := cfg.LocalDatabaseSettings(cfg.GraphDBs); db != nil {
		dbs = append(dbs, db)
	}
	dbs = append(dbs, cfg.GraphDBs...)

	for _, db := range dbs {
		cayley := netmap.NewCayleyGraph(db.System, db.URL, db.Options)
		if cayley == nil {
			return fmt.Errorf("System: Failed to create the %s graph", db.System)
		}

		g := netmap.NewGraph(cayley)
		if g == nil {
			return fmt.Errorf("System: Failed to create the %s graph", g.String())
		}

		// Load the ASN Cache with all prior knowledge of IP address ranges and ASNs
		//_ = ASNCacheFill(g, l.Cache())

		l.graphs = append(l.graphs, g)
	}

	return nil
}

// GetMemoryUsage returns the number bytes allocated to heap objects on this system.
func (l *LocalSystem) GetMemoryUsage() uint64 {
	var m runtime.MemStats

	runtime.ReadMemStats(&m)
	return m.Alloc
}

func (l *LocalSystem) manageDataSources() {
	var dataSources []service.Service

	for {
		select {
		case <-l.done:
			return
		case add := <-l.addSource:
			dataSources = append(dataSources, add)
			sort.Slice(dataSources, func(i, j int) bool {
				return dataSources[i].String() < dataSources[j].String()
			})
		case all := <-l.allSources:
			all <- dataSources
		}
	}
}

func (l *LocalSystem) loadCacheData() error {
	ranges, err := config.GetIP2ASNData()
	if err != nil {
		return err
	}

	for _, r := range ranges {
		cidr := amassnet.Range2CIDR(r.FirstIP, r.LastIP)
		if cidr == nil {
			continue
		}
		if ones, _ := cidr.Mask.Size(); ones == 0 {
			continue
		}

		l.cache.Update(&requests.ASNRequest{
			Address:     r.FirstIP.String(),
			ASN:         r.ASN,
			CC:          r.CC,
			Prefix:      cidr.String(),
			Description: r.Description,
		})
	}

	return nil
}

func customResolverSetup(cfg *config.Config, max int) resolve.Resolver {
	num := len(cfg.Resolvers)
	if num > max {
		num = max
	}

	if cfg.MaxDNSQueries == 0 {
		cfg.MaxDNSQueries = num * config.DefaultQueriesPerBaselineResolver
	} else if cfg.MaxDNSQueries < num {
		cfg.MaxDNSQueries = num
	}

	rate := cfg.MaxDNSQueries / num
	var trusted []resolve.Resolver
	for _, addr := range cfg.Resolvers {
		if r := resolve.NewBaseResolver(addr, rate, cfg.Log); r != nil {
			trusted = append(trusted, r)
		}
	}

	return resolve.NewResolverPool(trusted, 2*time.Second, nil, 1, cfg.Log)
}

func publicResolverSetup(cfg *config.Config, max int) resolve.Resolver {
	baselines := len(config.DefaultBaselineResolvers)

	num := len(config.PublicResolvers)
	if num > max {
		num = max - baselines
	}

	if cfg.MaxDNSQueries == 0 {
		cfg.MaxDNSQueries = num * config.DefaultQueriesPerPublicResolver
	} else if cfg.MaxDNSQueries < num {
		cfg.MaxDNSQueries = num
	}

	trusted := setupResolvers(config.DefaultBaselineResolvers, baselines, config.DefaultQueriesPerBaselineResolver, cfg.Log)
	if len(trusted) == 0 {
		return nil
	}

	wcd := resolve.NewBaseResolver("8.8.8.8", 100, cfg.Log)
	baseline := resolve.NewResolverPool(trusted, time.Second, wcd, 1, cfg.Log)

	r := setupResolvers(config.PublicResolvers, max, config.DefaultQueriesPerPublicResolver, cfg.Log)
	return resolve.NewResolverPool(r, 2*time.Second, baseline, 2, cfg.Log)
}

func setupResolvers(addrs []string, max, rate int, log *log.Logger) []resolve.Resolver {
	if len(addrs) <= 0 {
		return nil
	}

	finished := make(chan resolve.Resolver, 10)
	for _, addr := range addrs {
		if _, _, err := net.SplitHostPort(addr); err != nil {
			// Add the default port number to the IP address
			addr = net.JoinHostPort(addr, "53")
		}
		go func(ip string, ch chan resolve.Resolver) {
			if err := resolve.ClientSubnetCheck(ip); err == nil {
				if n := resolve.NewBaseResolver(ip, rate, log); n != nil {
					ch <- n
					return
				}
			}
			ch <- nil
		}(addr, finished)
	}

	l := len(addrs)
	var count int
	var resolvers []resolve.Resolver
	for i := 0; i < l; i++ {
		if r := <-finished; r != nil {
			if count < max {
				resolvers = append(resolvers, r)
				count++
				continue
			}
			r.Stop()
		}
	}

	if len(resolvers) == 0 {
		return nil
	}
	return resolvers
}
<commit_msg>Reduced the DNS query rate provided to wildcard detection<commit_after>// Copyright 2017-2021 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package systems

import (
	"errors"
	"fmt"
	"log"
	"net"
	"os"
	"runtime"
	"sort"
	"sync"
	"time"

	"github.com/OWASP/Amass/v3/config"
	"github.com/OWASP/Amass/v3/limits"
	amassnet "github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/caffix/netmap"
	"github.com/caffix/resolve"
	"github.com/caffix/service"
)

// LocalSystem implements a System to be executed within a single process.
type LocalSystem struct {
	Cfg               *config.Config
	pool              resolve.Resolver
	graphs            []*netmap.Graph
	cache             *requests.ASNCache
	done              chan struct{}
	doneAlreadyClosed bool
	addSource         chan service.Service
	allSources        chan chan []service.Service
}

// NewLocalSystem returns an initialized LocalSystem object.
func NewLocalSystem(c *config.Config) (*LocalSystem, error) {
	if err := c.CheckSettings(); err != nil {
		return nil, err
	}

	max := int(float64(limits.GetFileLimit()) * 0.7)

	var pool resolve.Resolver
	if len(c.Resolvers) == 0 {
		pool = publicResolverSetup(c, max)
	} else {
		pool = customResolverSetup(c, max)
	}
	if pool == nil {
		return nil, errors.New("The system was unable to build the pool of resolvers")
	}

	sys := &LocalSystem{
		Cfg:        c,
		pool:       pool,
		cache:      requests.NewASNCache(),
		done:       make(chan struct{}, 2),
		addSource:  make(chan service.Service),
		allSources: make(chan chan []service.Service, 10),
	}

	// Load the ASN information into the cache
	if err := sys.loadCacheData(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}
	// Make sure that the output directory is setup for this local system
	if err := sys.setupOutputDirectory(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}
	// Setup the correct graph database handler
	if err := sys.setupGraphDBs(); err != nil {
		_ = sys.Shutdown()
		return nil, err
	}

	go sys.manageDataSources()
	return sys, nil
}

// Config implements the System interface.
func (l *LocalSystem) Config() *config.Config {
	return l.Cfg
}

// Pool implements the System interface.
func (l *LocalSystem) Pool() resolve.Resolver {
	return l.pool
}

// Cache implements the System interface.
func (l *LocalSystem) Cache() *requests.ASNCache {
	return l.cache
}

// AddSource implements the System interface.
func (l *LocalSystem) AddSource(src service.Service) error {
	l.addSource <- src
	return nil
}

// AddAndStart implements the System interface.
func (l *LocalSystem) AddAndStart(srv service.Service) error {
	err := srv.Start()

	if err == nil {
		return l.AddSource(srv)
	}
	return err
}

// DataSources implements the System interface.
func (l *LocalSystem) DataSources() []service.Service {
	ch := make(chan []service.Service, 2)

	l.allSources <- ch
	return <-ch
}

// SetDataSources assigns the data sources that will be used by the system.
func (l *LocalSystem) SetDataSources(sources []service.Service) {
	f := func(src service.Service, ch chan error) { ch <- l.AddAndStart(src) }

	ch := make(chan error, len(sources))
	// Add all the data sources that successfully start to the list
	for _, src := range sources {
		go f(src, ch)
	}

	t := time.NewTimer(5 * time.Second)
	defer t.Stop()
loop:
	for i := 0; i < len(sources); i++ {
		select {
		case <-t.C:
			break loop
		case <-ch:
		}
	}
}

// GraphDatabases implements the System interface.
func (l *LocalSystem) GraphDatabases() []*netmap.Graph {
	return l.graphs
}

// Shutdown implements the System interface.
func (l *LocalSystem) Shutdown() error {
	if l.doneAlreadyClosed {
		return nil
	}
	l.doneAlreadyClosed = true

	var wg sync.WaitGroup
	for _, src := range l.DataSources() {
		wg.Add(1)

		go func(s service.Service, w *sync.WaitGroup) {
			defer w.Done()
			_ = s.Stop()
		}(src, &wg)
	}

	wg.Wait()
	close(l.done)

	for _, g := range l.GraphDatabases() {
		g.Close()
	}

	l.pool.Stop()
	l.cache = nil
	return nil
}

// GetAllSourceNames returns the names of all the available data sources.
func (l *LocalSystem) GetAllSourceNames() []string {
	var names []string

	for _, src := range l.DataSources() {
		names = append(names, src.String())
	}
	return names
}

func (l *LocalSystem) setupOutputDirectory() error {
	path := config.OutputDirectory(l.Cfg.Dir)
	if path == "" {
		return nil
	}

	var err error
	// If the directory does not yet exist, create it
	if err = os.MkdirAll(path, 0755); err != nil {
		return nil
	}

	return nil
}

// Select the graph that will store the System findings.
func (l *LocalSystem) setupGraphDBs() error {
	cfg := l.Config()

	var dbs []*config.Database
	if db := cfg.LocalDatabaseSettings(cfg.GraphDBs); db != nil {
		dbs = append(dbs, db)
	}
	dbs = append(dbs, cfg.GraphDBs...)

	for _, db := range dbs {
		cayley := netmap.NewCayleyGraph(db.System, db.URL, db.Options)
		if cayley == nil {
			return fmt.Errorf("System: Failed to create the %s graph", db.System)
		}

		g := netmap.NewGraph(cayley)
		if g == nil {
			return fmt.Errorf("System: Failed to create the %s graph", g.String())
		}

		// Load the ASN Cache with all prior knowledge of IP address ranges and ASNs
		//_ = ASNCacheFill(g, l.Cache())

		l.graphs = append(l.graphs, g)
	}

	return nil
}

// GetMemoryUsage returns the number bytes allocated to heap objects on this system.
func (l *LocalSystem) GetMemoryUsage() uint64 {
	var m runtime.MemStats

	runtime.ReadMemStats(&m)
	return m.Alloc
}

func (l *LocalSystem) manageDataSources() {
	var dataSources []service.Service

	for {
		select {
		case <-l.done:
			return
		case add := <-l.addSource:
			dataSources = append(dataSources, add)
			sort.Slice(dataSources, func(i, j int) bool {
				return dataSources[i].String() < dataSources[j].String()
			})
		case all := <-l.allSources:
			all <- dataSources
		}
	}
}

func (l *LocalSystem) loadCacheData() error {
	ranges, err := config.GetIP2ASNData()
	if err != nil {
		return err
	}

	for _, r := range ranges {
		cidr := amassnet.Range2CIDR(r.FirstIP, r.LastIP)
		if cidr == nil {
			continue
		}
		if ones, _ := cidr.Mask.Size(); ones == 0 {
			continue
		}

		l.cache.Update(&requests.ASNRequest{
			Address:     r.FirstIP.String(),
			ASN:         r.ASN,
			CC:          r.CC,
			Prefix:      cidr.String(),
			Description: r.Description,
		})
	}

	return nil
}

func customResolverSetup(cfg *config.Config, max int) resolve.Resolver {
	num := len(cfg.Resolvers)
	if num > max {
		num = max
	}

	if cfg.MaxDNSQueries == 0 {
		cfg.MaxDNSQueries = num * config.DefaultQueriesPerBaselineResolver
	} else if cfg.MaxDNSQueries < num {
		cfg.MaxDNSQueries = num
	}

	rate := cfg.MaxDNSQueries / num
	var trusted []resolve.Resolver
	for _, addr := range cfg.Resolvers {
		if r := resolve.NewBaseResolver(addr, rate, cfg.Log); r != nil {
			trusted = append(trusted, r)
		}
	}

	return resolve.NewResolverPool(trusted, 2*time.Second, nil, 1, cfg.Log)
}

func publicResolverSetup(cfg *config.Config, max int) resolve.Resolver {
	baselines := len(config.DefaultBaselineResolvers)

	num := len(config.PublicResolvers)
	if num > max {
		num = max - baselines
	}

	if cfg.MaxDNSQueries == 0 {
		cfg.MaxDNSQueries = num * config.DefaultQueriesPerPublicResolver
	} else if cfg.MaxDNSQueries < num {
		cfg.MaxDNSQueries = num
	}

	trusted := setupResolvers(config.DefaultBaselineResolvers, baselines, config.DefaultQueriesPerBaselineResolver, cfg.Log)
	if len(trusted) == 0 {
		return nil
	}

	wcd := resolve.NewBaseResolver("8.8.8.8", 50, cfg.Log)
	baseline := resolve.NewResolverPool(trusted, time.Second, wcd, 1, cfg.Log)

	r := setupResolvers(config.PublicResolvers, max, config.DefaultQueriesPerPublicResolver, cfg.Log)
	return resolve.NewResolverPool(r, 2*time.Second, baseline, 2, cfg.Log)
}

func setupResolvers(addrs []string, max, rate int, log *log.Logger) []resolve.Resolver {
	if len(addrs) <= 0 {
		return nil
	}

	finished := make(chan resolve.Resolver, 10)
	for _, addr := range addrs {
		if _, _, err := net.SplitHostPort(addr); err != nil {
			// Add the default port number to the IP address
			addr = net.JoinHostPort(addr, "53")
		}
		go func(ip string, ch chan resolve.Resolver) {
			if err := resolve.ClientSubnetCheck(ip); err == nil {
				if n := resolve.NewBaseResolver(ip, rate, log); n != nil {
					ch <- n
					return
				}
			}
			ch <- nil
		}(addr, finished)
	}

	l := len(addrs)
	var count int
	var resolvers []resolve.Resolver
	for i := 0; i < l; i++ {
		if r := <-finished; r != nil {
			if count < max {
				resolvers = append(resolvers, r)
				count++
				continue
			}
			r.Stop()
		}
	}

	if len(resolvers) == 0 {
		return nil
	}
	return resolvers
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"net/http"
	"strings"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"math"
	"b00lduck/datalogger/serial/parser"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

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

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)

}

var oldval_brauchwasser = float32(0)
var oldval_aussen = float32(0)
var oldval_kessel = float32(0)

func processDatagram(data []byte) error {

    if data[37] != 10 {
	return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
		return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
	}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
	return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
	return err
    }

    adc_brauchwasser := parser.ParseADCSensorC(5, data)
    if math.Abs(float64(adc_brauchwasser - oldval_brauchwasser)) > 0.2 {
		sendReading("HEIZ_BRAUCHW", adc_brauchwasser)
		fmt.Println("Brauchwasser: " + fmt.Sprintf("%.1f", adc_brauchwasser) + " C")
		oldval_brauchwasser = adc_brauchwasser
	}

	adc_aussen := parser.ParseADCSensorB(6, data)
	if math.Abs(float64(adc_aussen - oldval_aussen)) > 0.2 {
		sendReading("HEIZ_AUSSEN", adc_aussen)
		fmt.Println("Aussen: " + fmt.Sprintf("%.1f", adc_aussen) + " C")
		oldval_aussen = adc_aussen
	}

    adc_kessel := parser.ParseADCSensorA(7, data)
	if math.Abs(float64(adc_kessel - oldval_kessel)) > 0.5 {
		sendReading("HEIZ_KESSEL", adc_kessel)
		fmt.Println("Kessel: " + fmt.Sprintf("%.1f", adc_kessel) + " C")
		oldval_kessel = adc_kessel
	}

    return nil
}

func sendReading(code string, temp float32) {

	intval := fmt.Sprintf("%d", temp * 1000)

	client := &http.Client{}
	request, err := http.NewRequest("POST", "http://localhost:8080/thermometer/" + code + "/reading", strings.NewReader(intval))
	if err != nil {
		fmt.Println("Error creating thermometer request to dataservice")
		fmt.Println(err)
		return
	}
	request.ContentLength = 0
	x, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println(err)
	}

	if x.StatusCode != 200 {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println(x.Body)
	}

}
<commit_msg>ACQUISITION-SERIAL: test<commit_after>package main

import (
	"fmt"
	"time"
	"net/http"
	"strings"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"math"
	"b00lduck/datalogger/serial/parser"
	"io/ioutil"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

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

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)

}

var oldval_brauchwasser = float32(0)
var oldval_aussen = float32(0)
var oldval_kessel = float32(0)

func processDatagram(data []byte) error {

    if data[37] != 10 {
	return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
		return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
	}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
	return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
	return err
    }

    adc_brauchwasser := parser.ParseADCSensorC(5, data)
    if math.Abs(float64(adc_brauchwasser - oldval_brauchwasser)) > 0.2 {
		sendReading("HEIZ_BRAUCHW", adc_brauchwasser)
		fmt.Println("Brauchwasser: " + fmt.Sprintf("%.1f", adc_brauchwasser) + " C")
		oldval_brauchwasser = adc_brauchwasser
	}

	adc_aussen := parser.ParseADCSensorB(6, data)
	if math.Abs(float64(adc_aussen - oldval_aussen)) > 0.2 {
		sendReading("HEIZ_AUSSEN", adc_aussen)
		fmt.Println("Aussen: " + fmt.Sprintf("%.1f", adc_aussen) + " C")
		oldval_aussen = adc_aussen
	}

    adc_kessel := parser.ParseADCSensorA(7, data)
	if math.Abs(float64(adc_kessel - oldval_kessel)) > 0.5 {
		sendReading("HEIZ_KESSEL", adc_kessel)
		fmt.Println("Kessel: " + fmt.Sprintf("%.1f", adc_kessel) + " C")
		oldval_kessel = adc_kessel
	}

    return nil
}

func sendReading(code string, temp float32) {

	intval := fmt.Sprintf("%d", temp * 1000)

	client := &http.Client{}
	request, err := http.NewRequest("POST", "http://localhost:8080/thermometer/" + code + "/reading", strings.NewReader(intval))
	if err != nil {
		fmt.Println("Error creating thermometer request to dataservice")
		fmt.Println(err)
		return
	}
	request.ContentLength = 0
	x, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println(err)
	}

	if x.StatusCode != 200 {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println( ioutil.ReadAll(x.Body) )
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"b00lduck/datalogger/serial/parser"
	"b00lduck/datalogger/serial/sensor"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

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

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)
}

var thermBrauchwasser = sensor.NewThermometer("HEIZ_BRAUCHW", 0.25)
var thermAussen = sensor.NewThermometer("HEIZ_AUSSEN", 0.50)
var thermKessel = sensor.NewThermometer("HEIZ_KESSEL", 0.50)

var flagZirkulationspumpe = sensor.NewFlag("HEIZ_BWZP")
var flagLadepumpe = sensor.NewFlag("HEIZ_BWLP")
var flagWinter = sensor.NewFlag("HEIZ_WINT")
var flagUmwaelzpumpe = sensor.NewFlag("HEIZ_UWP")
var flagBrenner = sensor.NewFlag("HEIZ_BRENN")
var flagTag = sensor.NewFlag("HEIZ_TAG")

func processDatagram(data []byte) error {

    if data[37] != 10 {
		return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
			return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
		}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
		return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
		return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
		return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
		return err
    }

	// TODO: CRC check

	thermBrauchwasser.SetNewReading(parser.ParseADCSensorC(5, data))
    thermAussen.SetNewReading(parser.ParseADCSensorB(6, data))
	thermKessel.SetNewReading(parser.ParseADCSensorA(7, data))

	flagZirkulationspumpe.SetNewState(parser.ParseDigitalIn(0, data))
	flagLadepumpe.SetNewState(parser.ParseDigitalIn(1, data))
	flagWinter.SetNewState(parser.ParseDigitalIn(2, data))
	flagUmwaelzpumpe.SetNewState(parser.ParseDigitalIn(3, data))
	flagBrenner(parser.ParseDigitalIn(4, data))
	flagTag.SetNewState(parser.ParseDigitalIn(5, data))

    return nil
}

<commit_msg>GO: flag processing<commit_after>package main

import (
	"fmt"
	"time"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"b00lduck/datalogger/serial/parser"
	"b00lduck/datalogger/serial/sensor"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

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

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)
}

var thermBrauchwasser = sensor.NewThermometer("HEIZ_BRAUCHW", 0.25)
var thermAussen = sensor.NewThermometer("HEIZ_AUSSEN", 0.50)
var thermKessel = sensor.NewThermometer("HEIZ_KESSEL", 0.50)

var flagZirkulationspumpe = sensor.NewFlag("HEIZ_BWZP")
var flagLadepumpe = sensor.NewFlag("HEIZ_BWLP")
var flagWinter = sensor.NewFlag("HEIZ_WINT")
var flagUmwaelzpumpe = sensor.NewFlag("HEIZ_UWP")
var flagBrenner = sensor.NewFlag("HEIZ_BRENN")
var flagTag = sensor.NewFlag("HEIZ_TAG")

func processDatagram(data []byte) error {

    if data[37] != 10 {
		return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
			return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
		}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
		return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
		return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
		return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
		return err
    }

	// TODO: CRC check

	thermBrauchwasser.SetNewReading(parser.ParseADCSensorC(5, data))
    thermAussen.SetNewReading(parser.ParseADCSensorB(6, data))
	thermKessel.SetNewReading(parser.ParseADCSensorA(7, data))

	flagZirkulationspumpe.SetNewState(parser.ParseDigitalIn(0, data))
	flagLadepumpe.SetNewState(parser.ParseDigitalIn(1, data))
	flagWinter.SetNewState(parser.ParseDigitalIn(2, data))
	flagUmwaelzpumpe.SetNewState(parser.ParseDigitalIn(3, data))
	flagBrenner.SetNewState(parser.ParseDigitalIn(4, data))
	flagTag.SetNewState(parser.ParseDigitalIn(5, data))

    return nil
}

<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "lumberjack"
  "os"
  "time"
  proto "code.google.com/p/goprotobuf/proto"
)

func emit(events []*lumberjack.FileEvent) {
  envelope := &lumberjack.EventEnvelope{Events: events}
  data, _ := proto.Marshal(envelope)
  fmt.Printf("Flushing !!! %d events: %d encoded\n", len(events), len(data))
} /* emit */

func main() {
  // TODO(sissel): support flags for setting... stuff
  event_chan := make(chan *lumberjack.FileEvent, 32)
  publisher_chan := make(chan *lumberjack.EventEnvelope, 1)

  // The basic model of execution:
  // - prospector: finds files in paths/globs to harvest, starts harvesters
  // - harvester: reads a file, sends events to the spooler
  // - spooler: buffers events until ready to flush to the publisher
  // - publisher: writes to the network, notifies registrar
  // - registrar: records positions of files read
  // Finally, prospector uses the registrar information, on restart, to
  // determine where in each file to resume a harvester.

  // TODO(sissel): need a prospector scan for files and launch harvesters

  // Prospect the globs/paths given on the command line and launch harvesters
  go lumberjack.Prospect(os.Args[1:], event_chan)

  var window_size uint64 = 1024 // Make this a flag
  var idle_timeout time.Duration = 1 * time.Second // Make this a flag

  // Harvesters dump events into the spooler.
  go lumberjack.Spooler(event_chan, publisher_chan, window_size, idle_timeout)

  // Spooler flushes periodically to the publisher
  for x := range publisher_chan {
    // got a bunch of events, ship them out.
    fmt.Printf("Spooler gave me %d events\n", len(x.Events))
    for _, event := range x.Events {
      fmt.Println(event)
    }
  }

  // TODO(sissel): publisher should send state to the registrar
  // TODO(sissel): registrar records last acknowledged positions in all files.
} /* main */
<commit_msg>- use Spool; stub publisher<commit_after>package main

import (
  "fmt"
  "lumberjack"
  "os"
  "time"
  proto "code.google.com/p/goprotobuf/proto"
)

func emit(events []*lumberjack.FileEvent) {
  envelope := &lumberjack.EventEnvelope{Events: events}
  data, _ := proto.Marshal(envelope)
  fmt.Printf("Flushing !!! %d events: %d encoded\n", len(events), len(data))
} /* emit */

func main() {
  // TODO(sissel): support flags for setting... stuff
  event_chan := make(chan *lumberjack.FileEvent, 32)
  publisher_chan := make(chan *lumberjack.EventEnvelope, 1)

  // The basic model of execution:
  // - prospector: finds files in paths/globs to harvest, starts harvesters
  // - harvester: reads a file, sends events to the spooler
  // - spooler: buffers events until ready to flush to the publisher
  // - publisher: writes to the network, notifies registrar
  // - registrar: records positions of files read
  // Finally, prospector uses the registrar information, on restart, to
  // determine where in each file to resume a harvester.

  // TODO(sissel): need a prospector scan for files and launch harvesters

  // Prospect the globs/paths given on the command line and launch harvesters
  go lumberjack.Prospect(os.Args[1:], event_chan)

  var window_size uint64 = 1024 // Make this a flag
  var idle_timeout time.Duration = 1 * time.Second // Make this a flag

  // Harvesters dump events into the spooler.
  go lumberjack.Spool(event_chan, publisher_chan, window_size, idle_timeout)

  lumberjack.Publish(publisher_chan)

  // TODO(sissel): publisher should send state to the registrar
  // TODO(sissel): registrar records last acknowledged positions in all files.
} /* main */
<|endoftext|>


<commit_before>// Copyright 2013 Google Inc. 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 taglib provides utilities for parsing audio tags in
// various formats.
package taglib

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/hjfreyer/taglib-go/taglib/id3"
)

// GenericTag is implemented by all the tag types in this project. It
// gives an incomplete view of the information in each tag type, but
// is good enough for most purposes.
type GenericTag interface {
	Title() string
	Artist() string
	Album() string
	Comment() string
	Genre() string
	Year() time.Time
	Track() uint32
	Disc() uint32

	// UniqueFileIdentifiers returns a map from the URL of the owner of a
	// database assigning unique identifiers to files (e.g.
	// "http://musicbrainz.org") to the identifier uniquely identifying the
	// file.
	UniqueFileIdentifiers() map[string]string

	// CustomFrames returns non-standard, user-defined frames as a map from
	// descriptions (e.g. "PERFORMER", "MusicBrainz Album Id", etc.) to
	// values.
	CustomFrames() map[string]string

	// TagSize returns the total size of the tag's header and frames,
	// i.e. the position at which audio data starts.
	TagSize() uint32
}

// Decode reads r and determines which tag format the data is in, if
// any, and calls the decoding function for that format. size
// indicates the total number of bytes accessible through r.
func Decode(r io.ReaderAt, size int64) (GenericTag, error) {
	magic := make([]byte, 4)
	if _, err := r.ReadAt(magic, 0); err != nil {
		return nil, err
	}

	if !bytes.Equal(magic[:3], []byte("ID3")) {
		return nil, errors.New("taglib: format not recognised (not ID3)")
	}

	switch magic[3] {
	case 2:
		return nil, errors.New("taglib: format not supported (ID3 v2.2)")
	case 3:
		return id3.Decode23(r)
	case 4:
		return id3.Decode24(r)
	default:
		return nil, fmt.Errorf("taglib: format not supported (ID3 %d)", magic[3])
	}
}
<commit_msg>HACK: Update import path to use to forked repository.<commit_after>// Copyright 2013 Google Inc. 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 taglib provides utilities for parsing audio tags in
// various formats.
package taglib

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/derat/taglib-go/taglib/id3"
)

// GenericTag is implemented by all the tag types in this project. It
// gives an incomplete view of the information in each tag type, but
// is good enough for most purposes.
type GenericTag interface {
	Title() string
	Artist() string
	Album() string
	Comment() string
	Genre() string
	Year() time.Time
	Track() uint32
	Disc() uint32

	// UniqueFileIdentifiers returns a map from the URL of the owner of a
	// database assigning unique identifiers to files (e.g.
	// "http://musicbrainz.org") to the identifier uniquely identifying the
	// file.
	UniqueFileIdentifiers() map[string]string

	// CustomFrames returns non-standard, user-defined frames as a map from
	// descriptions (e.g. "PERFORMER", "MusicBrainz Album Id", etc.) to
	// values.
	CustomFrames() map[string]string

	// TagSize returns the total size of the tag's header and frames,
	// i.e. the position at which audio data starts.
	TagSize() uint32
}

// Decode reads r and determines which tag format the data is in, if
// any, and calls the decoding function for that format. size
// indicates the total number of bytes accessible through r.
func Decode(r io.ReaderAt, size int64) (GenericTag, error) {
	magic := make([]byte, 4)
	if _, err := r.ReadAt(magic, 0); err != nil {
		return nil, err
	}

	if !bytes.Equal(magic[:3], []byte("ID3")) {
		return nil, errors.New("taglib: format not recognised (not ID3)")
	}

	switch magic[3] {
	case 2:
		return nil, errors.New("taglib: format not supported (ID3 v2.2)")
	case 3:
		return id3.Decode23(r)
	case 4:
		return id3.Decode24(r)
	default:
		return nil, fmt.Errorf("taglib: format not supported (ID3 %d)", magic[3])
	}
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Gustav Simonsson <gustav.simonsson@gmail.com>
 * @date 2015
 *
 */
/*

This abstracts part of a user's interaction with an account she controls.
It's not an abstraction of core Ethereum accounts data type / logic -
for that see the core processing code of blocks / txs.

Currently this is pretty much a passthrough to the KeyStore2 interface,
and accounts persistence is derived from stored keys' addresses

*/
package accounts

import (
	"crypto/ecdsa"
	crand "crypto/rand"

	"errors"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/crypto"
)

var (
	ErrLocked = errors.New("account is locked")
	ErrNoKeys = errors.New("no keys in store")
)

type Account struct {
	Address []byte
}

type AccountManager struct {
	keyStore     crypto.KeyStore2
	unlockedKeys map[string]crypto.Key
	unlockTime   time.Duration
	mutex        sync.RWMutex
}

func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *AccountManager {
	return &AccountManager{
		keyStore:     keyStore,
		unlockedKeys: make(map[string]crypto.Key),
		unlockTime:   unlockTime,
	}
}

// Coinbase returns the account address that mining rewards are sent to.
func (am *AccountManager) Coinbase() (addr []byte, err error) {
	// TODO: persist coinbase address on disk
	return am.firstAddr()
}

// MainAccount returns the primary account used for transactions.
func (am *AccountManager) Default() (Account, error) {
	// TODO: persist main account address on disk
	addr, err := am.firstAddr()
	return Account{Address: addr}, err
}

func (am *AccountManager) firstAddr() ([]byte, error) {
	addrs, err := am.keyStore.GetKeyAddresses()
	if err != nil {
		return nil, err
	}
	if len(addrs) == 0 {
		return nil, ErrNoKeys
	}
	return addrs[0], nil
}

func (am *AccountManager) DeleteAccount(address []byte, auth string) error {
	return am.keyStore.DeleteKey(address, auth)
}

func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err error) {
	am.mutex.RLock()
	unlockedKey := am.unlockedKeys[string(a.Address)]
	am.mutex.RUnlock()
	if unlockedKey.Address == nil {
		return nil, ErrLocked
	}
	signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
	return signature, err
}

func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) {
	key, err := am.keyStore.GetKey(a.Address, keyAuth)
	if err != nil {
		return nil, err
	}
	am.mutex.RLock()
	am.unlockedKeys[string(a.Address)] = *key
	am.mutex.RUnlock()
	go unlockLater(am, a.Address)
	signature, err = crypto.Sign(toSign, key.PrivateKey)
	return signature, err
}

func (am *AccountManager) NewAccount(auth string) (Account, error) {
	key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
	if err != nil {
		return Account{}, err
	}
	return Account{Address: key.Address}, nil
}

func (am *AccountManager) Accounts() ([]Account, error) {
	addresses, err := am.keyStore.GetKeyAddresses()
	if err != nil {
		return nil, err
	}

	accounts := make([]Account, len(addresses))

	for i, addr := range addresses {
		accounts[i] = Account{
			Address: addr,
		}
	}
	return accounts, err
}

func unlockLater(am *AccountManager, addr []byte) {
	select {
	case <-time.After(am.unlockTime):
	}
	am.mutex.RLock()
	// TODO: how do we know the key is actually gone from memory?
	delete(am.unlockedKeys, string(addr))
	am.mutex.RUnlock()
}
<commit_msg>accounts: fix uses of sync.RWMutex<commit_after>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Gustav Simonsson <gustav.simonsson@gmail.com>
 * @date 2015
 *
 */
/*

This abstracts part of a user's interaction with an account she controls.
It's not an abstraction of core Ethereum accounts data type / logic -
for that see the core processing code of blocks / txs.

Currently this is pretty much a passthrough to the KeyStore2 interface,
and accounts persistence is derived from stored keys' addresses

*/
package accounts

import (
	"crypto/ecdsa"
	crand "crypto/rand"

	"errors"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/crypto"
)

var (
	ErrLocked = errors.New("account is locked")
	ErrNoKeys = errors.New("no keys in store")
)

type Account struct {
	Address []byte
}

type AccountManager struct {
	keyStore     crypto.KeyStore2
	unlockedKeys map[string]crypto.Key
	unlockTime   time.Duration
	mutex        sync.RWMutex
}

func NewAccountManager(keyStore crypto.KeyStore2, unlockTime time.Duration) *AccountManager {
	return &AccountManager{
		keyStore:     keyStore,
		unlockedKeys: make(map[string]crypto.Key),
		unlockTime:   unlockTime,
	}
}

// Coinbase returns the account address that mining rewards are sent to.
func (am *AccountManager) Coinbase() (addr []byte, err error) {
	// TODO: persist coinbase address on disk
	return am.firstAddr()
}

// MainAccount returns the primary account used for transactions.
func (am *AccountManager) Default() (Account, error) {
	// TODO: persist main account address on disk
	addr, err := am.firstAddr()
	return Account{Address: addr}, err
}

func (am *AccountManager) firstAddr() ([]byte, error) {
	addrs, err := am.keyStore.GetKeyAddresses()
	if err != nil {
		return nil, err
	}
	if len(addrs) == 0 {
		return nil, ErrNoKeys
	}
	return addrs[0], nil
}

func (am *AccountManager) DeleteAccount(address []byte, auth string) error {
	return am.keyStore.DeleteKey(address, auth)
}

func (am *AccountManager) Sign(a Account, toSign []byte) (signature []byte, err error) {
	am.mutex.RLock()
	unlockedKey := am.unlockedKeys[string(a.Address)]
	am.mutex.RUnlock()
	if unlockedKey.Address == nil {
		return nil, ErrLocked
	}
	signature, err = crypto.Sign(toSign, unlockedKey.PrivateKey)
	return signature, err
}

func (am *AccountManager) SignLocked(a Account, keyAuth string, toSign []byte) (signature []byte, err error) {
	key, err := am.keyStore.GetKey(a.Address, keyAuth)
	if err != nil {
		return nil, err
	}
	am.mutex.Lock()
	am.unlockedKeys[string(a.Address)] = *key
	am.mutex.Unlock()
	go unlockLater(am, a.Address)
	signature, err = crypto.Sign(toSign, key.PrivateKey)
	return signature, err
}

func (am *AccountManager) NewAccount(auth string) (Account, error) {
	key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
	if err != nil {
		return Account{}, err
	}
	return Account{Address: key.Address}, nil
}

func (am *AccountManager) Accounts() ([]Account, error) {
	addresses, err := am.keyStore.GetKeyAddresses()
	if err != nil {
		return nil, err
	}

	accounts := make([]Account, len(addresses))

	for i, addr := range addresses {
		accounts[i] = Account{
			Address: addr,
		}
	}
	return accounts, err
}

func unlockLater(am *AccountManager, addr []byte) {
	select {
	case <-time.After(am.unlockTime):
	}
	am.mutex.Lock()
	// TODO: how do we know the key is actually gone from memory?
	delete(am.unlockedKeys, string(addr))
	am.mutex.Unlock()
}

}
<|endoftext|>


<commit_before>package utils

import (
	"os"
	"strconv"
)

// Parses a file into the correct FTP-defined string.
func ParseFile(file os.FileInfo, parseType string) string {
	fileName := file.Name()
	bytes := strconv.FormatInt(file.Size(), 10)

	switch parseType {
	// ASCII data format type
	case "A":

		//      drwx------   3 slacker    users         104 Jul 27 01:45 public_html"   <- example
		return "drwx------   3 slacker    users         " + bytes + " Jul 27 01:45 " + fileName
	default:
		return "HELLO THERE"
	}
}<commit_msg>Adds better placeholders<commit_after>package utils

import (
	"os"
	"strconv"
)

// Parses a file into the correct FTP-defined string.
func ParseFile(file os.FileInfo, parseType string) string {
	fileName := file.Name()
	bytes := strconv.FormatInt(file.Size(), 10)

	switch parseType {
	// ASCII data format type
	case "A":
		if file.IsDir() {
			perms := "drwxr-xr-x 1 owner group"
		} else {
			perms := "-rw-r--r-- 1 owner group"
		}

		//      drwx------   3 slacker    users         104 Jul 27 01:45 public_html"   <- example
		return  perms  + "   3 slacker    users         " + bytes + " Jul 27 01:45 " + fileName
	default:
		return "HELLO THERE"
	}
}<|endoftext|>


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

package storage_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/storage"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
)

// TestRaftLogQueue verifies that the raft log queue correctly truncates the
// raft log.
func TestRaftLogQueue(t *testing.T) {
	defer leaktest.AfterTest(t)

	mtc := new(multiTestContext)

	// Turn off raft elections so the raft leader won't change out from under
	// us in this test.
	sc := storage.TestStoreContext
	sc.RaftTickInterval = time.Hour * 24
	sc.RaftElectionTimeoutTicks = 1000000
	mtc.storeContext = &sc

	mtc.Start(t, 3)
	defer mtc.Stop()

	// Write a single value to ensure we have a leader.
	pArgs := putArgs([]byte("key"), []byte("value"))
	if _, err := client.SendWrapped(rg1(mtc.stores[0]), nil, &pArgs); err != nil {
		t.Fatal(err)
	}

	// Get the raft leader (and ensure one exists).
	desc := mtc.stores[0].LookupReplica([]byte("a"), nil).Desc()
	raftLeaderRepl := mtc.getRaftLeader(desc.RangeID, time.Second)
	if raftLeaderRepl == nil {
		t.Fatalf("could not find raft leader replica for range %d", desc.RangeID)
	}
	originalIndex, err := raftLeaderRepl.FirstIndex()
	if err != nil {
		t.Fatal(err)
	}

	// Write a collection of values to increase the raft log.
	for i := 0; i < storage.RaftLogQueueStaleThreshold+1; i++ {
		pArgs = putArgs([]byte(fmt.Sprintf("key-%d", i)), []byte("value"))
		if _, err := client.SendWrapped(rg1(mtc.stores[0]), nil, &pArgs); err != nil {
			t.Fatal(err)
		}
	}

	// Sadly, occasionally the queue has a race with the force processing so
	// this succeeds within will captures those rare cases.
	var afterTruncationIndex uint64
	util.SucceedsWithin(t, time.Second, func() error {
		// Force a truncation check.
		for _, store := range mtc.stores {
			store.ForceRaftLogScanAndProcess(t)
		}

		// Ensure that firstIndex has increased indicating that the log
		// truncation has occurred.
		var err error
		afterTruncationIndex, err = raftLeaderRepl.FirstIndex()
		if err != nil {
			t.Fatal(err)
		}
		if afterTruncationIndex <= originalIndex {
			t.Fatalf("raft log has not been truncated yet, afterTruncationIndex:%d originalIndex:%d",
				afterTruncationIndex, originalIndex)
		}
		return nil
	})

	// Force a truncation check again to ensure that attempting to truncate an
	// already truncated log has no effect.
	for _, store := range mtc.stores {
		store.ForceRaftLogScanAndProcess(t)
	}

	after2ndTruncationIndex, err := raftLeaderRepl.FirstIndex()
	if err != nil {
		t.Fatal(err)
	}
	if afterTruncationIndex != after2ndTruncationIndex {
		t.Fatalf("raft log was truncated again and it shouldn't have been, afterTruncationIndex:%d after2ndTruncationIndex:%d",
			afterTruncationIndex, after2ndTruncationIndex)
	}
}
<commit_msg>Tiny fix in the raft log truncate queue's test.<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Bram Gruneir (bram+code@cockroachlabs.com)

package storage_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/client"
	"github.com/cockroachdb/cockroach/storage"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
)

// TestRaftLogQueue verifies that the raft log queue correctly truncates the
// raft log.
func TestRaftLogQueue(t *testing.T) {
	defer leaktest.AfterTest(t)

	mtc := new(multiTestContext)

	// Turn off raft elections so the raft leader won't change out from under
	// us in this test.
	sc := storage.TestStoreContext
	sc.RaftTickInterval = time.Hour * 24
	sc.RaftElectionTimeoutTicks = 1000000
	mtc.storeContext = &sc

	mtc.Start(t, 3)
	defer mtc.Stop()

	// Write a single value to ensure we have a leader.
	pArgs := putArgs([]byte("key"), []byte("value"))
	if _, err := client.SendWrapped(rg1(mtc.stores[0]), nil, &pArgs); err != nil {
		t.Fatal(err)
	}

	// Get the raft leader (and ensure one exists).
	desc := mtc.stores[0].LookupReplica([]byte("a"), nil).Desc()
	raftLeaderRepl := mtc.getRaftLeader(desc.RangeID, time.Second)
	if raftLeaderRepl == nil {
		t.Fatalf("could not find raft leader replica for range %d", desc.RangeID)
	}
	originalIndex, err := raftLeaderRepl.FirstIndex()
	if err != nil {
		t.Fatal(err)
	}

	// Write a collection of values to increase the raft log.
	for i := 0; i < storage.RaftLogQueueStaleThreshold+1; i++ {
		pArgs = putArgs([]byte(fmt.Sprintf("key-%d", i)), []byte("value"))
		if _, err := client.SendWrapped(rg1(mtc.stores[0]), nil, &pArgs); err != nil {
			t.Fatal(err)
		}
	}

	// Sadly, occasionally the queue has a race with the force processing so
	// this succeeds within will captures those rare cases.
	var afterTruncationIndex uint64
	util.SucceedsWithin(t, time.Second, func() error {
		// Force a truncation check.
		for _, store := range mtc.stores {
			store.ForceRaftLogScanAndProcess(t)
		}

		// Ensure that firstIndex has increased indicating that the log
		// truncation has occurred.
		var err error
		afterTruncationIndex, err = raftLeaderRepl.FirstIndex()
		if err != nil {
			t.Fatal(err)
		}
		if afterTruncationIndex <= originalIndex {
			return util.Errorf("raft log has not been truncated yet, afterTruncationIndex:%d originalIndex:%d",
				afterTruncationIndex, originalIndex)
		}
		return nil
	})

	// Force a truncation check again to ensure that attempting to truncate an
	// already truncated log has no effect.
	for _, store := range mtc.stores {
		store.ForceRaftLogScanAndProcess(t)
	}

	after2ndTruncationIndex, err := raftLeaderRepl.FirstIndex()
	if err != nil {
		t.Fatal(err)
	}
	if afterTruncationIndex != after2ndTruncationIndex {
		t.Fatalf("raft log was truncated again and it shouldn't have been, afterTruncationIndex:%d after2ndTruncationIndex:%d",
			afterTruncationIndex, after2ndTruncationIndex)
	}
}
<|endoftext|>


<commit_before>package s3_test

import (
	"crypto/md5"
	"encoding/base64"
	"io/ioutil"
	"testing"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/s3"
	"github.com/stretchr/testify/assert"
)

var svc = s3.New(&aws.Config{Region: "mock-region"})

func assertMD5(t *testing.T, req *aws.Request) {
	err := req.Build()
	assert.NoError(t, err)

	b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
	out := md5.Sum(b)
	assert.NotEmpty(t, b)
	assert.Equal(t, base64.StdEncoding.EncodeToString(out[:]), req.HTTPRequest.Header.Get("Content-MD5"))
}

func TestMD5InPutBucketCORS(t *testing.T) {
	req, _ := svc.PutBucketCORSRequest(&s3.PutBucketCORSInput{
		Bucket: aws.String("bucketname"),
		CORSConfiguration: &s3.CORSConfiguration{
			CORSRules: []*s3.CORSRule{
				&s3.CORSRule{AllowedMethods: []*string{aws.String("GET")}},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InPutBucketLifecycle(t *testing.T) {
	req, _ := svc.PutBucketLifecycleRequest(&s3.PutBucketLifecycleInput{
		Bucket: aws.String("bucketname"),
		LifecycleConfiguration: &s3.LifecycleConfiguration{
			Rules: []*s3.Rule{
				&s3.Rule{
					ID:     aws.String("ID"),
					Prefix: aws.String("Prefix"),
					Status: aws.String("Enabled"),
				},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InPutBucketTagging(t *testing.T) {
	req, _ := svc.PutBucketTaggingRequest(&s3.PutBucketTaggingInput{
		Bucket: aws.String("bucketname"),
		Tagging: &s3.Tagging{
			TagSet: []*s3.Tag{
				&s3.Tag{Key: aws.String("KEY"), Value: aws.String("VALUE")},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InDeleteObjects(t *testing.T) {
	req, _ := svc.DeleteObjectsRequest(&s3.DeleteObjectsInput{
		Bucket: aws.String("bucketname"),
		Delete: &s3.Delete{
			Objects: []*s3.ObjectIdentifier{
				&s3.ObjectIdentifier{Key: aws.String("key")},
			},
		},
	})
	assertMD5(t, req)
}
<commit_msg>Fix broken tests<commit_after>package s3_test

import (
	"crypto/md5"
	"encoding/base64"
	"io/ioutil"
	"testing"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/s3"
	"github.com/stretchr/testify/assert"
)

var svc = s3.New(&aws.Config{
	Region:      "mock-region",
	Credentials: aws.DetectCreds("AKID", "SECRET", ""),
})

func assertMD5(t *testing.T, req *aws.Request) {
	err := req.Build()
	assert.NoError(t, err)

	b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
	out := md5.Sum(b)
	assert.NotEmpty(t, b)
	assert.Equal(t, base64.StdEncoding.EncodeToString(out[:]), req.HTTPRequest.Header.Get("Content-MD5"))
}

func TestMD5InPutBucketCORS(t *testing.T) {
	req, _ := svc.PutBucketCORSRequest(&s3.PutBucketCORSInput{
		Bucket: aws.String("bucketname"),
		CORSConfiguration: &s3.CORSConfiguration{
			CORSRules: []*s3.CORSRule{
				&s3.CORSRule{AllowedMethods: []*string{aws.String("GET")}},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InPutBucketLifecycle(t *testing.T) {
	req, _ := svc.PutBucketLifecycleRequest(&s3.PutBucketLifecycleInput{
		Bucket: aws.String("bucketname"),
		LifecycleConfiguration: &s3.LifecycleConfiguration{
			Rules: []*s3.Rule{
				&s3.Rule{
					ID:     aws.String("ID"),
					Prefix: aws.String("Prefix"),
					Status: aws.String("Enabled"),
				},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InPutBucketTagging(t *testing.T) {
	req, _ := svc.PutBucketTaggingRequest(&s3.PutBucketTaggingInput{
		Bucket: aws.String("bucketname"),
		Tagging: &s3.Tagging{
			TagSet: []*s3.Tag{
				&s3.Tag{Key: aws.String("KEY"), Value: aws.String("VALUE")},
			},
		},
	})
	assertMD5(t, req)
}

func TestMD5InDeleteObjects(t *testing.T) {
	req, _ := svc.DeleteObjectsRequest(&s3.DeleteObjectsInput{
		Bucket: aws.String("bucketname"),
		Delete: &s3.Delete{
			Objects: []*s3.ObjectIdentifier{
				&s3.ObjectIdentifier{Key: aws.String("key")},
			},
		},
	})
	assertMD5(t, req)
}
<|endoftext|>


<commit_before>package libgobuster

import (
	"bufio"
	"context"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
)

const (
	// VERSION contains the current gobuster version
	VERSION = "1.4.1"
)

// SetupFunc is the "setup" function prototype for implementations
type SetupFunc func(*Gobuster) error

// ProcessFunc is the "process" function prototype for implementations
type ProcessFunc func(*Gobuster, string) ([]Result, error)

// ResultToStringFunc is the "to string" function prototype for implementations
type ResultToStringFunc func(*Gobuster, *Result) (*string, error)

// Gobuster is the main object when creating a new run
type Gobuster struct {
	Opts             *Options
	http             *httpClient
	WildcardIps      stringSet
	context          context.Context
	wordlistSize     int
	wordlistPosition int
	mu               *sync.RWMutex
	funcResToString  ResultToStringFunc
	funcProcessor    ProcessFunc
	funcSetup        SetupFunc
	IsWildcard       bool
	resultChan       chan Result
}

// NewGobuster returns a new Gobuster object
func NewGobuster(c context.Context, opts *Options, setupFunc SetupFunc, processFunc ProcessFunc, resultFunc ResultToStringFunc) (*Gobuster, error) {
	// validate given options
	multiErr := opts.validate()
	if multiErr != nil {
		return nil, multiErr
	}

	var g Gobuster
	g.WildcardIps = stringSet{Set: map[string]bool{}}
	g.context = c
	g.Opts = opts
	h, err := newHTTPClient(c, opts)
	if err != nil {
		return nil, err
	}
	g.http = h

	g.funcSetup = setupFunc
	g.funcProcessor = processFunc
	g.funcResToString = resultFunc
	g.mu = new(sync.RWMutex)

	g.resultChan = make(chan Result)

	return &g, nil
}

// Results returns a channel of Results
func (g *Gobuster) Results() <-chan Result {
	return g.resultChan
}

func (g *Gobuster) incrementWordlistPosition() {
	g.mu.Lock()
	g.wordlistPosition++
	g.mu.Unlock()
}

// PrintProgress outputs the current wordlist progress to stderr
func (g *Gobuster) PrintProgress() {
	g.mu.RLock()
	if g.Opts.Wordlist == "-" {
		fmt.Fprintf(os.Stderr, "\rProgress: %d", g.wordlistPosition)
	} else {
		fmt.Fprintf(os.Stderr, "\rProgress: %d / %d", g.wordlistPosition, g.wordlistSize)
	}
	g.mu.RUnlock()
}

// ClearProgress removes the last status line from stderr
func (g *Gobuster) ClearProgress() {
	fmt.Fprint(os.Stderr, "\r")
}

// GetRequest issues a GET request to the target and returns
// the status code, length and an error
func (g *Gobuster) GetRequest(url string) (*int, *int64, error) {
	return g.http.makeRequest(url, g.Opts.Cookies)
}

func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case <-g.context.Done():
			return
		case word := <-wordChan:
			g.incrementWordlistPosition()
			// Mode-specific processing
			res, err := g.funcProcessor(g, word)
			if err != nil {
				// do not exit and continue
				log.Printf("ERROR on word %s: %v", word, err)
				continue
			} else {
				for _, r := range res {
					g.resultChan <- r
				}
			}
		}
	}
}

func (g *Gobuster) getWordlist() (*bufio.Scanner, error) {
	if g.Opts.Wordlist == "-" {
		// Read directly from stdin
		return bufio.NewScanner(os.Stdin), nil
	}
	// Pull content from the wordlist
	wordlist, err := os.Open(g.Opts.Wordlist)
	if err != nil {
		return nil, fmt.Errorf("failed to open wordlist: %v", err)
	}

	lines, err := lineCounter(wordlist)
	if err != nil {
		return nil, fmt.Errorf("failed to get number of lines: %v", err)
	}
	g.wordlistSize = lines

	// rewind wordlist
	_, err = wordlist.Seek(0, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to rewind wordlist: %v", err)
	}
	return bufio.NewScanner(wordlist), nil
}

// Start the busting of the website with the given
// set of settings from the command line.
func (g *Gobuster) Start() error {
	if err := g.funcSetup(g); err != nil {
		return err
	}

	var printerGroup sync.WaitGroup
	printerGroup.Add(1)
	var workerGroup sync.WaitGroup
	workerGroup.Add(g.Opts.Threads)

	wordChan := make(chan string, g.Opts.Threads)

	// Create goroutines for each of the number of threads
	// specified.
	for i := 0; i < g.Opts.Threads; i++ {
		go g.worker(wordChan, &workerGroup)
	}

	scanner, err := g.getWordlist()
	if err != nil {
		return err
	}

Scan:
	for scanner.Scan() {
		select {
		case <-g.context.Done():
			break Scan
		default:
			word := strings.TrimSpace(scanner.Text())
			// Skip "comment" (starts with #), as well as empty lines
			if !strings.HasPrefix(word, "#") && len(word) > 0 {
				wordChan <- word
			}
		}
	}
	close(wordChan)
	return nil
}

// ShowConfig prints the current config to the screen
func (g *Gobuster) ShowConfig() {
	o := g.Opts
	fmt.Printf("[+] Mode         : %s\n", o.Mode)
	fmt.Printf("[+] Url/Domain   : %s\n", o.URL)
	fmt.Printf("[+] Threads      : %d\n", o.Threads)

	wordlist := "stdin (pipe)"
	if o.Wordlist != "-" {
		wordlist = o.Wordlist
	}
	fmt.Printf("[+] Wordlist     : %s\n", wordlist)

	if o.Mode == ModeDir {
		fmt.Printf("[+] Status codes : %s\n", o.StatusCodesParsed.Stringify())

		if o.Proxy != "" {
			fmt.Printf("[+] Proxy        : %s\n", o.Proxy)
		}

		if o.Cookies != "" {
			fmt.Printf("[+] Cookies      : %s\n", o.Cookies)
		}

		if o.UserAgent != "" {
			fmt.Printf("[+] User Agent   : %s\n", o.UserAgent)
		}

		if o.IncludeLength {
			fmt.Printf("[+] Show length  : true\n")
		}

		if o.Username != "" {
			fmt.Printf("[+] Auth User    : %s\n", o.Username)
		}

		if len(o.Extensions) > 0 {
			fmt.Printf("[+] Extensions   : %s\n", strings.Join(o.ExtensionsParsed, ","))
		}

		if o.UseSlash {
			fmt.Printf("[+] Add Slash    : true\n")
		}

		if o.FollowRedirect {
			fmt.Printf("[+] Follow Redir : true\n")
		}

		if o.Expanded {
			fmt.Printf("[+] Expanded     : true\n")
		}

		if o.NoStatus {
			fmt.Printf("[+] No status    : true\n")
		}

		if o.Verbose {
			fmt.Printf("[+] Verbose      : true\n")
		}

		fmt.Printf("[+] Timeout      : %s\n", o.Timeout.String())
	}
}
<commit_msg>fix progress counter<commit_after>package libgobuster

import (
	"bufio"
	"context"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
)

const (
	// VERSION contains the current gobuster version
	VERSION = "1.4.1"
)

// SetupFunc is the "setup" function prototype for implementations
type SetupFunc func(*Gobuster) error

// ProcessFunc is the "process" function prototype for implementations
type ProcessFunc func(*Gobuster, string) ([]Result, error)

// ResultToStringFunc is the "to string" function prototype for implementations
type ResultToStringFunc func(*Gobuster, *Result) (*string, error)

// Gobuster is the main object when creating a new run
type Gobuster struct {
	Opts             *Options
	http             *httpClient
	WildcardIps      stringSet
	context          context.Context
	requestsExpected int
	requestsIssued   int
	mu               *sync.RWMutex
	funcResToString  ResultToStringFunc
	funcProcessor    ProcessFunc
	funcSetup        SetupFunc
	IsWildcard       bool
	resultChan       chan Result
}

// NewGobuster returns a new Gobuster object
func NewGobuster(c context.Context, opts *Options, setupFunc SetupFunc, processFunc ProcessFunc, resultFunc ResultToStringFunc) (*Gobuster, error) {
	// validate given options
	multiErr := opts.validate()
	if multiErr != nil {
		return nil, multiErr
	}

	var g Gobuster
	g.WildcardIps = stringSet{Set: map[string]bool{}}
	g.context = c
	g.Opts = opts
	h, err := newHTTPClient(c, opts)
	if err != nil {
		return nil, err
	}
	g.http = h

	g.funcSetup = setupFunc
	g.funcProcessor = processFunc
	g.funcResToString = resultFunc
	g.mu = new(sync.RWMutex)

	g.resultChan = make(chan Result)

	return &g, nil
}

// Results returns a channel of Results
func (g *Gobuster) Results() <-chan Result {
	return g.resultChan
}

func (g *Gobuster) incrementRequests() {
	g.mu.Lock()
	g.requestsIssued++
	g.mu.Unlock()
}

// PrintProgress outputs the current wordlist progress to stderr
func (g *Gobuster) PrintProgress() {
	g.mu.RLock()
	if g.Opts.Wordlist == "-" {
		fmt.Fprintf(os.Stderr, "\rProgress: %d", g.requestsIssued)
	} else {
		fmt.Fprintf(os.Stderr, "\rProgress: %d / %d", g.requestsIssued, g.requestsExpected)
	}
	g.mu.RUnlock()
}

// ClearProgress removes the last status line from stderr
func (g *Gobuster) ClearProgress() {
	fmt.Fprint(os.Stderr, "\r")
}

// GetRequest issues a GET request to the target and returns
// the status code, length and an error
func (g *Gobuster) GetRequest(url string) (*int, *int64, error) {
	return g.http.makeRequest(url, g.Opts.Cookies)
}

func (g *Gobuster) worker(wordChan <-chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		select {
		case <-g.context.Done():
			return
		case word := <-wordChan:
			g.incrementRequests()
			// Mode-specific processing
			res, err := g.funcProcessor(g, word)
			if err != nil {
				// do not exit and continue
				log.Printf("ERROR on word %s: %v", word, err)
				continue
			} else {
				for _, r := range res {
					g.resultChan <- r
				}
			}
		}
	}
}

func (g *Gobuster) getWordlist() (*bufio.Scanner, error) {
	if g.Opts.Wordlist == "-" {
		// Read directly from stdin
		return bufio.NewScanner(os.Stdin), nil
	}
	// Pull content from the wordlist
	wordlist, err := os.Open(g.Opts.Wordlist)
	if err != nil {
		return nil, fmt.Errorf("failed to open wordlist: %v", err)
	}

	lines, err := lineCounter(wordlist)
	if err != nil {
		return nil, fmt.Errorf("failed to get number of lines: %v", err)
	}

	// mutiply by extensions to get the total number of requests
	if len(g.Opts.ExtensionsParsed) > 0 {
		lines = lines + (lines * len(g.Opts.ExtensionsParsed))
	}
	g.requestsExpected = lines

	// rewind wordlist
	_, err = wordlist.Seek(0, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to rewind wordlist: %v", err)
	}
	return bufio.NewScanner(wordlist), nil
}

// Start the busting of the website with the given
// set of settings from the command line.
func (g *Gobuster) Start() error {
	if err := g.funcSetup(g); err != nil {
		return err
	}

	var printerGroup sync.WaitGroup
	printerGroup.Add(1)
	var workerGroup sync.WaitGroup
	workerGroup.Add(g.Opts.Threads)

	wordChan := make(chan string, g.Opts.Threads)

	// Create goroutines for each of the number of threads
	// specified.
	for i := 0; i < g.Opts.Threads; i++ {
		go g.worker(wordChan, &workerGroup)
	}

	scanner, err := g.getWordlist()
	if err != nil {
		return err
	}

Scan:
	for scanner.Scan() {
		select {
		case <-g.context.Done():
			break Scan
		default:
			word := strings.TrimSpace(scanner.Text())
			// Skip "comment" (starts with #), as well as empty lines
			if !strings.HasPrefix(word, "#") && len(word) > 0 {
				wordChan <- word
			}
		}
	}
	close(wordChan)
	return nil
}

// ShowConfig prints the current config to the screen
func (g *Gobuster) ShowConfig() {
	o := g.Opts
	fmt.Printf("[+] Mode         : %s\n", o.Mode)
	fmt.Printf("[+] Url/Domain   : %s\n", o.URL)
	fmt.Printf("[+] Threads      : %d\n", o.Threads)

	wordlist := "stdin (pipe)"
	if o.Wordlist != "-" {
		wordlist = o.Wordlist
	}
	fmt.Printf("[+] Wordlist     : %s\n", wordlist)

	if o.Mode == ModeDir {
		fmt.Printf("[+] Status codes : %s\n", o.StatusCodesParsed.Stringify())

		if o.Proxy != "" {
			fmt.Printf("[+] Proxy        : %s\n", o.Proxy)
		}

		if o.Cookies != "" {
			fmt.Printf("[+] Cookies      : %s\n", o.Cookies)
		}

		if o.UserAgent != "" {
			fmt.Printf("[+] User Agent   : %s\n", o.UserAgent)
		}

		if o.IncludeLength {
			fmt.Printf("[+] Show length  : true\n")
		}

		if o.Username != "" {
			fmt.Printf("[+] Auth User    : %s\n", o.Username)
		}

		if len(o.Extensions) > 0 {
			fmt.Printf("[+] Extensions   : %s\n", strings.Join(o.ExtensionsParsed, ","))
		}

		if o.UseSlash {
			fmt.Printf("[+] Add Slash    : true\n")
		}

		if o.FollowRedirect {
			fmt.Printf("[+] Follow Redir : true\n")
		}

		if o.Expanded {
			fmt.Printf("[+] Expanded     : true\n")
		}

		if o.NoStatus {
			fmt.Printf("[+] No status    : true\n")
		}

		if o.Verbose {
			fmt.Printf("[+] Verbose      : true\n")
		}

		fmt.Printf("[+] Timeout      : %s\n", o.Timeout.String())
	}
}
<|endoftext|>


<commit_before>package types

import (
	"bytes"
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

func newConsensusParams(blockSize, partSize int) ConsensusParams {
	return ConsensusParams{
		BlockSize:   BlockSize{MaxBytes: blockSize},
		BlockGossip: BlockGossip{BlockPartSizeBytes: partSize},
	}
}

func TestConsensusParamsValidation(t *testing.T) {
	testCases := []struct {
		params ConsensusParams
		valid  bool
	}{
		{newConsensusParams(1, 1), true},
		{newConsensusParams(1, 0), false},
		{newConsensusParams(0, 1), false},
		{newConsensusParams(0, 0), false},
		{newConsensusParams(0, 10), false},
		{newConsensusParams(10, -1), false},
		{newConsensusParams(47*1024*1024, 400), true},
		{newConsensusParams(10, 400), true},
		{newConsensusParams(100*1024*1024, 400), true},
		{newConsensusParams(101*1024*1024, 400), false},
		{newConsensusParams(1024*1024*1024, 400), false},
	}
	for _, testCase := range testCases {
		if testCase.valid {
			assert.NoError(t, testCase.params.Validate(), "expected no error for valid params")
		} else {
			assert.Error(t, testCase.params.Validate(), "expected error for non valid params")
		}
	}
}

func makeParams(blockBytes, blockTx, blockGas, txBytes,
	txGas, partSize int) ConsensusParams {

	return ConsensusParams{
		BlockSize: BlockSize{
			MaxBytes: blockBytes,
			MaxTxs:   blockTx,
			MaxGas:   blockGas,
		},
		TxSize: TxSize{
			MaxBytes: txBytes,
			MaxGas:   txGas,
		},
		BlockGossip: BlockGossip{
			BlockPartSizeBytes: partSize,
		},
	}
}

func TestConsensusParamsHash(t *testing.T) {
	params := []ConsensusParams{
		makeParams(1, 2, 3, 4, 5, 6),
		makeParams(7, 2, 3, 4, 5, 6),
		makeParams(1, 7, 3, 4, 5, 6),
		makeParams(1, 2, 7, 4, 5, 6),
		makeParams(1, 2, 3, 7, 5, 6),
		makeParams(1, 2, 3, 4, 7, 6),
		makeParams(1, 2, 3, 4, 5, 7),
		makeParams(6, 5, 4, 3, 2, 1),
	}

	hashes := make([][]byte, len(params))
	for i := range params {
		hashes[i] = params[i].Hash()
	}

	// make sure there are no duplicates...
	// sort, then check in order for matches
	sort.Slice(hashes, func(i, j int) bool {
		return bytes.Compare(hashes[i], hashes[j]) < 0
	})
	for i := 0; i < len(hashes)-1; i++ {
		assert.NotEqual(t, hashes[i], hashes[i+1])
	}
}
<commit_msg>fix test<commit_after>package types

import (
	"bytes"
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

func newConsensusParams(blockSize, partSize int) ConsensusParams {
	return ConsensusParams{
		BlockSize:   BlockSize{MaxBytes: blockSize},
		BlockGossip: BlockGossip{BlockPartSizeBytes: partSize},
	}
}

func TestConsensusParamsValidation(t *testing.T) {
	testCases := []struct {
		params ConsensusParams
		valid  bool
	}{
		{newConsensusParams(1, 1), true},
		{newConsensusParams(1, 0), false},
		{newConsensusParams(0, 1), false},
		{newConsensusParams(0, 0), false},
		{newConsensusParams(0, 10), false},
		{newConsensusParams(10, -1), false},
		{newConsensusParams(47*1024*1024, 400), true},
		{newConsensusParams(10, 400), true},
		{newConsensusParams(100*1024*1024, 400), true},
		{newConsensusParams(101*1024*1024, 400), false},
		{newConsensusParams(1024*1024*1024, 400), false},
	}
	for _, testCase := range testCases {
		if testCase.valid {
			assert.NoError(t, testCase.params.Validate(), "expected no error for valid params")
		} else {
			assert.Error(t, testCase.params.Validate(), "expected error for non valid params")
		}
	}
}

func makeParams(blockBytes, blockTx, blockGas, txBytes,
	txGas, partSize int) ConsensusParams {

	return ConsensusParams{
		BlockSize: BlockSize{
			MaxBytes: blockBytes,
			MaxTxs:   blockTx,
			MaxGas:   int64(blockGas),
		},
		TxSize: TxSize{
			MaxBytes: txBytes,
			MaxGas:   int64(txGas),
		},
		BlockGossip: BlockGossip{
			BlockPartSizeBytes: partSize,
		},
	}
}

func TestConsensusParamsHash(t *testing.T) {
	params := []ConsensusParams{
		makeParams(1, 2, 3, 4, 5, 6),
		makeParams(7, 2, 3, 4, 5, 6),
		makeParams(1, 7, 3, 4, 5, 6),
		makeParams(1, 2, 7, 4, 5, 6),
		makeParams(1, 2, 3, 7, 5, 6),
		makeParams(1, 2, 3, 4, 7, 6),
		makeParams(1, 2, 3, 4, 5, 7),
		makeParams(6, 5, 4, 3, 2, 1),
	}

	hashes := make([][]byte, len(params))
	for i := range params {
		hashes[i] = params[i].Hash()
	}

	// make sure there are no duplicates...
	// sort, then check in order for matches
	sort.Slice(hashes, func(i, j int) bool {
		return bytes.Compare(hashes[i], hashes[j]) < 0
	})
	for i := 0; i < len(hashes)-1; i++ {
		assert.NotEqual(t, hashes[i], hashes[i+1])
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "menteslibres.net/gosexy/redis"
)

func main() {

    var client  *redis.Client
    var err error

    client = redis.New()

    err = client.Connect("127.0.0.1",6379)

    if err != nil {
        fmt.Println("Connect failed: %s\n")
        return
    }

    fmt.Println("Connected to redis-server.")

    fmt.Println("Welcome to my Coffee Counter. You can see how many times I've made coffee with the given brew type. Then you can increment one when you've made another cup")
  // Get list of Current coffee Items
    cl,err := client.LLen("coffees")// cl is a variable to store length of "coffees"
    // grab "coffees" list and store it in "Coffees" array
    Coffees := make([]string,int(cl))
    Coffees,err = client.LRange("coffees",0,-1)
    //print out each of the items
    var value string
    var n int64
    for n = 0; n < cl; n++ {
        string,err = client.Get(Coffees[n])
        option := string(n+1) + ". " + Coffees[n] + " : " + value + " Cups"
        fmt.Println(option)
    }

    client.Quit()

}

<commit_msg>fixed declaration errors :( okay, this is it... I promise<commit_after>package main

import (
    "fmt"
    "menteslibres.net/gosexy/redis"
)

func main() {

    var client  *redis.Client
    var err error

    client = redis.New()

    err = client.Connect("127.0.0.1",6379)

    if err != nil {
        fmt.Println("Connect failed: %s\n")
        return
    }

    fmt.Println("Connected to redis-server.")

    fmt.Println("Welcome to my Coffee Counter. You can see how many times I've made coffee with the given brew type. Then you can increment one when you've made another cup")
  // Get list of Current coffee Items
    cl,err := client.LLen("coffees")// cl is a variable to store length of "coffees"
    // grab "coffees" list and store it in "Coffees" array
    Coffees := make([]string,int(cl))
    Coffees,err = client.LRange("coffees",0,-1)
    //print out each of the items
    var value string
    var n int64
    for n = 0; n < cl; n++ {
        value,err = client.Get(Coffees[n])
        option := string(n+1) + ". " + Coffees[n] + " : " + value + " Cups"
        fmt.Println(option)
    }

    client.Quit()

}

<|endoftext|>


<commit_before>package waveform

import (
	"image/color"
	"testing"
)

// Named colors for easy testing
var (
	black = color.RGBA{0, 0, 0, 255}
	white = color.RGBA{255, 255, 255, 255}
	red   = color.RGBA{255, 0, 0, 255}
	green = color.RGBA{0, 255, 0, 255}
	blue  = color.RGBA{0, 0, 255, 255}
)

// TestSolidColor verifies that SolidColor always returns the same input
// color, for all input values.
func TestSolidColor(t *testing.T) {
	colors := []color.Color{
		black,
		white,
	}

	for i, c := range colors {
		fn := SolidColor(c)
		if out := fn(i, i, i, i, i, i); out != c {
			t.Fatalf("unexpected SolidColor color: %v != %v", out, c)
		}
	}
}

// TestFuzzColorOneColor verifies that FuzzColor produces only the single
// color used in its input.
func TestFuzzColorOneColor(t *testing.T) {
	testFuzzColor(t, []color.Color{black})
}

// TestFuzzColorMultipleColors verifies that FuzzColor produces only colors
// which are used in its input.
func TestFuzzColorMultipleColors(t *testing.T) {
	testFuzzColor(t, []color.Color{black, white, red, green, blue})
}

// TestStripeColorOneColor verifies that StripeColor produces a correct
// color sequence with a single input color.
func TestStripeColorOneColor(t *testing.T) {
	testStripeColor(t, []color.Color{black}, []color.Color{
		black, black, black, black,
	})
}

// TestStripeColorMultipleColors verifies that StripeColor produces a correct
// color sequence with multiple input colors.
func TestStripeColorMultipleColors(t *testing.T) {
	testStripeColor(t, []color.Color{
		black, white, white, red, green, green, green, blue,
	}, []color.Color{
		black, white, white, red, green, green, green, blue,
		black, white, white, red, green, green, green, blue,
	})
}

// testFuzzColor is a test helper which aids in testing the FuzzColor function.
func testFuzzColor(t *testing.T, in []color.Color) {
	// Make a set of colors from input slice
	set := make(map[color.RGBA]struct{})
	for _, c := range in {
		set[c.(color.RGBA)] = struct{}{}
	}

	// Validate that FuzzColor only produces colors which are present in
	// the input slice.
	fn := FuzzColor(in...)
	for i := 0; i < 10000; i++ {
		if out, ok := set[fn(i, i, i, i, i, i).(color.RGBA)]; !ok {
			t.Fatalf("color not in set: %v", out)
		}
	}
}

// testStripeColor is a test helper which aids in testing the StripeColor function.
func testStripeColor(t *testing.T, in []color.Color, out []color.Color) {
	// Validate that StripeColor produces expected output at each index
	fn := StripeColor(in...)
	for i := 0; i < len(out); i++ {
		if c := fn(i, 0, 0, 0, 0, 0); c != out[i] {
			t.Fatalf("[%02d] unexpected output color: %v != %v", i, c, out[i])
		}
	}
}
<commit_msg>colorfunc_test: add tests for CheckerColor<commit_after>package waveform

import (
	"image/color"
	"testing"
)

// Named colors for easy testing
var (
	black = color.RGBA{0, 0, 0, 255}
	white = color.RGBA{255, 255, 255, 255}
	red   = color.RGBA{255, 0, 0, 255}
	green = color.RGBA{0, 255, 0, 255}
	blue  = color.RGBA{0, 0, 255, 255}
)

// TestCheckerColorOneColor verifies that CheckerColor produces only the single
// color used in its input.
func TestCheckerColorOneColor(t *testing.T) {
	testCheckerColor(t, black, black)
}

// TestCheckerColorTwoColors verifies that CheckerColor produces only colors
// which are used in its input.
func TestCheckerColorTwoColors(t *testing.T) {
	testCheckerColor(t, black, white)
}

// TestFuzzColorOneColor verifies that FuzzColor produces only the single
// color used in its input.
func TestFuzzColorOneColor(t *testing.T) {
	testFuzzColor(t, []color.Color{black})
}

// TestFuzzColorMultipleColors verifies that FuzzColor produces only colors
// which are used in its input.
func TestFuzzColorMultipleColors(t *testing.T) {
	testFuzzColor(t, []color.Color{black, white, red, green, blue})
}

// TestSolidColor verifies that SolidColor always returns the same input
// color, for all input values.
func TestSolidColor(t *testing.T) {
	colors := []color.Color{
		black,
		white,
	}

	for i, c := range colors {
		fn := SolidColor(c)
		if out := fn(i, i, i, i, i, i); out != c {
			t.Fatalf("unexpected SolidColor color: %v != %v", out, c)
		}
	}
}

// TestStripeColorOneColor verifies that StripeColor produces a correct
// color sequence with a single input color.
func TestStripeColorOneColor(t *testing.T) {
	testStripeColor(t, []color.Color{black}, []color.Color{
		black, black, black, black,
	})
}

// TestStripeColorMultipleColors verifies that StripeColor produces a correct
// color sequence with multiple input colors.
func TestStripeColorMultipleColors(t *testing.T) {
	testStripeColor(t, []color.Color{
		black, white, white, red, green, green, green, blue,
	}, []color.Color{
		black, white, white, red, green, green, green, blue,
		black, white, white, red, green, green, green, blue,
	})
}

// testCheckerColor is a test helper which aids in testing the CheckerColor function.
func testCheckerColor(t *testing.T, colorA color.Color, colorB color.Color) {
	// Predefined values for test
	const maxX, maxY, size = 1000, 1000, 10

	// Generate checker function with input values
	fn := CheckerColor(colorA, colorB, size)

	// Iterate all coordinates and check color at each
	for x := 0; x < maxX; x++ {
		for y := 0; y < maxY; y++ {
			// Check color at specified coordinate
			c := fn(0, x, y, 0, maxX, maxY)

			// Apply checker algorithm to determine if color A or B should be used
			if ((uint(x)/size)+(uint(y)/size))%2 == 0 {
				if c != colorA {
					t.Fatalf("unexpected color: %v != %v", c, colorA)
				}
			} else {
				if c != colorB {
					t.Fatalf("unexpected color: %v != %v", c, colorB)
				}
			}
		}
	}
}

// testFuzzColor is a test helper which aids in testing the FuzzColor function.
func testFuzzColor(t *testing.T, in []color.Color) {
	// Make a set of colors from input slice
	set := make(map[color.RGBA]struct{})
	for _, c := range in {
		set[c.(color.RGBA)] = struct{}{}
	}

	// Validate that FuzzColor only produces colors which are present in
	// the input slice.
	fn := FuzzColor(in...)
	for i := 0; i < 10000; i++ {
		if out, ok := set[fn(i, i, i, i, i, i).(color.RGBA)]; !ok {
			t.Fatalf("color not in set: %v", out)
		}
	}
}

// testStripeColor is a test helper which aids in testing the StripeColor function.
func testStripeColor(t *testing.T, in []color.Color, out []color.Color) {
	// Validate that StripeColor produces expected output at each index
	fn := StripeColor(in...)
	for i := 0; i < len(out); i++ {
		if c := fn(i, 0, 0, 0, 0, 0); c != out[i] {
			t.Fatalf("[%02d] unexpected output color: %v != %v", i, c, out[i])
		}
	}
}
<|endoftext|>


<commit_before>package termite

import (
	"bytes"
	"os"
	"log"
	"sync"
	"rpc"
	"github.com/hanwen/go-fuse/fuse"
)

type RpcFs struct {
	fuse.DefaultFileSystem
	cache *DiskFileCache

	client *rpc.Client

	dirMutex    sync.Mutex
	directories map[string]*DirResponse

	attrMutex    sync.RWMutex
	attrResponse map[string]*AttrResponse
}

func NewRpcFs(server *rpc.Client, cache *DiskFileCache) *RpcFs {
	me := &RpcFs{}
	me.client = server
	me.directories = make(map[string]*DirResponse)
	me.cache = cache
	me.attrResponse = make(map[string]*AttrResponse)
	return me
}

func (me *RpcFs) GetDir(name string) *DirResponse {
	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()

	r, ok := me.directories[name]
	if ok {
		return r
	}

	// TODO - asynchronous.
	// TODO - eliminate cut & paste
	req := &DirRequest{Name: "/" + name}
	rep := &DirResponse{}
	err := me.client.Call("FsServer.ReadDir", req, rep)
	if err != nil {
		log.Println("GetDir error:", err)
		return nil
	}

	me.directories[name] = rep
	return rep
}

func (me *RpcFs) OpenDir(name string) (chan fuse.DirEntry, fuse.Status) {
	r := me.GetDir(name)

	if r == nil {
		return nil, fuse.ENOENT
	}
	c := make(chan fuse.DirEntry, len(r.NameModeMap))
	for k, mode := range r.NameModeMap {
		c <- fuse.DirEntry{
			Name: k,
			Mode: mode,
		}
	}
	close(c)
	return c, fuse.OK
}

func (me *RpcFs) Open(name string, flags uint32) (fuse.File, fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EPERM
	}
	a := me.getAttrResponse(name)
	if !a.Status.Ok() {
		return nil, a.Status
	}

	p := me.cache.Path(a.Hash)
	if _, err := os.Lstat(p); fuse.OsErrorToErrno(err) == fuse.ENOENT {
		log.Printf("Fetching contents for file %s", name)
		me.FetchHash(a.FileInfo.Size, a.Hash)
	}

	f, err := os.Open(p)
	if err != nil {
		return nil, fuse.OsErrorToErrno(err)
	}

	return &fuse.LoopbackFile{File: f}, fuse.OK
}

// TODO - should be streaming.
func (me *RpcFs) FetchHash(size int64, hash []byte) {
	b := FetchFromContentServer(me.client, "FsServer.FileContent", size, hash)
	savedHash := me.cache.Save(b)
	if bytes.Compare(hash, savedHash) != 0 {
		log.Fatalf("Corruption: savedHash %x != requested hash %x.", savedHash, hash)
	}
}

func (me *RpcFs) Readlink(name string) (string, fuse.Status) {
	a := me.getAttrResponse(name)

	if !a.Status.Ok() {
		return "", a.Status
	}
	if !a.FileInfo.IsSymlink() {
		return "", fuse.EINVAL
	}

	return a.Link, fuse.OK
}

func (me *RpcFs) getAttrResponse(name string) *AttrResponse {
	me.attrMutex.RLock()
	result, ok := me.attrResponse[name]
	me.attrMutex.RUnlock()

	if ok {
		return result
	}

	req := &AttrRequest{Name: "/" + name}
	rep := &AttrResponse{}
	err := me.client.Call("FsServer.GetAttr", req, rep)
	if err != nil {
		log.Println("GetAttr error:", err)
		return nil
	}

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()
	me.attrResponse[name] = rep
	return rep
}

func (me *RpcFs) GetAttr(name string) (*os.FileInfo, fuse.Status) {
	if name == "" {
		return &os.FileInfo{
			Mode: fuse.S_IFDIR | 0755,
		}, fuse.OK
	}

	r := me.getAttrResponse(name)
	return r.FileInfo, r.Status
}
<commit_msg>RpcFs: don't crash on broken connection.<commit_after>package termite

import (
	"bytes"
	"os"
	"log"
	"sync"
	"rpc"
	"github.com/hanwen/go-fuse/fuse"
)

type RpcFs struct {
	fuse.DefaultFileSystem
	cache *DiskFileCache

	client *rpc.Client

	dirMutex    sync.Mutex
	directories map[string]*DirResponse

	attrMutex    sync.RWMutex
	attrResponse map[string]*AttrResponse
}

func NewRpcFs(server *rpc.Client, cache *DiskFileCache) *RpcFs {
	me := &RpcFs{}
	me.client = server
	me.directories = make(map[string]*DirResponse)
	me.cache = cache
	me.attrResponse = make(map[string]*AttrResponse)
	return me
}

func (me *RpcFs) GetDir(name string) *DirResponse {
	me.dirMutex.Lock()
	defer me.dirMutex.Unlock()

	r, ok := me.directories[name]
	if ok {
		return r
	}

	// TODO - asynchronous.
	// TODO - eliminate cut & paste
	req := &DirRequest{Name: "/" + name}
	rep := &DirResponse{}
	err := me.client.Call("FsServer.ReadDir", req, rep)
	if err != nil {
		log.Println("GetDir error:", err)
		return nil
	}

	me.directories[name] = rep
	return rep
}

func (me *RpcFs) OpenDir(name string) (chan fuse.DirEntry, fuse.Status) {
	r := me.GetDir(name)

	if r == nil {
		return nil, fuse.ENOENT
	}
	c := make(chan fuse.DirEntry, len(r.NameModeMap))
	for k, mode := range r.NameModeMap {
		c <- fuse.DirEntry{
			Name: k,
			Mode: mode,
		}
	}
	close(c)
	return c, fuse.OK
}

func (me *RpcFs) Open(name string, flags uint32) (fuse.File, fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EPERM
	}
	a := me.getAttrResponse(name)
	if a == nil {
		return nil, fuse.ENOENT
	}
	if !a.Status.Ok() {
		return nil, a.Status
	}

	p := me.cache.Path(a.Hash)
	if _, err := os.Lstat(p); fuse.OsErrorToErrno(err) == fuse.ENOENT {
		log.Printf("Fetching contents for file %s", name)
		me.FetchHash(a.FileInfo.Size, a.Hash)
	}

	f, err := os.Open(p)
	if err != nil {
		return nil, fuse.OsErrorToErrno(err)
	}

	return &fuse.LoopbackFile{File: f}, fuse.OK
}

// TODO - should be streaming.
func (me *RpcFs) FetchHash(size int64, hash []byte) {
	b := FetchFromContentServer(me.client, "FsServer.FileContent", size, hash)
	savedHash := me.cache.Save(b)
	if bytes.Compare(hash, savedHash) != 0 {
		log.Fatalf("Corruption: savedHash %x != requested hash %x.", savedHash, hash)
	}
}

func (me *RpcFs) Readlink(name string) (string, fuse.Status) {
	a := me.getAttrResponse(name)
	if a == nil {
		return "", fuse.ENOENT
	}

	if !a.Status.Ok() {
		return "", a.Status
	}
	if !a.FileInfo.IsSymlink() {
		return "", fuse.EINVAL
	}

	return a.Link, fuse.OK
}

func (me *RpcFs) getAttrResponse(name string) *AttrResponse {
	me.attrMutex.RLock()
	result, ok := me.attrResponse[name]
	me.attrMutex.RUnlock()

	if ok {
		return result
	}

	req := &AttrRequest{Name: "/" + name}
	rep := &AttrResponse{}
	err := me.client.Call("FsServer.GetAttr", req, rep)
	if err != nil {
		log.Println("GetAttr error:", err)
		return nil
	}

	me.attrMutex.Lock()
	defer me.attrMutex.Unlock()
	me.attrResponse[name] = rep
	return rep
}

func (me *RpcFs) GetAttr(name string) (*os.FileInfo, fuse.Status) {
	if name == "" {
		return &os.FileInfo{
			Mode: fuse.S_IFDIR | 0755,
		}, fuse.OK
	}

	r := me.getAttrResponse(name)
	if r == nil {
		return nil, fuse.ENOENT
	}

	return r.FileInfo, r.Status
}
<|endoftext|>