<commit_before>package forward

import (
	"context"
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/spf13/cobra"

	"github.com/havoc-io/mutagen/cmd"
	"github.com/havoc-io/mutagen/cmd/mutagen/daemon"
	forwardingpkg "github.com/havoc-io/mutagen/pkg/forwarding"
	"github.com/havoc-io/mutagen/pkg/grpcutil"
	promptpkg "github.com/havoc-io/mutagen/pkg/prompt"
	"github.com/havoc-io/mutagen/pkg/selection"
	forwardingsvcpkg "github.com/havoc-io/mutagen/pkg/service/forwarding"
	"github.com/havoc-io/mutagen/pkg/url"
)

func createMain(command *cobra.Command, arguments []string) error {
	// Validate, extract, and parse URLs.
	if len(arguments) != 2 {
		return errors.New("invalid number of endpoint URLs provided")
	}
	source, err := url.Parse(arguments[0], url.Kind_Forwarding, true)
	if err != nil {
		return errors.Wrap(err, "unable to parse source URL")
	}
	destination, err := url.Parse(arguments[1], url.Kind_Forwarding, false)
	if err != nil {
		return errors.Wrap(err, "unable to parse destination URL")
	}

	// Parse, validate, and record labels.
	var labels map[string]string
	if len(createConfiguration.labels) > 0 {
		labels = make(map[string]string, len(createConfiguration.labels))
	}
	for _, label := range createConfiguration.labels {
		components := strings.SplitN(label, "=", 2)
		var key, value string
		key = components[0]
		if len(components) == 2 {
			value = components[1]
		}
		if err := selection.EnsureLabelKeyValid(key); err != nil {
			return errors.Wrap(err, "invalid label key")
		} else if err := selection.EnsureLabelValueValid(value); err != nil {
			return errors.Wrap(err, "invalid label value")
		}
		labels[key] = value
	}

	// Connect to the daemon and defer closure of the connection.
	daemonConnection, err := daemon.CreateClientConnection(true)
	if err != nil {
		return errors.Wrap(err, "unable to connect to daemon")
	}
	defer daemonConnection.Close()

	// Create a session service client.
	sessionService := forwardingsvcpkg.NewForwardingClient(daemonConnection)

	// Invoke the session create method. The stream will close when the
	// associated context is cancelled.
	createContext, cancel := context.WithCancel(context.Background())
	defer cancel()
	stream, err := sessionService.Create(createContext)
	if err != nil {
		return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to invoke create")
	}

	// Send the initial request.
	request := &forwardingsvcpkg.CreateRequest{
		Specification: &forwardingsvcpkg.CreationSpecification{
			Source:                   source,
			Destination:              destination,
			Configuration:            &forwardingpkg.Configuration{},
			ConfigurationSource:      &forwardingpkg.Configuration{},
			ConfigurationDestination: &forwardingpkg.Configuration{},
			Labels:                   labels,
		},
	}
	if err := stream.Send(request); err != nil {
		return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send create request")
	}

	// Create a status line printer and defer a break.
	statusLinePrinter := &cmd.StatusLinePrinter{}
	defer statusLinePrinter.BreakIfNonEmpty()

	// Receive and process responses until we're done.
	for {
		if response, err := stream.Recv(); err != nil {
			return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "create failed")
		} else if err = response.EnsureValid(); err != nil {
			return errors.Wrap(err, "invalid create response received")
		} else if response.Session != "" {
			statusLinePrinter.Print(fmt.Sprintf("Created session %s", response.Session))
			return nil
		} else if response.Message != "" {
			statusLinePrinter.Print(response.Message)
			if err := stream.Send(&forwardingsvcpkg.CreateRequest{}); err != nil {
				return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send message response")
			}
		} else if response.Prompt != "" {
			statusLinePrinter.BreakIfNonEmpty()
			if response, err := promptpkg.PromptCommandLine(response.Prompt); err != nil {
				return errors.Wrap(err, "unable to perform prompting")
			} else if err = stream.Send(&forwardingsvcpkg.CreateRequest{Response: response}); err != nil {
				return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send prompt response")
			}
		}
	}
}

var createCommand = &cobra.Command{
	Use:          "create <source> <destination>",
	Short:        "Create and start a new forwarding session",
	RunE:         createMain,
	SilenceUsage: true,
}

var createConfiguration struct {
	// help indicates whether or not help information should be shown for the
	// command.
	help bool
	// labels are the label specifications for the session.
	labels []string
}

func init() {
	// Grab a handle for the command line flags.
	flags := createCommand.Flags()

	// Disable alphabetical sorting of flags in help output.
	flags.SortFlags = false

	// Manually add a help flag to override the default message. Cobra will
	// still implement its logic automatically.
	flags.BoolVarP(&createConfiguration.help, "help", "h", false, "Show help information")

	// Wire up label flags.
	flags.StringSliceVarP(&createConfiguration.labels, "label", "l", nil, "Specify labels")
}
<commit_msg>Modified forward create command to normalize Unix socket paths.<commit_after>package forward

import (
	"context"
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/spf13/cobra"

	"github.com/havoc-io/mutagen/cmd"
	"github.com/havoc-io/mutagen/cmd/mutagen/daemon"
	"github.com/havoc-io/mutagen/pkg/filesystem"
	forwardingpkg "github.com/havoc-io/mutagen/pkg/forwarding"
	"github.com/havoc-io/mutagen/pkg/grpcutil"
	promptpkg "github.com/havoc-io/mutagen/pkg/prompt"
	"github.com/havoc-io/mutagen/pkg/selection"
	forwardingsvcpkg "github.com/havoc-io/mutagen/pkg/service/forwarding"
	"github.com/havoc-io/mutagen/pkg/url"
	forwardingurl "github.com/havoc-io/mutagen/pkg/url/forwarding"
)

func createMain(command *cobra.Command, arguments []string) error {
	// Validate, extract, and parse URLs.
	if len(arguments) != 2 {
		return errors.New("invalid number of endpoint URLs provided")
	}
	source, err := url.Parse(arguments[0], url.Kind_Forwarding, true)
	if err != nil {
		return errors.Wrap(err, "unable to parse source URL")
	}
	destination, err := url.Parse(arguments[1], url.Kind_Forwarding, false)
	if err != nil {
		return errors.Wrap(err, "unable to parse destination URL")
	}

	// If either URL is a local Unix domain socket path, make sure it's
	// normalized.
	if source.Protocol == url.Protocol_Local {
		if protocol, path, err := forwardingurl.Parse(source.Path); err != nil {
			return errors.Wrap(err, "unable to parse source forwarding endpoint URL")
		} else if protocol == "unix" {
			if normalized, err := filesystem.Normalize(path); err != nil {
				return errors.Wrap(err, "unable to normalize source forwarding endpoint socket path")
			} else {
				source.Path = fmt.Sprintf("%s:%s", protocol, normalized)
			}
		}
	}
	if destination.Protocol == url.Protocol_Local {
		if protocol, path, err := forwardingurl.Parse(destination.Path); err != nil {
			return errors.Wrap(err, "unable to parse destination forwarding endpoint URL")
		} else if protocol == "unix" {
			if normalized, err := filesystem.Normalize(path); err != nil {
				return errors.Wrap(err, "unable to normalize destination forwarding endpoint socket path")
			} else {
				destination.Path = fmt.Sprintf("%s:%s", protocol, normalized)
			}
		}
	}

	// Parse, validate, and record labels.
	var labels map[string]string
	if len(createConfiguration.labels) > 0 {
		labels = make(map[string]string, len(createConfiguration.labels))
	}
	for _, label := range createConfiguration.labels {
		components := strings.SplitN(label, "=", 2)
		var key, value string
		key = components[0]
		if len(components) == 2 {
			value = components[1]
		}
		if err := selection.EnsureLabelKeyValid(key); err != nil {
			return errors.Wrap(err, "invalid label key")
		} else if err := selection.EnsureLabelValueValid(value); err != nil {
			return errors.Wrap(err, "invalid label value")
		}
		labels[key] = value
	}

	// Connect to the daemon and defer closure of the connection.
	daemonConnection, err := daemon.CreateClientConnection(true)
	if err != nil {
		return errors.Wrap(err, "unable to connect to daemon")
	}
	defer daemonConnection.Close()

	// Create a session service client.
	sessionService := forwardingsvcpkg.NewForwardingClient(daemonConnection)

	// Invoke the session create method. The stream will close when the
	// associated context is cancelled.
	createContext, cancel := context.WithCancel(context.Background())
	defer cancel()
	stream, err := sessionService.Create(createContext)
	if err != nil {
		return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to invoke create")
	}

	// Send the initial request.
	request := &forwardingsvcpkg.CreateRequest{
		Specification: &forwardingsvcpkg.CreationSpecification{
			Source:                   source,
			Destination:              destination,
			Configuration:            &forwardingpkg.Configuration{},
			ConfigurationSource:      &forwardingpkg.Configuration{},
			ConfigurationDestination: &forwardingpkg.Configuration{},
			Labels:                   labels,
		},
	}
	if err := stream.Send(request); err != nil {
		return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send create request")
	}

	// Create a status line printer and defer a break.
	statusLinePrinter := &cmd.StatusLinePrinter{}
	defer statusLinePrinter.BreakIfNonEmpty()

	// Receive and process responses until we're done.
	for {
		if response, err := stream.Recv(); err != nil {
			return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "create failed")
		} else if err = response.EnsureValid(); err != nil {
			return errors.Wrap(err, "invalid create response received")
		} else if response.Session != "" {
			statusLinePrinter.Print(fmt.Sprintf("Created session %s", response.Session))
			return nil
		} else if response.Message != "" {
			statusLinePrinter.Print(response.Message)
			if err := stream.Send(&forwardingsvcpkg.CreateRequest{}); err != nil {
				return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send message response")
			}
		} else if response.Prompt != "" {
			statusLinePrinter.BreakIfNonEmpty()
			if response, err := promptpkg.PromptCommandLine(response.Prompt); err != nil {
				return errors.Wrap(err, "unable to perform prompting")
			} else if err = stream.Send(&forwardingsvcpkg.CreateRequest{Response: response}); err != nil {
				return errors.Wrap(grpcutil.PeelAwayRPCErrorLayer(err), "unable to send prompt response")
			}
		}
	}
}

var createCommand = &cobra.Command{
	Use:          "create <source> <destination>",
	Short:        "Create and start a new forwarding session",
	RunE:         createMain,
	SilenceUsage: true,
}

var createConfiguration struct {
	// help indicates whether or not help information should be shown for the
	// command.
	help bool
	// labels are the label specifications for the session.
	labels []string
}

func init() {
	// Grab a handle for the command line flags.
	flags := createCommand.Flags()

	// Disable alphabetical sorting of flags in help output.
	flags.SortFlags = false

	// Manually add a help flag to override the default message. Cobra will
	// still implement its logic automatically.
	flags.BoolVarP(&createConfiguration.help, "help", "h", false, "Show help information")

	// Wire up label flags.
	flags.StringSliceVarP(&createConfiguration.labels, "label", "l", nil, "Specify labels")
}
<|endoftext|>


<commit_before>package main_test

import (
	"bufio"
	"bytes"
	"net"
	"time"

	"github.com/cloudfoundry-incubator/routing-api/db"
	"github.com/tedsuo/ifrit/ginkgomon"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Routes API", func() {
	var (
		err              error
		route1           db.Route
		addr             *net.UDPAddr
		fakeStatsdServer *net.UDPConn
		fakeStatsdChan   chan string
	)

	BeforeEach(func() {
		routingAPIProcess = ginkgomon.Invoke(routingAPIRunner)
		addr, err = net.ResolveUDPAddr("udp", "localhost:8125")
		Expect(err).ToNot(HaveOccurred())

		fakeStatsdServer, err = net.ListenUDP("udp", addr)
		fakeStatsdServer.SetReadDeadline(time.Now().Add(15 * time.Second))
		Expect(err).ToNot(HaveOccurred())
		fakeStatsdChan = make(chan string, 1)

		go func() {
			defer GinkgoRecover()
			for {
				buffer := make([]byte, 1000)
				_, err := fakeStatsdServer.Read(buffer)
				if err != nil {
					close(fakeStatsdChan)
					return
				}
				scanner := bufio.NewScanner(bytes.NewBuffer(buffer))
				for scanner.Scan() {
					select {
					case fakeStatsdChan <- scanner.Text():
					}
				}
			}
		}()

		time.Sleep(1000 * time.Millisecond)
	})

	AfterEach(func() {
		ginkgomon.Kill(routingAPIProcess)
		err := fakeStatsdServer.Close()
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("Stats for event subscribers", func() {
		Context("Subscribe", func() {
			It("should increase subscriptions by 4", func() {

				eventStream1, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream1.Close()

				eventStream2, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream2.Close()

				eventStream3, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream3.Close()

				eventStream4, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream4.Close()

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
			})
		})
	})

	Describe("Stats for total routes", func() {

		BeforeEach(func() {
			route1 = db.Route{
				Route:   "a.b.c",
				Port:    33,
				IP:      "1.1.1.1",
				TTL:     55,
				LogGuid: "potato",
			}
		})

		Context("periodically receives total routes", func() {
			It("Gets statsd messages for existing routes", func() {
				//The first time is because we get the event of adding the self route
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:1|g")))
				//Do it again to make sure it's not because of events
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:1|g")))
			})
		})

		Context("when creating and updating a new route", func() {
			It("Gets statsd messages for new routes", func() {
				client.UpsertRoutes([]db.Route{route1})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
			})
		})

		Context("when deleting a route", func() {
			It("gets statsd messages for deleted routes", func() {
				client.UpsertRoutes([]db.Route{route1})

				client.DeleteRoutes([]db.Route{route1})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:-1|g")))
			})
		})

		Context("when expiring a route", func() {
			It("gets statsd messages for expired routes", func() {
				routeExpire := db.Route{
					Route:   "z.a.k",
					Port:    63,
					IP:      "42.42.42.42",
					TTL:     1,
					LogGuid: "Tomato",
				}

				client.UpsertRoutes([]db.Route{routeExpire})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:-1|g")))
			})
		})
	})
})
<commit_msg>Fixed a ginkgo race condition in stats_test.go<commit_after>package main_test

import (
	"bufio"
	"bytes"
	"net"
	"time"

	"github.com/cloudfoundry-incubator/routing-api/db"
	"github.com/tedsuo/ifrit/ginkgomon"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Routes API", func() {
	var (
		err              error
		route1           db.Route
		addr             *net.UDPAddr
		fakeStatsdServer *net.UDPConn
		fakeStatsdChan   chan string
	)

	BeforeEach(func() {
		routingAPIProcess = ginkgomon.Invoke(routingAPIRunner)
		addr, err = net.ResolveUDPAddr("udp", "localhost:8125")
		Expect(err).ToNot(HaveOccurred())

		fakeStatsdServer, err = net.ListenUDP("udp", addr)
		fakeStatsdServer.SetReadDeadline(time.Now().Add(15 * time.Second))
		Expect(err).ToNot(HaveOccurred())
		fakeStatsdChan = make(chan string, 1)

		go func(statsChan chan string) {
			defer GinkgoRecover()
			for {
				buffer := make([]byte, 1000)
				_, err := fakeStatsdServer.Read(buffer)
				if err != nil {
					close(statsChan)
					return
				}
				scanner := bufio.NewScanner(bytes.NewBuffer(buffer))
				for scanner.Scan() {
					select {
					case statsChan <- scanner.Text():
					}
				}
			}
		}(fakeStatsdChan)

		time.Sleep(1000 * time.Millisecond)
	})

	AfterEach(func() {
		ginkgomon.Kill(routingAPIProcess)
		err := fakeStatsdServer.Close()
		Expect(err).ToNot(HaveOccurred())
	})

	Describe("Stats for event subscribers", func() {
		Context("Subscribe", func() {
			It("should increase subscriptions by 4", func() {

				eventStream1, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream1.Close()

				eventStream2, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream2.Close()

				eventStream3, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream3.Close()

				eventStream4, err := client.SubscribeToEvents()
				Expect(err).NotTo(HaveOccurred())
				defer eventStream4.Close()

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_subscriptions:+1|g")))
			})
		})
	})

	Describe("Stats for total routes", func() {

		BeforeEach(func() {
			route1 = db.Route{
				Route:   "a.b.c",
				Port:    33,
				IP:      "1.1.1.1",
				TTL:     55,
				LogGuid: "potato",
			}
		})

		Context("periodically receives total routes", func() {
			It("Gets statsd messages for existing routes", func() {
				//The first time is because we get the event of adding the self route
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:1|g")))
				//Do it again to make sure it's not because of events
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:1|g")))
			})
		})

		Context("when creating and updating a new route", func() {
			It("Gets statsd messages for new routes", func() {
				client.UpsertRoutes([]db.Route{route1})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
			})
		})

		Context("when deleting a route", func() {
			It("gets statsd messages for deleted routes", func() {
				client.UpsertRoutes([]db.Route{route1})

				client.DeleteRoutes([]db.Route{route1})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:-1|g")))
			})
		})

		Context("when expiring a route", func() {
			It("gets statsd messages for expired routes", func() {
				routeExpire := db.Route{
					Route:   "z.a.k",
					Port:    63,
					IP:      "42.42.42.42",
					TTL:     1,
					LogGuid: "Tomato",
				}

				client.UpsertRoutes([]db.Route{routeExpire})

				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:+1|g")))
				Eventually(fakeStatsdChan).Should(Receive(Equal("routing_api.total_routes:-1|g")))
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"gopkg.in/natefinch/lumberjack.v2"
	"k8s.io/klog"
)

func main() {
	terminationLog := flag.String("termination-log-file", "", "Write logs after SIGTERM to this file (in addition to stderr)")
	terminationLock := flag.String("termination-touch-file", "", "Touch this file on SIGTERM and delete on termination")

	klog.InitFlags(nil)
	flag.Set("v", "9")

	// never log to stderr, only through our termination log writer (which sends it also to stderr)
	flag.Set("logtostderr", "false")
	flag.Set("stderrthreshold", "99")

	flag.Parse()
	args := flag.CommandLine.Args()

	if len(args) == 0 {
		fmt.Println("Missing command line")
		os.Exit(1)
	}

	// use special tee-like writer when termination log is set
	termCh := make(chan struct{})
	var stderr io.Writer = os.Stderr
	if len(*terminationLog) > 0 {
		stderr = &terminationFileWriter{
			Writer:             os.Stderr,
			fn:                 *terminationLog,
			startFileLoggingCh: termCh,
		}

		// do the klog file writer dance: klog writes to all outputs of lower
		// severity. No idea why. So we discard for anything other than info.
		// Otherwise, we would see errors multiple times.
		klog.SetOutput(ioutil.Discard)
		klog.SetOutputBySeverity("INFO", stderr)
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = stderr

	// forward SIGTERM and SIGINT to child
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for s := range sigCh {
			select {
			case <-termCh:
			default:
				close(termCh)
			}

			klog.Infof("Received signal %s. Forwarding to sub-process %q.", s, args[0])

			if len(*terminationLock) > 0 {
				klog.Infof("Touching termination lock file %q", *terminationLock)
				if err := touch(*terminationLock); err != nil {
					klog.Infof("error touching %s: %v", *terminationLock, err)
					// keep going
				}
			}

			cmd.Process.Signal(s)
		}
	}()

	klog.Infof("Launching sub-process %q", cmd)
	rc := 0
	if err := cmd.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			rc = exitError.ExitCode()
		} else {
			klog.Infof("Failed to launch %s: %v", args[0], err)
			os.Exit(255)
		}
	}

	// remove signal handling
	signal.Stop(sigCh)
	close(sigCh)
	wg.Wait()

	if len(*terminationLock) > 0 {
		klog.Infof("Deleting termination lock file %q", *terminationLock)
		os.Remove(*terminationLock)
	}

	klog.Infof("Termination finished with exit code %d", rc)
	os.Exit(rc)
}

// terminationFileWriter forwards everything to the embedded writer. When
// startFileLoggingCh is closed, everything is appended to the given file name
// in addition.
type terminationFileWriter struct {
	io.Writer
	fn                 string
	startFileLoggingCh <-chan struct{}

	logger io.Writer
}

func (w *terminationFileWriter) Write(bs []byte) (int, error) {
	select {
	case <-w.startFileLoggingCh:
		if w.logger == nil {
			l := &lumberjack.Logger{
				Filename:   w.fn,
				MaxSize:    100,
				MaxBackups: 3,
				MaxAge:     28,
				Compress:   false,
			}
			w.logger = l
			fmt.Fprintf(os.Stderr, "Copying termination logs to %q\n", w.fn)
		}
		if n, err := w.logger.Write(bs); err != nil {
			return n, err
		} else if n != len(bs) {
			return n, io.ErrShortWrite
		}
	default:
	}

	return w.Writer.Write(bs)
}

func touch(fn string) error {
	_, err := os.Stat(fn)
	if os.IsNotExist(err) {
		file, err := os.Create(fn)
		if err != nil {
			return err
		}
		defer file.Close()
		return nil
	}

	currentTime := time.Now().Local()
	return os.Chtimes(fn, currentTime, currentTime)
}
<commit_msg>watch-termination: hide oauth tokens<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"gopkg.in/natefinch/lumberjack.v2"
	"k8s.io/klog"
)

func main() {
	terminationLog := flag.String("termination-log-file", "", "Write logs after SIGTERM to this file (in addition to stderr)")
	terminationLock := flag.String("termination-touch-file", "", "Touch this file on SIGTERM and delete on termination")

	klog.InitFlags(nil)
	flag.Set("v", "9")

	// never log to stderr, only through our termination log writer (which sends it also to stderr)
	flag.Set("logtostderr", "false")
	flag.Set("stderrthreshold", "99")

	flag.Parse()
	args := flag.CommandLine.Args()

	if len(args) == 0 {
		fmt.Println("Missing command line")
		os.Exit(1)
	}

	// use special tee-like writer when termination log is set
	termCh := make(chan struct{})
	var stderr io.Writer = os.Stderr
	if len(*terminationLog) > 0 {
		stderr = &terminationFileWriter{
			Writer:             os.Stderr,
			fn:                 *terminationLog,
			startFileLoggingCh: termCh,
		}

		// do the klog file writer dance: klog writes to all outputs of lower
		// severity. No idea why. So we discard for anything other than info.
		// Otherwise, we would see errors multiple times.
		klog.SetOutput(ioutil.Discard)
		klog.SetOutputBySeverity("INFO", stderr)
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = stderr

	// forward SIGTERM and SIGINT to child
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for s := range sigCh {
			select {
			case <-termCh:
			default:
				close(termCh)
			}

			klog.Infof("Received signal %s. Forwarding to sub-process %q.", s, args[0])

			if len(*terminationLock) > 0 {
				klog.Infof("Touching termination lock file %q", *terminationLock)
				if err := touch(*terminationLock); err != nil {
					klog.Infof("error touching %s: %v", *terminationLock, err)
					// keep going
				}
			}

			cmd.Process.Signal(s)
		}
	}()

	klog.Infof("Launching sub-process %q", cmd)
	rc := 0
	if err := cmd.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			rc = exitError.ExitCode()
		} else {
			klog.Infof("Failed to launch %s: %v", args[0], err)
			os.Exit(255)
		}
	}

	// remove signal handling
	signal.Stop(sigCh)
	close(sigCh)
	wg.Wait()

	if len(*terminationLock) > 0 {
		klog.Infof("Deleting termination lock file %q", *terminationLock)
		os.Remove(*terminationLock)
	}

	klog.Infof("Termination finished with exit code %d", rc)
	os.Exit(rc)
}

// terminationFileWriter forwards everything to the embedded writer. When
// startFileLoggingCh is closed, everything is appended to the given file name
// in addition.
type terminationFileWriter struct {
	io.Writer
	fn                 string
	startFileLoggingCh <-chan struct{}

	logger io.Writer
}

func (w *terminationFileWriter) Write(bs []byte) (int, error) {
	// temporary hack to avoid logging sensitive tokens.
	// TODO: drop when we moved to a non-sensitive storage format
	if strings.Contains(string(bs), "URI=\"/apis/oauth.openshift.io/v1/oauthaccesstokens/") || strings.Contains(string(bs), "URI=\"/apis/oauth.openshift.io/v1/oauthauthorizetokens/") {
		return len(bs), nil
	}

	select {
	case <-w.startFileLoggingCh:
		if w.logger == nil {
			l := &lumberjack.Logger{
				Filename:   w.fn,
				MaxSize:    100,
				MaxBackups: 3,
				MaxAge:     28,
				Compress:   false,
			}
			w.logger = l
			fmt.Fprintf(os.Stderr, "Copying termination logs to %q\n", w.fn)
		}
		if n, err := w.logger.Write(bs); err != nil {
			return n, err
		} else if n != len(bs) {
			return n, io.ErrShortWrite
		}
	default:
	}

	return w.Writer.Write(bs)
}

func touch(fn string) error {
	_, err := os.Stat(fn)
	if os.IsNotExist(err) {
		file, err := os.Create(fn)
		if err != nil {
			return err
		}
		defer file.Close()
		return nil
	}

	currentTime := time.Now().Local()
	return os.Chtimes(fn, currentTime, currentTime)
}
<|endoftext|>


<commit_before>package main

/*
 * parse challenges.json, print all keys
 * get output for keys
 * split string
 *
 */
import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

const defaultFailedCode = 1

func check(e error) {
	if e != nil {
		errorExit(e.Error())
	}
}

func errorExit(s string) {
	type CmdError struct{ Error string }
	result := CmdError{Error: s}
	b, _ := json.MarshalIndent(result, "", "  ")
	os.Stdout.Write(b)
	os.Exit(0)
}

func runCombinedOutput(command string) (cmdout string, exitCode int) {
	cmd := exec.Command("bash", "-O", "globstar", "-c", "export MANPAGER=cat;"+command)
	outb, err := cmd.CombinedOutput()
	cmdout = fmt.Sprintf("%s", outb)
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			ws := exitError.Sys().(syscall.WaitStatus)
			exitCode = ws.ExitStatus()
		}
	} else {
		ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
		exitCode = ws.ExitStatus()
	}
	return cmdout, exitCode
}

func newBool(b bool) *bool {
	return &b
}

func main() {
	progDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	check(err)

	type CmdResult struct {
		CmdOut                  string
		CmdExitCode             int
		OutputPass              *bool  `json:",omitempty"`
		TestsPass               *bool  `json:",omitempty"`
		TestsOut                string `json:",omitempty"`
		AfterRandOutputPass     *bool  `json:",omitempty"`
		AfterRandExpectedOutput string `json:",omitempty"`
		AfterRandOutput         string `json:",omitempty"`
		AfterRandTestsPass      *bool  `json:",omitempty"`
		AfterRandTestsOut       string `json:",omitempty"`
	}

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s <command>:\n", os.Args[0])
		flag.PrintDefaults()
	}

	slugNamePtr := flag.String("slug", "hello_world", "a string")
	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	commandArg := flag.Args()[0]
	// if the base64 decode fails assume the command was passed in
	// without encoding
	decoded, err := base64.StdEncoding.DecodeString(commandArg)
	var command string
	if err != nil {
		command = commandArg
	} else {
		command = string(decoded)
	}

	challengesJSON, err := ioutil.ReadFile(progDir + "/ch/" + *slugNamePtr + ".json")
	if err != nil {
		errorExit("Challenge " + *slugNamePtr + " not found.")
	}
	ch, err := readChallenge(challengesJSON)
	check(err)
	cmdOut, cmdExitCode := runCombinedOutput(command)

	result := CmdResult{
		CmdOut:      cmdOut,
		CmdExitCode: cmdExitCode,
	}

	if ch.HasExpectedOutput() {
		result.OutputPass = newBool(ch.MatchesOutput(cmdOut))
	}

	testFile := progDir + "/cmdtests/" + ch.Slug
	if _, err := os.Stat(testFile); err == nil {
		testOut, testExitCode := runCombinedOutput(testFile)
		if testExitCode == 0 {
			result.TestsPass = newBool(true)
		} else {
			result.TestsPass = newBool(false)
		}
		result.TestsOut = testOut
	}

	randFile := progDir + "/randomizers/" + ch.Slug
	if _, err := os.Stat(randFile); err == nil {
		randOut, randExitCode := runCombinedOutput(randFile)
		result.AfterRandExpectedOutput = randOut
		if randExitCode == 0 {
			// Randomizer has run, check output against the new
			// expected output
			newCh := challenge{}
			lineSlice := strings.Split(randOut, "\n")
			lineSlice = lineSlice[:len(lineSlice)-1]
			newCh.ExpectedOutput.Lines = lineSlice
			newCh.ExpectedOutput.Order = ch.ExpectedOutput.Order
			newCh.ExpectedOutput.ReSub = ch.ExpectedOutput.ReSub
			// TODO exit code?
			randCmdOut, _ := runCombinedOutput(command)
			result.AfterRandOutput = randCmdOut
			result.AfterRandOutputPass = newBool(newCh.MatchesOutput(randCmdOut))
			if _, err := os.Stat(testFile); err == nil {
				randTestOut, randTestExitCode := runCombinedOutput(testFile)
				if randTestExitCode == 0 {
					result.AfterRandTestsPass = newBool(true)
				} else {
					result.AfterRandTestsPass = newBool(false)
				}
				result.AfterRandTestsOut = randTestOut
			}
		} else {
			errorExit("Unable to run random check.")
		}
	}
	b, err := json.Marshal(result)
	check(err)
	os.Stdout.Write(append(b, "\n"...))
}
<commit_msg>Fallback to sh if bash does not exist<commit_after>package main

/*
 * parse challenges.json, print all keys
 * get output for keys
 * split string
 *
 */
import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

const defaultFailedCode = 1

func check(e error) {
	if e != nil {
		errorExit(e.Error())
	}
}

func errorExit(s string) {
	type CmdError struct{ Error string }
	result := CmdError{Error: s}
	b, _ := json.MarshalIndent(result, "", "  ")
	os.Stdout.Write(b)
	os.Exit(0)
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

func runCombinedOutput(command string) (cmdout string, exitCode int) {
	bashArgs := []string{"-O", "globstar", "-c", "export MANPAGER=cat;" + command}
	shArgs := []string{"-c", command}
	var args *[]string
	var interpreter string

	if fileExists("/ro_volume/bash") {
		interpreter = "/ro_volume/bash"
		args = &bashArgs
	} else {
		interpreter = "sh"
		args = &shArgs
	}

	cmd := exec.Command(interpreter, *args...)
	outb, err := cmd.CombinedOutput()
	cmdout = fmt.Sprintf("%s", outb)
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			ws := exitError.Sys().(syscall.WaitStatus)
			exitCode = ws.ExitStatus()
		}
	} else {
		ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
		exitCode = ws.ExitStatus()
	}
	return cmdout, exitCode
}

func newBool(b bool) *bool {
	return &b
}

func main() {
	progDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	check(err)

	type CmdResult struct {
		CmdOut                  string
		CmdExitCode             int
		OutputPass              *bool  `json:",omitempty"`
		TestsPass               *bool  `json:",omitempty"`
		TestsOut                string `json:",omitempty"`
		AfterRandOutputPass     *bool  `json:",omitempty"`
		AfterRandExpectedOutput string `json:",omitempty"`
		AfterRandOutput         string `json:",omitempty"`
		AfterRandTestsPass      *bool  `json:",omitempty"`
		AfterRandTestsOut       string `json:",omitempty"`
	}

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s <command>:\n", os.Args[0])
		flag.PrintDefaults()
	}

	slugNamePtr := flag.String("slug", "hello_world", "a string")
	flag.Parse()
	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	commandArg := flag.Args()[0]
	// if the base64 decode fails assume the command was passed in
	// without encoding
	decoded, err := base64.StdEncoding.DecodeString(commandArg)
	var command string
	if err != nil {
		command = commandArg
	} else {
		command = string(decoded)
	}

	challengesJSON, err := ioutil.ReadFile(progDir + "/ch/" + *slugNamePtr + ".json")
	if err != nil {
		errorExit("Challenge " + *slugNamePtr + " not found.")
	}
	ch, err := readChallenge(challengesJSON)
	check(err)
	cmdOut, cmdExitCode := runCombinedOutput(command)

	result := CmdResult{
		CmdOut:      cmdOut,
		CmdExitCode: cmdExitCode,
	}

	if ch.HasExpectedOutput() {
		result.OutputPass = newBool(ch.MatchesOutput(cmdOut))
	}

	testFile := progDir + "/cmdtests/" + ch.Slug
	if _, err := os.Stat(testFile); err == nil {
		testOut, testExitCode := runCombinedOutput(testFile)
		if testExitCode == 0 {
			result.TestsPass = newBool(true)
		} else {
			result.TestsPass = newBool(false)
		}
		result.TestsOut = testOut
	}

	randFile := progDir + "/randomizers/" + ch.Slug
	if _, err := os.Stat(randFile); err == nil {
		randOut, randExitCode := runCombinedOutput(randFile)
		result.AfterRandExpectedOutput = randOut
		if randExitCode == 0 {
			// Randomizer has run, check output against the new
			// expected output
			newCh := challenge{}
			lineSlice := strings.Split(randOut, "\n")
			lineSlice = lineSlice[:len(lineSlice)-1]
			newCh.ExpectedOutput.Lines = lineSlice
			newCh.ExpectedOutput.Order = ch.ExpectedOutput.Order
			newCh.ExpectedOutput.ReSub = ch.ExpectedOutput.ReSub
			// TODO exit code?
			randCmdOut, _ := runCombinedOutput(command)
			result.AfterRandOutput = randCmdOut
			result.AfterRandOutputPass = newBool(newCh.MatchesOutput(randCmdOut))
			if _, err := os.Stat(testFile); err == nil {
				randTestOut, randTestExitCode := runCombinedOutput(testFile)
				if randTestExitCode == 0 {
					result.AfterRandTestsPass = newBool(true)
				} else {
					result.AfterRandTestsPass = newBool(false)
				}
				result.AfterRandTestsOut = randTestOut
			}
		} else {
			errorExit("Unable to run random check.")
		}
	}
	b, err := json.Marshal(result)
	check(err)
	os.Stdout.Write(append(b, "\n"...))
}
<|endoftext|>


<commit_before>package tools

import (
	"NetworkObserver/configuration"
	"NetworkObserver/reporter"
	"errors"
	"strconv"
	"strings"
	"time"
)

type TestData struct {
	Location        string
	Runlen          string
	Ext_ip          string
	Ext_url         string
	Speedtestfile   string
	Ping_delay      string
	Speedtest_delay string
}

type pingResponse struct {
	internal     bool
	external_ip  bool
	external_url bool

	err error
}

var internalHourly = ""
var externalIPHourly = ""
var externalURLHourly = ""

func SetupTest(td TestData) (pingInfo, error) {
	internalHourly = ""
	externalIPHourly = ""
	externalURLHourly = ""

	pi := pingInfo{}
	err := errors.New("")

	if td.Ext_ip == "" {
		pi.externalip = configuration.GetRandomExternalIP()
	} else {
		pi.externalip = td.Ext_ip
	}

	if td.Ext_url == "" {
		pi.externalurl = configuration.GetRandomExternalURL()
	} else {
		pi.externalurl = td.Ext_url
	}

	pi.internalip, err = configuration.GetInternalIPbyKey(td.Location)
	if err != nil {
		return pingInfo{}, err
	}

	pi.pingDelay = td.Ping_delay

	return pi, nil
}

func RunTest(pi pingInfo, runlen int) {
	timeline := make([]string, 3)
	timeline[0] = ""
	timeline[1] = ""
	timeline[2] = ""

	lp := time.Now()
	end := time.Now().Add(time.Duration(runlen) * time.Hour)

	for time.Now().Before(end) {
		delay, _ := strconv.Atoi(pi.pingDelay)
		if time.Now().After(lp.Add(time.Duration(delay) * time.Second)) {
			pr := Ping(pi)
			lp = time.Now()

			if pr.internal {
				timeline[0] = timeline[0] + "o"
			} else {
				timeline[0] = timeline[0] + "*"
			}

			if pr.external_ip {
				timeline[1] = timeline[1] + "o"
			} else {
				timeline[1] = timeline[1] + "*"
			}

			if pr.external_url {
				timeline[2] = timeline[2] + "o"
			} else {
				timeline[2] = timeline[2] + "*"
			}

			// 3600 = number of seconds in an hour
			if updateReportTimeline(timeline, 10) { //3600/delay) {
				timeline[0] = ""
				timeline[1] = ""
				timeline[2] = ""
			}
		}
		// speedtest -- later
	}
}

func updateReportTimeline(tl []string, countPerHour int) bool {
	reset := false
	if countPerHour <= len(tl[0]) {
		if strings.Contains(tl[0], "*") {
			internalHourly += "*"
		} else {
			internalHourly += "o"
		}

		if strings.Contains(tl[1], "*") {
			externalIPHourly += "*"
		} else {
			externalIPHourly += "o"
		}

		if strings.Contains(tl[2], "*") {
			externalURLHourly += "*"
		} else {
			externalURLHourly += "o"
		}

		reset = true
	}

	tl_str := "Internal: " + tl[0] + "\nPast Hours: " + internalHourly +
		"External IP: " + tl[1] + "\nPast Hours: " + externalIPHourly +
		"External URL: " + tl[2] + "\nPast Hours: " + externalURLHourly

	reporter.SetTimeline(tl_str)

	return reset
}
<commit_msg>Modified how timeline as per issue #8<commit_after>package tools

import (
	"NetworkObserver/configuration"
	"NetworkObserver/reporter"
	"errors"
	"strconv"
	"time"
)

type TestData struct {
	Location        string
	Runlen          string
	Ext_ip          string
	Ext_url         string
	Speedtestfile   string
	Ping_delay      string
	Speedtest_delay string
}

type pingResponse struct {
	internal     bool
	external_ip  bool
	external_url bool

	err error
}

var internalHourly = ""
var externalIPHourly = ""
var externalURLHourly = ""

func SetupTest(td TestData) (pingInfo, error) {
	internalHourly = ""
	externalIPHourly = ""
	externalURLHourly = ""

	pi := pingInfo{}
	err := errors.New("")

	if td.Ext_ip == "" {
		pi.externalip = configuration.GetRandomExternalIP()
	} else {
		pi.externalip = td.Ext_ip
	}

	if td.Ext_url == "" {
		pi.externalurl = configuration.GetRandomExternalURL()
	} else {
		pi.externalurl = td.Ext_url
	}

	pi.internalip, err = configuration.GetInternalIPbyKey(td.Location)
	if err != nil {
		return pingInfo{}, err
	}

	pi.pingDelay = td.Ping_delay

	return pi, nil
}

func RunTest(pi pingInfo, runlen int) {
	tl := map[string]int{
		"internal": 0,
		"extip":    0,
		"exturl":   0,
		"total":    0,
	}

	lp := time.Now()
	end := time.Now().Add(time.Duration(runlen) * time.Hour)

	for time.Now().Before(end) {
		delay, _ := strconv.Atoi(pi.pingDelay)
		if time.Now().After(lp.Add(time.Duration(delay) * time.Second)) {
			pr := Ping(pi)
			lp = time.Now()

			if pr.internal {
				tl["internal"]++
			}
			if pr.external_ip {
				tl["extip"]++
			}
			if pr.external_url {
				tl["exturl"]++
			}
			tl["total"]++

			timeline := "Internal Ping Success Count: " + strconv.Itoa(tl["internal"]) + "/" + strconv.Itoa(tl["total"]) +
				"\nExternal IP Ping Success Count: " + strconv.Itoa(tl["extip"]) + "/" + strconv.Itoa(tl["total"]) +
				"\nExternal URL Ping Success Count: " + strconv.Itoa(tl["exturl"]) + "/" + strconv.Itoa(tl["total"])

			reporter.SetTimeline(timeline)
		}
		// speedtest -- later
	}
}
<|endoftext|>


<commit_before>package torkeys

import (
	"crypto/sha1"

	"github.com/mmcloughlin/openssl"
)

// GenerateRSA generates an RSA key pair according to the Tor requirements.
//
// Reference: https://github.com/torproject/torspec/blob/master/tor-spec.txt#L77-L80
//
//	   For a public-key cipher, we use RSA with 1024-bit keys and a fixed
//	   exponent of 65537.  We use OAEP-MGF1 padding, with SHA-1 as its digest
//	   function.  We leave the optional "Label" parameter unset. (For OAEP
//	   padding, see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf)
//
func GenerateRSA() (openssl.PrivateKey, error) {
	return openssl.GenerateRSAKeyWithExponent(1024, 65537)
}

// PublicKeyHash computes the hash of a public key as defined in the spec
// below.
//
// Reference: https://github.com/torproject/torspec/blob/master/tor-spec.txt#L109-L110
//
//	   When we refer to "the hash of a public key", we mean the SHA-1 hash of the
//	   DER encoding of an ASN.1 RSA public key (as specified in PKCS.1).
//
func PublicKeyHash(k openssl.PublicKey) ([]byte, error) {
	der, err := k.MarshalPKCS1PublicKeyDER()
	if err != nil {
		return nil, err
	}

	h := sha1.Sum(der)

	return h[:], nil
}
<commit_msg>types for public/private keys<commit_after>package torkeys

import (
	"crypto/sha1"

	"github.com/mmcloughlin/openssl"
)

// PublicKey is an RSA public key.
type PublicKey interface {
	openssl.PublicKey
}

// PrivateKey is an RSA private key.
type PrivateKey interface {
	openssl.PrivateKey
}

// GenerateRSA generates an RSA key pair according to the Tor requirements.
//
// Reference: https://github.com/torproject/torspec/blob/master/tor-spec.txt#L77-L80
//
//	   For a public-key cipher, we use RSA with 1024-bit keys and a fixed
//	   exponent of 65537.  We use OAEP-MGF1 padding, with SHA-1 as its digest
//	   function.  We leave the optional "Label" parameter unset. (For OAEP
//	   padding, see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf)
//
func GenerateRSA() (PrivateKey, error) {
	return openssl.GenerateRSAKeyWithExponent(1024, 65537)
}

// PublicKeyHash computes the hash of a public key as defined in the spec
// below.
//
// Reference: https://github.com/torproject/torspec/blob/master/tor-spec.txt#L109-L110
//
//	   When we refer to "the hash of a public key", we mean the SHA-1 hash of the
//	   DER encoding of an ASN.1 RSA public key (as specified in PKCS.1).
//
func PublicKeyHash(k PublicKey) ([]byte, error) {
	der, err := k.MarshalPKCS1PublicKeyDER()
	if err != nil {
		return nil, err
	}

	h := sha1.Sum(der)

	return h[:], nil
}
<|endoftext|>


<commit_before>package goldb

import "github.com/syndtr/goleveldb/leveldb"

type Transaction struct {
	Context
	tr   *leveldb.Transaction
	err  error
	seq  map[Entity]uint64
	Data interface{}
}

func (t *Transaction) Discard() {
	t.tr.Discard()
}

func (t *Transaction) Commit() error {
	t.err = t.tr.Commit()
	return t.err
}

func (t *Transaction) Error() error {
	return t.err
}

func (t *Transaction) Fail(err error) {
	t.err = err
}

const tabSequences Entity = 0x7fffffff

func (t *Transaction) SequenceCurVal(tab Entity) (seq uint64) {
	if t.seq == nil {
		t.seq = map[Entity]uint64{}
	}
	seq, ok := t.seq[tab]
	if ok {
		return
	}
	key := Key(tabSequences, int(tab))
	if _, err := t.GetVar(key, &seq); err != nil {
		t.Fail(err)
	} else { // success
		t.seq[tab] = seq
	}
	return
}

func (t *Transaction) SequenceNextVal(tab Entity) (seq uint64) {
	seq = t.SequenceCurVal(tab) + 1
	t.seq[tab] = seq
	var key = Key(tabSequences, int(tab))
	t.PutVar(key, seq)
	return seq
}

func (t *Transaction) Put(key, data []byte) error {
	if t.err != nil {
		return t.err
	}
	t.err = t.tr.Put(key, data, t.WriteOptions)
	return t.err
}

func (t *Transaction) PutID(key []byte, id uint64) error {
	return t.Put(key, encodeUint(id))
}

func (t *Transaction) PutInt(key []byte, num int64) error {
	return t.PutVar(key, num)
}

func (t *Transaction) PutVar(key []byte, v interface{}) error {
	return t.Put(key, encodeValue(v))
}

// Increment increments int-value by key
func (t *Transaction) IncInt(key []byte, inc int64) (v int64, err error) {
	if _, err = t.GetVar(key, &v); err == nil {
		v += inc
		err = t.Put(key, encodeValue(v))
	}
	return
}

func (t *Transaction) Del(key []byte) error {
	if t.err != nil {
		return t.err
	}
	t.err = t.tr.Delete(key, t.WriteOptions)
	return t.err
}
<commit_msg>refactor transaction: remove tr.error, panic on put-get error<commit_after>package goldb

import "github.com/syndtr/goleveldb/leveldb"

type Transaction struct {
	Context
	tr   *leveldb.Transaction
	seq  map[Entity]uint64
	Data interface{}
}

func (t *Transaction) Discard() {
	t.tr.Discard()
}

func (t *Transaction) Commit() error {
	return t.tr.Commit()
}

func (t *Transaction) Fail(err error) {
	panic(err)
}

func panicOnErr(err error) {
	if err != nil {
		panic(err)
	}
}

const tabSequences Entity = 0x7fffffff

func (t *Transaction) SequenceCurVal(tab Entity) (seq uint64) {
	if t.seq == nil {
		t.seq = map[Entity]uint64{}
	}
	seq, ok := t.seq[tab]
	if ok {
		return
	}
	var key = Key(tabSequences, int(tab))
	t.GetVar(key, &seq)
	t.seq[tab] = seq
	return
}

func (t *Transaction) SequenceNextVal(tab Entity) (seq uint64) {
	seq = t.SequenceCurVal(tab) + 1
	t.seq[tab] = seq
	var key = Key(tabSequences, int(tab))
	t.PutVar(key, seq)
	return seq
}

func (t *Transaction) Put(key, data []byte) {
	if err := t.tr.Put(key, data, t.WriteOptions); err != nil {
		t.Fail(err)
	}
}

func (t *Transaction) PutID(key []byte, id uint64) {
	t.Put(key, encodeUint(id))
}

func (t *Transaction) PutInt(key []byte, num int64) {
	t.PutVar(key, num)
}

func (t *Transaction) PutVar(key []byte, v interface{}) {
	t.Put(key, encodeValue(v))
}

// Increment increments int-value by key
func (t *Transaction) Increment(key []byte, delta int64) (v int64) {
	if _, err := t.GetVar(key, &v); err != nil {
		t.Fail(err)
	}
	v += delta
	t.Put(key, encodeValue(v))
	return
}

func (t *Transaction) Delete(key []byte) {
	if err := t.tr.Delete(key, t.WriteOptions); err != nil {
		t.Fail(err)
	}
}
<|endoftext|>


<commit_before>package redis

import (
	"container/list"
	"sync"
)

// connPool is a stack-like structure that holds the connections of a Client.
type connPool struct {
	available int
	free      list.List
	lock      sync.Mutex
	emptyCond *sync.Cond
	config    *Config
	closed    bool
}

func newConnPool(config *Config) *connPool {
	cp := &connPool{
		available: config.PoolCapacity,
		config:    config,
		closed:    false,
	}

	cp.emptyCond = sync.NewCond(&cp.lock)
	return cp
}

func (cp *connPool) push(c *conn) {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	if cp.closed {
		return
	}

	if !c.closed() {
		cp.free.PushFront(c)
	}

	cp.available++
	cp.emptyCond.Signal()
}

func (cp *connPool) pull() (c *conn, err *Error) {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	if cp.closed {
		return nil, newError("connection pool is closed", ErrorConnection)
	}

	for cp.available == 0 {
		cp.emptyCond.Wait()
	}

	if cp.free.Len() > 0 {
		c, _ = cp.free.Remove(cp.free.Back()).(*conn)
	} else {
		// Lazy creation of a connection
		c, err = newConn(cp.config)

		if err != nil {
			return nil, err
		}
	}

	cp.available--
	return c, nil
}

func (cp *connPool) close() {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	for e := cp.free.Front(); e != nil; e = e.Next() {
		c, _ := e.Value.(*conn)
		c.close()
	}

	cp.free.Init()
	cp.closed = true
}
<commit_msg>Fix potential deadlock in conn pool(issune #15)<commit_after>package redis

import (
	"container/list"
	"sync"
)

// connPool is a stack-like structure that holds the connections of a Client.
type connPool struct {
	available int
	free      list.List
	lock      sync.Mutex
	emptyCond *sync.Cond
	config    *Config
	closed    bool
}

func newConnPool(config *Config) *connPool {
	cp := &connPool{
		available: config.PoolCapacity,
		config:    config,
		closed:    false,
	}

	cp.emptyCond = sync.NewCond(&cp.lock)
	return cp
}

func (cp *connPool) push(c *conn) {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	if cp.closed {
		return
	}

	if !c.closed() {
		cp.free.PushFront(c)
	}

	cp.available++
	cp.emptyCond.Signal()
}

func (cp *connPool) pull() (c *conn, err *Error) {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	if cp.closed {
		return nil, newError("connection pool is closed", ErrorConnection)
	}

	for cp.available == 0 {
		cp.emptyCond.Wait()
	}

	if cp.free.Len() > 0 {
		c, _ = cp.free.Remove(cp.free.Back()).(*conn)
	} else {
		// Lazy creation of a connection
		c, err = newConn(cp.config)

		if err != nil {
	        cp.emptyCond.Signal()
			return nil, err
		}
	}

	cp.available--
	return c, nil
}

func (cp *connPool) close() {
	cp.lock.Lock()
	defer cp.lock.Unlock()
	for e := cp.free.Front(); e != nil; e = e.Next() {
		c, _ := e.Value.(*conn)
		c.close()
	}

	cp.free.Init()
	cp.closed = true
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"

	"gopkg.in/reform.v1"
)

var (
	fF      = flag.String("f", "", "file to execute")
	driverF = flag.String("db-driver", "", "database driver")
	sourceF = flag.String("db-source", "", "database connection string")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "reform-db. %s.\n\n", reform.Version)
		flag.PrintDefaults()
	}
	flag.Parse()

	log.SetPrefix("reform-db: ")
	log.Print("Internal tool. Do not use it yet.")

	b, err := readSQL(*fF)
	if err != nil {
		log.Fatal(err)
	}

	db, err := sql.Open(*driverF, *sourceF)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	b = bytes.TrimSpace(b)
	if len(b) > 0 {
		_, err = db.Exec(string(b))
		if err != nil {
			log.Fatal(err)
		}
	}
}

func readSQL(path string) ([]byte, error) {
	if path == "" {
		return ioutil.ReadAll(os.Stdin)
	}
	return ioutil.ReadFile(path)
}
<commit_msg>reform-db: use single connection, better errors.<commit_after>package main

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"

	"gopkg.in/reform.v1"
)

var (
	fF      = flag.String("f", "", "file to execute")
	driverF = flag.String("db-driver", "", "database driver")
	sourceF = flag.String("db-source", "", "database connection string")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "reform-db. %s.\n\n", reform.Version)
		flag.PrintDefaults()
	}
	flag.Parse()

	log.SetPrefix("reform-db: ")
	log.Print("Internal tool. Do not use it yet.")

	b, err := readSQL(*fF)
	if err != nil {
		log.Fatalf("failed to read %q: %s", *fF, err)
	}

	db, err := sql.Open(*driverF, *sourceF)
	if err != nil {
		log.Fatalf("failed to connect to %s %q: %s", *driverF, *sourceF, err)
	}
	defer db.Close()

	// Use single connection so various session-related variables work.
	// For example: "PRAGMA foreign_keys" for SQLite3, "SET IDENTITY_INSERT" for MS SQL, etc.
	db.SetMaxIdleConns(1)
	db.SetMaxOpenConns(1)
	db.SetConnMaxLifetime(0)

	err = db.Ping()
	if err != nil {
		log.Fatalf("failed to ping database: %s", err)
	}

	b = bytes.TrimSpace(b)
	if len(b) > 0 {
		q := string(b)
		_, err := db.Exec(q)
		if err != nil {
			log.Fatalf("failed to execute %s: %s", q, err)
		}
	}
}

func readSQL(path string) ([]byte, error) {
	if path == "" {
		return ioutil.ReadAll(os.Stdin)
	}
	return ioutil.ReadFile(path)
}
<|endoftext|>


<commit_before>package registry

import (
	"errors"
	"time"

	log "github.com/coreos/fleet/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/fleet/etcd"
	"github.com/coreos/fleet/event"
)

type EventStream struct {
	etcd     etcd.Client
	registry *EtcdRegistry
}

func NewEventStream(client etcd.Client, registry Registry) (*EventStream, error) {
	reg, ok := registry.(*EtcdRegistry)
	if !ok {
		return nil, errors.New("EventStream currently only works with EtcdRegistry")
	}

	return &EventStream{client, reg}, nil
}

func (es *EventStream) Stream(idx uint64, sendFunc func(*event.Event), stop chan bool) {
	filters := []func(*etcd.Result) *event.Event{
		filterEventJobDestroyed,
		filterEventJobScheduled,
		filterEventJobUnscheduled,
		es.filterJobTargetStateChanges,
		es.filterEventJobOffered,
	}

	etcdchan := make(chan *etcd.Result)
	go watch(es.etcd, idx, etcdchan, es.registry.keyPrefix, stop)
	go pipe(etcdchan, filters, sendFunc, stop)
}

func pipe(etcdchan chan *etcd.Result, filters []func(res *etcd.Result) *event.Event, sendFunc func(*event.Event), stop chan bool) {
	for true {
		select {
		case <-stop:
			return
		case res := <-etcdchan:
			log.V(1).Infof("Received %v from etcd watch", res)
			for _, f := range filters {
				ev := f(res)
				if ev == nil {
					continue
				}

				log.V(1).Infof("Translated %v to Event(Type=%s)", res, ev.Type)
				sendFunc(ev)
			}
		}
	}
}

func watch(client etcd.Client, idx uint64, etcdchan chan *etcd.Result, key string, stop chan bool) {
	for true {
		select {
		case <-stop:
			log.V(1).Infof("Gracefully closing etcd watch loop: key=%s", key)
			return
		default:
			req := &etcd.Watch{
				Key:       key,
				WaitIndex: idx,
				Recursive: true,
			}

			log.V(1).Infof("Creating etcd watcher: %v", req)

			resp, err := client.Wait(req, stop)
			if err == nil {
				if resp.Node != nil {
					idx = resp.Node.ModifiedIndex + 1
				}
				etcdchan <- resp
				continue
			}

			log.Errorf("etcd watcher %v returned error: %v", req, err)

			etcdError, ok := err.(etcd.Error)
			if !ok {
				// Let's not slam the etcd server in the event that we know
				// an unexpected error occurred.
				time.Sleep(time.Second)
				continue
			}

			switch etcdError.ErrorCode {
			case etcd.ErrorEventIndexCleared:
				// This is racy, but adding one to the last known index
				// will help get this watcher back into the range of
				// etcd's internal event history
				idx = idx + 1
			default:
				// Let's not slam the etcd server in the event that we know
				// an unexpected error occurred.
				time.Sleep(time.Second)
			}
		}
	}
}
<commit_msg>registry: simplify conditionless loops<commit_after>package registry

import (
	"errors"
	"time"

	log "github.com/coreos/fleet/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/fleet/etcd"
	"github.com/coreos/fleet/event"
)

type EventStream struct {
	etcd     etcd.Client
	registry *EtcdRegistry
}

func NewEventStream(client etcd.Client, registry Registry) (*EventStream, error) {
	reg, ok := registry.(*EtcdRegistry)
	if !ok {
		return nil, errors.New("EventStream currently only works with EtcdRegistry")
	}

	return &EventStream{client, reg}, nil
}

func (es *EventStream) Stream(idx uint64, sendFunc func(*event.Event), stop chan bool) {
	filters := []func(*etcd.Result) *event.Event{
		filterEventJobDestroyed,
		filterEventJobScheduled,
		filterEventJobUnscheduled,
		es.filterJobTargetStateChanges,
		es.filterEventJobOffered,
	}

	etcdchan := make(chan *etcd.Result)
	go watch(es.etcd, idx, etcdchan, es.registry.keyPrefix, stop)
	go pipe(etcdchan, filters, sendFunc, stop)
}

func pipe(etcdchan chan *etcd.Result, filters []func(res *etcd.Result) *event.Event, sendFunc func(*event.Event), stop chan bool) {
	for {
		select {
		case <-stop:
			return
		case res := <-etcdchan:
			log.V(1).Infof("Received %v from etcd watch", res)
			for _, f := range filters {
				ev := f(res)
				if ev == nil {
					continue
				}

				log.V(1).Infof("Translated %v to Event(Type=%s)", res, ev.Type)
				sendFunc(ev)
			}
		}
	}
}

func watch(client etcd.Client, idx uint64, etcdchan chan *etcd.Result, key string, stop chan bool) {
	for {
		select {
		case <-stop:
			log.V(1).Infof("Gracefully closing etcd watch loop: key=%s", key)
			return
		default:
			req := &etcd.Watch{
				Key:       key,
				WaitIndex: idx,
				Recursive: true,
			}

			log.V(1).Infof("Creating etcd watcher: %v", req)

			resp, err := client.Wait(req, stop)
			if err == nil {
				if resp.Node != nil {
					idx = resp.Node.ModifiedIndex + 1
				}
				etcdchan <- resp
				continue
			}

			log.Errorf("etcd watcher %v returned error: %v", req, err)

			etcdError, ok := err.(etcd.Error)
			if !ok {
				// Let's not slam the etcd server in the event that we know
				// an unexpected error occurred.
				time.Sleep(time.Second)
				continue
			}

			switch etcdError.ErrorCode {
			case etcd.ErrorEventIndexCleared:
				// This is racy, but adding one to the last known index
				// will help get this watcher back into the range of
				// etcd's internal event history
				idx = idx + 1
			default:
				// Let's not slam the etcd server in the event that we know
				// an unexpected error occurred.
				time.Sleep(time.Second)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"encoding/json"
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"sync"

	"github.com/thinkofdeath/steven/platform/gl"
	"github.com/thinkofdeath/steven/render/atlas"
	"github.com/thinkofdeath/steven/resource"
)

var (
	textures         []*atlas.Type
	textureViews     []*image.NRGBA
	textureMap       = map[string]TextureInfo{}
	textureLock      sync.RWMutex
	animatedTextures []*animatedTexture
)

const atlasSize = 1024

// TextureInfo returns information about a texture in an atlas
type TextureInfo struct {
	Atlas     int
	imageView *image.NRGBA
	*atlas.Rect
}

// GetTexture returns the related TextureInfo for the requested texture.
// If the texture isn't found a placeholder is returned instead.
func GetTexture(name string) *TextureInfo {
	textureLock.RLock()
	defer textureLock.RUnlock()
	t, ok := textureMap[name]
	if !ok {
		t = textureMap["missing_texture"]
	}
	return &t
}

// LoadTextures (re)loads all the block textures from the resource pack(s)
// TODO(Think) better error handling (if possible to recover?)
func LoadTextures() {
	textureLock.Lock()
	defer textureLock.Unlock()

	// Clear existing
	textures = nil
	textureMap = map[string]TextureInfo{}

	for _, file := range resource.Search("minecraft", "textures/blocks/", ".png") {
		r, err := resource.Open("minecraft", file)
		if err != nil {
			panic(err)
		}
		img, err := png.Decode(r)
		if err != nil {
			panic(err)
		}
		width, height := img.Bounds().Dx(), img.Bounds().Dy()
		var ani *animatedTexture
		if width != height {
			height = width
			old := img
			img := image.NewNRGBA(image.Rect(0, 0, width, width))
			draw.Draw(img, img.Bounds(), old, image.ZP, draw.Over)
			ani = loadAnimation(file, old.Bounds().Dy()/old.Bounds().Dx())
			ani.Image = old
			animatedTextures = append(animatedTextures, ani)
		}
		var pix []byte
		switch img := img.(type) {
		case *image.NRGBA:
			pix = img.Pix
		case *image.RGBA:
			pix = img.Pix
		default:
			panic(fmt.Sprintf("unsupported image type %T", img))
		}
		name := file[len("textures/blocks/") : len(file)-4]
		at, rect := addTexture(pix, width, height)
		info := TextureInfo{
			Rect:  rect,
			Atlas: at,
		}
		textureMap[name] = info
		if ani != nil {
			ani.Info = info
		}
	}

	at, rect := addTexture([]byte{
		0, 0, 0, 255,
		255, 0, 255, 255,
		255, 0, 255, 255,
		0, 0, 0, 255,
	}, 2, 2)
	textureMap["missing_texture"] = TextureInfo{
		Rect:  rect,
		Atlas: at,
	}
}

func addTexture(pix []byte, width, height int) (int, *atlas.Rect) {
	for i, a := range textures {
		rect, err := a.Add(pix, width, height)
		if err == nil {
			return i, rect
		}
	}
	a := atlas.New(atlasSize, atlasSize, 4)
	textures = append(textures, a)
	textureViews = append(textureViews, &image.NRGBA{
		Pix:    a.Buffer,
		Stride: 4 * atlasSize,
		Rect:   image.Rect(0, 0, atlasSize, atlasSize),
	})
	rect, err := a.Add(pix, width, height)
	if err != nil {
		panic(err)
	}
	return len(textures) - 1, rect
}

type animatedTexture struct {
	Info          TextureInfo
	Image         image.Image
	Interpolate   bool
	Frames        []textureFrame
	RemainingTime float64
	CurrentFrame  int
}

type textureFrame struct {
	Index int
	Time  int
}

func tickAnimatedTextures(delta float64) {
	delta /= 3 // default is 60 a second, minecraft is 20
	for _, ani := range animatedTextures {
		ani.RemainingTime -= delta
		if ani.RemainingTime < 0 {
			ani.CurrentFrame++
			ani.CurrentFrame %= len(ani.Frames)
			ani.RemainingTime += float64(ani.Frames[ani.CurrentFrame].Time)
			img := textureViews[ani.Info.Atlas]
			r := ani.Info.Rect
			y := r.Width * ani.Frames[ani.CurrentFrame].Index
			src := image.Rect(r.X, r.Y, r.X+r.Width, r.Y+r.Height)
			draw.Draw(img, src, ani.Image, image.Pt(0, y), draw.Src)
		}
	}
	for i, gt := range glTextures {
		gt.Bind(gl.Texture2D)
		gt.SubImage2D(0, 0, 0, atlasSize, atlasSize, gl.RGBA, gl.UnsignedByte, textures[i].Buffer)
		regenMipMaps(gt, textures[i].Buffer, atlasSize, atlasSize, 1)
	}
}

func loadAnimation(file string, max int) *animatedTexture {
	a := &animatedTexture{}
	defer func() {
		a.RemainingTime = float64(a.Frames[0].Time)
	}()

	type animation struct {
		FrameTime   int
		Interpolate bool
		Frames      []json.RawMessage
	}
	type base struct {
		Animation animation
	}

	meta, err := resource.Open("minecraft", file+".mcmeta")
	if err != nil {
		panic(err)
	}
	defer meta.Close()
	b := &base{}
	err = json.NewDecoder(meta).Decode(b)
	if err != nil {
		panic(err)
	}
	frameTime := b.Animation.FrameTime
	if frameTime == 0 {
		frameTime = 1
	}
	a.Interpolate = b.Animation.Interpolate

	if len(b.Animation.Frames) == 0 {
		a.Frames = make([]textureFrame, max)
		for i := range a.Frames {
			a.Frames[i] = textureFrame{
				Index: i,
				Time:  frameTime,
			}
		}
		return a
	}

	a.Frames = make([]textureFrame, len(b.Animation.Frames))
	for i := range a.Frames {
		a.Frames[i].Time = frameTime
		if b.Animation.Frames[i][0] == '{' {
			if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i]); err != nil {
				panic(err)
			}
			a.Frames[i].Time *= frameTime
			continue
		}
		if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i].Index); err != nil {
			panic(err)
		}
	}

	return a
}

func genMipMaps(g gl.Texture, buffer []byte, width, height, level int) {
	if level > 4 {
		g.Parameter(gl.TextureMaxLevel, gl.TextureValue(level-1))
		return
	}
	nw, nh, data := shrinkTexture(buffer, width, height)
	g.Image2D(level, nw, nh, gl.RGBA, gl.UnsignedByte, data)
	genMipMaps(g, data, nw, nh, level+1)
}

func regenMipMaps(g gl.Texture, buffer []byte, width, height, level int) {
	if level > 4 {
		g.Parameter(gl.TextureMaxLevel, gl.TextureValue(level-1))
		return
	}
	nw, nh, data := shrinkTexture(buffer, width, height)
	g.SubImage2D(level, 0, 0, nw, nh, gl.RGBA, gl.UnsignedByte, data)
	regenMipMaps(g, data, nw, nh, level+1)
}

func shrinkTexture(buffer []byte, width, height int) (nw, nh int, data []byte) {
	nw = width >> 1
	nh = height >> 1
	data = make([]byte, nw*nh*4)
	for x := 0; x < nw; x++ {
		for y := 0; y < nh; y++ {
			i := (y*nw + x) * 4
			i2 := ((y<<1)*width + (x << 1)) * 4
			data[i] = buffer[i2]
			data[i+1] = buffer[i2+1]
			data[i+2] = buffer[i2+2]
			data[i+3] = buffer[i2+3]
		}
	}
	return
}

type glTexture struct {
	Data          []byte
	Width, Height int
	Format        gl.TextureFormat
	Type          gl.Type
	Filter        gl.TextureValue
	MinFilter     gl.TextureValue
	Wrap          gl.TextureValue
}

func createTexture(t glTexture) gl.Texture {
	if t.Format == 0 {
		t.Format = gl.RGB
	}
	if t.Type == 0 {
		t.Type = gl.UnsignedByte
	}
	if t.Filter == 0 {
		t.Filter = gl.Nearest
	}
	if t.MinFilter == 0 {
		t.MinFilter = t.Filter
	}
	if t.Wrap == 0 {
		t.Wrap = gl.ClampToEdge
	}

	texture := gl.CreateTexture()
	texture.Bind(gl.Texture2D)
	texture.Image2D(0, t.Width, t.Height, t.Format, t.Type, t.Data)
	texture.Parameter(gl.TextureMagFilter, t.Filter)
	texture.Parameter(gl.TextureMinFilter, t.MinFilter)
	texture.Parameter(gl.TextureWrapS, t.Wrap)
	texture.Parameter(gl.TextureWrapT, t.Wrap)
	return texture
}
<commit_msg>render: don't animate mipmaps<commit_after>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"encoding/json"
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"sync"

	"github.com/thinkofdeath/steven/platform/gl"
	"github.com/thinkofdeath/steven/render/atlas"
	"github.com/thinkofdeath/steven/resource"
)

var (
	textures         []*atlas.Type
	textureViews     []*image.NRGBA
	textureMap       = map[string]TextureInfo{}
	textureLock      sync.RWMutex
	animatedTextures []*animatedTexture
)

const atlasSize = 1024

// TextureInfo returns information about a texture in an atlas
type TextureInfo struct {
	Atlas     int
	imageView *image.NRGBA
	*atlas.Rect
}

// GetTexture returns the related TextureInfo for the requested texture.
// If the texture isn't found a placeholder is returned instead.
func GetTexture(name string) *TextureInfo {
	textureLock.RLock()
	defer textureLock.RUnlock()
	t, ok := textureMap[name]
	if !ok {
		t = textureMap["missing_texture"]
	}
	return &t
}

// LoadTextures (re)loads all the block textures from the resource pack(s)
// TODO(Think) better error handling (if possible to recover?)
func LoadTextures() {
	textureLock.Lock()
	defer textureLock.Unlock()

	// Clear existing
	textures = nil
	textureMap = map[string]TextureInfo{}

	for _, file := range resource.Search("minecraft", "textures/blocks/", ".png") {
		r, err := resource.Open("minecraft", file)
		if err != nil {
			panic(err)
		}
		img, err := png.Decode(r)
		if err != nil {
			panic(err)
		}
		width, height := img.Bounds().Dx(), img.Bounds().Dy()
		var ani *animatedTexture
		if width != height {
			height = width
			old := img
			img := image.NewNRGBA(image.Rect(0, 0, width, width))
			draw.Draw(img, img.Bounds(), old, image.ZP, draw.Over)
			ani = loadAnimation(file, old.Bounds().Dy()/old.Bounds().Dx())
			ani.Image = old
			animatedTextures = append(animatedTextures, ani)
		}
		var pix []byte
		switch img := img.(type) {
		case *image.NRGBA:
			pix = img.Pix
		case *image.RGBA:
			pix = img.Pix
		default:
			panic(fmt.Sprintf("unsupported image type %T", img))
		}
		name := file[len("textures/blocks/") : len(file)-4]
		at, rect := addTexture(pix, width, height)
		info := TextureInfo{
			Rect:  rect,
			Atlas: at,
		}
		textureMap[name] = info
		if ani != nil {
			ani.Info = info
		}
	}

	at, rect := addTexture([]byte{
		0, 0, 0, 255,
		255, 0, 255, 255,
		255, 0, 255, 255,
		0, 0, 0, 255,
	}, 2, 2)
	textureMap["missing_texture"] = TextureInfo{
		Rect:  rect,
		Atlas: at,
	}
}

func addTexture(pix []byte, width, height int) (int, *atlas.Rect) {
	for i, a := range textures {
		rect, err := a.Add(pix, width, height)
		if err == nil {
			return i, rect
		}
	}
	a := atlas.New(atlasSize, atlasSize, 4)
	textures = append(textures, a)
	textureViews = append(textureViews, &image.NRGBA{
		Pix:    a.Buffer,
		Stride: 4 * atlasSize,
		Rect:   image.Rect(0, 0, atlasSize, atlasSize),
	})
	rect, err := a.Add(pix, width, height)
	if err != nil {
		panic(err)
	}
	return len(textures) - 1, rect
}

type animatedTexture struct {
	Info          TextureInfo
	Image         image.Image
	Interpolate   bool
	Frames        []textureFrame
	RemainingTime float64
	CurrentFrame  int
}

type textureFrame struct {
	Index int
	Time  int
}

func tickAnimatedTextures(delta float64) {
	delta /= 3 // default is 60 a second, minecraft is 20
	for _, ani := range animatedTextures {
		ani.RemainingTime -= delta
		if ani.RemainingTime < 0 {
			ani.CurrentFrame++
			ani.CurrentFrame %= len(ani.Frames)
			ani.RemainingTime += float64(ani.Frames[ani.CurrentFrame].Time)
			img := textureViews[ani.Info.Atlas]
			r := ani.Info.Rect
			y := r.Width * ani.Frames[ani.CurrentFrame].Index
			src := image.Rect(r.X, r.Y, r.X+r.Width, r.Y+r.Height)
			draw.Draw(img, src, ani.Image, image.Pt(0, y), draw.Src)
		}
	}
	for i, gt := range glTextures {
		gt.Bind(gl.Texture2D)
		gt.SubImage2D(0, 0, 0, atlasSize, atlasSize, gl.RGBA, gl.UnsignedByte, textures[i].Buffer)
	}
}

func loadAnimation(file string, max int) *animatedTexture {
	a := &animatedTexture{}
	defer func() {
		a.RemainingTime = float64(a.Frames[0].Time)
	}()

	type animation struct {
		FrameTime   int
		Interpolate bool
		Frames      []json.RawMessage
	}
	type base struct {
		Animation animation
	}

	meta, err := resource.Open("minecraft", file+".mcmeta")
	if err != nil {
		panic(err)
	}
	defer meta.Close()
	b := &base{}
	err = json.NewDecoder(meta).Decode(b)
	if err != nil {
		panic(err)
	}
	frameTime := b.Animation.FrameTime
	if frameTime == 0 {
		frameTime = 1
	}
	a.Interpolate = b.Animation.Interpolate

	if len(b.Animation.Frames) == 0 {
		a.Frames = make([]textureFrame, max)
		for i := range a.Frames {
			a.Frames[i] = textureFrame{
				Index: i,
				Time:  frameTime,
			}
		}
		return a
	}

	a.Frames = make([]textureFrame, len(b.Animation.Frames))
	for i := range a.Frames {
		a.Frames[i].Time = frameTime
		if b.Animation.Frames[i][0] == '{' {
			if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i]); err != nil {
				panic(err)
			}
			a.Frames[i].Time *= frameTime
			continue
		}
		if err = json.Unmarshal(b.Animation.Frames[i], &a.Frames[i].Index); err != nil {
			panic(err)
		}
	}

	return a
}

func genMipMaps(g gl.Texture, buffer []byte, width, height, level int) {
	if level > 3 {
		g.Parameter(gl.TextureMaxLevel, gl.TextureValue(level-1))
		return
	}
	nw, nh, data := shrinkTexture(buffer, width, height)
	g.Image2D(level, nw, nh, gl.RGBA, gl.UnsignedByte, data)
	genMipMaps(g, data, nw, nh, level+1)
}

func shrinkTexture(buffer []byte, width, height int) (nw, nh int, data []byte) {
	nw = width >> 1
	nh = height >> 1
	data = make([]byte, nw*nh*4)
	for x := 0; x < nw; x++ {
		for y := 0; y < nh; y++ {
			i := (y*nw + x) * 4
			i2 := ((y<<1)*width + (x << 1)) * 4
			data[i] = buffer[i2]
			data[i+1] = buffer[i2+1]
			data[i+2] = buffer[i2+2]
			data[i+3] = buffer[i2+3]
		}
	}
	return
}

type glTexture struct {
	Data          []byte
	Width, Height int
	Format        gl.TextureFormat
	Type          gl.Type
	Filter        gl.TextureValue
	MinFilter     gl.TextureValue
	Wrap          gl.TextureValue
}

func createTexture(t glTexture) gl.Texture {
	if t.Format == 0 {
		t.Format = gl.RGB
	}
	if t.Type == 0 {
		t.Type = gl.UnsignedByte
	}
	if t.Filter == 0 {
		t.Filter = gl.Nearest
	}
	if t.MinFilter == 0 {
		t.MinFilter = t.Filter
	}
	if t.Wrap == 0 {
		t.Wrap = gl.ClampToEdge
	}

	texture := gl.CreateTexture()
	texture.Bind(gl.Texture2D)
	texture.Image2D(0, t.Width, t.Height, t.Format, t.Type, t.Data)
	texture.Parameter(gl.TextureMagFilter, t.Filter)
	texture.Parameter(gl.TextureMinFilter, t.MinFilter)
	texture.Parameter(gl.TextureWrapS, t.Wrap)
	texture.Parameter(gl.TextureWrapT, t.Wrap)
	return texture
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"strings"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/guardduty"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func testAccAwsGuardDutyFilter_basic(t *testing.T) {
	resourceName := "aws_guardduty_filter.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsGuardDutyFilterDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGuardDutyFilterConfig_full(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsGuardDutyFilterExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "detector_id"),
					resource.TestCheckResourceAttr(resourceName, "name", "test-filter"),
					resource.TestCheckResourceAttr(resourceName, "action", "ARCHIVE"),
					resource.TestCheckResourceAttr(resourceName, "rank", "1"),
				),
			},
		},
	})
}

func testAccAwsGuardDutyFilter_import(t *testing.T) {
	resourceName := "aws_guardduty_filter.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsGuardDutyFilterDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGuardDutyFilterConfig_full(),
			},

			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsGuardDutyFilterDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).guarddutyconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_guardduty_filter" {
			continue
		}

		parts := strings.SplitN(rs.Primary.ID, "_", 2)

		input := &guardduty.GetFilterInput{
			DetectorId: aws.String(parts[0]),
			FilterName: aws.String(parts[1]),
		}

		_, err := conn.GetFilter(input)
		if err != nil {
			if isAWSErr(err, guardduty.ErrCodeBadRequestException, "The request is rejected because the input detectorId is not owned by the current account.") {
				return nil
			}
			return err
		}

		return fmt.Errorf("Expected GuardDuty Filter to be destroyed, %s found", rs.Primary.Attributes["filter_name"])
	}

	return nil
}

func testAccCheckAwsGuardDutyFilterExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		_, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		return nil
	}
}

func testAccGuardDutyFilterConfig_full() string {
	return fmt.Sprintf(`
%[1]s

resource "aws_guardduty_filter" "test" {
  detector_id = "${aws_guardduty_detector.test.id}"
	name        = "test-filter"
	action      = "ARCHIVE"
	rank        = 1

  finding_criteria {
    criterion {
      field     = "region"
      values    = ["eu-west-1"]
      condition = "equals"
    }

    criterion {
      field     = "service.additionalInfo.threatListName"
      values    = ["some-threat", "another-threat"]
      condition = "not_equals"
    }

    criterion {
      field     = "updatedAt"
      values    = ["1570744740000"]
      condition = "less_than"
    }

    criterion {
      field     = "updatedAt"
      values    = ["1570744240000"]
      condition = "greater_than"
    }
  }
}`, testAccGuardDutyDetectorConfig_basic3)
}

const testAccGuardDutyFilterConfig_to_fail_1 = `
resource "aws_guardduty_filter" "test" {}`

const testAccGuardDutyFilterConfig_to_fail_2 = `
resource "aws_guardduty_filter" "test" {
	detector_id = "123456271278c0df5e089123480d8765"
}`
<commit_msg>Removed obsolete tests cases<commit_after>package aws

import (
	"fmt"
	"strings"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/guardduty"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func testAccAwsGuardDutyFilter_basic(t *testing.T) {
	resourceName := "aws_guardduty_filter.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsGuardDutyFilterDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGuardDutyFilterConfig_full(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsGuardDutyFilterExists(resourceName),
					resource.TestCheckResourceAttrSet(resourceName, "detector_id"),
					resource.TestCheckResourceAttr(resourceName, "name", "test-filter"),
					resource.TestCheckResourceAttr(resourceName, "action", "ARCHIVE"),
					resource.TestCheckResourceAttr(resourceName, "rank", "1"),
				),
			},
		},
	})
}

func testAccAwsGuardDutyFilter_import(t *testing.T) {
	resourceName := "aws_guardduty_filter.test"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsGuardDutyFilterDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccGuardDutyFilterConfig_full(),
			},

			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsGuardDutyFilterDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).guarddutyconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_guardduty_filter" {
			continue
		}

		parts := strings.SplitN(rs.Primary.ID, "_", 2)

		input := &guardduty.GetFilterInput{
			DetectorId: aws.String(parts[0]),
			FilterName: aws.String(parts[1]),
		}

		_, err := conn.GetFilter(input)
		if err != nil {
			if isAWSErr(err, guardduty.ErrCodeBadRequestException, "The request is rejected because the input detectorId is not owned by the current account.") {
				return nil
			}
			return err
		}

		return fmt.Errorf("Expected GuardDuty Filter to be destroyed, %s found", rs.Primary.Attributes["filter_name"])
	}

	return nil
}

func testAccCheckAwsGuardDutyFilterExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		_, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		return nil
	}
}

func testAccGuardDutyFilterConfig_full() string {
	return fmt.Sprintf(`
%[1]s

resource "aws_guardduty_filter" "test" {
  detector_id = "${aws_guardduty_detector.test.id}"
	name        = "test-filter"
	action      = "ARCHIVE"
	rank        = 1

  finding_criteria {
    criterion {
      field     = "region"
      values    = ["eu-west-1"]
      condition = "equals"
    }

    criterion {
      field     = "service.additionalInfo.threatListName"
      values    = ["some-threat", "another-threat"]
      condition = "not_equals"
    }

    criterion {
      field     = "updatedAt"
      values    = ["1570744740000"]
      condition = "less_than"
    }

    criterion {
      field     = "updatedAt"
      values    = ["1570744240000"]
      condition = "greater_than"
    }
  }
}`, testAccGuardDutyDetectorConfig_basic3)
}
<|endoftext|>


<commit_before>package main

import (
	// Stdlib
	"fmt"
	"os"
	"regexp"
	"strings"

	// Internal
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/hooks"

	// Vendor
	"github.com/fatih/color"
)

func main() {
	// Register the magical -salsaflow.version flag.
	hooks.IdentifyYourself()

	// Run the hook logic itself.
	if err := hook(); err != nil {
		errs.Fatal(err)
	}
}

func hook() error {
	// There are always 3 arguments passed to this hook.
	prevRef, newRef, flag := os.Args[1], os.Args[2], os.Args[3]

	// Return in case prevRef is the zero hash since that means
	// that this hook is being run right after 'git clone'.
	if prevRef == git.ZeroHash {
		return nil
	}

	// Return in case flag is '0'. That signals retrieving a file from the index.
	if flag == "0" {
		return nil
	}

	// Return unless the new HEAD is a core branch.
	isCore, err := isCoreBranch(newRef)
	if err != nil {
		return err
	}
	if !isCore {
		return nil
	}

	// Get the relevant commits.
	// These are the commits specified by newRef..prevRef, e.g. trunk..story/foobar.
	commits, err := git.ShowCommitRange(fmt.Sprintf("%v..%v", newRef, prevRef))
	if err != nil {
		return err
	}

	// Collect the commits with missing Story-Id tag.
	missing := make([]*git.Commit, 0, len(commits))
	for _, commit := range commits {
		if commit.StoryIdTag == "" {
			missing = append(missing, commit)
		}
	}
	if len(missing) == 0 {
		return nil
	}

	// Print the warning.
	printWarning(missing)
	return nil
}

func isCoreBranch(ref string) (bool, error) {
	// Get the ref names using 'git log'.
	// This prints the ref names in the following format:
	//
	//   (ref1, ref2, ..., refN)
	//
	outputBuffer, err := git.Log("-1", "--pretty=format:%d", ref)
	if err != nil {
		return false, err
	}
	output := outputBuffer.String()

	// Parse the output.
	match := regexp.MustCompile("^[ ]*[(]([^)]+)[)][ ]*$").FindStringSubmatch(output)
	if len(match) != 2 {
		return false, fmt.Errorf("failed to parse git log: %v", output)
	}
	refNames := strings.Split(match[1], ", ")

	// Iterate over the ref names and return the result.
	for _, ref := range refNames {
		isCore, err := git.IsCoreBranch(ref)
		if err != nil {
			return false, err
		}
		if isCore {
			return true, nil
		}
	}
	return false, nil
}

func printWarning(commits []*git.Commit) {
	// Let's be colorful!
	redBold := color.New(color.FgRed).Add(color.Bold)
	redBold.Println("\nWarning: There are some commits missing the Story-Id tag.")

	red := color.New(color.FgRed)
	red.Println("Make sure this is really what you want before proceeding further.\n")

	yellow := color.New(color.FgYellow).SprintFunc()
	for _, commit := range commits {
		fmt.Printf("  %v %v\n", yellow(commit.SHA), commit.MessageTitle)
	}
	fmt.Println()
}
<commit_msg>hooks/post-checkout: Fix review issue<commit_after>package main

import (
	// Stdlib
	"fmt"
	"os"
	"regexp"
	"strings"

	// Internal
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/hooks"

	// Vendor
	"github.com/fatih/color"
)

func main() {
	// Register the magical -salsaflow.version flag.
	hooks.IdentifyYourself()

	// Run the hook logic itself.
	if err := hook(); err != nil {
		errs.Fatal(err)
	}
}

func hook() error {
	// There are always 3 arguments passed to this hook.
	prevRef, newRef, flag := os.Args[1], os.Args[2], os.Args[3]

	// Return in case prevRef is the zero hash since that means
	// that this hook is being run right after 'git clone'.
	if prevRef == git.ZeroHash {
		return nil
	}

	// Return in case flag is '0'. That signals retrieving a file from the index.
	if flag == "0" {
		return nil
	}

	// Return unless the new HEAD is a core branch.
	isCore, err := isCoreBranch(newRef)
	if err != nil {
		return err
	}
	if !isCore {
		return nil
	}

	// Get the relevant commits.
	// These are the commits specified by newRef..prevRef, e.g. trunk..story/foobar.
	commits, err := git.ShowCommitRange(fmt.Sprintf("%v..%v", newRef, prevRef))
	if err != nil {
		return err
	}

	// Collect the commits with missing Story-Id tag.
	missing := make([]*git.Commit, 0, len(commits))
	for _, commit := range commits {
		if commit.StoryIdTag == "" {
			missing = append(missing, commit)
		}
	}
	if len(missing) == 0 {
		return nil
	}

	// Print the warning.
	printWarning(missing)
	return nil
}

func isCoreBranch(ref string) (bool, error) {
	// Since the hook is passed the commit hashes, we need to get the actual
	// ref names for the hash to be able to check whether any core branch is affected.
	//
	// So, let's get the ref names using 'git log'.
	// This prints the ref names for the given hash in the following format:
	//
	//   (refName1, refName2, ..., refNameN)
	//
	outputBuffer, err := git.Log("-1", "--pretty=format:%d", ref)
	if err != nil {
		return false, err
	}
	output := outputBuffer.String()

	// Parse the output.
	match := regexp.MustCompile("^[ ]*[(]([^)]+)[)][ ]*$").FindStringSubmatch(output)
	if len(match) != 2 {
		return false, fmt.Errorf("failed to parse git log: %v", output)
	}
	refNames := strings.Split(match[1], ", ")

	// Iterate over the ref names and return the result.
	// The commit is considered a core branch tip when any of the associated
	// ref names equals to a core branch names.
	for _, refName := range refNames {
		isCore, err := git.IsCoreBranch(refName)
		if err != nil {
			return false, err
		}
		if isCore {
			return true, nil
		}
	}
	return false, nil
}

func printWarning(commits []*git.Commit) {
	// Let's be colorful!
	redBold := color.New(color.FgRed).Add(color.Bold)
	redBold.Println("\nWarning: There are some commits missing the Story-Id tag.")

	red := color.New(color.FgRed)
	red.Println("Make sure this is really what you want before proceeding further.\n")

	yellow := color.New(color.FgYellow).SprintFunc()
	for _, commit := range commits {
		fmt.Printf("  %v %v\n", yellow(commit.SHA), commit.MessageTitle)
	}
	fmt.Println()
}
<|endoftext|>


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

package pdata

import (
	"time"
)

// Timestamp is a time specified as UNIX Epoch time in nanoseconds since
// 00:00:00 UTC on 1 January 1970.
type Timestamp uint64

// NewTimestampFromTime constructs a new Timestamp from the provided time.Time.
func NewTimestampFromTime(t time.Time) Timestamp {
	return Timestamp(uint64(t.UnixNano()))
}

// TimestampFromTime constructs a new Timestamp from the provided time.Time.
// Deprecated: use NewTimestampFromTime instead.
func TimestampFromTime(t time.Time) Timestamp {
	return Timestamp(uint64(t.UnixNano()))
}

// AsTime converts this to a time.Time.
func (ts Timestamp) AsTime() time.Time {
	return time.Unix(0, int64(ts)).UTC()
}

// String returns the string representation of this in UTC.
func (ts Timestamp) String() string {
	return ts.AsTime().String()
}
<commit_msg>Remove deprecated pdata.TimestampFromTime. Closes: #3925 (#3935)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pdata

import (
	"time"
)

// Timestamp is a time specified as UNIX Epoch time in nanoseconds since
// 00:00:00 UTC on 1 January 1970.
type Timestamp uint64

// NewTimestampFromTime constructs a new Timestamp from the provided time.Time.
func NewTimestampFromTime(t time.Time) Timestamp {
	return Timestamp(uint64(t.UnixNano()))
}

// AsTime converts this to a time.Time.
func (ts Timestamp) AsTime() time.Time {
	return time.Unix(0, int64(ts)).UTC()
}

// String returns the string representation of this in UTC.
func (ts Timestamp) String() string {
	return ts.AsTime().String()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/golang/freetype/truetype"
	"github.com/tburke/netpbm"
	"golang.org/x/image/draw"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/gomedium"
	"golang.org/x/image/math/fixed"

	"image"
)

type Point [2]float64

func DegmintoFloat(val string, dir string) float64 {
	p := strings.Index(val, ".")
	if p < 2 {
		return 0
	}
	deg, err := strconv.ParseFloat(val[0:p-2], 64)
	if err != nil {
		return 0
	}
	min, err := strconv.ParseFloat(val[p-2:], 64)
	if err != nil {
		return 0
	}
	deg += min / 60
	if dir[0] == 'S' || dir[0] == 'W' {
		deg = -deg
	}
	return deg
}

func (p *Point) FromGPS(lat, latdir, lon, londir string) error {
	p[0] = DegmintoFloat(lat, latdir)
	p[1] = DegmintoFloat(lon, londir)
	return nil
}

func TimeFromGPS(gtime, date string) time.Time {
	var yr, dy int
	var mo time.Month
	if len(date) > 5 {
		dy, _ = strconv.Atoi(date[0:2])
		month, _ := strconv.Atoi(date[2:4])
		mo = time.Month(month)
		yr, _ = strconv.Atoi(date[4:6])
		yr += 2000
	} else {
		t := time.Now()
		yr = t.Year()
		mo = t.Month()
		dy = t.Day()
	}
	hr, _ := strconv.Atoi(gtime[0:2])
	mn, _ := strconv.Atoi(gtime[2:4])
	sc, _ := strconv.Atoi(gtime[4:6])
	return time.Date(yr, mo, dy, hr, mn, sc, 0, time.UTC)
}

type GPRMC struct {
	Time      time.Time
	Validity  byte
	LatLong   Point
	Speed     float32
	Course    float32
	Variation float32
	EastWest  byte
}

func (g *GPRMC) FromNMEA(s []string) error {
	if s[0] != "$GPRMC" {
		return errors.New("Record is not a GPRMC record")
	}
	if len(s) != 13 {
		return errors.New("Record does not have 13 fields")
	}
	g.Time = TimeFromGPS(s[1], s[9])
	g.Validity = s[2][0]
	g.LatLong.FromGPS(s[3], s[4], s[5], s[6])
	f, _ := strconv.ParseFloat(s[7], 32)
	g.Speed = float32(f)
	f, _ = strconv.ParseFloat(s[8], 32)
	g.Course = float32(f)
	f, _ = strconv.ParseFloat(s[10], 32)
	g.Variation = float32(f)
	if len(s[11]) > 0 {
		g.EastWest = s[10][0]
	}
	return nil
}

func epd_write(i image.Image) error {
	cmd, err := os.OpenFile("/dev/epd/command", os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	img, err := os.OpenFile("/dev/epd/LE/display", os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	cmd.Write([]byte("C"))
	netpbm.PbmData(img, i)
	cmd.Write([]byte("P"))
	img.Close()
	cmd.Close()
	return nil
}

func show_data(name, value string) image.Image {
	i := image.NewRGBA(image.Rect(0, 0, 264, 176))
	draw.Src.Draw(i, i.Bounds(), image.White, image.ZP)
	tt, _ := truetype.Parse(gomedium.TTF)
	face := truetype.NewFace(tt, &truetype.Options{
		Size:    52,
		Hinting: font.HintingNone,
		DPI:     72,
	})

	d := &font.Drawer{
		Dst:  i,
		Src:  image.Black,
		Face: face,
	}
	d.Dot = fixed.P(60, 80)
	d.DrawString(name)
	d.Dot = fixed.P(60, 160)
	d.DrawString(value)

	return i
}

func show_speed() error {
	f, _ := os.Open("/dev/ttyUSB0")
	r := csv.NewReader(f)
	r.FieldsPerRecord = -1
	for {
		rec, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("USB0 Read: %v\n", rec)
		if rec[0] == "$GPRMC" {
			var g GPRMC
			g.FromNMEA(rec)
			img := show_data("Speed", strconv.FormatFloat(float64(g.Speed), 'f', -1, 32))
			epd_write(img)
			break
		}
	}
	f.Close()
	return nil
}

func main() {
	for {
		err := show_speed()
		/*
			fmt.Println("Show data")
			img := show_data("Speed", "6.3")
			fmt.Println("Write image")
			err := epd_write(img)
		*/
		if err != nil {
			fmt.Println(err)
		}
		time.Sleep(1 * time.Minute)
	}
}

/*
https://github.com/tarm/serial/blob/master/serial_linux.go
Set baud
cflagToUse := syscall.CREAD | syscall.CLOCAL | syscall.B4800
t := syscall.Termios{
		Iflag:  syscall.IGNPAR,
		Cflag:  cflagToUse,
		Cc:     [32]uint8{syscall.VMIN: vmin, syscall.VTIME: vtime},
		Ispeed: syscall.B4800,
		Ospeed: syscall.B4800,
	}

if _, _, errno := syscall.Syscall6(
		syscall.SYS_IOCTL,
		uintptr(fd),
		uintptr(syscall.TCSETS),
		uintptr(unsafe.Pointer(&t)),
		0,
		0,
		0,
	); errno != 0 {
		return nil, errno
	}

*/
<commit_msg>gps notes.<commit_after>package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/golang/freetype/truetype"
	"github.com/tburke/netpbm"
	"golang.org/x/image/draw"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/gomedium"
	"golang.org/x/image/math/fixed"

	"image"
)

type Point [2]float64

func DegmintoFloat(val string, dir string) float64 {
	p := strings.Index(val, ".")
	if p < 2 {
		return 0
	}
	deg, err := strconv.ParseFloat(val[0:p-2], 64)
	if err != nil {
		return 0
	}
	min, err := strconv.ParseFloat(val[p-2:], 64)
	if err != nil {
		return 0
	}
	deg += min / 60
	if dir[0] == 'S' || dir[0] == 'W' {
		deg = -deg
	}
	return deg
}

func (p *Point) FromGPS(lat, latdir, lon, londir string) error {
	p[0] = DegmintoFloat(lat, latdir)
	p[1] = DegmintoFloat(lon, londir)
	return nil
}

func TimeFromGPS(gtime, date string) time.Time {
	var yr, dy int
	var mo time.Month
	if len(date) > 5 {
		dy, _ = strconv.Atoi(date[0:2])
		month, _ := strconv.Atoi(date[2:4])
		mo = time.Month(month)
		yr, _ = strconv.Atoi(date[4:6])
		yr += 2000
	} else {
		t := time.Now()
		yr = t.Year()
		mo = t.Month()
		dy = t.Day()
	}
	hr, _ := strconv.Atoi(gtime[0:2])
	mn, _ := strconv.Atoi(gtime[2:4])
	sc, _ := strconv.Atoi(gtime[4:6])
	return time.Date(yr, mo, dy, hr, mn, sc, 0, time.UTC)
}

type GPRMC struct {
	Time      time.Time
	Validity  byte
	LatLong   Point
	Speed     float32
	Course    float32
	Variation float32
	EastWest  byte
}

func (g *GPRMC) FromNMEA(s []string) error {
	if s[0] != "$GPRMC" {
		return errors.New("Record is not a GPRMC record")
	}
	if len(s) != 13 {
		return errors.New("Record does not have 13 fields")
	}
	g.Time = TimeFromGPS(s[1], s[9])
	g.Validity = s[2][0]
	g.LatLong.FromGPS(s[3], s[4], s[5], s[6])
	f, _ := strconv.ParseFloat(s[7], 32)
	g.Speed = float32(f)
	f, _ = strconv.ParseFloat(s[8], 32)
	g.Course = float32(f)
	f, _ = strconv.ParseFloat(s[10], 32)
	g.Variation = float32(f)
	if len(s[11]) > 0 {
		g.EastWest = s[10][0]
	}
	return nil
}

func epd_write(i image.Image) error {
	cmd, err := os.OpenFile("/dev/epd/command", os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	img, err := os.OpenFile("/dev/epd/LE/display", os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	cmd.Write([]byte("C"))
	netpbm.PbmData(img, i)
	cmd.Write([]byte("P"))
	img.Close()
	cmd.Close()
	return nil
}

func show_data(name, value string) image.Image {
	i := image.NewRGBA(image.Rect(0, 0, 264, 176))
	draw.Src.Draw(i, i.Bounds(), image.White, image.ZP)
	tt, _ := truetype.Parse(gomedium.TTF)
	face := truetype.NewFace(tt, &truetype.Options{
		Size:    52,
		Hinting: font.HintingNone,
		DPI:     72,
	})

	d := &font.Drawer{
		Dst:  i,
		Src:  image.Black,
		Face: face,
	}
	d.Dot = fixed.P(60, 80)
	d.DrawString(name)
	d.Dot = fixed.P(60, 160)
	d.DrawString(value)

	return i
}

func show_speed() error {
	f, _ := os.Open("/dev/ttyUSB0")
	r := csv.NewReader(f)
	r.FieldsPerRecord = -1
	for {
		rec, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("USB0 Read: %v\n", rec)
		if rec[0] == "$GPRMC" {
			var g GPRMC
			g.FromNMEA(rec)
			img := show_data("Speed", strconv.FormatFloat(float64(g.Speed), 'f', -1, 32))
			epd_write(img)
			break
		}
	}
	f.Close()
	return nil
}

func main() {
	for {
		err := show_speed()
		/*
			fmt.Println("Show data")
			img := show_data("Speed", "6.3")
			fmt.Println("Write image")
			err := epd_write(img)
		*/
		if err != nil {
			fmt.Println(err)
		}
		time.Sleep(1 * time.Minute)
	}
}

/*
http://www.catb.org/gpsd/installation.html
https://github.com/tarm/serial/blob/master/serial_linux.go
Set baud
cflagToUse := syscall.CREAD | syscall.CLOCAL | syscall.B4800
t := syscall.Termios{
		Iflag:  syscall.IGNPAR,
		Cflag:  cflagToUse,
		Cc:     [32]uint8{syscall.VMIN: vmin, syscall.VTIME: vtime},
		Ispeed: syscall.B4800,
		Ospeed: syscall.B4800,
	}

if _, _, errno := syscall.Syscall6(
		syscall.SYS_IOCTL,
		uintptr(fd),
		uintptr(syscall.TCSETS),
		uintptr(unsafe.Pointer(&t)),
		0,
		0,
		0,
	); errno != 0 {
		return nil, errno
	}

*/
<|endoftext|>