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

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file contains the list manipulation primitive functions.

package golisp

import ()

func RegisterListManipulationPrimitives() {
	MakePrimitiveFunction("list", "*", ListImpl)
	MakePrimitiveFunction("make-list", "1|2", MakeListImpl)
	MakePrimitiveFunction("length", "1", ListLengthImpl)
	MakePrimitiveFunction("cons", "2", ConsImpl)
	MakePrimitiveFunction("reverse", "1", ReverseImpl)
	MakePrimitiveFunction("flatten", "1", FlattenImpl)
	MakePrimitiveFunction("flatten*", "1", RecursiveFlattenImpl)
	MakePrimitiveFunction("append", "*", AppendImpl)
	MakeSpecialForm("append!", "2", AppendBangImpl)
	MakePrimitiveFunction("copy", "1", CopyImpl)
	MakePrimitiveFunction("partition", "2", PartitionImpl)
	MakePrimitiveFunction("sublist", "3", SublistImpl)
}

func MakeListImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	kVal := Car(args)
	if !IntegerP(kVal) {
		err = ProcessError("make-list requires a number as it's first argument.", env)
		return
	}

	k := IntegerValue(kVal)
	var element *Data

	if Length(args) == 1 {
		element = nil
	} else {
		element = Cadr(args)
	}

	var items []*Data
	items = make([]*Data, 0, k)
	for ; k > 0; k = k - 1 {
		items = append(items, element)
	}
	return ArrayToList(items), nil
}

func ListImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return args, nil
}

func ListLengthImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return IntegerWithValue(int64(Length(Car(args)))), nil
}

func ConsImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	car := Car(args)
	cdr := Cadr(args)
	return Cons(car, cdr), nil
}

func ReverseImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Reverse(Car(args)), nil
}

func FlattenImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Flatten(Car(args))
}

func RecursiveFlattenImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return RecursiveFlatten(Car(args))
}

func AppendBangImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	firstList, err := Eval(Car(args), env)
	if err != nil {
		return
	}

	second, err := Eval(Cadr(args), env)
	if err != nil {
		return
	}

	if ListP(second) {
		result = AppendBangList(firstList, second)
	} else {
		result = AppendBang(firstList, second)
	}

	if SymbolP(Car(args)) {
		env.BindTo(Car(args), result)
	}

	return
}

func AppendImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	// No args -> empty list
	if Length(args) == 0 {
		return
	}

	// step through args, accumulating elements
	var items []*Data = make([]*Data, 0, 10)
	var item *Data
	for cell := args; NotNilP(cell); cell = Cdr(cell) {
		item = Car(cell)
		if ListP(item) {
			for itemCell := item; NotNilP(itemCell); itemCell = Cdr(itemCell) {
				items = append(items, Car(itemCell))
			}
		} else {
			items = append(items, item)
		}
	}
	result = ArrayToList(items)
	return
}

func CopyImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Copy(Car(args)), nil
}

func partitionBySize(determiner *Data, l *Data) (result *Data, err error) {
	size := int(IntegerValue(determiner))
	var pieces []*Data = make([]*Data, 0, 5)
	var chunk []*Data = make([]*Data, 0, 5)
	for c := l; NotNilP(c); c = Cdr(c) {
		if len(chunk) < size {
			chunk = append(chunk, Car(c))
		} else {
			pieces = append(pieces, ArrayToList(chunk))
			chunk = make([]*Data, 0, 5)
			chunk = append(chunk, Car(c))
		}
	}
	if len(chunk) > 0 {
		pieces = append(pieces, ArrayToList(chunk))
	}
	return ArrayToList(pieces), nil
}

func partitionByPredicate(determiner *Data, l *Data, env *SymbolTableFrame) (result *Data, err error) {
	pieces := make([]*Data, 0, 5)
	falseSection := make([]*Data, 0, 5)
	trueSection := make([]*Data, 0, 5)
	var predicateResult *Data
	for c := l; NotNilP(c); c = Cdr(c) {
		predicateResult, err = Apply(determiner, InternalMakeList(Car(c)), env)
		if err != nil {
			return
		}
		if BooleanValue(predicateResult) {
			trueSection = append(trueSection, Car(c))
		} else {
			falseSection = append(falseSection, Car(c))
		}
	}

	pieces = append(pieces, ArrayToList(trueSection))
	pieces = append(pieces, ArrayToList(falseSection))

	return ArrayToList(pieces), nil
}

func PartitionImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	determiner := Car(args)
	if !IntegerP(determiner) && !FunctionP(determiner) {
		err = ProcessError("partition requires a number or function as it's first argument.", env)
		return
	}

	l := Cadr(args)
	if !ListP(l) {
		err = ProcessError("partition requires a list as it's second argument.", env)
		return
	}

	if IntegerP(determiner) {
		return partitionBySize(determiner, l)
	} else {
		return partitionByPredicate(determiner, l, env)
	}
}

func SublistImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	n := First(args)
	if !IntegerP(n) {
		err = ProcessError("sublist requires a number as it's first argument.", env)
		return
	}
	first := int(IntegerValue(n))

	n = Second(args)
	if !IntegerP(n) {
		err = ProcessError("sublist requires a number as it's second argument.", env)
		return
	}
	last := int(IntegerValue(n))

	if first >= last {
		result = nil
		return
	}

	l := Third(args)
	if !ListP(l) {
		err = ProcessError("sublist requires a list as it's third argument.", env)
		return
	}

	var cell *Data
	var i int
	for i, cell = 1, l; i < first && NotNilP(cell); i, cell = i+1, Cdr(cell) {
	}

	var items []*Data = make([]*Data, 0, Length(args))
	for ; i <= last && NotNilP(cell); i, cell = i+1, Cdr(cell) {
		items = append(items, Car(cell))
	}
	result = ArrayToList(items)
	return
}
<commit_msg>Fix sublist to take the Scheme standard argument order.<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file contains the list manipulation primitive functions.

package golisp

import ()

func RegisterListManipulationPrimitives() {
	MakePrimitiveFunction("list", "*", ListImpl)
	MakePrimitiveFunction("make-list", "1|2", MakeListImpl)
	MakePrimitiveFunction("length", "1", ListLengthImpl)
	MakePrimitiveFunction("cons", "2", ConsImpl)
	MakePrimitiveFunction("reverse", "1", ReverseImpl)
	MakePrimitiveFunction("flatten", "1", FlattenImpl)
	MakePrimitiveFunction("flatten*", "1", RecursiveFlattenImpl)
	MakePrimitiveFunction("append", "*", AppendImpl)
	MakeSpecialForm("append!", "2", AppendBangImpl)
	MakePrimitiveFunction("copy", "1", CopyImpl)
	MakePrimitiveFunction("partition", "2", PartitionImpl)
	MakePrimitiveFunction("sublist", "3", SublistImpl)
}

func MakeListImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	kVal := Car(args)
	if !IntegerP(kVal) {
		err = ProcessError("make-list requires a number as it's first argument.", env)
		return
	}

	k := IntegerValue(kVal)
	var element *Data

	if Length(args) == 1 {
		element = nil
	} else {
		element = Cadr(args)
	}

	var items []*Data
	items = make([]*Data, 0, k)
	for ; k > 0; k = k - 1 {
		items = append(items, element)
	}
	return ArrayToList(items), nil
}

func ListImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return args, nil
}

func ListLengthImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return IntegerWithValue(int64(Length(Car(args)))), nil
}

func ConsImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	car := Car(args)
	cdr := Cadr(args)
	return Cons(car, cdr), nil
}

func ReverseImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Reverse(Car(args)), nil
}

func FlattenImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Flatten(Car(args))
}

func RecursiveFlattenImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return RecursiveFlatten(Car(args))
}

func AppendBangImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	firstList, err := Eval(Car(args), env)
	if err != nil {
		return
	}

	second, err := Eval(Cadr(args), env)
	if err != nil {
		return
	}

	if ListP(second) {
		result = AppendBangList(firstList, second)
	} else {
		result = AppendBang(firstList, second)
	}

	if SymbolP(Car(args)) {
		env.BindTo(Car(args), result)
	}

	return
}

func AppendImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	// No args -> empty list
	if Length(args) == 0 {
		return
	}

	// step through args, accumulating elements
	var items []*Data = make([]*Data, 0, 10)
	var item *Data
	for cell := args; NotNilP(cell); cell = Cdr(cell) {
		item = Car(cell)
		if ListP(item) {
			for itemCell := item; NotNilP(itemCell); itemCell = Cdr(itemCell) {
				items = append(items, Car(itemCell))
			}
		} else {
			items = append(items, item)
		}
	}
	result = ArrayToList(items)
	return
}

func CopyImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	return Copy(Car(args)), nil
}

func partitionBySize(determiner *Data, l *Data) (result *Data, err error) {
	size := int(IntegerValue(determiner))
	var pieces []*Data = make([]*Data, 0, 5)
	var chunk []*Data = make([]*Data, 0, 5)
	for c := l; NotNilP(c); c = Cdr(c) {
		if len(chunk) < size {
			chunk = append(chunk, Car(c))
		} else {
			pieces = append(pieces, ArrayToList(chunk))
			chunk = make([]*Data, 0, 5)
			chunk = append(chunk, Car(c))
		}
	}
	if len(chunk) > 0 {
		pieces = append(pieces, ArrayToList(chunk))
	}
	return ArrayToList(pieces), nil
}

func partitionByPredicate(determiner *Data, l *Data, env *SymbolTableFrame) (result *Data, err error) {
	pieces := make([]*Data, 0, 5)
	falseSection := make([]*Data, 0, 5)
	trueSection := make([]*Data, 0, 5)
	var predicateResult *Data
	for c := l; NotNilP(c); c = Cdr(c) {
		predicateResult, err = Apply(determiner, InternalMakeList(Car(c)), env)
		if err != nil {
			return
		}
		if BooleanValue(predicateResult) {
			trueSection = append(trueSection, Car(c))
		} else {
			falseSection = append(falseSection, Car(c))
		}
	}

	pieces = append(pieces, ArrayToList(trueSection))
	pieces = append(pieces, ArrayToList(falseSection))

	return ArrayToList(pieces), nil
}

func PartitionImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	determiner := Car(args)
	if !IntegerP(determiner) && !FunctionP(determiner) {
		err = ProcessError("partition requires a number or function as it's first argument.", env)
		return
	}

	l := Cadr(args)
	if !ListP(l) {
		err = ProcessError("partition requires a list as it's second argument.", env)
		return
	}

	if IntegerP(determiner) {
		return partitionBySize(determiner, l)
	} else {
		return partitionByPredicate(determiner, l, env)
	}
}

func SublistImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	l := Car(args)
	if !ListP(l) {
		err = ProcessError("sublist requires a list as it's first argument.", env)
		return
	}

	n := Cadr(args)
	if !IntegerP(n) {
		err = ProcessError("sublist requires a number as it's second argument (start).", env)
		return
	}
	first := int(IntegerValue(n))

	n = Caddr(args)
	if !IntegerP(n) {
		err = ProcessError("sublist requires a number as it's third argument (end).", env)
		return
	}
	last := int(IntegerValue(n))

	if first >= last {
		result = nil
		return
	}

	var cell *Data
	var i int
	for i, cell = 1, l; i < first && NotNilP(cell); i, cell = i+1, Cdr(cell) {
	}

	var items []*Data = make([]*Data, 0, Length(args))
	for ; i < last && NotNilP(cell); i, cell = i+1, Cdr(cell) {
		items = append(items, Car(cell))
	}
	result = ArrayToList(items)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"time"
)

var discordClient = discordConfig{
	Boss:      os.Getenv("DISCORD_BOSS"),
	Token:     os.Getenv("DISCORD_TOKEN"),
	AvatarURL: "https://axolotl.gazzy.online/static/axolotlava.jpg",
	Debug:     false,
}

func init() {
	requireEnvVars("DATABASE_HOST", "DATABASE_PORT", "DATABASE_DB", "DISCORD_BOSS", "DISCORD_TOKEN")
}

func main() {
	defer webServer()
	dbConn()

	go discordStart(&discordClient)
	go tickerHelper(10*time.Minute, rssReader, false)
	go tickerHelper(10*time.Hour, maintainAnimeList, true)
}
<commit_msg>change avatar<commit_after>package main

import (
	"os"
	"time"
)

var discordClient = discordConfig{
	Boss:      os.Getenv("DISCORD_BOSS"),
	Token:     os.Getenv("DISCORD_TOKEN"),
	AvatarURL: "https://cdn.discordapp.com/attachments/450681214781882379/450777891626811393/75ecbeedecd376ae8a32b8d7b0a5cfc3.png",
	Debug:     false,
}

func init() {
	requireEnvVars("DATABASE_HOST", "DATABASE_PORT", "DATABASE_DB", "DISCORD_BOSS", "DISCORD_TOKEN")
}

func main() {
	defer webServer()
	dbConn()

	go discordStart(&discordClient)
	go tickerHelper(10*time.Minute, rssReader, false)
	go tickerHelper(10*time.Hour, maintainAnimeList, true)
}
<|endoftext|>


<commit_before>// Copyright 2015 Apcera Inc. All rights reserved.

package test

import (
	"bufio"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/nats-io/gnatsd/server"
	"github.com/nats-io/nats"
)

func TestTLSConnection(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tls.conf")
	defer srv.Shutdown()

	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	nurl := fmt.Sprintf("tls://%s:%s@%s/", opts.Username, opts.Password, endpoint)
	nc, err := nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server")
	}

	// Do simple SecureConnect
	nc, err = nats.Connect(fmt.Sprintf("tls://%s/", endpoint))
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server with no auth")
	}

	// Now do more advanced checking, verifying servername and using rootCA.

	nc, err = nats.Connect(nurl, nats.RootCAs("./configs/certs/ca.pem"))
	if err != nil {
		t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
	}
	defer nc.Close()

	subj := "foo-tls"
	sub, _ := nc.SubscribeSync(subj)

	nc.Publish(subj, []byte("We are Secure!"))
	nc.Flush()
	nmsgs, _ := sub.QueuedMsgs()
	if nmsgs != 1 {
		t.Fatalf("Expected to receive a message over the TLS connection")
	}
}

func TestTLSClientCertificate(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tlsverify.conf")
	defer srv.Shutdown()

	nurl := fmt.Sprintf("tls://%s:%d", opts.Host, opts.Port)

	_, err := nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server without a certificate")
	}

	_, err = nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to secure connect to secure server without a certificate")
	}

	// Load client certificate to sucessfully connect.
	certFile := "./configs/certs/client-cert.pem"
	keyFile := "./configs/certs/client-key.pem"
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		t.Fatalf("error parsing X509 certificate/key pair: %v", err)
	}

	// Load in root CA for server verification
	rootPEM, err := ioutil.ReadFile("./configs/certs/ca.pem")
	if err != nil || rootPEM == nil {
		t.Fatalf("failed to read root certificate")
	}
	pool := x509.NewCertPool()
	ok := pool.AppendCertsFromPEM([]byte(rootPEM))
	if !ok {
		t.Fatalf("failed to parse root certificate")
	}

	config := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   opts.Host,
		RootCAs:      pool,
		MinVersion:   tls.VersionTLS12,
	}

	copts := nats.DefaultOptions
	copts.Url = nurl
	copts.Secure = true
	copts.TLSConfig = config

	nc, err := copts.Connect()
	if err != nil {
		t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
	}
	nc.Flush()
	defer nc.Close()
}

func TestTLSConnectionTimeout(t *testing.T) {
	opts := LoadConfig("./configs/tls.conf")
	opts.TLSTimeout = 0.25

	srv := RunServer(opts)
	defer srv.Shutdown()

	// Dial with normal TCP
	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	conn, err := net.Dial("tcp", endpoint)
	if err != nil {
		t.Fatalf("Could not connect to %q", endpoint)
	}
	defer conn.Close()

	// Read deadlines
	conn.SetReadDeadline(time.Now().Add(2 * time.Second))

	// Read the INFO string.
	br := bufio.NewReader(conn)
	info, err := br.ReadString('\n')
	if err != nil {
		t.Fatalf("Failed to read INFO - %v", err)
	}
	if !strings.HasPrefix(info, "INFO ") {
		t.Fatalf("INFO response incorrect: %s\n", info)
	}
	wait := time.Duration(opts.TLSTimeout * float64(time.Second))
	time.Sleep(wait)
	// Read deadlines
	conn.SetReadDeadline(time.Now().Add(2 * time.Second))
	tlsErr, err := br.ReadString('\n')
	if err == nil && !strings.Contains(tlsErr, "-ERR 'Secure Connection - TLS Required") {
		t.Fatalf("TLS Timeout response incorrect: %q\n", tlsErr)
	}
}

func stressConnect(t *testing.T, wg *sync.WaitGroup, errCh chan error, url string, index int) {
	defer wg.Done()

	subName := fmt.Sprintf("foo.%d", index)

	for i := 0; i < 100; i++ {
		nc, err := nats.Connect(url, nats.RootCAs("./configs/certs/ca.pem"))
		if err != nil {
			errCh <- fmt.Errorf("Unable to create TLS connection: %v\n", err)
			return
		}
		defer nc.Close()

		sub, err := nc.SubscribeSync(subName)
		if err != nil {
			errCh <- fmt.Errorf("Unable to subscribe on '%s': %v\n", subName, err)
			return
		}

		if err := nc.Publish(subName, []byte("secure data")); err != nil {
			errCh <- fmt.Errorf("Unable to send on '%s': %v\n", subName, err)
		}

		if _, err := sub.NextMsg(2 * time.Second); err != nil {
			errCh <- fmt.Errorf("Unable to get next message: %v\n", err)
		}

		nc.Close()
	}

	errCh <- nil
}

func TestTLSStressConnect(t *testing.T) {
	opts, err := server.ProcessConfigFile("./configs/tls.conf")
	if err != nil {
		panic(fmt.Sprintf("Error processing configuration file: %v", err))
	}
	opts.NoSigs, opts.NoLog = true, true

	// For this test, remove the authorization
	opts.Authorization = ""

	// Increase ssl timeout
	opts.TLSTimeout = 2.0

	srv := RunServer(opts)
	defer srv.Shutdown()

	nurl := fmt.Sprintf("tls://%s:%d", opts.Host, opts.Port)

	threadCount := 3

	errCh := make(chan error, threadCount)

	var wg sync.WaitGroup
	wg.Add(threadCount)

	for i := 0; i < threadCount; i++ {
		go stressConnect(t, &wg, errCh, nurl, i)
	}

	wg.Wait()

	var lastError error
	lastError = nil
	for i := 0; i < threadCount; i++ {
		err := <-errCh
		if err != nil {
			lastError = err
		}
	}

	if lastError != nil {
		t.Fatalf("%v\n", lastError)
	}
}

func TestTLSBadAuthError(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tls.conf")
	defer srv.Shutdown()

	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	nurl := fmt.Sprintf("tls://%s:%s@%s/", opts.Username, "NOT_THE_PASSWORD", endpoint)

	_, err := nats.Connect(nurl, nats.RootCAs("./configs/certs/ca.pem"))
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server")
	}
	if err.Error() != nats.ErrAuthorization.Error() {
		t.Fatalf("Excpected and auth violation, got %v\n", err)
	}
}
<commit_msg>spelling<commit_after>// Copyright 2015 Apcera Inc. All rights reserved.

package test

import (
	"bufio"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/nats-io/gnatsd/server"
	"github.com/nats-io/nats"
)

func TestTLSConnection(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tls.conf")
	defer srv.Shutdown()

	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	nurl := fmt.Sprintf("tls://%s:%s@%s/", opts.Username, opts.Password, endpoint)
	nc, err := nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server")
	}

	// Do simple SecureConnect
	nc, err = nats.Connect(fmt.Sprintf("tls://%s/", endpoint))
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server with no auth")
	}

	// Now do more advanced checking, verifying servername and using rootCA.

	nc, err = nats.Connect(nurl, nats.RootCAs("./configs/certs/ca.pem"))
	if err != nil {
		t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
	}
	defer nc.Close()

	subj := "foo-tls"
	sub, _ := nc.SubscribeSync(subj)

	nc.Publish(subj, []byte("We are Secure!"))
	nc.Flush()
	nmsgs, _ := sub.QueuedMsgs()
	if nmsgs != 1 {
		t.Fatalf("Expected to receive a message over the TLS connection")
	}
}

func TestTLSClientCertificate(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tlsverify.conf")
	defer srv.Shutdown()

	nurl := fmt.Sprintf("tls://%s:%d", opts.Host, opts.Port)

	_, err := nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server without a certificate")
	}

	_, err = nats.Connect(nurl)
	if err == nil {
		t.Fatalf("Expected error trying to secure connect to secure server without a certificate")
	}

	// Load client certificate to successfully connect.
	certFile := "./configs/certs/client-cert.pem"
	keyFile := "./configs/certs/client-key.pem"
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		t.Fatalf("error parsing X509 certificate/key pair: %v", err)
	}

	// Load in root CA for server verification
	rootPEM, err := ioutil.ReadFile("./configs/certs/ca.pem")
	if err != nil || rootPEM == nil {
		t.Fatalf("failed to read root certificate")
	}
	pool := x509.NewCertPool()
	ok := pool.AppendCertsFromPEM([]byte(rootPEM))
	if !ok {
		t.Fatalf("failed to parse root certificate")
	}

	config := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ServerName:   opts.Host,
		RootCAs:      pool,
		MinVersion:   tls.VersionTLS12,
	}

	copts := nats.DefaultOptions
	copts.Url = nurl
	copts.Secure = true
	copts.TLSConfig = config

	nc, err := copts.Connect()
	if err != nil {
		t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
	}
	nc.Flush()
	defer nc.Close()
}

func TestTLSConnectionTimeout(t *testing.T) {
	opts := LoadConfig("./configs/tls.conf")
	opts.TLSTimeout = 0.25

	srv := RunServer(opts)
	defer srv.Shutdown()

	// Dial with normal TCP
	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	conn, err := net.Dial("tcp", endpoint)
	if err != nil {
		t.Fatalf("Could not connect to %q", endpoint)
	}
	defer conn.Close()

	// Read deadlines
	conn.SetReadDeadline(time.Now().Add(2 * time.Second))

	// Read the INFO string.
	br := bufio.NewReader(conn)
	info, err := br.ReadString('\n')
	if err != nil {
		t.Fatalf("Failed to read INFO - %v", err)
	}
	if !strings.HasPrefix(info, "INFO ") {
		t.Fatalf("INFO response incorrect: %s\n", info)
	}
	wait := time.Duration(opts.TLSTimeout * float64(time.Second))
	time.Sleep(wait)
	// Read deadlines
	conn.SetReadDeadline(time.Now().Add(2 * time.Second))
	tlsErr, err := br.ReadString('\n')
	if err == nil && !strings.Contains(tlsErr, "-ERR 'Secure Connection - TLS Required") {
		t.Fatalf("TLS Timeout response incorrect: %q\n", tlsErr)
	}
}

func stressConnect(t *testing.T, wg *sync.WaitGroup, errCh chan error, url string, index int) {
	defer wg.Done()

	subName := fmt.Sprintf("foo.%d", index)

	for i := 0; i < 100; i++ {
		nc, err := nats.Connect(url, nats.RootCAs("./configs/certs/ca.pem"))
		if err != nil {
			errCh <- fmt.Errorf("Unable to create TLS connection: %v\n", err)
			return
		}
		defer nc.Close()

		sub, err := nc.SubscribeSync(subName)
		if err != nil {
			errCh <- fmt.Errorf("Unable to subscribe on '%s': %v\n", subName, err)
			return
		}

		if err := nc.Publish(subName, []byte("secure data")); err != nil {
			errCh <- fmt.Errorf("Unable to send on '%s': %v\n", subName, err)
		}

		if _, err := sub.NextMsg(2 * time.Second); err != nil {
			errCh <- fmt.Errorf("Unable to get next message: %v\n", err)
		}

		nc.Close()
	}

	errCh <- nil
}

func TestTLSStressConnect(t *testing.T) {
	opts, err := server.ProcessConfigFile("./configs/tls.conf")
	if err != nil {
		panic(fmt.Sprintf("Error processing configuration file: %v", err))
	}
	opts.NoSigs, opts.NoLog = true, true

	// For this test, remove the authorization
	opts.Authorization = ""

	// Increase ssl timeout
	opts.TLSTimeout = 2.0

	srv := RunServer(opts)
	defer srv.Shutdown()

	nurl := fmt.Sprintf("tls://%s:%d", opts.Host, opts.Port)

	threadCount := 3

	errCh := make(chan error, threadCount)

	var wg sync.WaitGroup
	wg.Add(threadCount)

	for i := 0; i < threadCount; i++ {
		go stressConnect(t, &wg, errCh, nurl, i)
	}

	wg.Wait()

	var lastError error
	lastError = nil
	for i := 0; i < threadCount; i++ {
		err := <-errCh
		if err != nil {
			lastError = err
		}
	}

	if lastError != nil {
		t.Fatalf("%v\n", lastError)
	}
}

func TestTLSBadAuthError(t *testing.T) {
	srv, opts := RunServerWithConfig("./configs/tls.conf")
	defer srv.Shutdown()

	endpoint := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
	nurl := fmt.Sprintf("tls://%s:%s@%s/", opts.Username, "NOT_THE_PASSWORD", endpoint)

	_, err := nats.Connect(nurl, nats.RootCAs("./configs/certs/ca.pem"))
	if err == nil {
		t.Fatalf("Expected error trying to connect to secure server")
	}
	if err.Error() != nats.ErrAuthorization.Error() {
		t.Fatalf("Excpected and auth violation, got %v\n", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bitbucket.org/gdamore/mangos"
	"bitbucket.org/gdamore/mangos/protocol/rep"
	"bitbucket.org/gdamore/mangos/transport/all"
	"flag"
	"fmt"
	"github.com/ugorji/go/codec"
	"reflect"
	"strconv"
	"time"
)

var (
	mh codec.MsgpackHandle
	b  []byte
)

func boomerangMetrics(d map[string][]string) {
	fmt.Println("------ server msg ------ ")
	nt_dns, _ := delta(d["nt_dns_st"][0], d["nt_dns_end"][0])                               // domainLookupEnd - domainLookupStart
	nt_con, _ := delta(d["nt_con_st"][0], d["nt_con_end"][0])                               // connectEnd - connectStart
	nt_domcontloaded, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcontloaded_end"][0]) // domContentLoadedEnd - domContentLoadedStart
	nt_processed, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcomp"][0])               // domComplete - domContentLoadedStart
	nt_request, _ := delta(d["nt_req_st"][0], d["nt_res_st"][0])                            // ResponseStart - RequestStart
	nt_response, _ := delta(d["nt_res_st"][0], d["nt_res_end"][0])                          // ResponseEnd - ResponseStart
	nt_navtype := d["nt_nav_type"][0]
	roundtrip, _ := delta(d["rt.bstart"][0], d["rt.end"][0])
	page := d["r"][0]
	url := d["u"][0]

	fmt.Println("Navigation type: ", nt_navtype)
	fmt.Println("Navigation timing DNS: ", nt_dns)
	fmt.Println("Navigation timing Connection: ", nt_con)
	fmt.Println("Navigation timing DOM content loaded: ", nt_domcontloaded)
	fmt.Println("Navigation timing DOM processing: ", nt_processed)
	fmt.Println("Navigation timing Request: ", nt_request)
	fmt.Println("Navigation timing Response: ", nt_response)
	fmt.Println("Roundtrip: ", roundtrip)
	fmt.Println("Page: ", page)
	fmt.Println("URL: ", url)
	fmt.Println("------ server msg ------ ")
}

func jsMetrics(d map[string][]string) {
	fmt.Println("------ server msg ------ ")
	nt_dns, _ := delta(d["nt_dns_st"][0], d["nt_dns_end"][0])                               // domainLookupEnd - domainLookupStart
	nt_con, _ := delta(d["nt_con_st"][0], d["nt_con_end"][0])                               // connectEnd - connectStart
	nt_domcontloaded, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcontloaded_end"][0]) // domContentLoadedEnd - domContentLoadedStart
	nt_processed, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcomp"][0])               // domComplete - domContentLoadedStart
	nt_request, _ := delta(d["nt_req_st"][0], d["nt_res_st"][0])                            // ResponseStart - RequestStart
	nt_response, _ := delta(d["nt_res_st"][0], d["nt_res_end"][0])                          // ResponseEnd - ResponseStart
	nt_navtype := d["nt_nav_type"][0]
	roundtrip, _ := delta(d["rt.bstart"][0], d["rt.end"][0])
	page := d["r"][0]
	url := d["u"][0]

	fmt.Println("Navigation type: ", nt_navtype)
	fmt.Println("Navigation timing DNS: ", nt_dns)
	fmt.Println("Navigation timing Connection: ", nt_con)
	fmt.Println("Navigation timing DOM content loaded: ", nt_domcontloaded)
	fmt.Println("Navigation timing DOM processing: ", nt_processed)
	fmt.Println("Navigation timing Request: ", nt_request)
	fmt.Println("Navigation timing Response: ", nt_response)
	fmt.Println("Roundtrip: ", roundtrip)
	fmt.Println("Page: ", page)
	fmt.Println("URL: ", url)
	fmt.Println("------ server msg ------ ")

}

// Calculate delta between start and end
func delta(start string, end string) (int, error) {
	s, err := strconv.Atoi(start)
	if err != nil {
		return -1, err
	}
	e, err := strconv.Atoi(end)
	if err != nil {
		return -1, err
	}
	return e - s, nil
}

func decode(buf []byte) (error, map[string][]string) {

	doc := map[string][]string(nil)
	dec := codec.NewDecoderBytes(buf, &mh)
	err := dec.Decode(&doc)

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

func main() {
	// consumer -type boomerang -listen tcp://127.0.0.1:8000 -statsd 192.168.33.20:8125
	var (
		listenAddr   string
		statsdServer string
		trackerType  string
	)

	flag.StringVar(&listenAddr, "listen", "tcp://127.0.0.1:8000", "Listening string - default: tcp://127.0.0.1:8000")
	flag.StringVar(&statsdServer, "statsd", "127.0.0.1:8125", "statsd endpoint - default: 127.0.0.1:8125")
	flag.StringVar(&trackerType, "tracker", "boomerang", "tracker type - default: boomerang [boomerang, js]")

	responseServerReady := make(chan struct{})
	responseServer, err := rep.NewSocket()
	defer responseServer.Close()

	all.AddTransports(responseServer)
	if err != nil {
		fmt.Println("Error connecting: ", err)
		return
	}
	fmt.Println("Listening:", listenAddr)
	fmt.Println("Statsd endpoint:", statsdServer)
	fmt.Println("Tracker type: ", trackerType)
	fmt.Println("Consumer ready")

	go func() {
		var err error
		var serverMsg *mangos.Message

		if err = responseServer.Listen(listenAddr); err != nil {
			fmt.Printf("\nServer listen failed: %v", err)
			return
		}

		close(responseServerReady)
		mh.MapType = reflect.TypeOf(map[string][]string(nil))

		for {
			if serverMsg, err = responseServer.RecvMsg(); err != nil {
				fmt.Printf("\nServer receive failed: %v", err)
			}
			err, d := decode(serverMsg.Body)
			if len(d) < 1 {
				fmt.Println("Discarded message")
				continue
			}
			switch trackerType {
			case "boomerang":
				boomerangMetrics(d)
			case "js":
				jsMetrics(d)
			}

			serverMsg.Body = []byte("OK")
			if err = responseServer.SendMsg(serverMsg); err != nil {
				fmt.Printf("\nServer send failed: %v", err)
				return
			}
		}
		fmt.Println("Listening")
	}()

	for {
		time.Sleep(10 * time.Second)
	}
}
<commit_msg>begin statsd client<commit_after>package main

import (
	"bitbucket.org/gdamore/mangos"
	"bitbucket.org/gdamore/mangos/protocol/rep"
	"bitbucket.org/gdamore/mangos/transport/all"
	"flag"
	"fmt"
	"github.com/ugorji/go/codec"
	"net"
	"reflect"
	"strconv"
	"time"
)

var (
	mh codec.MsgpackHandle
	b  []byte
)

func boomerangMetrics(udpAddr *net.UDPAddr, d map[string][]string) {
	fmt.Println("------ server msg ------ ")
	nt_dns, _ := delta(d["nt_dns_st"][0], d["nt_dns_end"][0])                               // domainLookupEnd - domainLookupStart
	nt_con, _ := delta(d["nt_con_st"][0], d["nt_con_end"][0])                               // connectEnd - connectStart
	nt_domcontloaded, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcontloaded_end"][0]) // domContentLoadedEnd - domContentLoadedStart
	nt_processed, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcomp"][0])               // domComplete - domContentLoadedStart
	nt_request, _ := delta(d["nt_req_st"][0], d["nt_res_st"][0])                            // ResponseStart - RequestStart
	nt_response, _ := delta(d["nt_res_st"][0], d["nt_res_end"][0])                          // ResponseEnd - ResponseStart
	nt_navtype := d["nt_nav_type"][0]
	roundtrip, _ := delta(d["rt.bstart"][0], d["rt.end"][0])
	page := d["r"][0]
	url := d["u"][0]

	fmt.Println("Navigation type: ", nt_navtype)
	fmt.Println("Navigation timing DNS: ", nt_dns)
	fmt.Println("Navigation timing Connection: ", nt_con)
	fmt.Println("Navigation timing DOM content loaded: ", nt_domcontloaded)
	fmt.Println("Navigation timing DOM processing: ", nt_processed)
	fmt.Println("Navigation timing Request: ", nt_request)
	fmt.Println("Navigation timing Response: ", nt_response)
	fmt.Println("Roundtrip: ", roundtrip)
	fmt.Println("Page: ", page)
	fmt.Println("URL: ", url)
	fmt.Println("------ server msg ------ ")
}

func jsMetrics(udpAddr *net.UDPAddr, d map[string][]string) {
	fmt.Println("------ server msg ------ ")
	nt_dns, _ := delta(d["nt_dns_st"][0], d["nt_dns_end"][0])                               // domainLookupEnd - domainLookupStart
	nt_con, _ := delta(d["nt_con_st"][0], d["nt_con_end"][0])                               // connectEnd - connectStart
	nt_domcontloaded, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcontloaded_end"][0]) // domContentLoadedEnd - domContentLoadedStart
	nt_processed, _ := delta(d["nt_domcontloaded_st"][0], d["nt_domcomp"][0])               // domComplete - domContentLoadedStart
	nt_request, _ := delta(d["nt_req_st"][0], d["nt_res_st"][0])                            // ResponseStart - RequestStart
	nt_response, _ := delta(d["nt_res_st"][0], d["nt_res_end"][0])                          // ResponseEnd - ResponseStart
	nt_navtype := d["nt_nav_type"][0]
	roundtrip, _ := delta(d["rt.bstart"][0], d["rt.end"][0])
	page := d["r"][0]
	url := d["u"][0]

	fmt.Println("Navigation type: ", nt_navtype)
	fmt.Println("Navigation timing DNS: ", nt_dns)
	fmt.Println("Navigation timing Connection: ", nt_con)
	fmt.Println("Navigation timing DOM content loaded: ", nt_domcontloaded)
	fmt.Println("Navigation timing DOM processing: ", nt_processed)
	fmt.Println("Navigation timing Request: ", nt_request)
	fmt.Println("Navigation timing Response: ", nt_response)
	fmt.Println("Roundtrip: ", roundtrip)
	fmt.Println("Page: ", page)
	fmt.Println("URL: ", url)
	fmt.Println("------ server msg ------ ")

}

// Calculate delta between start and end
func delta(start string, end string) (int, error) {
	s, err := strconv.Atoi(start)
	if err != nil {
		return -1, err
	}
	e, err := strconv.Atoi(end)
	if err != nil {
		return -1, err
	}
	return e - s, nil
}

func decode(buf []byte) (error, map[string][]string) {

	doc := map[string][]string(nil)
	dec := codec.NewDecoderBytes(buf, &mh)
	err := dec.Decode(&doc)

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

func main() {
	// consumer -type boomerang -listen tcp://127.0.0.1:8000 -statsd 192.168.33.20:8125
	var (
		listenAddr   string
		statsdServer string
		trackerType  string
	)

	flag.StringVar(&listenAddr, "listen", "tcp://127.0.0.1:8000", "Listening string - default: tcp://127.0.0.1:8000")
	flag.StringVar(&statsdServer, "statsd", "127.0.0.1:8125", "statsd endpoint - default: 127.0.0.1:8125")
	flag.StringVar(&trackerType, "tracker", "boomerang", "tracker type - default: boomerang [boomerang, js]")

	responseServerReady := make(chan struct{})
	responseServer, err := rep.NewSocket()
	defer responseServer.Close()

	all.AddTransports(responseServer)
	if err != nil {
		fmt.Println("Error connecting: ", err)
		return
	}
	fmt.Println("Listening:", listenAddr)
	fmt.Println("Statsd endpoint:", statsdServer)
	fmt.Println("Tracker type: ", trackerType)
	fmt.Println("Consumer ready")
	udpAddr, err := net.ResolveUDPAddr("udp4", statsdServer)

	if err != nil {
		fmt.Println("Error resolving statsd server", err)
		return
	}

	go func() {
		var err error
		var serverMsg *mangos.Message

		if err = responseServer.Listen(listenAddr); err != nil {
			fmt.Printf("\nServer listen failed: %v", err)
			return
		}

		close(responseServerReady)
		mh.MapType = reflect.TypeOf(map[string][]string(nil))

		for {
			if serverMsg, err = responseServer.RecvMsg(); err != nil {
				fmt.Printf("\nServer receive failed: %v", err)
			}
			err, d := decode(serverMsg.Body)
			if len(d) < 1 {
				fmt.Println("Discarded message")
				continue
			}
			switch trackerType {
			case "boomerang":
				boomerangMetrics(udpAddr, d)
			case "js":
				jsMetrics(udpAddr, d)
			}

			serverMsg.Body = []byte("OK")
			if err = responseServer.SendMsg(serverMsg); err != nil {
				fmt.Printf("\nServer send failed: %v", err)
				return
			}
		}
		fmt.Println("Listening")
	}()

	for {
		time.Sleep(10 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"strings"

	"github.com/FreeFeed/clio-restore/internal/account"
	"github.com/FreeFeed/clio-restore/internal/clio"
	"github.com/FreeFeed/clio-restore/internal/dbutil"
	"github.com/FreeFeed/clio-restore/internal/hashtags"
	"github.com/davidmz/mustbe"
	"github.com/lib/pq"
	"github.com/satori/go.uuid"
)

func (a *App) restoreEntry(entry *clio.Entry) {
	// check if entry already imported
	alreadyExists := false
	mustbe.OK(a.DB.QueryRow(
		`select exists(select 1 from archive_post_names where old_post_name = $1)`,
		entry.Name,
	).Scan(&alreadyExists))

	if alreadyExists {
		errorLog.Println("entry already imported")
		return
	}

	a.Tx = mustbe.OKVal(a.DB.Begin()).(*sql.Tx)
	defer func() {
		if p := recover(); p != nil {
			a.Tx.Rollback()
			a.Tx = nil
			panic(p)
		}
		a.Tx.Commit()
		a.Tx = nil
	}()

	// thumbnails & files
	var attachUIDs []string
	attachUIDs = append(attachUIDs, a.restoreThumbnails(entry)...)
	attachUIDs = append(attachUIDs, a.restoreFiles(entry)...)

	// create post
	createdAt := entry.Date
	updatedAt := createdAt
	for _, c := range entry.Comments {
		if c.Date.After(updatedAt) {
			updatedAt = c.Date
		}
	}

	postUID := uuid.NewV4().String()
	dbutil.MustInsert(a.Tx, "posts", dbutil.H{
		"uid":                  postUID,
		"body":                 entry.Body,
		"user_id":              entry.Author.UID,
		"created_at":           createdAt,
		"updated_at":           updatedAt,
		"bumped_at":            updatedAt,
		"comments_disabled":    entry.Author.DisableComments,
		"destination_feed_ids": pq.Array([]int{entry.Author.Feeds.Posts.ID}),
	})

	infoLog.Println("created post with UID", postUID)

	// register old post name
	dbutil.MustInsert(a.Tx, "archive_post_names", dbutil.H{
		"post_id":       postUID,
		"old_post_name": entry.Name,
		"old_url":       entry.URL,
	})

	// register via
	if viaID := a.getViaID(entry.Via); viaID != 0 {
		dbutil.MustInsert(a.Tx, "archive_posts_via", dbutil.H{"via_id": viaID, "post_id": postUID})
	}

	// post hashtags
	for _, h := range entry.Hashtags {
		dbutil.MustInsertWithoutConflict(a.Tx, "hashtag_usages", dbutil.H{
			"hashtag_id": hashtags.GetID(a.Tx, h),
			"entity_id":  postUID,
			"type":       "post",
		})
	}

	// atach attachments
	if len(attachUIDs) > 0 {
		mustbe.OKVal(a.Tx.Exec(
			`update attachments set
				post_id = $1,
				user_id = $2,
				created_at = $3,
				updated_at = $4
			where uid in (`+strings.Join(dbutil.QuoteStrings(attachUIDs), ",")+`)`,
			postUID,
			entry.Author.UID,
			entry.Date,
			entry.Date,
		))
	}

	a.incrementUserStat(entry.Author, statPosts)

	// post feed_ids - all UIDs of post's feeds
	feedIds := make(map[string]bool)
	feedIds[entry.Author.Feeds.Posts.UID] = true

	// add comments
	infoLog.Println("adding comments")
	for _, c := range entry.Comments {
		if a.commentPost(postUID, entry.Author, c) {
			feedIds[c.Author.Feeds.Comments.UID] = true
			a.incrementUserStat(c.Author, statComments)
		}
	}

	// add likes
	infoLog.Println("adding likes")
	for _, l := range entry.Likes {
		if a.likePost(postUID, l) {
			feedIds[l.Author.Feeds.Likes.UID] = true
			a.incrementUserStat(l.Author, statLikes)
		}
	}

	infoLog.Println("updating feed_ids")
	{ // update post's feed_ids
		var ids []string
		for id := range feedIds {
			ids = append(ids, dbutil.QuoteString(id))
		}
		mustbe.OKVal(a.Tx.Exec(
			`update posts set feed_ids = (
				select array_agg(distinct f.id) from
					feeds f
					join subscriptions s on
						f.user_id = s.user_id and f.name = 'RiverOfNews'
						or f.uid = s.feed_id
				where s.feed_id in (`+strings.Join(ids, ",")+`)
			) where uid = $1`,
			postUID,
		))
	}
}

func (a *App) likePost(postUID string, like *clio.Like) (restoredVisible bool) {
	restoredVisible = like.Author.RestoreCommentsAndLikes
	if restoredVisible {
		// like is visible
		dbutil.MustInsert(a.Tx, "likes", dbutil.H{
			"post_id":    postUID,
			"user_id":    like.Author.UID,
			"created_at": like.Date,
		})
	} else {
		// like is hidden
		if like.Author.UID != "" {
			dbutil.MustInsert(a.Tx, "hidden_likes", dbutil.H{
				"post_id": postUID,
				"user_id": like.Author.UID,
				"date":    like.Date,
			})
		} else {
			dbutil.MustInsert(a.Tx, "hidden_likes", dbutil.H{
				"post_id":      postUID,
				"old_username": like.Author.OldUserName,
				"date":         like.Date,
			})
		}
	}
	return
}

func (a *App) commentPost(postUID string, postAuthor *account.Account, comment *clio.Comment) (restoredVisible bool) {
	commentID := uuid.NewV4().String()
	restoredVisible = comment.Author.RestoreCommentsAndLikes ||
		comment.Author.OldUserName == postAuthor.OldUserName
	if restoredVisible {
		// comment is visible
		dbutil.MustInsert(a.Tx, "comments", dbutil.H{
			"uid":        commentID,
			"post_id":    postUID,
			"body":       comment.Body,
			"user_id":    comment.Author.UID,
			"created_at": comment.Date,
			"updated_at": comment.Date,
			"hide_type":  commentTypeVisible,
		})

		// comment hashtags
		for _, h := range comment.Hashtags {
			dbutil.MustInsertWithoutConflict(a.Tx, "hashtag_usages", dbutil.H{
				"hashtag_id": hashtags.GetID(a.Tx, h),
				"entity_id":  commentID,
				"type":       "comment",
			})
		}

	} else {
		// comment is hidden
		dbutil.MustInsert(a.Tx, "comments", dbutil.H{
			"uid":        commentID,
			"post_id":    postUID,
			"body":       hiddenCommentBody,
			"user_id":    nil,
			"created_at": comment.Date,
			"updated_at": comment.Date,
			"hide_type":  commentTypeHidden,
		})

		if comment.Author.UID != "" {
			dbutil.MustInsert(a.Tx, "hidden_comments", dbutil.H{
				"comment_id": commentID,
				"body":       comment.Body,
				"user_id":    comment.Author.UID,
			})
		} else {
			dbutil.MustInsert(a.Tx, "hidden_comments", dbutil.H{
				"comment_id":   commentID,
				"body":         comment.Body,
				"old_username": comment.Author.OldUserName,
			})
		}
	}
	return
}

func (a *App) incrementUserStat(acc *account.Account, t statType) {
	colName := pq.QuoteIdentifier(string(t) + "_count")
	mustbe.OKVal(a.Tx.Exec(
		`update user_stats set `+colName+` = `+colName+` + 1 where user_id = $1`,
		acc.UID,
	))
}
<commit_msg>Correct feed_ids algorithm<commit_after>package main

import (
	"database/sql"
	"strings"

	"github.com/FreeFeed/clio-restore/internal/account"
	"github.com/FreeFeed/clio-restore/internal/clio"
	"github.com/FreeFeed/clio-restore/internal/dbutil"
	"github.com/FreeFeed/clio-restore/internal/hashtags"
	"github.com/davidmz/mustbe"
	"github.com/lib/pq"
	"github.com/satori/go.uuid"
)

func (a *App) restoreEntry(entry *clio.Entry) {
	// check if entry already imported
	alreadyExists := false
	mustbe.OK(a.DB.QueryRow(
		`select exists(select 1 from archive_post_names where old_post_name = $1)`,
		entry.Name,
	).Scan(&alreadyExists))

	if alreadyExists {
		errorLog.Println("entry already imported")
		return
	}

	a.Tx = mustbe.OKVal(a.DB.Begin()).(*sql.Tx)
	defer func() {
		if p := recover(); p != nil {
			a.Tx.Rollback()
			a.Tx = nil
			panic(p)
		}
		a.Tx.Commit()
		a.Tx = nil
	}()

	// thumbnails & files
	var attachUIDs []string
	attachUIDs = append(attachUIDs, a.restoreThumbnails(entry)...)
	attachUIDs = append(attachUIDs, a.restoreFiles(entry)...)

	// create post
	createdAt := entry.Date
	updatedAt := createdAt
	for _, c := range entry.Comments {
		if c.Date.After(updatedAt) {
			updatedAt = c.Date
		}
	}

	postUID := uuid.NewV4().String()
	dbutil.MustInsert(a.Tx, "posts", dbutil.H{
		"uid":                  postUID,
		"body":                 entry.Body,
		"user_id":              entry.Author.UID,
		"created_at":           createdAt,
		"updated_at":           updatedAt,
		"bumped_at":            updatedAt,
		"comments_disabled":    entry.Author.DisableComments,
		"destination_feed_ids": pq.Array([]int{entry.Author.Feeds.Posts.ID}),
	})

	infoLog.Println("created post with UID", postUID)

	// register old post name
	dbutil.MustInsert(a.Tx, "archive_post_names", dbutil.H{
		"post_id":       postUID,
		"old_post_name": entry.Name,
		"old_url":       entry.URL,
	})

	// register via
	if viaID := a.getViaID(entry.Via); viaID != 0 {
		dbutil.MustInsert(a.Tx, "archive_posts_via", dbutil.H{"via_id": viaID, "post_id": postUID})
	}

	// post hashtags
	for _, h := range entry.Hashtags {
		dbutil.MustInsertWithoutConflict(a.Tx, "hashtag_usages", dbutil.H{
			"hashtag_id": hashtags.GetID(a.Tx, h),
			"entity_id":  postUID,
			"type":       "post",
		})
	}

	// atach attachments
	if len(attachUIDs) > 0 {
		mustbe.OKVal(a.Tx.Exec(
			`update attachments set
				post_id = $1,
				user_id = $2,
				created_at = $3,
				updated_at = $4
			where uid in (`+strings.Join(dbutil.QuoteStrings(attachUIDs), ",")+`)`,
			postUID,
			entry.Author.UID,
			entry.Date,
			entry.Date,
		))
	}

	a.incrementUserStat(entry.Author, statPosts)

	// post feed_ids - all UIDs/IDs of post's feeds
	feedIDs := make(map[string]int)
	feedIDs[entry.Author.Feeds.Posts.UID] = entry.Author.Feeds.Posts.ID

	// add comments
	infoLog.Println("adding comments")
	for _, c := range entry.Comments {
		if a.commentPost(postUID, entry.Author, c) {
			feedIDs[c.Author.Feeds.Comments.UID] = c.Author.Feeds.Comments.ID
			a.incrementUserStat(c.Author, statComments)
		}
	}

	// add likes
	infoLog.Println("adding likes")
	for _, l := range entry.Likes {
		if a.likePost(postUID, l) {
			feedIDs[l.Author.Feeds.Likes.UID] = l.Author.Feeds.Likes.ID
			a.incrementUserStat(l.Author, statLikes)
		}
	}

	infoLog.Println("updating feed_ids")
	{ // update post's feed_ids
		var (
			intIDs pq.Int64Array
			UIDs   []string
		)
		for uid := range feedIDs {
			UIDs = append(UIDs, dbutil.QuoteString(uid))
		}
		// 1) All 'RiverOfNews' feeds of users subscribed to activity feeds
		mustbe.OK(a.Tx.QueryRow(
			`select array_agg(distinct f.id) from
				subscriptions s
				join feeds f on f.user_id = s.user_id and f.name = 'RiverOfNews'
				where s.feed_id in (` + strings.Join(UIDs, ",") + `)`,
		).Scan(&intIDs))
		// 2) Activity feeds itself
		for _, intID := range feedIDs {
			intIDs = append(intIDs, int64(intID))
		}

		mustbe.OKVal(a.Tx.Exec(`update posts set feed_ids = $1 where uid = $2`, intIDs, postUID))
	}
}

func (a *App) likePost(postUID string, like *clio.Like) (restoredVisible bool) {
	restoredVisible = like.Author.RestoreCommentsAndLikes
	if restoredVisible {
		// like is visible
		dbutil.MustInsert(a.Tx, "likes", dbutil.H{
			"post_id":    postUID,
			"user_id":    like.Author.UID,
			"created_at": like.Date,
		})
	} else {
		// like is hidden
		if like.Author.UID != "" {
			dbutil.MustInsert(a.Tx, "hidden_likes", dbutil.H{
				"post_id": postUID,
				"user_id": like.Author.UID,
				"date":    like.Date,
			})
		} else {
			dbutil.MustInsert(a.Tx, "hidden_likes", dbutil.H{
				"post_id":      postUID,
				"old_username": like.Author.OldUserName,
				"date":         like.Date,
			})
		}
	}
	return
}

func (a *App) commentPost(postUID string, postAuthor *account.Account, comment *clio.Comment) (restoredVisible bool) {
	commentID := uuid.NewV4().String()
	restoredVisible = comment.Author.RestoreCommentsAndLikes ||
		comment.Author.OldUserName == postAuthor.OldUserName
	if restoredVisible {
		// comment is visible
		dbutil.MustInsert(a.Tx, "comments", dbutil.H{
			"uid":        commentID,
			"post_id":    postUID,
			"body":       comment.Body,
			"user_id":    comment.Author.UID,
			"created_at": comment.Date,
			"updated_at": comment.Date,
			"hide_type":  commentTypeVisible,
		})

		// comment hashtags
		for _, h := range comment.Hashtags {
			dbutil.MustInsertWithoutConflict(a.Tx, "hashtag_usages", dbutil.H{
				"hashtag_id": hashtags.GetID(a.Tx, h),
				"entity_id":  commentID,
				"type":       "comment",
			})
		}

	} else {
		// comment is hidden
		dbutil.MustInsert(a.Tx, "comments", dbutil.H{
			"uid":        commentID,
			"post_id":    postUID,
			"body":       hiddenCommentBody,
			"user_id":    nil,
			"created_at": comment.Date,
			"updated_at": comment.Date,
			"hide_type":  commentTypeHidden,
		})

		if comment.Author.UID != "" {
			dbutil.MustInsert(a.Tx, "hidden_comments", dbutil.H{
				"comment_id": commentID,
				"body":       comment.Body,
				"user_id":    comment.Author.UID,
			})
		} else {
			dbutil.MustInsert(a.Tx, "hidden_comments", dbutil.H{
				"comment_id":   commentID,
				"body":         comment.Body,
				"old_username": comment.Author.OldUserName,
			})
		}
	}
	return
}

func (a *App) incrementUserStat(acc *account.Account, t statType) {
	colName := pq.QuoteIdentifier(string(t) + "_count")
	mustbe.OKVal(a.Tx.Exec(
		`update user_stats set `+colName+` = `+colName+` + 1 where user_id = $1`,
		acc.UID,
	))
}
<|endoftext|>


<commit_before>// Package handlers provides HTTP request handlers.
package handlers

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

	"github.com/julienschmidt/httprouter"
	"github.com/thomaso-mirodin/go-shorten/storage"
)

func getShortFromRequest(r *http.Request) (short string, err error) {
	short = r.URL.Path[1:]

	if short == "" {
		switch r.Header.Get("Content-Type") {
		case "application/json":
			err = fmt.Errorf("Content-Type of application/json not yet supported")
		default:
			short = r.PostFormValue("code")
		}
	}

	return
}

func getURLFromRequest(r *http.Request) (url string, err error) {
	switch r.Header.Get("Content-Type") {
	case "application/json":
		err = fmt.Errorf("Content-Type of application/json not yet supported")
		return
	default:
		url = r.PostFormValue("url")
	}

	if url == "" {
		err = fmt.Errorf("No URL Provided")
	}

	return
}

func GetShortHandler(store storage.Storage) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		short, err := getShortFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		url, err := store.Load(short)
		if err != nil {
			http.Redirect(w, r, "/#"+short, http.StatusFound)
			return
		}

		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": short, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, url)
		default:
			http.Redirect(w, r, url, http.StatusFound)
		}
	}
}

func SetShortHandler(store storage.Storage) httprouter.Handle {
	named, namedOk := store.(storage.NamedStorage)
	unnamed, unnamedOk := store.(storage.UnnamedStorage)

	return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		short, err := getShortFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		url, err := getURLFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		if short == "" {
			if !unnamedOk {
				http.Error(w, "Current storage layer does not support storing an unnamed url", http.StatusBadRequest)
				return
			}

			short, err = unnamed.Save(url)
		} else {
			if !namedOk {
				http.Error(w, "Current storage layer does not support storing a named url", http.StatusBadRequest)
				return
			}

			err = named.SaveName(short, url)
		}
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to save '%s' to '%s' because: %s", url, short, err), http.StatusInternalServerError)
			return
		}

		// Return the short code formatted based on Accept headers
		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": short, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/html":
			w.Header().Set("Content-Type", "text/html; charset=utf-8")
			fmt.Fprintln(w, "<html>hello world</html")
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, short)
		default:
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, short)
		}
	}

}
<commit_msg>Add TODO<commit_after>// Package handlers provides HTTP request handlers.
package handlers

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

	"github.com/julienschmidt/httprouter"
	"github.com/thomaso-mirodin/go-shorten/storage"
)

func getShortFromRequest(r *http.Request) (short string, err error) {
	short = r.URL.Path[1:]

	if short == "" {
		switch r.Header.Get("Content-Type") {
		case "application/json":
			err = fmt.Errorf("Content-Type of application/json not yet supported")
		default:
			short = r.PostFormValue("code")
		}
	}

	return
}

func getURLFromRequest(r *http.Request) (url string, err error) {
	switch r.Header.Get("Content-Type") {
	case "application/json":
		err = fmt.Errorf("Content-Type of application/json not yet supported")
		return
	default:
		url = r.PostFormValue("url")
	}

	if url == "" {
		err = fmt.Errorf("No URL Provided")
	}

	return
}

func GetShortHandler(store storage.Storage) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		short, err := getShortFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		url, err := store.Load(short)
		if err != nil {
			// TODO(thomaso-mirodin) 2016-03-07: Replace with a templated index.html and go back to a 404 status code
			http.Redirect(w, r, "/#"+short, http.StatusFound)
			return
		}

		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": short, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, url)
		default:
			http.Redirect(w, r, url, http.StatusFound)
		}
	}
}

func SetShortHandler(store storage.Storage) httprouter.Handle {
	named, namedOk := store.(storage.NamedStorage)
	unnamed, unnamedOk := store.(storage.UnnamedStorage)

	return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		short, err := getShortFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		url, err := getURLFromRequest(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		if short == "" {
			if !unnamedOk {
				http.Error(w, "Current storage layer does not support storing an unnamed url", http.StatusBadRequest)
				return
			}

			short, err = unnamed.Save(url)
		} else {
			if !namedOk {
				http.Error(w, "Current storage layer does not support storing a named url", http.StatusBadRequest)
				return
			}

			err = named.SaveName(short, url)
		}
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to save '%s' to '%s' because: %s", url, short, err), http.StatusInternalServerError)
			return
		}

		// Return the short code formatted based on Accept headers
		switch r.Header.Get("Accept") {
		case "application/json":
			w.Header().Set("Content-Type", "application/json; charset=utf-8")

			err := json.NewEncoder(w).Encode(map[string]string{"short": short, "url": url})
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "text/html":
			w.Header().Set("Content-Type", "text/html; charset=utf-8")
			fmt.Fprintln(w, "<html>hello world</html")
		case "text/plain":
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, short)
		default:
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			fmt.Fprintln(w, short)
		}
	}

}
<|endoftext|>


<commit_before>package discoverers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/abesto/easyssh/from_sexp"
	"github.com/abesto/easyssh/interfaces"
	"github.com/abesto/easyssh/util"
	"os/exec"
	"strings"
)

func Make(input string) interfaces.Discoverer {
	return from_sexp.MakeFromString(input, nil, makeByName).(interfaces.Discoverer)
}

func SupportedDiscovererNames() []string {
	var keys = make([]string, len(discovererMakerMap))
	var i = 0
	for key := range discovererMakerMap {
		keys[i] = key
		i += 1
	}
	return keys
}

func makeFromSExp(data []interface{}) interfaces.Discoverer {
	return from_sexp.Make(data, nil, makeByName).(interfaces.Discoverer)
}

const (
	nameCommaSeparated = "comma-separated"
	nameKnife          = "knife"
	nameFirstMatching  = "first-matching"
)

var discovererMakerMap = map[string]func() interfaces.Discoverer{
	nameCommaSeparated: func() interfaces.Discoverer { return &commaSeparated{} },
	nameKnife:          func() interfaces.Discoverer { return &knifeSearch{} },
	nameFirstMatching:  func() interfaces.Discoverer { return &firstMatching{} },
}

func makeByName(name string) interface{} {
	var d interfaces.Discoverer
	for key, maker := range discovererMakerMap {
		if key == name {
			d = maker()
		}
	}
	if d == nil {
		util.Abort("Discoverer \"%s\" is not known", name)
	}
	return d
}

type commaSeparated struct{}

func (d *commaSeparated) Discover(input string) []string {
	return strings.Split(input, ",")
}
func (d *commaSeparated) SetArgs(args []interface{}) {
	if len(args) > 0 {
		util.Abort("%s takes no configuration, got %s", d, args)
	}
}
func (d *commaSeparated) String() string {
	return fmt.Sprintf("<%s>", nameCommaSeparated)
}

type knifeSearch struct{}

func (d *knifeSearch) Discover(input string) []string {
	if !strings.Contains(input, ":") {
		util.Logger.Debugf("Host lookup string doesn't contain ':', it won't match anything in a knife search node query")
		return []string{}
	}

	util.Logger.Infof("Looking up nodes with knife matching %s", input)

	var cmd = exec.Command("knife", "search", "node", "-F", "json", input)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	var error = cmd.Run()
	if error != nil {
		fmt.Print(stderr.String())
		util.Abort(error.Error())
	}

	var data map[string]interface{}
	json.Unmarshal(stdout.Bytes(), &data)

	var ips = []string{}
	for _, row := range data["rows"].([]interface{}) {
		var automatic = row.(map[string]interface{})["automatic"].(map[string]interface{})
		if cloud_v2, ok := automatic["cloud_v2"]; ok && cloud_v2 != nil {
			ips = append(ips, cloud_v2.(map[string]interface{})["public_ipv4"].(string))
		} else {
			ips = append(ips, automatic["ipaddress"].(string))
		}
	}

	return ips
}
func (d *knifeSearch) SetArgs(args []interface{}) {
	if len(args) > 0 {
		util.Abort("%s takes no configuration, got %s", d, args)
	}
}
func (d *knifeSearch) String() string {
	return fmt.Sprintf("<%s>", nameKnife)
}

type firstMatching struct {
	discoverers []interfaces.Discoverer
}

func (d *firstMatching) Discover(input string) []string {
	var hosts []string
	for _, discoverer := range d.discoverers {
		util.Logger.Debugf("Trying discoverer %s", discoverer)
		hosts = discoverer.Discover(input)
		if len(hosts) > 0 {
			return hosts
		}
	}
	return []string{}
}
func (d *firstMatching) SetArgs(args []interface{}) {
	d.discoverers = []interfaces.Discoverer{}
	for _, exp := range args {
		d.discoverers = append(d.discoverers, makeFromSExp(exp.([]interface{})))
	}
}
func (d *firstMatching) String() string {
	var strs = []string{}
	for _, child := range d.discoverers {
		strs = append(strs, child.String())
	}
	return fmt.Sprintf("<%s %s>", nameFirstMatching, strings.Join(strs, " "))
}
<commit_msg>knife-hostname returns knife results by hostname<commit_after>package discoverers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/abesto/easyssh/from_sexp"
	"github.com/abesto/easyssh/interfaces"
	"github.com/abesto/easyssh/util"
	"os/exec"
	"strings"
)

func Make(input string) interfaces.Discoverer {
	return from_sexp.MakeFromString(input, nil, makeByName).(interfaces.Discoverer)
}

func SupportedDiscovererNames() []string {
	var keys = make([]string, len(discovererMakerMap))
	var i = 0
	for key := range discovererMakerMap {
		keys[i] = key
		i += 1
	}
	return keys
}

func makeFromSExp(data []interface{}) interfaces.Discoverer {
	return from_sexp.Make(data, nil, makeByName).(interfaces.Discoverer)
}

const (
	nameCommaSeparated = "comma-separated"
	nameKnife          = "knife"
	nameKnifeHostname  = "knife-hostname"
	nameFirstMatching  = "first-matching"
)

var discovererMakerMap = map[string]func() interfaces.Discoverer{
	nameCommaSeparated: func() interfaces.Discoverer { return &commaSeparated{} },
	nameKnife:          func() interfaces.Discoverer { return &knifeSearch{PublicIp} },
	nameKnifeHostname:  func() interfaces.Discoverer { return &knifeSearch{PublicHostname} },
	nameFirstMatching:  func() interfaces.Discoverer { return &firstMatching{} },
}

func makeByName(name string) interface{} {
	var d interfaces.Discoverer
	for key, maker := range discovererMakerMap {
		if key == name {
			d = maker()
		}
	}
	if d == nil {
		util.Abort("Discoverer \"%s\" is not known", name)
	}
	return d
}

type commaSeparated struct{}

func (d *commaSeparated) Discover(input string) []string {
	return strings.Split(input, ",")
}
func (d *commaSeparated) SetArgs(args []interface{}) {
	if len(args) > 0 {
		util.Abort("%s takes no configuration, got %s", d, args)
	}
}
func (d *commaSeparated) String() string {
	return fmt.Sprintf("<%s>", nameCommaSeparated)
}

type knifeSearchResultType int
const (
	PublicIp knifeSearchResultType = iota
	PublicHostname
)
type knifeSearch struct{
	resultType knifeSearchResultType
}

func (d *knifeSearch) Discover(input string) []string {
	if !strings.Contains(input, ":") {
		util.Logger.Debugf("Host lookup string doesn't contain ':', it won't match anything in a knife search node query")
		return []string{}
	}

	util.Logger.Infof("Looking up nodes with knife matching %s", input)

	var cmd = exec.Command("knife", "search", "node", "-F", "json", input)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	var error = cmd.Run()
	if error != nil {
		fmt.Print(stderr.String())
		util.Abort(error.Error())
	}

	var data map[string]interface{}
	json.Unmarshal(stdout.Bytes(), &data)

	var ips = []string{}
	fieldName := "public_ipv4"
	if d.resultType == PublicHostname {
		fieldName = "public_hostname"
	}
	for _, row := range data["rows"].([]interface{}) {
		var automatic = row.(map[string]interface{})["automatic"].(map[string]interface{})
		if cloud_v2, ok := automatic["cloud_v2"]; ok && cloud_v2 != nil {
			ips = append(ips, cloud_v2.(map[string]interface{})[fieldName].(string))
		} else {
			ips = append(ips, automatic["ipaddress"].(string))
		}
	}

	return ips
}
func (d *knifeSearch) SetArgs(args []interface{}) {
	if len(args) > 0 {
		util.Abort("%s takes no configuration, got %s", d, args)
	}
}
func (d *knifeSearch) String() string {
	return fmt.Sprintf("<%s>", nameKnife)
}

type firstMatching struct {
	discoverers []interfaces.Discoverer
}

func (d *firstMatching) Discover(input string) []string {
	var hosts []string
	for _, discoverer := range d.discoverers {
		util.Logger.Debugf("Trying discoverer %s", discoverer)
		hosts = discoverer.Discover(input)
		if len(hosts) > 0 {
			return hosts
		}
	}
	return []string{}
}
func (d *firstMatching) SetArgs(args []interface{}) {
	d.discoverers = []interfaces.Discoverer{}
	for _, exp := range args {
		d.discoverers = append(d.discoverers, makeFromSExp(exp.([]interface{})))
	}
}
func (d *firstMatching) String() string {
	var strs = []string{}
	for _, child := range d.discoverers {
		strs = append(strs, child.String())
	}
	return fmt.Sprintf("<%s %s>", nameFirstMatching, strings.Join(strs, " "))
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"os"
	"runtime"
	"strconv"
)

// ConfigurationInfo contains the config file's content
type ConfigurationInfo struct {
	MachineName string            `json:"machineName"`
	Arch        string            `json:"arch"`
	Tags        map[string]string `json:"tags"`
	BindIP      string            `json:"bindIP"`
	BindPort    int               `json:"bindPort"`
	EtcdAddress string            `json:"etcdAddress"`
	PublicIP    string            `json:"publicIP"`
	Zone        string            `json:"zone"`
}

func newConfigurationInfo() ConfigurationInfo {
	config := ConfigurationInfo{}
	config.MachineName, _ = os.Hostname()
	config.BindIP = "127.0.0.1"
	config.BindPort = 7384 // "IT" in ASCII to decimal
	config.EtcdAddress = "http://127.0.0.1:2379"
	config.Zone = "dc"
	config.Arch = runtime.GOARCH
	return config
}

// GetConfiguration reads the confiruration from config.json and returns it
func GetConfiguration() ConfigurationInfo {
	returnConfig := newConfigurationInfo()
	data, err := os.Open("config.json")
	if err == nil { // Only read when available
		jsonParser := json.NewDecoder(data)
		jsonParser.Decode(&returnConfig)
	}
	readEnv(&returnConfig)
	return returnConfig
}

func readEnv(conf *ConfigurationInfo) {
	if name := os.Getenv("DISPATCH_MACHINENAME"); name != "" {
		conf.MachineName = name
	}
	if bindip := os.Getenv("DISPATCH_BINDIP"); bindip != "" {
		conf.BindIP = bindip
	}
	if bindport := os.Getenv("DISPATCH_BINDPORT"); bindport != "" {
		if port, err := strconv.Atoi(bindport); err == nil {
			conf.BindPort = port
		}
	}
	if etcdaddress := os.Getenv("DISPATCH_ETCDADDRESS"); etcdaddress != "" {
		conf.EtcdAddress = etcdaddress
	}
	if publicip := os.Getenv("DISPATCH_PUBLICIP"); publicip != "" {
		conf.PublicIP = publicip
	}
	if zone := os.Getenv("DISPATCH_ZONE"); zone != "" {
		conf.Zone = zone
	}
}
<commit_msg>fix typo<commit_after>package config

import (
	"encoding/json"
	"os"
	"runtime"
	"strconv"
)

// ConfigurationInfo contains the config file's content
type ConfigurationInfo struct {
	MachineName string            `json:"machineName"`
	Arch        string            `json:"arch"`
	Tags        map[string]string `json:"tags"`
	BindIP      string            `json:"bindIP"`
	BindPort    int               `json:"bindPort"`
	EtcdAddress string            `json:"etcdAddress"`
	PublicIP    string            `json:"publicIP"`
	Zone        string            `json:"zone"`
}

func newConfigurationInfo() ConfigurationInfo {
	config := ConfigurationInfo{}
	config.MachineName, _ = os.Hostname()
	config.BindIP = "127.0.0.1"
	config.BindPort = 7384 // "IT" in ASCII to decimal
	config.EtcdAddress = "http://127.0.0.1:2379"
	config.Zone = "dc"
	config.Arch = runtime.GOARCH
	return config
}

// GetConfiguration reads the configuration from config.json and returns it
func GetConfiguration() ConfigurationInfo {
	returnConfig := newConfigurationInfo()
	data, err := os.Open("config.json")
	if err == nil { // Only read when available
		jsonParser := json.NewDecoder(data)
		jsonParser.Decode(&returnConfig)
	}
	readEnv(&returnConfig)
	return returnConfig
}

func readEnv(conf *ConfigurationInfo) {
	if name := os.Getenv("DISPATCH_MACHINENAME"); name != "" {
		conf.MachineName = name
	}
	if bindip := os.Getenv("DISPATCH_BINDIP"); bindip != "" {
		conf.BindIP = bindip
	}
	if bindport := os.Getenv("DISPATCH_BINDPORT"); bindport != "" {
		if port, err := strconv.Atoi(bindport); err == nil {
			conf.BindPort = port
		}
	}
	if etcdaddress := os.Getenv("DISPATCH_ETCDADDRESS"); etcdaddress != "" {
		conf.EtcdAddress = etcdaddress
	}
	if publicip := os.Getenv("DISPATCH_PUBLICIP"); publicip != "" {
		conf.PublicIP = publicip
	}
	if zone := os.Getenv("DISPATCH_ZONE"); zone != "" {
		conf.Zone = zone
	}
}
<|endoftext|>


<commit_before>package checker

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/catatsuy/private-isu/benchmarker/cache"
	"github.com/catatsuy/private-isu/benchmarker/util"
)

type Actionable interface {
	Play(s *Session) error
}

type Action struct {
	Method string
	Path   string

	PostData           map[string]string
	Headers            map[string]string
	ExpectedStatusCode int
	ExpectedLocation   string
	ExpectedHeaders    map[string]string
	ExpectedHTML       map[string]string

	Description string

	CheckFunc func(w *Session, body io.Reader) error
}

type Asset struct {
	Path string
	MD5  string
}

func init() {
	var _ Actionable = &Action{}
	var _ Actionable = &AssetAction{}
	var _ Actionable = &UploadAction{}
}

func NewAction(method, path string) *Action {
	return &Action{
		Method:             method,
		Path:               path,
		ExpectedStatusCode: http.StatusOK,
	}
}

func (a *Action) Play(s *Session) error {
	formData := url.Values{}
	for key, val := range a.PostData {
		formData.Set(key, val)
	}

	buf := bytes.NewBufferString(formData.Encode())
	req, err := s.NewRequest(a.Method, a.Path, buf)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	if req.Method == "POST" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	defer res.Body.Close()

	if res.StatusCode != a.ExpectedStatusCode {
		s.Fail(res.Request, fmt.Errorf("Response code should be %d, got %d", a.ExpectedStatusCode, res.StatusCode))
	}

	if a.ExpectedLocation != "" {
		if a.ExpectedLocation != res.Request.URL.Path {
			return s.Fail(
				res.Request,
				fmt.Errorf(
					"Expected location is miss match %s, got: %s",
					a.ExpectedLocation, res.Request.URL.Path,
				))
		}
	}

	if a.CheckFunc != nil {
		err := a.CheckFunc(s, res.Body)
		if err != nil {
			return s.Fail(
				res.Request,
				err,
			)
		}
	}

	s.Success(1)

	return nil
}

type AssetAction struct {
	*Action
	Asset *Asset
}

func NewAssetAction(path string, asset *Asset) *AssetAction {
	return &AssetAction{
		Asset: asset,
		Action: &Action{
			Method:             "GET",
			Path:               path,
			ExpectedStatusCode: http.StatusOK,
		},
	}
}

func (a *AssetAction) Play(s *Session) error {
	formData := url.Values{}
	for key, val := range a.PostData {
		formData.Set(key, val)
	}

	buf := bytes.NewBufferString(formData.Encode())
	req, err := s.NewRequest(a.Method, a.Path, buf)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	urlCache, cacheFound := cache.GetInstance().Get(a.Path)
	if cacheFound {
		urlCache.Apply(req)
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	// 2回ioutil.ReadAllを呼ぶとおかしくなる
	uc, md5 := cache.NewURLCache(res)
	if uc != nil {
		cache.GetInstance().Set(a.Path, uc)
	}

	success := false

	// キャッシュが有効でかつStatusNotModifiedのときは成功
	if cacheFound && res.StatusCode == http.StatusNotModified {
		success = true
	}

	if res.StatusCode == http.StatusOK &&
		((uc == nil && util.GetMD5ByIO(res.Body) == a.Asset.MD5) || md5 == a.Asset.MD5) {
		success = true
	}

	defer res.Body.Close()

	if !success {
		return s.Fail(
			res.Request,
			fmt.Errorf(
				"Expected location is miss match %s, got: %s",
				a.ExpectedLocation, res.Request.URL.Path,
			))
	}

	s.Success(1)

	return nil
}

type UploadAction struct {
	*Action
	UploadParamName string
	Asset           *Asset
}

func NewUploadAction(method, path, uploadParamname string) *UploadAction {
	return &UploadAction{
		UploadParamName: uploadParamname,
		Action: &Action{
			Method: method,
			Path:   path,
		},
	}
}

func (a *UploadAction) Play(s *Session) error {
	req, err := s.NewFileUploadRequest(a.Path, a.PostData, a.UploadParamName, a.Asset.Path)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	defer res.Body.Close()

	if res.StatusCode != a.ExpectedStatusCode {
		s.Fail(res.Request, fmt.Errorf("Response code should be %d, got %d", a.ExpectedStatusCode, res.StatusCode))
	}

	if a.ExpectedLocation != "" {
		if a.ExpectedLocation != res.Request.URL.Path {
			return s.Fail(
				res.Request,
				fmt.Errorf(
					"Expected location is miss match %s, got: %s",
					a.ExpectedLocation, res.Request.URL.Path,
				))
		}
	}

	if a.CheckFunc != nil {
		err := a.CheckFunc(s, res.Body)
		if err != nil {
			return s.Fail(
				res.Request,
				err,
			)
		}
	}

	s.Success(1)

	return nil
}
<commit_msg>interfaceはとりあえず外す<commit_after>package checker

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"

	"github.com/catatsuy/private-isu/benchmarker/cache"
	"github.com/catatsuy/private-isu/benchmarker/util"
)

type Action struct {
	Method string
	Path   string

	PostData           map[string]string
	Headers            map[string]string
	ExpectedStatusCode int
	ExpectedLocation   string
	ExpectedHeaders    map[string]string
	ExpectedHTML       map[string]string

	Description string

	CheckFunc func(w *Session, body io.Reader) error
}

type Asset struct {
	Path string
	MD5  string
}

func NewAction(method, path string) *Action {
	return &Action{
		Method:             method,
		Path:               path,
		ExpectedStatusCode: http.StatusOK,
	}
}

func (a *Action) Play(s *Session) error {
	formData := url.Values{}
	for key, val := range a.PostData {
		formData.Set(key, val)
	}

	buf := bytes.NewBufferString(formData.Encode())
	req, err := s.NewRequest(a.Method, a.Path, buf)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	if req.Method == "POST" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	defer res.Body.Close()

	if res.StatusCode != a.ExpectedStatusCode {
		s.Fail(res.Request, fmt.Errorf("Response code should be %d, got %d", a.ExpectedStatusCode, res.StatusCode))
	}

	if a.ExpectedLocation != "" {
		if a.ExpectedLocation != res.Request.URL.Path {
			return s.Fail(
				res.Request,
				fmt.Errorf(
					"Expected location is miss match %s, got: %s",
					a.ExpectedLocation, res.Request.URL.Path,
				))
		}
	}

	if a.CheckFunc != nil {
		err := a.CheckFunc(s, res.Body)
		if err != nil {
			return s.Fail(
				res.Request,
				err,
			)
		}
	}

	s.Success(1)

	return nil
}

type AssetAction struct {
	*Action
	Asset *Asset
}

func NewAssetAction(path string, asset *Asset) *AssetAction {
	return &AssetAction{
		Asset: asset,
		Action: &Action{
			Method:             "GET",
			Path:               path,
			ExpectedStatusCode: http.StatusOK,
		},
	}
}

func (a *AssetAction) Play(s *Session) error {
	formData := url.Values{}
	for key, val := range a.PostData {
		formData.Set(key, val)
	}

	buf := bytes.NewBufferString(formData.Encode())
	req, err := s.NewRequest(a.Method, a.Path, buf)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	urlCache, cacheFound := cache.GetInstance().Get(a.Path)
	if cacheFound {
		urlCache.Apply(req)
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	// 2回ioutil.ReadAllを呼ぶとおかしくなる
	uc, md5 := cache.NewURLCache(res)
	if uc != nil {
		cache.GetInstance().Set(a.Path, uc)
	}

	success := false

	// キャッシュが有効でかつStatusNotModifiedのときは成功
	if cacheFound && res.StatusCode == http.StatusNotModified {
		success = true
	}

	if res.StatusCode == http.StatusOK &&
		((uc == nil && util.GetMD5ByIO(res.Body) == a.Asset.MD5) || md5 == a.Asset.MD5) {
		success = true
	}

	defer res.Body.Close()

	if !success {
		return s.Fail(
			res.Request,
			fmt.Errorf(
				"Expected location is miss match %s, got: %s",
				a.ExpectedLocation, res.Request.URL.Path,
			))
	}

	s.Success(1)

	return nil
}

type UploadAction struct {
	*Action
	UploadParamName string
	Asset           *Asset
}

func NewUploadAction(method, path, uploadParamname string) *UploadAction {
	return &UploadAction{
		UploadParamName: uploadParamname,
		Action: &Action{
			Method: method,
			Path:   path,
		},
	}
}

func (a *UploadAction) Play(s *Session) error {
	req, err := s.NewFileUploadRequest(a.Path, a.PostData, a.UploadParamName, a.Asset.Path)

	if err != nil {
		return s.Fail(req, err)
	}

	for key, val := range a.Headers {
		req.Header.Add(key, val)
	}

	res, err := s.SendRequest(req)

	if err != nil {
		return s.Fail(req, err)
	}

	defer res.Body.Close()

	if res.StatusCode != a.ExpectedStatusCode {
		s.Fail(res.Request, fmt.Errorf("Response code should be %d, got %d", a.ExpectedStatusCode, res.StatusCode))
	}

	if a.ExpectedLocation != "" {
		if a.ExpectedLocation != res.Request.URL.Path {
			return s.Fail(
				res.Request,
				fmt.Errorf(
					"Expected location is miss match %s, got: %s",
					a.ExpectedLocation, res.Request.URL.Path,
				))
		}
	}

	if a.CheckFunc != nil {
		err := a.CheckFunc(s, res.Body)
		if err != nil {
			return s.Fail(
				res.Request,
				err,
			)
		}
	}

	s.Success(1)

	return nil
}
<|endoftext|>


<commit_before>// Go binding for nanomsg

package nanomsg

// #include <nanomsg/nn.h>
// #include <nanomsg/pair.h>
// #include <nanomsg/reqrep.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lnanomsg
import "C"

import (
	"reflect"
	"runtime"
	"unsafe"
)

// C.NN_MSG is defined as size_t(-1), which makes cgo produce an error.
const nn_msg = ^C.size_t(0)

// SP address families.
type Domain int

const (
	SP     = Domain(C.AF_SP)
	SP_RAW = Domain(C.AF_SP_RAW)
)

type Protocol int

const (
	// reqrep.h
	REQ = Protocol(C.NN_REQ)
	REP = Protocol(C.NN_REP)

	// pair.h
	PAIR = Protocol(C.NN_PAIR)
)

type Socket struct {
	socket C.int
}

// Create a socket.
func NewSocket(domain Domain, protocol Protocol) (*Socket, error) {
	soc, err := C.nn_socket(C.int(domain), C.int(protocol))
	if err != nil {
		return nil, nnError(err)
	}

	socket := &Socket{soc}
	runtime.SetFinalizer(socket, (*Socket).Close)
	return socket, nil
}

// Close a socket.
func (s *Socket) Close() error {
	if s.socket != 0 {
		if rc, err := C.nn_close(s.socket); rc != 0 {
			return nnError(err)
		}
		s.socket = C.int(0)
	}
	return nil
}

// Add a local endpoint to the socket.
func (s *Socket) Bind(address string) (*Endpoint, error) {
	cstr := C.CString(address)
	defer C.free(unsafe.Pointer(cstr))
	eid, err := C.nn_bind(s.socket, cstr)
	if eid < 0 {
		return nil, nnError(err)
	}
	return &Endpoint{address, eid}, nil
}

// Add a remote endpoint to the socket.
func (s *Socket) Connect(address string) (*Endpoint, error) {
	cstr := C.CString(address)
	defer C.free(unsafe.Pointer(cstr))
	eid, err := C.nn_connect(s.socket, cstr)
	if eid < 0 {
		return nil, nnError(err)
	}
	return &Endpoint{address, eid}, nil
}

// Removes an endpoint from the socket.
func (s *Socket) Shutdown(endpoint *Endpoint) error {
	if rc, err := C.nn_shutdown(s.socket, endpoint.endpoint); rc != 0 {
		return nnError(err)
	}
	return nil
}

func (s *Socket) Send(data []byte, flags int) error {
	msg := unsafe.Pointer(&data[0])
	msgSize := C.size_t(len(data))
	if size, err := C.nn_send(s.socket, msg, msgSize, C.int(flags)); size < 0 {
		return nnError(err)
	}

	return nil
}

func (s *Socket) Recv(flags int) ([]byte, error) {
	var size C.int
	var err error
	var buf unsafe.Pointer

	if size, err = C.nn_recv(s.socket, unsafe.Pointer(&buf), nn_msg, C.int(flags)); size < 0 {
		return nil, nnError(err)
	}

	// TODO why is the latter variant faster than the zero copy variant?
	zeroCopy := true
	if zeroCopy {
		capacity := int(size)
		header := &reflect.SliceHeader{
			Data: uintptr(buf),
			Len: capacity,
			Cap: capacity,
		}
		data := *((*[]byte)(unsafe.Pointer(header)))
		runtime.SetFinalizer(&data, finalizeMsg)
		return data, nil
	} else {
		data := C.GoBytes(buf, size)
		if rc, err := C.nn_freemsg(buf); rc != 0 {
			return data, nnError(err)
		}
		return data, nil
	}
}

func finalizeMsg(datap *[]byte) error {
	hdrp := (*reflect.SliceHeader)(unsafe.Pointer(datap))
	if rc, err := C.nn_freemsg(unsafe.Pointer(hdrp.Data)); rc != 0 {
		return nnError(err)
	}
	return nil
}

type Endpoint struct {
	Address string
	endpoint C.int
}

func (e *Endpoint) String() string {
	return e.Address
}
<commit_msg>Cosmetic changes<commit_after>// Go binding for nanomsg

package nanomsg

// #include <nanomsg/nn.h>
// #include <nanomsg/pair.h>
// #include <nanomsg/reqrep.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lnanomsg
import "C"

import (
	"reflect"
	"runtime"
	"unsafe"
)

// C.NN_MSG is defined as size_t(-1), which makes cgo produce an error.
const nn_msg = ^C.size_t(0)

// SP address families.
type Domain int

const (
	SP     = Domain(C.AF_SP)
	SP_RAW = Domain(C.AF_SP_RAW)
)

type Protocol int

const (
	// reqrep.h
	REQ = Protocol(C.NN_REQ)
	REP = Protocol(C.NN_REP)

	// pair.h
	PAIR = Protocol(C.NN_PAIR)
)

type Socket struct {
	socket C.int
}

// Create a socket.
func NewSocket(domain Domain, protocol Protocol) (*Socket, error) {
	soc, err := C.nn_socket(C.int(domain), C.int(protocol))
	if err != nil {
		return nil, nnError(err)
	}

	socket := &Socket{soc}
	runtime.SetFinalizer(socket, (*Socket).Close)
	return socket, nil
}

// Close a socket.
func (s *Socket) Close() error {
	if s.socket != 0 {
		if rc, err := C.nn_close(s.socket); rc != 0 {
			return nnError(err)
		}
		s.socket = C.int(0)
	}
	return nil
}

// Add a local endpoint to the socket.
func (s *Socket) Bind(address string) (*Endpoint, error) {
	cstr := C.CString(address)
	defer C.free(unsafe.Pointer(cstr))
	eid, err := C.nn_bind(s.socket, cstr)
	if eid < 0 {
		return nil, nnError(err)
	}
	return &Endpoint{address, eid}, nil
}

// Add a remote endpoint to the socket.
func (s *Socket) Connect(address string) (*Endpoint, error) {
	cstr := C.CString(address)
	defer C.free(unsafe.Pointer(cstr))
	eid, err := C.nn_connect(s.socket, cstr)
	if eid < 0 {
		return nil, nnError(err)
	}
	return &Endpoint{address, eid}, nil
}

// Removes an endpoint from the socket.
func (s *Socket) Shutdown(endpoint *Endpoint) error {
	if rc, err := C.nn_shutdown(s.socket, endpoint.endpoint); rc != 0 {
		return nnError(err)
	}
	return nil
}

func (s *Socket) Send(data []byte, flags int) error {
	buf := unsafe.Pointer(&data[0])
	length := C.size_t(len(data))
	if size, err := C.nn_send(s.socket, buf, length, C.int(flags)); size < 0 {
		return nnError(err)
	}

	return nil
}

func (s *Socket) Recv(flags int) ([]byte, error) {
	var err error
	var buf unsafe.Pointer
	var length C.int

	if length, err = C.nn_recv(s.socket, unsafe.Pointer(&buf), nn_msg, C.int(flags)); length < 0 {
		return nil, nnError(err)
	}

	// TODO why is the latter variant faster than the zero copy variant?
	zeroCopy := true
	if zeroCopy {
		capacity := int(length)
		header := &reflect.SliceHeader{
			Data: uintptr(buf),
			Len: capacity,
			Cap: capacity,
		}
		data := *((*[]byte)(unsafe.Pointer(header)))
		runtime.SetFinalizer(&data, finalizeMsg)
		return data, nil
	} else {
		data := C.GoBytes(buf, length)
		if rc, err := C.nn_freemsg(buf); rc != 0 {
			return data, nnError(err)
		}
		return data, nil
	}
}

func finalizeMsg(datap *[]byte) error {
	hdrp := (*reflect.SliceHeader)(unsafe.Pointer(datap))
	if rc, err := C.nn_freemsg(unsafe.Pointer(hdrp.Data)); rc != 0 {
		return nnError(err)
	}
	return nil
}

type Endpoint struct {
	Address string
	endpoint C.int
}

func (e *Endpoint) String() string {
	return e.Address
}
<|endoftext|>


<commit_before>package mch

import (
	"net/http"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
	"io"
)

type NotifyMsg struct {
	AppID    string
	MchID    string
	SubAppID string
	SubMchID string

	OrderInfo
}

type NotifyHandler struct {
	handler func(*NotifyMsg) error

	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	*zap.SugaredLogger
}

func NewNotifyHandler(appID, mchID, apiKey string, handler ...func(*NotifyMsg) error) *NotifyHandler {
	var h func(*NotifyMsg) error
	if len(handler) > 0 {
		h = handler[0]
	}
	return &NotifyHandler{
		handler: h,

		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
}

func (nm *NotifyHandler) serveError(w io.Writer, reason string) {
	nm.Errorw("NotifyHandler serve error", "error", reason)
	err := EncodeXML(w, map[string]string{
		"return_code": ReturnCodeFail,
		"return_msg":  reason,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}

func (nm *NotifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	nm.Serve(w, r, nm.handler)
}

func (nm *NotifyHandler) Serve(w io.Writer, r *http.Request, handler func(*NotifyMsg) error) {
	if r.Method != "POST" {
		nm.serveError(w, "unexpected HTTP Method: "+r.Method)
		return
	}

	req, err := DecodeXML(r.Body)
	if err != nil {
		nm.serveError(w, err.Error())
		return
	}

	returnCode := req["return_code"]
	if returnCode != ReturnCodeSuccess {
		err = &Error{
			ReturnCode: returnCode,
			ReturnMsg:  req["return_msg"],
		}
		nm.serveError(w, err.Error())
		return
	}

	resultCode := req["result_code"]
	if resultCode != ResultCodeSuccess {
		err = &BizError{
			ResultCode:  resultCode,
			ErrCode:     req["err_code"],
			ErrCodeDesc: req["err_code_des"],
		}
		nm.serveError(w, err.Error())
		return
	}

	if nm.appID != "" {
		wantAppId := nm.appID
		haveAppId := req["appid"]
		if !wechat.Compare(haveAppId, wantAppId) {
			nm.serveError(w, fmt.Sprintf("appid mismatch, have: %s, want: %s", haveAppId, wantAppId))
			return
		}
	}
	if nm.mchID != "" {
		wantMchId := nm.mchID
		haveMchId := req["mch_id"]
		if !wechat.Compare(haveMchId, wantMchId) {
			nm.serveError(w, fmt.Sprintf("mch_id mismatch, have: %s, want: %s", haveMchId, wantMchId))
			return
		}
	}

	if nm.subAppID != "" {
		wantSubAppId := nm.subAppID
		haveSubAppId := req["sub_appid"]
		if haveSubAppId != "" && !wechat.Compare(haveSubAppId, wantSubAppId) {
			nm.serveError(w, fmt.Sprintf("sub_appid mismatch, have: %s, want: %s", haveSubAppId, wantSubAppId))
			return
		}
	}
	if nm.subMchID != "" {
		wantSubMchId := nm.subMchID
		haveSubMchId := req["sub_mch_id"]
		if !wechat.Compare(haveSubMchId, wantSubMchId) {
			nm.serveError(w, fmt.Sprintf("sub_mch_id mismatch, have: %s, want: %s", haveSubMchId, wantSubMchId))
			return
		}
	}

	haveSign := req["sign"]
	var wantSign string
	switch signType := req["sign_type"]; signType {
	case "", SignTypeMD5:
		wantSign = Sign(req, nm.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		wantSign = Sign(req, nm.apiKey, hmac.New(sha256.New, []byte(nm.apiKey)))
	default:
		nm.serveError(w, fmt.Sprintf("unsupported notification sign_type: %s", signType))
		return
	}
	if !wechat.Compare(haveSign, wantSign) {
		nm.serveError(w, fmt.Sprintf("sign mismatch,\nhave: %s,\nwant: %s", haveSign, wantSign))
		return
	}

	orderInfo, err := getOrderInfo(req)
	if err != nil {
		nm.serveError(w, err.Error())
	}

	msg := NotifyMsg{
		AppID: req["appid"],
		MchID: req["mch_id"],
		SubAppID: req["sub_appid"],
		SubMchID: req["sub_mch_id"],
		OrderInfo: *orderInfo,
	}
	err = handler(&msg)
	if err != nil {
		nm.serveError(w, err.Error())
	}

	err = EncodeXML(w, map[string]string{
		"return_code": ReturnCodeSuccess,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}
<commit_msg>Update source files<commit_after>package mch

import (
	"net/http"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
	"io"
	"gitee.com/jiudaoyun/shefuren/api"
)

type NotifyMsg struct {
	AppID    string
	MchID    string
	SubAppID string
	SubMchID string

	OrderInfo
}

type NotifyHandler struct {
	handler func(*NotifyMsg) error

	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	*zap.SugaredLogger
}

func NewNotifyHandler(appID, mchID, apiKey string, handler ...func(*NotifyMsg) error) *NotifyHandler {
	var h func(*NotifyMsg) error
	if len(handler) > 0 {
		h = handler[0]
	}
	return &NotifyHandler{
		handler: h,

		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
}

func (nm *NotifyHandler) serveError(w io.Writer, reason string) {
	nm.Errorw("NotifyHandler serve error", "error", reason)
	err := EncodeXML(w, map[string]string{
		"return_code": ReturnCodeFail,
		"return_msg":  reason,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}

func (nm *NotifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	nm.Serve(w, r, nm.handler)
}

func (nm *NotifyHandler) Serve(w io.Writer, r *http.Request, handler func(*NotifyMsg) error) {
	if r.Method != "POST" {
		nm.serveError(w, "unexpected HTTP Method: "+r.Method)
		return
	}

	req, err := DecodeXML(r.Body)
	if err != nil {
		nm.serveError(w, err.Error())
		return
	}

	api.Sugar.Infof("wechat callback: %s", req)

	returnCode := req["return_code"]
	if returnCode != ReturnCodeSuccess {
		err = &Error{
			ReturnCode: returnCode,
			ReturnMsg:  req["return_msg"],
		}
		nm.serveError(w, err.Error())
		return
	}

	resultCode := req["result_code"]
	if resultCode != ResultCodeSuccess {
		err = &BizError{
			ResultCode:  resultCode,
			ErrCode:     req["err_code"],
			ErrCodeDesc: req["err_code_des"],
		}
		nm.serveError(w, err.Error())
		return
	}

	if nm.appID != "" {
		wantAppId := nm.appID
		haveAppId := req["appid"]
		if !wechat.Compare(haveAppId, wantAppId) {
			nm.serveError(w, fmt.Sprintf("appid mismatch, have: %s, want: %s", haveAppId, wantAppId))
			return
		}
	}
	if nm.mchID != "" {
		wantMchId := nm.mchID
		haveMchId := req["mch_id"]
		if !wechat.Compare(haveMchId, wantMchId) {
			nm.serveError(w, fmt.Sprintf("mch_id mismatch, have: %s, want: %s", haveMchId, wantMchId))
			return
		}
	}

	if nm.subAppID != "" {
		wantSubAppId := nm.subAppID
		haveSubAppId := req["sub_appid"]
		if haveSubAppId != "" && !wechat.Compare(haveSubAppId, wantSubAppId) {
			nm.serveError(w, fmt.Sprintf("sub_appid mismatch, have: %s, want: %s", haveSubAppId, wantSubAppId))
			return
		}
	}
	if nm.subMchID != "" {
		wantSubMchId := nm.subMchID
		haveSubMchId := req["sub_mch_id"]
		if !wechat.Compare(haveSubMchId, wantSubMchId) {
			nm.serveError(w, fmt.Sprintf("sub_mch_id mismatch, have: %s, want: %s", haveSubMchId, wantSubMchId))
			return
		}
	}

	haveSign := req["sign"]
	var wantSign string
	switch signType := req["sign_type"]; signType {
	case "", SignTypeMD5:
		wantSign = Sign(req, nm.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		wantSign = Sign(req, nm.apiKey, hmac.New(sha256.New, []byte(nm.apiKey)))
	default:
		nm.serveError(w, fmt.Sprintf("unsupported notification sign_type: %s", signType))
		return
	}
	if !wechat.Compare(haveSign, wantSign) {
		nm.serveError(w, fmt.Sprintf("sign mismatch,\nhave: %s,\nwant: %s", haveSign, wantSign))
		return
	}

	orderInfo, err := getOrderInfo(req)
	if err != nil {
		nm.serveError(w, err.Error())
	}

	msg := NotifyMsg{
		AppID: req["appid"],
		MchID: req["mch_id"],
		SubAppID: req["sub_appid"],
		SubMchID: req["sub_mch_id"],
		OrderInfo: *orderInfo,
	}
	err = handler(&msg)
	if err != nil {
		nm.serveError(w, err.Error())
	}

	err = EncodeXML(w, map[string]string{
		"return_code": ReturnCodeSuccess,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}
<|endoftext|>


<commit_before>package netconf

import (
	"bytes"
	"errors"
	"net"
	"os"
	"os/exec"
	"strings"

	log "github.com/Sirupsen/logrus"

	"github.com/ryanuber/go-glob"
	"github.com/vishvananda/netlink"
)

func createInterfaces(netCfg *NetworkConfig) error {
	for name, iface := range netCfg.Interfaces {
		if !iface.Bridge {
			continue
		}

		bridge := netlink.Bridge{}
		bridge.LinkAttrs.Name = name

		if err := netlink.LinkAdd(&bridge); err != nil {
			log.Errorf("Failed to create bridge %s: %v", name, err)
		}
	}

	return nil
}

func ApplyNetworkConfigs(netCfg *NetworkConfig) error {
	if err := createInterfaces(netCfg); err != nil {
		return err
	}

	links, err := netlink.LinkList()
	if err != nil {
		return err
	}

	//apply network config
	for _, link := range links {
		linkName := link.Attrs().Name
		var match InterfaceConfig

		for key, netConf := range netCfg.Interfaces {
			if netConf.Match == "" {
				netConf.Match = key
			}

			if netConf.Match == "" {
				continue
			}

			if len(netConf.Match) > 4 && strings.ToLower(netConf.Match[:3]) == "mac" {
				haAddr, err := net.ParseMAC(netConf.Match[4:])
				if err != nil {
					return err
				}
				if bytes.Compare(haAddr, link.Attrs().HardwareAddr) == 0 {
					// MAC address match is used over all other matches
					match = netConf
					break
				}
			}

			// "" means match has not been found
			if match.Match == "" && matches(linkName, netConf.Match) {
				match = netConf
			}

			if netConf.Match == linkName {
				// Found exact match, use it over wildcard match
				match = netConf
			}
		}

		if match.Match != "" {
			err = applyNetConf(link, match)
			if err != nil {
				log.Errorf("Failed to apply settings to %s : %v", linkName, err)
			}
		}
	}

	if err != nil {
		return err
	}

	return nil
}

func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
	if netConf.DHCP {
		log.Infof("Running DHCP on %s", link.Attrs().Name)
		cmd := exec.Command("dhcpcd", "-A4", "-e", "force_hostname=true", link.Attrs().Name)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			log.Error(err)
		}
	} else if netConf.IPV4LL {
		if err := AssignLinkLocalIP(link); err != nil {
			log.Error("IPV4LL set failed")
			return err
		}
	} else if netConf.Address == "" {
		return nil
	} else {
		addr, err := netlink.ParseAddr(netConf.Address)
		if err != nil {
			return err
		}
		if err := netlink.AddrAdd(link, addr); err != nil {
			log.Error("addr add failed")
			return err
		}
		log.Infof("Set %s on %s", netConf.Address, link.Attrs().Name)
	}

	if netConf.MTU > 0 {
		if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil {
			log.Error("set MTU Failed")
			return err
		}
	}

	if err := netlink.LinkSetUp(link); err != nil {
		log.Error("failed to setup link")
		return err
	}

	if netConf.Gateway != "" {
		gatewayIp := net.ParseIP(netConf.Gateway)
		if gatewayIp == nil {
			return errors.New("Invalid gateway address " + netConf.Gateway)
		}

		route := netlink.Route{
			Scope: netlink.SCOPE_UNIVERSE,
			Gw:    net.ParseIP(netConf.Gateway),
		}
		if err := netlink.RouteAdd(&route); err != nil {
			log.Error("gateway set failed")
			return err
		}

		log.Infof("Set default gateway %s", netConf.Gateway)
	}

	return nil
}

func matches(link, conf string) bool {
	return glob.Glob(conf, link)
}
<commit_msg>Fix error handling<commit_after>package netconf

import (
	"bytes"
	"errors"
	"net"
	"os"
	"os/exec"
	"strings"

	log "github.com/Sirupsen/logrus"

	"github.com/ryanuber/go-glob"
	"github.com/vishvananda/netlink"
)

func createInterfaces(netCfg *NetworkConfig) error {
	for name, iface := range netCfg.Interfaces {
		if !iface.Bridge {
			continue
		}

		bridge := netlink.Bridge{}
		bridge.LinkAttrs.Name = name

		if err := netlink.LinkAdd(&bridge); err != nil {
			log.Errorf("Failed to create bridge %s: %v", name, err)
		}
	}

	return nil
}

func ApplyNetworkConfigs(netCfg *NetworkConfig) error {
	log.Debugf("Config: %#v", netCfg)
	if err := createInterfaces(netCfg); err != nil {
		return err
	}

	links, err := netlink.LinkList()
	if err != nil {
		return err
	}

	//apply network config
	for _, link := range links {
		linkName := link.Attrs().Name
		var match InterfaceConfig

		for key, netConf := range netCfg.Interfaces {
			if netConf.Match == "" {
				netConf.Match = key
			}

			if netConf.Match == "" {
				continue
			}

			if len(netConf.Match) > 4 && strings.ToLower(netConf.Match[:3]) == "mac" {
				haAddr, err := net.ParseMAC(netConf.Match[4:])
				if err != nil {
					return err
				}
				if bytes.Compare(haAddr, link.Attrs().HardwareAddr) == 0 {
					// MAC address match is used over all other matches
					match = netConf
					break
				}
			}

			// "" means match has not been found
			if match.Match == "" && matches(linkName, netConf.Match) {
				match = netConf
			}

			if netConf.Match == linkName {
				// Found exact match, use it over wildcard match
				match = netConf
			}
		}

		if match.Match != "" {
			err = applyNetConf(link, match)
			if err != nil {
				log.Errorf("Failed to apply settings to %s : %v", linkName, err)
			}
		}
	}

	if err != nil {
		return err
	}

	return nil
}

func applyNetConf(link netlink.Link, netConf InterfaceConfig) error {
	if netConf.DHCP {
		log.Infof("Running DHCP on %s", link.Attrs().Name)
		cmd := exec.Command("dhcpcd", "-A4", "-e", "force_hostname=true", link.Attrs().Name)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			log.Error(err)
		}
	} else if netConf.IPV4LL {
		if err := AssignLinkLocalIP(link); err != nil {
			log.Errorf("IPV4LL set failed: %v", err)
			return err
		}
	} else if netConf.Address == "" {
		return nil
	} else {
		addr, err := netlink.ParseAddr(netConf.Address)
		if err != nil {
			return err
		}
		if err := netlink.AddrAdd(link, addr); err != nil {
			//Ignore this error
			log.Errorf("addr add failed: %v", err)
		} else {
			log.Infof("Set %s on %s", netConf.Address, link.Attrs().Name)
		}
	}

	if netConf.MTU > 0 {
		if err := netlink.LinkSetMTU(link, netConf.MTU); err != nil {
			log.Errorf("set MTU Failed: %v", err)
			return err
		}
	}

	if err := netlink.LinkSetUp(link); err != nil {
		log.Errorf("failed to setup link: %v", err)
		return err
	}

	if netConf.Gateway != "" {
		gatewayIp := net.ParseIP(netConf.Gateway)
		if gatewayIp == nil {
			return errors.New("Invalid gateway address " + netConf.Gateway)
		}

		route := netlink.Route{
			Scope: netlink.SCOPE_UNIVERSE,
			Gw:    net.ParseIP(netConf.Gateway),
		}
		if err := netlink.RouteAdd(&route); err != nil {
			log.Errorf("gateway set failed: %v", err)
			return err
		}

		log.Infof("Set default gateway %s", netConf.Gateway)
	}

	return nil
}

func matches(link, conf string) bool {
	return glob.Glob(conf, link)
}
<|endoftext|>