<commit_before>package ali

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"
)

func urlValues(c *Client, param PayParam) url.Values {
	values := url.Values{}
	values.Add("app_id", c.config.AppID)
	values.Add("method", param.URI())
	values.Add("format", "JSON")
	values.Add("charset", "utf-8")
	values.Add("sign_type", c.config.SignType)
	values.Add("timestamp", generateTimestampStr())
	values.Add("version", "1.0")
	values.Add("biz_content", param.BizContent())

	for k, v := range param.ExtraParams() {
		values.Add(k, v)
	}

	var keys []string
	for k := range values {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	values.Add("sign", signature(keys, values, c.config.AppPrivateKey, c.config.SignType))
	fmt.Printf("VALUES %v\n", values)
	return values
}

func signature(keys []string, values url.Values, privateKey []byte, signType string) string {
	if values == nil {
		values = url.Values{}
	}

	var valueList []string
	for _, k := range keys {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}

	concat := strings.Join(valueList, "&")
	fmt.Println("CONCAT", concat)

	var sign string
	if signType == "RSA" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA1)
		fmt.Println("RSA", sign)
	} else if signType == "RSA2" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA256)
		fmt.Println("RSA2", sign)
	}
	return sign
}

func signPKCS1v15(source, privateKey []byte, hash crypto.Hash) string {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		fmt.Println("BLOCK", block, len(privateKey))
		return ""
	}

	rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println("RSAPRIVATE", err)
		return ""
	}

	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, hash, hashed)
	if err != nil {
		fmt.Println("SIGNPKCS", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(s)
}

func verify(values url.Values, publicKey []byte, signType string) bool {
	decoded, err := base64.StdEncoding.DecodeString(values.Get("sign"))
	if err != nil {
		return false
	}

	var excluded []string
	for k, v := range values {
		if k == "sign" || k == "sign_type" {
			continue
		}
		if len(v) > 0 {
			excluded = append(excluded, k)
		}
	}

	sort.Strings(excluded)

	var valueList []string
	for _, k := range excluded {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}
	concat := strings.Join(valueList, "&")

	var ok bool
	if signType == "RSA" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA1)
	} else if signType == "RSA2" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA256)
	}
	return ok
}

func verifyPKCS1v15(source, sign, publicKey []byte, hash crypto.Hash) bool {
	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	block, _ := pem.Decode(publicKey)
	if block == nil {
		return false
	}

	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return false
	}

	rsaPublicKey := pub.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(rsaPublicKey, hash, hashed, sign)
	if err != nil {
		return false
	}
	return true
}

func generateTimestampStr() string {
	now := time.Now()
	year, month, day := now.Date()
	hour, min, sec := now.Clock()
	return fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
}

func marshalJSON(val interface{}) string {
	data, err := json.Marshal(val)
	if err != nil {
		return ""
	}
	return string(data)
}
<commit_msg>bugfix<commit_after>package ali

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"
)

func urlValues(c *Client, param PayParam) url.Values {
	values := url.Values{}
	values.Add("app_id", c.config.AppID)
	values.Add("method", param.URI())
	values.Add("format", "JSON")
	values.Add("charset", "utf-8")
	values.Add("sign_type", c.config.SignType)
	values.Add("timestamp", generateTimestampStr())
	values.Add("version", "1.0")
	values.Add("biz_content", param.BizContent())

	for k, v := range param.ExtraParams() {
		values.Add(k, v)
	}

	var keys []string
	for k := range values {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	values.Add("sign", signature(keys, values, c.config.AppPrivateKey, c.config.SignType))
	fmt.Printf("VALUES %v\n", values)
	return values
}

func signature(keys []string, values url.Values, privateKey []byte, signType string) string {
	if values == nil {
		values = url.Values{}
	}

	var valueList []string
	for _, k := range keys {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}

	concat := strings.Join(valueList, "&")
	fmt.Println("CONCAT", concat)

	var sign string
	if signType == "RSA" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA1)
		fmt.Println("RSA", sign)
	} else if signType == "RSA2" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA256)
		fmt.Println("RSA2", sign)
	}
	return sign
}

func signPKCS1v15(source, privateKey []byte, hash crypto.Hash) string {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		fmt.Println("BLOCK", block, len(privateKey))
		return ""
	}

	// rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println("RSAPRIVATE", err)
		return ""
	}

	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), hash, hashed)
	if err != nil {
		fmt.Println("SIGNPKCS", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(s)
}

func verify(values url.Values, publicKey []byte, signType string) bool {
	decoded, err := base64.StdEncoding.DecodeString(values.Get("sign"))
	if err != nil {
		return false
	}

	var excluded []string
	for k, v := range values {
		if k == "sign" || k == "sign_type" {
			continue
		}
		if len(v) > 0 {
			excluded = append(excluded, k)
		}
	}

	sort.Strings(excluded)

	var valueList []string
	for _, k := range excluded {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}
	concat := strings.Join(valueList, "&")

	var ok bool
	if signType == "RSA" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA1)
	} else if signType == "RSA2" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA256)
	}
	return ok
}

func verifyPKCS1v15(source, sign, publicKey []byte, hash crypto.Hash) bool {
	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	block, _ := pem.Decode(publicKey)
	if block == nil {
		return false
	}

	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return false
	}

	rsaPublicKey := pub.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(rsaPublicKey, hash, hashed, sign)
	if err != nil {
		return false
	}
	return true
}

func generateTimestampStr() string {
	now := time.Now()
	year, month, day := now.Date()
	hour, min, sec := now.Clock()
	return fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
}

func marshalJSON(val interface{}) string {
	data, err := json.Marshal(val)
	if err != nil {
		return ""
	}
	return string(data)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/nsqio/go-nsq"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

const updateDuration = 1 * time.Second

var fatalErr error

func fatal(e error) {
	fmt.Println(e)
	flag.PrintDefaults()
	fatalErr = e
}

func main() {

	defer func() {
		if fatalErr != nil {
			os.Exit(1)
		}
	}()

	log.Println("Connecting to database...")
	db, err := mgo.Dial("localhost")
	if err != nil {
		fatal(err)
		return
	}
	defer func() {
		log.Println("Closing database connection...")
		db.Close()
	}()
	pollData := db.DB("ballots").C("polls")

	var counts map[string]int
	var countsLock sync.Mutex

	log.Println("Connecting to nsq...")
	q, err := nsq.NewConsumer("votes", "counter", nsq.NewConfig())
	if err != nil {
		fatal(err)
		return
	}

	q.AddHandler(nsq.HandlerFunc(func(m *nsq.Message) error {
		countsLock.Lock()
		defer countsLock.Unlock()
		if counts == nil {
			counts = make(map[string]int)
		}
		vote := string(m.Body)
		counts[vote]++
		return nil
	}))

	if err := q.ConnectToNSQLookupd("localhost:4161"); err != nil {
		fatal(err)
		return
	}

	log.Println("Waiting for votes on nsq...")
	ticker := time.NewTicker(updateDuration)
	termChan := make(chan os.Signal, 1)
	signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	for {
		select {
		case <-ticker.C:
			doCount(&countsLock, &counts, pollData)
		case <-termChan:
			ticker.Stop()
			q.Stop()
		case <-q.StopChan:
			// finished
			return
		}
	}

}

func doCount(countsLock *sync.Mutex, counts *map[string]int, pollData *mgo.Collection) {
	countsLock.Lock()
	defer countsLock.Unlock()
	if len(*counts) == 0 {
		log.Println("No new votes, skipping database update")
		return
	}
	log.Println("Updating database...")
	log.Println(*counts)
	ok := true
	for option, count := range *counts {
		sel := bson.M{"options": bson.M{"$in": []string{option}}}
		up := bson.M{"$inc": bson.M{"results." + option: count}}
		if _, err := pollData.UpdateAll(sel, up); err != nil {
			log.Println("failed to update:", err)
			ok = false
		}
	}
	if ok {
		log.Println("Finished updating database...")
		*counts = nil // reset counts
	}
}
<commit_msg>removed blank line<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/nsqio/go-nsq"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

const updateDuration = 1 * time.Second

var fatalErr error

func fatal(e error) {
	fmt.Println(e)
	flag.PrintDefaults()
	fatalErr = e
}

func main() {

	defer func() {
		if fatalErr != nil {
			os.Exit(1)
		}
	}()

	log.Println("Connecting to database...")
	db, err := mgo.Dial("localhost")
	if err != nil {
		fatal(err)
		return
	}
	defer func() {
		log.Println("Closing database connection...")
		db.Close()
	}()
	pollData := db.DB("ballots").C("polls")

	var counts map[string]int
	var countsLock sync.Mutex

	log.Println("Connecting to nsq...")
	q, err := nsq.NewConsumer("votes", "counter", nsq.NewConfig())
	if err != nil {
		fatal(err)
		return
	}

	q.AddHandler(nsq.HandlerFunc(func(m *nsq.Message) error {
		countsLock.Lock()
		defer countsLock.Unlock()
		if counts == nil {
			counts = make(map[string]int)
		}
		vote := string(m.Body)
		counts[vote]++
		return nil
	}))

	if err := q.ConnectToNSQLookupd("localhost:4161"); err != nil {
		fatal(err)
		return
	}

	log.Println("Waiting for votes on nsq...")
	ticker := time.NewTicker(updateDuration)
	termChan := make(chan os.Signal, 1)
	signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	for {
		select {
		case <-ticker.C:
			doCount(&countsLock, &counts, pollData)
		case <-termChan:
			ticker.Stop()
			q.Stop()
		case <-q.StopChan:
			// finished
			return
		}
	}

}

func doCount(countsLock *sync.Mutex, counts *map[string]int, pollData *mgo.Collection) {
	countsLock.Lock()
	defer countsLock.Unlock()
	if len(*counts) == 0 {
		log.Println("No new votes, skipping database update")
		return
	}
	log.Println("Updating database...")
	log.Println(*counts)
	ok := true
	for option, count := range *counts {
		sel := bson.M{"options": bson.M{"$in": []string{option}}}
		up := bson.M{"$inc": bson.M{"results." + option: count}}
		if _, err := pollData.UpdateAll(sel, up); err != nil {
			log.Println("failed to update:", err)
			ok = false
		}
	}
	if ok {
		log.Println("Finished updating database...")
		*counts = nil // reset counts
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// This test file is about running git commands with git filters configured
// In order to do this, we have to actually run 'go build' to produce a git-lob
// binary, and configure filters & .gitattributes in a repo to do it
var _ = Describe("Integration", func() {

	BeforeEach(func() {
		// This singular BeforeEach will just perform the build
		outp, err := exec.Command("go", "build").CombinedOutput()
		if err != nil {
			Fail(fmt.Sprintf("Failed to call 'go build': %v\n%v", err.Error(), string(outp)))
		}
	})

	// Function to create a git repo configured with git-lob filters for integration testing
	createConfiguredRepoFunc := func(root string) {
		CreateGitRepoForTest(root)
		ioutil.WriteFile(filepath.Join(root, ".gitattributes"),
			[]byte(`*.png filter=testlob -crlf
*.jpg filter=testlob -crlf
*.zip filter=testlob -crlf
*.tiff filter=testlob -crlf
*.tga filter=testlob -crlf
*.dds filter=testlob -crlf
*.bmp filter=testlob -crlf
*.mov filter=testlob -crlf`), 0644)
		f, err := os.OpenFile(filepath.Join(root, ".git", "config"), os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
		if err != nil {
			Fail(fmt.Sprintf("Can't write gitconfig: %v", err.Error()))
		}
		// Here we have to assume that go test is running in the root source folder
		cwd, _ := os.Getwd()
		gitlobbinary := filepath.Join(cwd, "git-lob")
		f.WriteString(fmt.Sprintf(`
[filter "testlob"]
  clean = "%v filter-clean %%f"
  smudge = "%v filter-smudge %%f"
`, gitlobbinary, gitlobbinary))
		f.Close()
	}

	Context("Integration tests", func() {
		// All actual tests nested here
		root := filepath.Join(os.TempDir(), "IntegrationTest")
		var oldwd string
		filespercommit := [][]string{
			[]string{
				"img1.png", "img2.jpg",
				filepath.Join("movies", "movie1.mov"),
				filepath.Join("movies", "movie2.mov"),
				filepath.Join("other", "files", "windows.bmp"),
			},
			[]string{
				"img3.tga", "img4.tiff", "img5.png",
				filepath.Join("movies", "movie3.mov"),
				filepath.Join("movies", "movie4.mov"),
				filepath.Join("other", "files", "windows7.bmp"),
			},
			[]string{
				"img6.jpg",
				filepath.Join("other", "files", "windows10.bmp"),
			},
		}
		sizeForFile := func(filename string, i int) int64 {
			// not actually that big, we're not doing size tests here
			if strings.HasSuffix(filename, ".mov") {
				return int64(i%3*1000 + 2000)
			} else {
				return int64(i%3*100 + 300)
			}
		}
		checkExistsAndRightSize := func(fileset int) {
			files := filespercommit[fileset]
			for i, file := range files {
				sz := sizeForFile(file, i)
				stat, err := os.Stat(file)
				Expect(err).To(BeNil(), fmt.Sprintf("%v should exist", file))
				Expect(stat.Size()).To(BeEquivalentTo(sz), fmt.Sprintf("%v should be correct size", file))
			}
		}
		checkNotExists := func(fileset int) {
			files := filespercommit[fileset]
			for _, file := range files {
				_, err := os.Stat(file)
				Expect(err).ToNot(BeNil(), fmt.Sprintf("%v should not exist", file))
			}
		}

		BeforeEach(func() {
			createConfiguredRepoFunc(root)
			oldwd, _ = os.Getwd()
			os.Chdir(root)
		})
		AfterEach(func() {
			os.Chdir(oldwd)
			os.RemoveAll(root)
		})

		It("Git filters work", func() {

			diffregex := regexp.MustCompile("(?m)git-lob: ([A-Fa-f0-9]{40})")
			// Create commits
			for ci, commitfiles := range filespercommit {
				for i, file := range commitfiles {
					err := os.MkdirAll(filepath.Dir(file), 0755)
					Expect(err).To(BeNil(), "Shouldn't fail creating dir")
					sz := sizeForFile(file, i)
					// Create real content
					CreateRandomFileForTest(sz, file)
					// git add, will write placeholder & store via filter (or should)
					err = exec.Command("git", "add", file).Run()
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail in git add for %v", file))

					// Check content of index & that binaries created

					diffout, err := exec.Command("git", "diff", "--cached", file).CombinedOutput()
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail in git diff for %v", file))
					match := diffregex.FindStringSubmatch(string(diffout))
					Expect(match).ToNot(BeNil(), fmt.Sprintf("Should find git-lob ref in diff for %v", file))
					Expect(match).To(HaveLen(2), "Should be 2 matches")
					sha := match[1]

					// confirm that the file is stored correctly
					err = CheckLOBFilesForSHA(sha, GetLocalLOBRoot(), false)
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail checking storage for %v", file))
				}
				// Commit & tag
				err := exec.Command("git", "commit", "-m", fmt.Sprintf("Commit %d", ci)).Run()
				Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail commit %d", ci))
				err = exec.Command("git", "tag", "-a", "-m", "Nothing", fmt.Sprintf("Tag%d", ci)).Run()
				Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail tagging %d", ci))
			}

			// Now check out a few times to make sure working copy changes appropriately
			err := exec.Command("git", "checkout", "Tag0").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkNotExists(1)
			checkNotExists(2)

			err = exec.Command("git", "checkout", "Tag1").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkExistsAndRightSize(1)
			checkNotExists(2)

			err = exec.Command("git", "checkout", "Tag2").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkExistsAndRightSize(1)
			checkExistsAndRightSize(2)

		})

	})
})
<commit_msg>Confirm that working copy is left clean by git filters<commit_after>package main

import (
	"fmt"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// This test file is about running git commands with git filters configured
// In order to do this, we have to actually run 'go build' to produce a git-lob
// binary, and configure filters & .gitattributes in a repo to do it
var _ = Describe("Integration", func() {

	BeforeEach(func() {
		// This singular BeforeEach will just perform the build
		outp, err := exec.Command("go", "build").CombinedOutput()
		if err != nil {
			Fail(fmt.Sprintf("Failed to call 'go build': %v\n%v", err.Error(), string(outp)))
		}
	})

	// Function to create a git repo configured with git-lob filters for integration testing
	createConfiguredRepoFunc := func(root string) {
		CreateGitRepoForTest(root)
		ioutil.WriteFile(filepath.Join(root, ".gitattributes"),
			[]byte(`*.png filter=testlob -crlf
*.jpg filter=testlob -crlf
*.zip filter=testlob -crlf
*.tiff filter=testlob -crlf
*.tga filter=testlob -crlf
*.dds filter=testlob -crlf
*.bmp filter=testlob -crlf
*.mov filter=testlob -crlf`), 0644)
		f, err := os.OpenFile(filepath.Join(root, ".git", "config"), os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
		if err != nil {
			Fail(fmt.Sprintf("Can't write gitconfig: %v", err.Error()))
		}
		// Here we have to assume that go test is running in the root source folder
		cwd, _ := os.Getwd()
		gitlobbinary := filepath.Join(cwd, "git-lob")
		f.WriteString(fmt.Sprintf(`
[filter "testlob"]
  clean = "%v filter-clean %%f"
  smudge = "%v filter-smudge %%f"
`, gitlobbinary, gitlobbinary))
		f.Close()
	}

	Context("Integration tests", func() {
		// All actual tests nested here
		root := filepath.Join(os.TempDir(), "IntegrationTest")
		var oldwd string
		filespercommit := [][]string{
			[]string{
				"img1.png", "img2.jpg",
				filepath.Join("movies", "movie1.mov"),
				filepath.Join("movies", "movie2.mov"),
				filepath.Join("other", "files", "windows.bmp"),
			},
			[]string{
				"img3.tga", "img4.tiff", "img5.png",
				filepath.Join("movies", "movie3.mov"),
				filepath.Join("movies", "movie4.mov"),
				filepath.Join("other", "files", "windows7.bmp"),
			},
			[]string{
				"img6.jpg",
				filepath.Join("other", "files", "windows10.bmp"),
			},
		}
		sizeForFile := func(filename string, i int) int64 {
			// not actually that big, we're not doing size tests here
			if strings.HasSuffix(filename, ".mov") {
				return int64(i%3*1000 + 2000)
			} else {
				return int64(i%3*100 + 300)
			}
		}
		checkExistsAndRightSize := func(fileset int) {
			files := filespercommit[fileset]
			for i, file := range files {
				sz := sizeForFile(file, i)
				stat, err := os.Stat(file)
				Expect(err).To(BeNil(), fmt.Sprintf("%v should exist", file))
				Expect(stat.Size()).To(BeEquivalentTo(sz), fmt.Sprintf("%v should be correct size", file))
			}
		}
		checkNotExists := func(fileset int) {
			files := filespercommit[fileset]
			for _, file := range files {
				_, err := os.Stat(file)
				Expect(err).ToNot(BeNil(), fmt.Sprintf("%v should not exist", file))
			}
		}
		checkGitStatusNotModified := func() {
			outp, err := exec.Command("git", "status", "--porcelain", "-uno").CombinedOutput()
			Expect(outp).To(HaveLen(0), "Should be no modified files")
			Expect(err).To(BeNil(), "git status should succeed")
		}

		BeforeEach(func() {
			createConfiguredRepoFunc(root)
			oldwd, _ = os.Getwd()
			os.Chdir(root)
		})
		AfterEach(func() {
			os.Chdir(oldwd)
			os.RemoveAll(root)
		})

		It("Git filters work", func() {

			diffregex := regexp.MustCompile("(?m)git-lob: ([A-Fa-f0-9]{40})")
			// Create commits
			for ci, commitfiles := range filespercommit {
				for i, file := range commitfiles {
					err := os.MkdirAll(filepath.Dir(file), 0755)
					Expect(err).To(BeNil(), "Shouldn't fail creating dir")
					sz := sizeForFile(file, i)
					// Create real content
					CreateRandomFileForTest(sz, file)
					// git add, will write placeholder & store via filter (or should)
					err = exec.Command("git", "add", file).Run()
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail in git add for %v", file))

					// Check content of index & that binaries created

					diffout, err := exec.Command("git", "diff", "--cached", file).CombinedOutput()
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail in git diff for %v", file))
					match := diffregex.FindStringSubmatch(string(diffout))
					Expect(match).ToNot(BeNil(), fmt.Sprintf("Should find git-lob ref in diff for %v", file))
					Expect(match).To(HaveLen(2), "Should be 2 matches")
					sha := match[1]

					// confirm that the file is stored correctly
					err = CheckLOBFilesForSHA(sha, GetLocalLOBRoot(), false)
					Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail checking storage for %v", file))
				}
				// Commit & tag
				err := exec.Command("git", "commit", "-m", fmt.Sprintf("Commit %d", ci)).Run()
				Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail commit %d", ci))
				err = exec.Command("git", "tag", "-a", "-m", "Nothing", fmt.Sprintf("Tag%d", ci)).Run()
				Expect(err).To(BeNil(), fmt.Sprintf("Shouldn't fail tagging %d", ci))

				checkGitStatusNotModified()
			}

			// Now check out a few times to make sure working copy changes appropriately
			err := exec.Command("git", "checkout", "Tag0").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkNotExists(1)
			checkNotExists(2)
			checkGitStatusNotModified()

			err = exec.Command("git", "checkout", "Tag1").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkExistsAndRightSize(1)
			checkNotExists(2)
			checkGitStatusNotModified()

			err = exec.Command("git", "checkout", "Tag2").Run()
			Expect(err).To(BeNil(), "Shouldn't fail to checkout")
			checkExistsAndRightSize(0)
			checkExistsAndRightSize(1)
			checkExistsAndRightSize(2)
			checkGitStatusNotModified()

		})

	})
})
<|endoftext|>


<commit_before>package juggler_test

import (
	"net/http/httptest"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/PuerkitoBio/exp/juggler"
	"github.com/PuerkitoBio/exp/juggler/broker/redisbroker"
	"github.com/PuerkitoBio/exp/juggler/callee"
	"github.com/PuerkitoBio/exp/juggler/internal/jugglertest"
	"github.com/PuerkitoBio/exp/juggler/internal/redistest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
)

// IntgConfig holds the configuration of an integration test execution.
type IntgConfig struct {
	RedisPoolMaxActive   int
	RedisPoolMaxIdle     int
	RedisPoolIdleTimeout time.Duration

	BrokerBlockingTimeout time.Duration
	BrokerCallCap         int
	BrokerResultCap       int

	ServerReadLimit               int64
	ServerReadTimeout             time.Duration
	ServerWriteLimit              int64
	ServerWriteTimeout            time.Duration
	ServerAcquireWriteLockTimeout time.Duration

	NCallees          int // number of callees listening on the URIs
	NWorkersPerCallee int // number of workers per callee
	NClients          int // number of clients generating calls

	NURIs         int           // number of different URIs to pick from at random
	NChannels     int           // number of different channels to pick from at random
	Duration      time.Duration // duration of the test
	ClientMsgRate time.Duration // send a message at this rate
	ServerPubRate time.Duration // publish a server-side event at this rate
	ThunkDelay    time.Duration // artificial delay of the call
}

type runStats struct {
	Call    int64
	Pub     int64
	Sub     int64
	Unsb    int64
	Exp     int64
	OK      int64
	Err     int64
	Res     int64
	Evnt    int64
	Unknown int64
}

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("integration tests don't run with the -short flag")
	}
	runIntegrationTest(t, &IntgConfig{}) // TODO : parse flags into IntgConfig
}

func incStats(stats *runStats, m msg.Msg) {
	switch m.Type() {
	case msg.CallMsg:
		atomic.AddInt64(&stats.Call, 1)
	case msg.PubMsg:
		atomic.AddInt64(&stats.Pub, 1)
	case msg.SubMsg:
		atomic.AddInt64(&stats.Sub, 1)
	case msg.UnsbMsg:
		atomic.AddInt64(&stats.Unsb, 1)
	case msg.ExpMsg:
		atomic.AddInt64(&stats.Exp, 1)
	case msg.OKMsg:
		atomic.AddInt64(&stats.OK, 1)
	case msg.ErrMsg:
		atomic.AddInt64(&stats.Err, 1)
	case msg.ResMsg:
		atomic.AddInt64(&stats.Res, 1)
	case msg.EvntMsg:
		atomic.AddInt64(&stats.Evnt, 1)
	default:
		atomic.AddInt64(&stats.Unknown, 1)
	}
}

func serverStatsHandler(stats *runStats) juggler.Handler {
	return juggler.HandlerFunc(func(ctx context.Context, c *juggler.Conn, m msg.Msg) {
		incStats(stats, m)
		juggler.ProcessMsg(ctx, c, m)
	})
}

func clientStatsHandler(stats *runStats) juggler.ClientHandler {
	return juggler.ClientHandlerFunc(func(ctx context.Context, c *juggler.Client, m msg.Msg) {
		incStats(stats, m)
	})
}

func runIntegrationTest(t *testing.T, conf *IntgConfig) {
	dbgl := &jugglertest.DebugLog{T: t}

	// start/create:
	// 1. redis-server
	// 2. redis pool and broker
	// 3. juggler server
	// 4. m callees
	// 5. n clients

	// 1. redis-server
	cmd, port := redistest.StartServer(t, nil)
	defer cmd.Process.Kill()

	// 2. create the redis pool and broker
	pool := redistest.NewPool(t, ":"+port)
	pool.MaxActive = conf.RedisPoolMaxActive
	pool.MaxIdle = conf.RedisPoolMaxIdle
	pool.IdleTimeout = conf.RedisPoolIdleTimeout
	brk := &redisbroker.Broker{
		Pool:    pool,
		Dial:    pool.Dial,
		LogFunc: dbgl.Printf,

		BlockingTimeout: conf.BrokerBlockingTimeout,
		CallCap:         conf.BrokerCallCap,
		ResultCap:       conf.BrokerResultCap,
	}

	// 3. create the juggler server
	var srvStats runStats
	srv := &juggler.Server{
		CallerBroker: brk,
		PubSubBroker: brk,
		LogFunc:      dbgl.Printf,

		ReadHandler:  serverStatsHandler(&srvStats),
		WriteHandler: serverStatsHandler(&srvStats),

		ReadLimit:               conf.ServerReadLimit,
		ReadTimeout:             conf.ServerReadTimeout,
		WriteLimit:              conf.ServerWriteLimit,
		WriteTimeout:            conf.ServerWriteTimeout,
		AcquireWriteLockTimeout: conf.ServerAcquireWriteLockTimeout,
	}
	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	httpsrv := httptest.NewServer(juggler.Upgrade(upg, srv))
	defer httpsrv.Close()

	// TODO : get URIs
	uris := []string{}
	thunk := func(cp *msg.CallPayload) (interface{}, error) {
		time.Sleep(conf.ThunkDelay)
		return "ok", nil
	}

	// 4. start m callees
	calleeStarted := make(chan struct{})
	for i := 0; i < conf.NCallees; i++ {
		go func() {
			cle := callee.Callee{
				Broker:  brk,
				LogFunc: dbgl.Printf,
			}

			conn, err := brk.Calls(uris...)
			if err != nil {
				t.Fatalf("failed to get CallsConn: %v", err)
			}
			defer conn.Close()
			ch := conn.Calls()

			for j := 0; j < conf.NWorkersPerCallee; j++ {
				go func() {
					calleeStarted <- struct{}{}
					for cp := range ch {
						if err := cle.InvokeAndStoreResult(cp, thunk); err != nil {
							t.Fatalf("InvokeAndStoreResult failed: %v", err)
						}
					}
				}()
			}
		}()
	}

	// 5. start n clients
	var clientStats runStats
	clientStarted := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(conf.NClients)

	for i := 0; i < conf.NClients; i++ {
		go func() {
			defer wg.Done()

			cli, err := juggler.Dial(&websocket.Dialer{}, strings.Replace(httpsrv.URL, "http:", "ws:", 1), nil,
				juggler.SetHandler(clientStatsHandler(&clientStats)))
			if err != nil {
				t.Fatalf("Dial failed: %v", err)
			}
			_ = cli

			// TODO : run predetermined requests...
			clientStarted <- struct{}{}
		}()
	}

	// wait for callees to come online
	for i, cnt := 0, conf.NCallees*conf.NWorkersPerCallee; i < cnt; i++ {
		<-calleeStarted
	}
	// start clients
	for i := 0; i < conf.NClients; i++ {
		<-clientStarted
	}
	// wait for completion
	wg.Wait()
}
<commit_msg>juggler: prepare execution<commit_after>package juggler_test

import (
	"net/http/httptest"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/PuerkitoBio/exp/juggler"
	"github.com/PuerkitoBio/exp/juggler/broker/redisbroker"
	"github.com/PuerkitoBio/exp/juggler/callee"
	"github.com/PuerkitoBio/exp/juggler/internal/jugglertest"
	"github.com/PuerkitoBio/exp/juggler/internal/redistest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
	"github.com/stretchr/testify/require"
)

// IntgConfig holds the configuration of an integration test execution.
type IntgConfig struct {
	RedisPoolMaxActive   int
	RedisPoolMaxIdle     int
	RedisPoolIdleTimeout time.Duration

	BrokerBlockingTimeout time.Duration
	BrokerCallCap         int
	BrokerResultCap       int

	ServerReadLimit               int64
	ServerReadTimeout             time.Duration
	ServerWriteLimit              int64
	ServerWriteTimeout            time.Duration
	ServerAcquireWriteLockTimeout time.Duration

	NCallees          int // number of callees listening on the URIs
	NWorkersPerCallee int // number of workers per callee
	NClients          int // number of clients generating calls

	NURIs         int           // number of different URIs to pick from at random
	NChannels     int           // number of different channels to pick from at random
	Duration      time.Duration // duration of the test
	ClientMsgRate time.Duration // send a message at this rate
	ServerPubRate time.Duration // publish a server-side event at this rate
	ThunkDelay    time.Duration // artificial delay of the call
}

func (conf *IntgConfig) URIs() []string {
	uris := make([]string, conf.NURIs)
	for i := 0; i < conf.NURIs; i++ {
		uris[i] = strconv.Itoa(i)
	}
	return uris
}

type runStats struct {
	Call    int64
	Pub     int64
	Sub     int64
	Unsb    int64
	Exp     int64
	OK      int64
	Err     int64
	Res     int64
	Evnt    int64
	Unknown int64
}

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("integration tests don't run with the -short flag")
	}
	runIntegrationTest(t, &IntgConfig{}) // TODO : parse flags into IntgConfig
}

func incStats(stats *runStats, m msg.Msg) {
	switch m.Type() {
	case msg.CallMsg:
		atomic.AddInt64(&stats.Call, 1)
	case msg.PubMsg:
		atomic.AddInt64(&stats.Pub, 1)
	case msg.SubMsg:
		atomic.AddInt64(&stats.Sub, 1)
	case msg.UnsbMsg:
		atomic.AddInt64(&stats.Unsb, 1)
	case msg.ExpMsg:
		atomic.AddInt64(&stats.Exp, 1)
	case msg.OKMsg:
		atomic.AddInt64(&stats.OK, 1)
	case msg.ErrMsg:
		atomic.AddInt64(&stats.Err, 1)
	case msg.ResMsg:
		atomic.AddInt64(&stats.Res, 1)
	case msg.EvntMsg:
		atomic.AddInt64(&stats.Evnt, 1)
	default:
		atomic.AddInt64(&stats.Unknown, 1)
	}
}

func serverHandler(stats *runStats) juggler.Handler {
	return juggler.HandlerFunc(func(ctx context.Context, c *juggler.Conn, m msg.Msg) {
		incStats(stats, m)
		juggler.ProcessMsg(ctx, c, m)
	})
}

func clientHandler(stats *runStats) juggler.ClientHandler {
	return juggler.ClientHandlerFunc(func(ctx context.Context, c *juggler.Client, m msg.Msg) {
		incStats(stats, m)
	})
}

type runConfig struct {
	conf *IntgConfig

	msgsPerClient [][]msg.Msg
	serverPubs    []msg.Msg
}

func prepareExec(conf *IntgConfig) *runConfig {
	return &runConfig{conf: conf}
}

func runIntegrationTest(t *testing.T, conf *IntgConfig) {
	dbgl := &jugglertest.DebugLog{T: t}

	// start/create:
	// 1. redis-server
	// 2. redis pool and broker
	// 3. juggler server
	// 4. m callees
	// 5. n clients

	// 1. redis-server
	cmd, port := redistest.StartServer(t, nil)
	defer cmd.Process.Kill()

	// 2. create the redis pool and broker
	pool := redistest.NewPool(t, ":"+port)
	pool.MaxActive = conf.RedisPoolMaxActive
	pool.MaxIdle = conf.RedisPoolMaxIdle
	pool.IdleTimeout = conf.RedisPoolIdleTimeout
	brk := &redisbroker.Broker{
		Pool:    pool,
		Dial:    pool.Dial,
		LogFunc: dbgl.Printf,

		BlockingTimeout: conf.BrokerBlockingTimeout,
		CallCap:         conf.BrokerCallCap,
		ResultCap:       conf.BrokerResultCap,
	}

	// 3. create the juggler server
	var srvStats runStats
	srv := &juggler.Server{
		CallerBroker: brk,
		PubSubBroker: brk,
		LogFunc:      dbgl.Printf,

		ReadHandler:  serverHandler(&srvStats),
		WriteHandler: serverHandler(&srvStats),

		ReadLimit:               conf.ServerReadLimit,
		ReadTimeout:             conf.ServerReadTimeout,
		WriteLimit:              conf.ServerWriteLimit,
		WriteTimeout:            conf.ServerWriteTimeout,
		AcquireWriteLockTimeout: conf.ServerAcquireWriteLockTimeout,
	}
	upg := &websocket.Upgrader{Subprotocols: juggler.Subprotocols}
	httpsrv := httptest.NewServer(juggler.Upgrade(upg, srv))
	defer httpsrv.Close()

	uris := conf.URIs()
	rc := prepareExec(conf)
	thunk := func(cp *msg.CallPayload) (interface{}, error) {
		time.Sleep(conf.ThunkDelay)
		return "ok", nil
	}

	// 4. start m callees
	calleeStarted := make(chan struct{})
	for i := 0; i < conf.NCallees; i++ {
		go func() {
			cle := callee.Callee{
				Broker:  brk,
				LogFunc: dbgl.Printf,
			}

			conn, err := brk.Calls(uris...)
			if err != nil {
				t.Fatalf("failed to get CallsConn: %v", err)
			}
			defer conn.Close()
			ch := conn.Calls()

			for j := 0; j < conf.NWorkersPerCallee; j++ {
				go func() {
					calleeStarted <- struct{}{}
					for cp := range ch {
						if err := cle.InvokeAndStoreResult(cp, thunk); err != nil {
							t.Fatalf("InvokeAndStoreResult failed: %v", err)
						}
					}
				}()
			}
		}()
	}

	// 5. start n clients
	var clientStats runStats
	clientStarted := make(chan struct{})
	wg := sync.WaitGroup{}
	wg.Add(conf.NClients)

	for i := 0; i < conf.NClients; i++ {
		go func(i int) {
			defer wg.Done()

			cli, err := juggler.Dial(&websocket.Dialer{}, strings.Replace(httpsrv.URL, "http:", "ws:", 1), nil,
				juggler.SetHandler(clientHandler(&clientStats)))
			if err != nil {
				t.Fatalf("Dial failed: %v", err)
			}

			clientStarted <- struct{}{}
			for _, m := range rc.msgsPerClient[i] {
			}
			require.NoError(t, cli.Close(), "Close client %d", i)
		}(i)
	}

	// wait for callees to come online
	for i, cnt := 0, conf.NCallees*conf.NWorkersPerCallee; i < cnt; i++ {
		<-calleeStarted
	}
	// start clients
	for i := 0; i < conf.NClients; i++ {
		<-clientStarted
	}
	// wait for completion
	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver/utils"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pbds "github.com/brotherlogic/discogssyncer/server"
	pbdi "github.com/brotherlogic/discovery/proto"
	pbd "github.com/brotherlogic/godiscogs"
)

func findServer(name string) (string, int) {
	conn, err := grpc.Dial(utils.Discover, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Cannot reach discover server: %v (trying to discover %v)", err, name)
	}
	defer conn.Close()

	registry := pbdi.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	re := &pbdi.RegistryEntry{Name: name}
	r, err := registry.Discover(ctx, re)

	e, ok := status.FromError(err)
	if ok && e.Code() == codes.Unavailable {
		log.Printf("RETRY")
		r, err = registry.Discover(ctx, re)
	}

	if err != nil {
		return "", -1
	}
	return r.Ip, int(r.Port)
}

func run() {
	s := time.Now()
	host, port := findServer("discogssyncer")

	conn, err := grpc.Dial(host+":"+strconv.Itoa(port), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Cannot reach discover server: %v", err)
	}
	defer conn.Close()

	client := pbds.NewDiscogsServiceClient(conn)
	res, err := client.GetReleasesInFolder(context.Background(), &pbds.FolderList{Folders: []*pbd.Folder{&pbd.Folder{Id: 812802}}})
	if err != nil {
		log.Printf("ERROR: %v", err)
	}

	log.Printf("Found %v in %v", len(res.GetRecords()), time.Now().Sub(s))
}

func main() {
	run()
}
<commit_msg>Investigated slow metadata pull. This closes #246.<commit_after>package main

import (
	"context"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver/utils"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pbds "github.com/brotherlogic/discogssyncer/server"
	pbdi "github.com/brotherlogic/discovery/proto"
	pbd "github.com/brotherlogic/godiscogs"
)

func findServer(name string) (string, int) {
	conn, err := grpc.Dial(utils.Discover, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Cannot reach discover server: %v (trying to discover %v)", err, name)
	}
	defer conn.Close()

	registry := pbdi.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	re := &pbdi.RegistryEntry{Name: name}
	r, err := registry.Discover(ctx, re)

	e, ok := status.FromError(err)
	if ok && e.Code() == codes.Unavailable {
		log.Printf("RETRY")
		r, err = registry.Discover(ctx, re)
	}

	if err != nil {
		return "", -1
	}
	return r.Ip, int(r.Port)
}

func run() {
	s := time.Now()
	host, port := findServer("discogssyncer")

	conn, err := grpc.Dial(host+":"+strconv.Itoa(port), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Cannot reach discover server: %v", err)
	}
	defer conn.Close()

	client := pbds.NewDiscogsServiceClient(conn)
	res, err := client.GetReleasesInFolder(context.Background(), &pbds.FolderList{Folders: []*pbd.Folder{&pbd.Folder{Id: 812802}}})
	if err != nil {
		log.Printf("ERROR: %v", err)
	}

	log.Printf("Found %v in a total of %v", len(res.GetRecords()), time.Now().Sub(s))
}

func main() {
	run()
}
<|endoftext|>


<commit_before>package api

import (
	"goApiSample/core/helper"
	"net/http"

	. "goApiSample/core"
	. "goApiSample/core/dto"
	"goApiSample/service"

	"strings"

	"github.com/labstack/echo"
)

func Find(c echo.Context) error {
	dto := FruitQuery{}
	//1.check request format
	if err := c.Bind(&dto); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Object"))
	}
	//1.check condition
	if apiMessage := helper.CheckQueryCondition(&dto.APIParam, Fruit{}); apiMessage != nil {
		return c.JSON(http.StatusBadRequest, apiMessage)
	}

	//3.Query data
	if fruits, err := service.GetFruitService().Find(&dto); err != nil {
		return c.JSON(http.StatusInternalServerError, helper.SystemMessage(err.Error()))
	} else {
		if len(fruits) == 0 {
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: make([]interface{}, 0)}})
		}
		if len(dto.Fields) != 0 {
			fields := strings.Split(dto.Fields, ",")
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: helper.FilterFieldsMap(fruits, fields)}})
		} else {
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: fruits}})
		}
	}
}

func Get(c echo.Context) error {
	if code := c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))

	} else if _, fruits, err := service.GetFruitService().Get(code); err != nil {
		return c.JSON(http.StatusInternalServerError, helper.SystemMessage(err.Error()))
	} else {
		return c.JSON(http.StatusOK, APIResult{Success: true, Result: fruits})
	}
}

func Post(c echo.Context) error {
	fruitsParam := new([]Fruit)
	if err := c.Bind(fruitsParam); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Array"))
	} else {
		if apiError := service.GetFruitService().Post(fruitsParam); apiError != nil {
			if apiError.Code == 10001 {
				return c.JSON(http.StatusInternalServerError, apiError)
			} else {
				return c.JSON(http.StatusOK, apiError)
			}
		} else {
			return c.JSON(http.StatusCreated, APIResult{Success: true, Result: nil})
		}
	}
}

func Patch(c echo.Context) error {
	var code string
	if code = c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))
	}
	fruitsParam := new(Fruit)
	if err := c.Bind(fruitsParam); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Object"))
	} else {

		if affectedRows, e := service.GetFruitService().Patch(code, fruitsParam); e != nil {
			return c.JSON(http.StatusInternalServerError, helper.SystemMessage(e.Error()))
		} else if affectedRows == 0 {
			return c.JSON(http.StatusNotFound, helper.NewApiMessage(10010, "", "Code:"+code))
		} else {
			return c.JSON(http.StatusNoContent, APIResult{Success: true, Result: nil})
		}
	}
}

func Delete(c echo.Context) error {
	var code string
	if code = c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))
	} else {
		if apiError := service.GetFruitService().Delete(code); apiError != nil {
			if apiError.Code == 10001 {
				return c.JSON(http.StatusInternalServerError, apiError)
			} else if apiError.Code == 10010 {
				return c.JSON(http.StatusNotFound, apiError)
			} else {
				return c.JSON(http.StatusOK, apiError)
			}
		} else {
			return c.JSON(http.StatusNoContent, APIResult{Success: true, Result: nil})
		}
	}
}
<commit_msg>no data,return nil<commit_after>package api

import (
	"goApiSample/core/helper"
	"net/http"

	. "goApiSample/core"
	. "goApiSample/core/dto"
	"goApiSample/service"

	"strings"

	"github.com/labstack/echo"
)

func Find(c echo.Context) error {
	dto := FruitQuery{}
	//1.check request format
	if err := c.Bind(&dto); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Object"))
	}
	//1.check condition
	if apiMessage := helper.CheckQueryCondition(&dto.APIParam, Fruit{}); apiMessage != nil {
		return c.JSON(http.StatusBadRequest, apiMessage)
	}

	//3.Query data
	if fruits, err := service.GetFruitService().Find(&dto); err != nil {
		return c.JSON(http.StatusInternalServerError, helper.SystemMessage(err.Error()))
	} else {
		if len(fruits) == 0 {
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: make([]interface{}, 0)}})
		}
		if len(dto.Fields) != 0 {
			fields := strings.Split(dto.Fields, ",")
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: helper.FilterFieldsMap(fruits, fields)}})
		} else {
			return c.JSON(http.StatusOK, APIResult{Success: true, Result: QueryResult{TotalCount: len(fruits), Items: fruits}})
		}
	}
}

func Get(c echo.Context) error {
	if code := c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))

	} else if has, fruits, err := service.GetFruitService().Get(code); err != nil {
		return c.JSON(http.StatusInternalServerError, helper.SystemMessage(err.Error()))
	} else {
		if has == false {
			fruits = nil
		}
		return c.JSON(http.StatusOK, APIResult{Success: true, Result: fruits})
	}
}

func Post(c echo.Context) error {
	fruitsParam := new([]Fruit)
	if err := c.Bind(fruitsParam); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Array"))
	} else {
		if apiError := service.GetFruitService().Post(fruitsParam); apiError != nil {
			if apiError.Code == 10001 {
				return c.JSON(http.StatusInternalServerError, apiError)
			} else {
				return c.JSON(http.StatusOK, apiError)
			}
		} else {
			return c.JSON(http.StatusCreated, APIResult{Success: true, Result: nil})
		}
	}
}

func Patch(c echo.Context) error {
	var code string
	if code = c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))
	}
	fruitsParam := new(Fruit)
	if err := c.Bind(fruitsParam); err != nil {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10004, err.Error(), "Object"))
	} else {

		if affectedRows, e := service.GetFruitService().Patch(code, fruitsParam); e != nil {
			return c.JSON(http.StatusInternalServerError, helper.SystemMessage(e.Error()))
		} else if affectedRows == 0 {
			return c.JSON(http.StatusNotFound, helper.NewApiMessage(10010, "", "Code:"+code))
		} else {
			return c.JSON(http.StatusNoContent, APIResult{Success: true, Result: nil})
		}
	}
}

func Delete(c echo.Context) error {
	var code string
	if code = c.Param("Code"); len(code) == 0 {
		return c.JSON(http.StatusBadRequest, helper.NewApiMessage(10009, "", "Code"))
	} else {
		if apiError := service.GetFruitService().Delete(code); apiError != nil {
			if apiError.Code == 10001 {
				return c.JSON(http.StatusInternalServerError, apiError)
			} else if apiError.Code == 10010 {
				return c.JSON(http.StatusNotFound, apiError)
			} else {
				return c.JSON(http.StatusOK, apiError)
			}
		} else {
			return c.JSON(http.StatusNoContent, APIResult{Success: true, Result: nil})
		}
	}
}
<|endoftext|>


<commit_before>package api

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

	"github.com/Rugvip/bullettime/interfaces"

	"github.com/Rugvip/bullettime/types"

	"github.com/julienschmidt/httprouter"
)

func dummy() interface{} {
	return struct{}{}
}

type CreateRoomResponse struct {
	RoomId    types.RoomId `json:"room_id"`
	RoomAlias *types.Alias `json:"room_alias,omitempty"`
}

type eventIdResponse struct {
	EventId types.EventId `json:"event_id"`
}

type userRequest struct {
	UserId types.UserId `json:"user_id"`
}

func (e roomsEndpoint) createRoom(req *http.Request, body *types.RoomDescription) interface{} {
	creator, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	hostname := strings.Split(req.Host, ":")[0]
	room, alias, err := e.roomService.CreateRoom(hostname, creator, body)
	if err != nil {
		return err
	}
	return CreateRoomResponse{room, alias}
}

func (e roomsEndpoint) doWildcardJoin(req *http.Request, params httprouter.Params) interface{} {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	roomIdOrAlias := params[0].Value
	room, parseErr := types.ParseRoomId(roomIdOrAlias)
	if parseErr != nil {
		alias, parseErr := types.ParseAlias(roomIdOrAlias)
		if parseErr != nil {
			return types.BadParamError("invalid room id or alias: " + roomIdOrAlias)
		}
		room, err = e.roomService.LookupAlias(alias)
		if err != nil {
			return err
		}
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipMember
	_, err = e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return struct{}{}
}

func (e roomsEndpoint) sendMessage(req *http.Request, params httprouter.Params, content *map[string]interface{}) interface{} {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	room, parseErr := types.ParseRoomId(params[0].Value)
	if parseErr != nil {
		return types.BadParamError(parseErr.Error())
	}
	eventType := params[1].Value
	typedContent := types.NewGenericContent(*content, eventType)
	message, err := e.roomService.AddMessage(room, user, typedContent)
	if err != nil {
		return err
	}
	return eventIdResponse{message.EventId}
}

func (e roomsEndpoint) doInvite(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipInvited
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doKick(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipLeaving
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doBan(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipBanned
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doJoin(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipMember
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doKnock(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipKnocking
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doLeave(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipLeaving
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doInitialSync(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}

	query := req.URL.Query()
	limitStr := query.Get("limit")
	var limit uint64

	var parseErr error
	if limitStr == "" {
		limit = 10 //TODO: make configurable
	} else {
		limit, parseErr = strconv.ParseUint(limitStr, 10, 32)
		if parseErr != nil {
			return types.BadQueryError(parseErr.Error())
		}
		if limit > 100 {
			limit = 100 //TODO: make configurable
		}
	}

	roomSync, err := e.syncService.RoomSync(user, room, uint(limit))
	if err != nil {
		return err
	}
	return roomSync
}

func (e roomsEndpoint) handlePutState(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		WriteJsonResponseWithStatus(rw, err)
		return
	}
	eventType := params[1].Value
	stateKey := ""
	if len(params) > 2 {
		stateKey = params[2].Value
	}

	var content types.TypedContent
	switch eventType {
	case types.EventTypeMembership:
		content = &types.MembershipEventContent{}
	case types.EventTypeName:
		content = &types.NameEventContent{}
	case types.EventTypeTopic:
		content = &types.TopicEventContent{}
	case types.EventTypePowerLevels:
		content = &types.PowerLevelsEventContent{}
	case types.EventTypeJoinRules:
		content = &types.JoinRulesEventContent{}
	}
	var jsonErr error
	if content != nil {
		jsonErr = json.NewDecoder(req.Body).Decode(content)
	} else {
		genericContent := types.NewGenericContent(map[string]interface{}{}, eventType)
		content = genericContent
		jsonErr = json.NewDecoder(req.Body).Decode(&genericContent.Content)
	}
	if jsonErr != nil {
		switch err := jsonErr.(type) {
		case *json.SyntaxError:
			msg := fmt.Sprintf("error at [%d]: %s", err.Offset, err.Error())
			WriteJsonResponseWithStatus(rw, types.NotJsonError(msg))
		case *json.UnmarshalTypeError:
			msg := fmt.Sprintf("error at [%d]: expected type %s but got %s", err.Offset, err.Type, err.Value)
			WriteJsonResponseWithStatus(rw, types.BadJsonError(msg))
		default:
			WriteJsonResponseWithStatus(rw, types.BadJsonError(err.Error()))
		}
		return
	}
	state, err := e.roomService.SetState(room, user, content, stateKey)
	if err != nil {
		WriteJsonResponseWithStatus(rw, err)
		return
	}
	res := eventIdResponse{state.EventId}
	WriteJsonResponse(rw, 200, res)
}

func (e roomsEndpoint) getMessages(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}

	var from *types.StreamToken
	var to *types.StreamToken

	query := req.URL.Query()
	fromStr := query.Get("from")
	toStr := query.Get("to")
	dir := query.Get("dir")
	limitStr := query.Get("limit")

	if fromStr != "" {
		token, err := types.ParseStreamToken(fromStr)
		if err != nil {
			return types.BadQueryError(err.Error())
		}
		from = &token
	}

	if toStr != "" {
		token, err := types.ParseStreamToken(toStr)
		if err != nil {
			return types.BadQueryError(err.Error())
		}
		to = &token
	}

	if dir == "b" {
		token := types.NewStreamToken(0, 0, 0)
		to = &token
	}

	var limit uint64

	var parseErr error
	if limitStr == "" {
		limit = 10 //TODO: make configurable
	} else {
		limit, parseErr = strconv.ParseUint(limitStr, 10, 32)
		if parseErr != nil {
			return types.BadQueryError(parseErr.Error())
		}
		if limit > 100 {
			limit = 100 //TODO: make configurable
		}
	}
	eventRange, err := e.eventService.Messages(user, room, from, to, uint(limit))
	log.Println("TO", to, eventRange)
	if err != nil {
		return err
	}

	return eventRange
}

func (e roomsEndpoint) getRoomAndUser(req *http.Request, params httprouter.Params) (types.RoomId, types.UserId, types.Error) {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return types.RoomId{}, types.UserId{}, err
	}
	room, parseErr := types.ParseRoomId(params[0].Value)
	if parseErr != nil {
		return types.RoomId{}, types.UserId{}, types.BadParamError(parseErr.Error())
	}
	return room, user, nil
}

func (e roomsEndpoint) Register(mux *httprouter.Router) {
	mux.POST("/rooms/:roomId/send/:eventType", jsonHandler(e.sendMessage))
	mux.PUT("/rooms/:roomId/send/:eventType/:txn", jsonHandler(e.sendMessage))
	// mux.GET("/rooms/:roomId/state/:eventType", jsonHandler(dummy))
	mux.PUT("/rooms/:roomId/state/:eventType", e.handlePutState)
	mux.PUT("/rooms/:roomId/state/:eventType/:stateKey", e.handlePutState)
	// mux.GET("/rooms/:roomId/state/:eventType/:stateKey", jsonHandler(dummy))
	mux.POST("/rooms/:roomId/invite", jsonHandler(e.doInvite))
	mux.POST("/rooms/:roomId/kick", jsonHandler(e.doKick))
	mux.POST("/rooms/:roomId/ban", jsonHandler(e.doBan))
	mux.POST("/rooms/:roomId/join", jsonHandler(e.doJoin))
	mux.POST("/rooms/:roomId/knock", jsonHandler(e.doKnock))
	mux.POST("/rooms/:roomId/leave", jsonHandler(e.doLeave))
	mux.GET("/rooms/:roomId/messages", jsonHandler(e.getMessages))
	// mux.GET("/rooms/:roomId/members", jsonHandler(dummy))
	// mux.GET("/rooms/:roomId/state", jsonHandler(dummy))
	// mux.PUT("/rooms/:roomId/typing/:userId", jsonHandler(dummy))
	mux.GET("/rooms/:roomId/initialSync", jsonHandler(e.doInitialSync))
	mux.POST("/join/:roomAliasOrId", jsonHandler(e.doWildcardJoin))
	mux.POST("/createRoom", jsonHandler(e.createRoom))
}

type roomsEndpoint struct {
	userService  interfaces.UserService
	tokenService interfaces.TokenService
	roomService  interfaces.RoomService
	syncService  interfaces.SyncService
	eventService interfaces.EventService
}

func NewRoomsEndpoint(
	userService interfaces.UserService,
	tokenService interfaces.TokenService,
	roomService interfaces.RoomService,
	syncService interfaces.SyncService,
	eventService interfaces.EventService,
) Endpoint {
	return roomsEndpoint{
		userService,
		tokenService,
		roomService,
		syncService,
		eventService,
	}
}
<commit_msg>api/rooms: minor style fix, reordered handler<commit_after>package api

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

	"github.com/Rugvip/bullettime/interfaces"

	"github.com/Rugvip/bullettime/types"

	"github.com/julienschmidt/httprouter"
)

func dummy() interface{} {
	return struct{}{}
}

type CreateRoomResponse struct {
	RoomId    types.RoomId `json:"room_id"`
	RoomAlias *types.Alias `json:"room_alias,omitempty"`
}

type eventIdResponse struct {
	EventId types.EventId `json:"event_id"`
}

type userRequest struct {
	UserId types.UserId `json:"user_id"`
}

func (e roomsEndpoint) createRoom(req *http.Request, body *types.RoomDescription) interface{} {
	creator, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	hostname := strings.Split(req.Host, ":")[0]
	room, alias, err := e.roomService.CreateRoom(hostname, creator, body)
	if err != nil {
		return err
	}
	return CreateRoomResponse{room, alias}
}

func (e roomsEndpoint) doWildcardJoin(req *http.Request, params httprouter.Params) interface{} {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	roomIdOrAlias := params[0].Value
	room, parseErr := types.ParseRoomId(roomIdOrAlias)
	if parseErr != nil {
		alias, parseErr := types.ParseAlias(roomIdOrAlias)
		if parseErr != nil {
			return types.BadParamError("invalid room id or alias: " + roomIdOrAlias)
		}
		room, err = e.roomService.LookupAlias(alias)
		if err != nil {
			return err
		}
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipMember
	_, err = e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return struct{}{}
}

func (e roomsEndpoint) sendMessage(req *http.Request, params httprouter.Params, content *map[string]interface{}) interface{} {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return err
	}
	room, parseErr := types.ParseRoomId(params[0].Value)
	if parseErr != nil {
		return types.BadParamError(parseErr.Error())
	}
	eventType := params[1].Value
	typedContent := types.NewGenericContent(*content, eventType)
	message, err := e.roomService.AddMessage(room, user, typedContent)
	if err != nil {
		return err
	}
	return eventIdResponse{message.EventId}
}

func (e roomsEndpoint) doInvite(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipInvited
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doKick(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipLeaving
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doBan(req *http.Request, params httprouter.Params, body *userRequest) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipBanned
	state, err := e.roomService.SetState(room, user, &content, body.UserId.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doJoin(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipMember
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doKnock(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipKnocking
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doLeave(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}
	content := types.MembershipEventContent{}
	content.Membership = types.MembershipLeaving
	state, err := e.roomService.SetState(room, user, &content, user.String())
	if err != nil {
		return err
	}
	return eventIdResponse{state.EventId}
}

func (e roomsEndpoint) doInitialSync(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}

	query := req.URL.Query()
	limitStr := query.Get("limit")
	var limit uint64

	var parseErr error
	if limitStr == "" {
		limit = 10 //TODO: make configurable
	} else {
		limit, parseErr = strconv.ParseUint(limitStr, 10, 32)
		if parseErr != nil {
			return types.BadQueryError(parseErr.Error())
		}
		if limit > 100 {
			limit = 100 //TODO: make configurable
		}
	}

	roomSync, err := e.syncService.RoomSync(user, room, uint(limit))
	if err != nil {
		return err
	}
	return roomSync
}

func (e roomsEndpoint) handlePutState(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		WriteJsonResponseWithStatus(rw, err)
		return
	}
	eventType := params[1].Value
	stateKey := ""
	if len(params) > 2 {
		stateKey = params[2].Value
	}

	var content types.TypedContent
	switch eventType {
	case types.EventTypeMembership:
		content = &types.MembershipEventContent{}
	case types.EventTypeName:
		content = &types.NameEventContent{}
	case types.EventTypeTopic:
		content = &types.TopicEventContent{}
	case types.EventTypePowerLevels:
		content = &types.PowerLevelsEventContent{}
	case types.EventTypeJoinRules:
		content = &types.JoinRulesEventContent{}
	}
	var jsonErr error
	if content != nil {
		jsonErr = json.NewDecoder(req.Body).Decode(content)
	} else {
		genericContent := types.NewGenericContent(map[string]interface{}{}, eventType)
		content = genericContent
		jsonErr = json.NewDecoder(req.Body).Decode(&genericContent.Content)
	}
	if jsonErr != nil {
		switch err := jsonErr.(type) {
		case *json.SyntaxError:
			msg := fmt.Sprintf("error at [%d]: %s", err.Offset, err.Error())
			WriteJsonResponseWithStatus(rw, types.NotJsonError(msg))
		case *json.UnmarshalTypeError:
			msg := fmt.Sprintf("error at [%d]: expected type %s but got %s", err.Offset, err.Type, err.Value)
			WriteJsonResponseWithStatus(rw, types.BadJsonError(msg))
		default:
			WriteJsonResponseWithStatus(rw, types.BadJsonError(err.Error()))
		}
		return
	}
	state, err := e.roomService.SetState(room, user, content, stateKey)
	if err != nil {
		WriteJsonResponseWithStatus(rw, err)
		return
	}
	res := eventIdResponse{state.EventId}
	WriteJsonResponse(rw, 200, res)
}

func (e roomsEndpoint) getMessages(req *http.Request, params httprouter.Params) interface{} {
	room, user, err := e.getRoomAndUser(req, params)
	if err != nil {
		return err
	}

	var from *types.StreamToken
	var to *types.StreamToken

	query := req.URL.Query()
	fromStr := query.Get("from")
	toStr := query.Get("to")
	dir := query.Get("dir")
	limitStr := query.Get("limit")

	if fromStr != "" {
		token, err := types.ParseStreamToken(fromStr)
		if err != nil {
			return types.BadQueryError(err.Error())
		}
		from = &token
	}

	if toStr != "" {
		token, err := types.ParseStreamToken(toStr)
		if err != nil {
			return types.BadQueryError(err.Error())
		}
		to = &token
	}

	if dir == "b" {
		token := types.NewStreamToken(0, 0, 0)
		to = &token
	}

	var limit uint64

	var parseErr error
	if limitStr == "" {
		limit = 10 //TODO: make configurable
	} else {
		limit, parseErr = strconv.ParseUint(limitStr, 10, 32)
		if parseErr != nil {
			return types.BadQueryError(parseErr.Error())
		}
		if limit > 100 {
			limit = 100 //TODO: make configurable
		}
	}
	eventRange, err := e.eventService.Messages(user, room, from, to, uint(limit))
	log.Println("TO", to, eventRange)
	if err != nil {
		return err
	}

	return eventRange
}

func (e roomsEndpoint) getRoomAndUser(req *http.Request, params httprouter.Params) (types.RoomId, types.UserId, types.Error) {
	user, err := readAccessToken(e.userService, e.tokenService, req)
	if err != nil {
		return types.RoomId{}, types.UserId{}, err
	}
	room, parseErr := types.ParseRoomId(params[0].Value)
	if parseErr != nil {
		return types.RoomId{}, types.UserId{}, types.BadParamError(parseErr.Error())
	}
	return room, user, nil
}

func (e roomsEndpoint) Register(mux *httprouter.Router) {
	mux.POST("/rooms/:roomId/send/:eventType", jsonHandler(e.sendMessage))
	mux.PUT("/rooms/:roomId/send/:eventType/:txn", jsonHandler(e.sendMessage))
	mux.PUT("/rooms/:roomId/state/:eventType", e.handlePutState)
	mux.PUT("/rooms/:roomId/state/:eventType/:stateKey", e.handlePutState)
	// mux.GET("/rooms/:roomId/state/:eventType", jsonHandler(dummy))
	// mux.GET("/rooms/:roomId/state/:eventType/:stateKey", jsonHandler(dummy))
	mux.POST("/rooms/:roomId/invite", jsonHandler(e.doInvite))
	mux.POST("/rooms/:roomId/kick", jsonHandler(e.doKick))
	mux.POST("/rooms/:roomId/ban", jsonHandler(e.doBan))
	mux.POST("/rooms/:roomId/join", jsonHandler(e.doJoin))
	mux.POST("/rooms/:roomId/knock", jsonHandler(e.doKnock))
	mux.POST("/rooms/:roomId/leave", jsonHandler(e.doLeave))
	mux.GET("/rooms/:roomId/messages", jsonHandler(e.getMessages))
	// mux.GET("/rooms/:roomId/members", jsonHandler(dummy))
	// mux.GET("/rooms/:roomId/state", jsonHandler(dummy))
	// mux.PUT("/rooms/:roomId/typing/:userId", jsonHandler(dummy))
	mux.GET("/rooms/:roomId/initialSync", jsonHandler(e.doInitialSync))
	mux.POST("/join/:roomAliasOrId", jsonHandler(e.doWildcardJoin))
	mux.POST("/createRoom", jsonHandler(e.createRoom))
}

type roomsEndpoint struct {
	userService  interfaces.UserService
	tokenService interfaces.TokenService
	roomService  interfaces.RoomService
	syncService  interfaces.SyncService
	eventService interfaces.EventService
}

func NewRoomsEndpoint(
	userService interfaces.UserService,
	tokenService interfaces.TokenService,
	roomService interfaces.RoomService,
	syncService interfaces.SyncService,
	eventService interfaces.EventService,
) Endpoint {
	return roomsEndpoint{
		userService,
		tokenService,
		roomService,
		syncService,
		eventService,
	}
}
<|endoftext|>


<commit_before>package api

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/swarm/cluster"
)

// Emit an HTTP error and log it.
func httpError(w http.ResponseWriter, err string, status int) {
	log.WithField("status", status).Errorf("HTTP error: %v", err)
	http.Error(w, err, status)
}

func sendJSONMessage(w io.Writer, id, status string) {
	message := struct {
		ID       string      `json:"id,omitempty"`
		Status   string      `json:"status,omitempty"`
		Progress interface{} `json:"progressDetail,omitempty"`
	}{
		id,
		status,
		struct{}{}, // this is required by the docker cli to have a proper display
	}
	json.NewEncoder(w).Encode(message)
}

func sendErrorJSONMessage(w io.Writer, errorCode int, errorMessage string) {
	error := struct {
		Code    int    `json:"code,omitempty"`
		Message string `json:"message,omitempty"`
	}{
		errorCode,
		errorMessage,
	}

	message := struct {
		ErrorMsg string      `json:"error,omitempty"`
		Error    interface{} `json:"errorDetail,omitempty"`
	}{
		errorMessage,
		&error,
	}

	json.NewEncoder(w).Encode(message)
}

func getContainerFromVars(c *context, vars map[string]string) (string, *cluster.Container, error) {
	if name, ok := vars["name"]; ok {
		if container := c.cluster.Container(name); container != nil {
			if !container.Engine.IsHealthy() {
				return name, container, fmt.Errorf("Container %s running on unhealthy node %s", name, container.Engine.Name)
			}
			return name, container, nil
		}
		return name, nil, fmt.Errorf("No such container: %s", name)
	}

	if ID, ok := vars["execid"]; ok {
		for _, container := range c.cluster.Containers() {
			for _, execID := range container.Info.ExecIDs {
				if ID == execID {
					return "", container, nil
				}
			}
		}
		return "", nil, fmt.Errorf("Exec %s not found", ID)
	}

	return "", nil, errors.New("Not found")
}

// from https://github.com/golang/go/blob/master/src/net/http/httputil/reverseproxy.go#L82
func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

// prevents leak with https
func closeIdleConnections(client *http.Client) {
	if tr, ok := client.Transport.(*http.Transport); ok {
		tr.CloseIdleConnections()
	}
}

func proxyAsync(engine *cluster.Engine, w http.ResponseWriter, r *http.Request, callback func(*http.Response)) error {
	// RequestURI may not be sent to client
	r.RequestURI = ""

	client, scheme := engine.HTTPClientAndScheme()

	r.URL.Scheme = scheme
	r.URL.Host = engine.Addr

	log.WithFields(log.Fields{"method": r.Method, "url": r.URL}).Debug("Proxy request")
	resp, err := client.Do(r)
	if err != nil {
		return err
	}

	copyHeader(w.Header(), resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(NewWriteFlusher(w), resp.Body)

	if callback != nil {
		callback(resp)
	}

	// cleanup
	resp.Body.Close()

	return nil
}

func proxy(engine *cluster.Engine, w http.ResponseWriter, r *http.Request) error {
	return proxyAsync(engine, w, r, nil)
}

type tlsClientConn struct {
	*tls.Conn
	rawConn net.Conn
}

func (c *tlsClientConn) CloseWrite() error {
	// Go standard tls.Conn doesn't provide the CloseWrite() method so we do it
	// on its underlying connection.
	if cwc, ok := c.rawConn.(interface {
		CloseWrite() error
	}); ok {
		log.Debug("Calling CloseWrite on Hijacked TLS Conn")
		return cwc.CloseWrite()
	}
	return nil
}

// We need to copy Go's implementation of tls.Dial (pkg/cryptor/tls/tls.go) in
// order to return our custom tlsClientCon struct which holds both the tls.Conn
// object _and_ its underlying raw connection. The rationale for this is that
// we need to be able to close the write end of the connection when attaching,
// which tls.Conn does not provide.
func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) {
	// We want the Timeout and Deadline values from dialer to cover the
	// whole process: TCP connection and TLS handshake. This means that we
	// also need to start our own timers now.
	timeout := dialer.Timeout

	if !dialer.Deadline.IsZero() {
		deadlineTimeout := dialer.Deadline.Sub(time.Now())
		if timeout == 0 || deadlineTimeout < timeout {
			timeout = deadlineTimeout
		}
	}

	var errChannel chan error

	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- errors.New("")
		})
	}

	rawConn, err := dialer.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	// When we set up a TCP connection for hijack, there could be long periods
	// of inactivity (a long running command with no output) that in certain
	// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
	// state. Setting TCP KeepAlive on the socket connection will prohibit
	// ECONNTIMEOUT unless the socket connection truly is broken
	if tcpConn, ok := rawConn.(*net.TCPConn); ok {
		tcpConn.SetKeepAlive(true)
		tcpConn.SetKeepAlivePeriod(30 * time.Second)
	}

	colonPos := strings.LastIndex(addr, ":")
	if colonPos == -1 {
		colonPos = len(addr)
	}
	hostname := addr[:colonPos]

	// If no ServerName is set, infer the ServerName
	// from the hostname we're connecting to.
	if config.ServerName == "" {
		// Make a copy to avoid polluting argument or default.
		c := *config
		c.ServerName = hostname
		config = &c
	}

	conn := tls.Client(rawConn, config)

	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()

		err = <-errChannel
	}

	if err != nil {
		rawConn.Close()
		return nil, err
	}

	// This is Docker difference with standard's crypto/tls package: returned a
	// wrapper which holds both the TLS and raw connections.
	return &tlsClientConn{conn, rawConn}, nil
}

func dialHijack(tlsConfig *tls.Config, addr string) (net.Conn, error) {
	if tlsConfig == nil {
		return net.Dial("tcp", addr)
	}
	return tlsDialWithDialer(new(net.Dialer), "tcp", addr, tlsConfig)
}

func hijack(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request) error {
	if parts := strings.SplitN(addr, "://", 2); len(parts) == 2 {
		addr = parts[1]
	}

	log.WithField("addr", addr).Debug("Proxy hijack request")

	var (
		d   net.Conn
		err error
	)

	d, err = dialHijack(tlsConfig, addr)
	if err != nil {
		return err
	}
	hj, ok := w.(http.Hijacker)
	if !ok {
		return err
	}
	nc, _, err := hj.Hijack()
	if err != nil {
		return err
	}
	defer nc.Close()
	defer d.Close()

	err = r.Write(d)
	if err != nil {
		return err
	}

	cp := func(dst io.Writer, src io.Reader, chDone chan struct{}) {
		io.Copy(dst, src)
		if conn, ok := dst.(interface {
			CloseWrite() error
		}); ok {
			conn.CloseWrite()
		}
		close(chDone)
	}
	inDone := make(chan struct{})
	outDone := make(chan struct{})
	go cp(d, nc, inDone)
	go cp(nc, d, outDone)

	// 1. When stdin is done, wait for stdout always
	// 2. When stdout is done, close the stream and wait for stdin to finish
	//
	// On 2, stdin copy should return immediately now since the out stream is closed.
	// Note that we probably don't actually even need to wait here.
	//
	// If we don't close the stream when stdout is done, in some cases stdin will hange
	select {
	case <-inDone:
		// wait for out to be done
		<-outDone
	case <-outDone:
		// close the conn and wait for stdin
		nc.Close()
		<-inDone
	}
	return nil
}

func boolValue(r *http.Request, k string) bool {
	s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
	return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
}

func intValueOrZero(r *http.Request, k string) int {
	val, err := strconv.Atoi(r.FormValue(k))
	if err != nil {
		return 0
	}
	return val
}

func int64ValueOrZero(r *http.Request, k string) int64 {
	val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
	if err != nil {
		return 0
	}
	return val
}

func tagHasDigest(tag string) bool {
	return strings.Contains(tag, ":")
}
<commit_msg>Remove closeIdleConnections function.<commit_after>package api

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/swarm/cluster"
)

// Emit an HTTP error and log it.
func httpError(w http.ResponseWriter, err string, status int) {
	log.WithField("status", status).Errorf("HTTP error: %v", err)
	http.Error(w, err, status)
}

func sendJSONMessage(w io.Writer, id, status string) {
	message := struct {
		ID       string      `json:"id,omitempty"`
		Status   string      `json:"status,omitempty"`
		Progress interface{} `json:"progressDetail,omitempty"`
	}{
		id,
		status,
		struct{}{}, // this is required by the docker cli to have a proper display
	}
	json.NewEncoder(w).Encode(message)
}

func sendErrorJSONMessage(w io.Writer, errorCode int, errorMessage string) {
	error := struct {
		Code    int    `json:"code,omitempty"`
		Message string `json:"message,omitempty"`
	}{
		errorCode,
		errorMessage,
	}

	message := struct {
		ErrorMsg string      `json:"error,omitempty"`
		Error    interface{} `json:"errorDetail,omitempty"`
	}{
		errorMessage,
		&error,
	}

	json.NewEncoder(w).Encode(message)
}

func getContainerFromVars(c *context, vars map[string]string) (string, *cluster.Container, error) {
	if name, ok := vars["name"]; ok {
		if container := c.cluster.Container(name); container != nil {
			if !container.Engine.IsHealthy() {
				return name, container, fmt.Errorf("Container %s running on unhealthy node %s", name, container.Engine.Name)
			}
			return name, container, nil
		}
		return name, nil, fmt.Errorf("No such container: %s", name)
	}

	if ID, ok := vars["execid"]; ok {
		for _, container := range c.cluster.Containers() {
			for _, execID := range container.Info.ExecIDs {
				if ID == execID {
					return "", container, nil
				}
			}
		}
		return "", nil, fmt.Errorf("Exec %s not found", ID)
	}

	return "", nil, errors.New("Not found")
}

// from https://github.com/golang/go/blob/master/src/net/http/httputil/reverseproxy.go#L82
func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func proxyAsync(engine *cluster.Engine, w http.ResponseWriter, r *http.Request, callback func(*http.Response)) error {
	// RequestURI may not be sent to client
	r.RequestURI = ""

	client, scheme := engine.HTTPClientAndScheme()

	r.URL.Scheme = scheme
	r.URL.Host = engine.Addr

	log.WithFields(log.Fields{"method": r.Method, "url": r.URL}).Debug("Proxy request")
	resp, err := client.Do(r)
	if err != nil {
		return err
	}

	copyHeader(w.Header(), resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(NewWriteFlusher(w), resp.Body)

	if callback != nil {
		callback(resp)
	}

	// cleanup
	resp.Body.Close()

	return nil
}

func proxy(engine *cluster.Engine, w http.ResponseWriter, r *http.Request) error {
	return proxyAsync(engine, w, r, nil)
}

type tlsClientConn struct {
	*tls.Conn
	rawConn net.Conn
}

func (c *tlsClientConn) CloseWrite() error {
	// Go standard tls.Conn doesn't provide the CloseWrite() method so we do it
	// on its underlying connection.
	if cwc, ok := c.rawConn.(interface {
		CloseWrite() error
	}); ok {
		log.Debug("Calling CloseWrite on Hijacked TLS Conn")
		return cwc.CloseWrite()
	}
	return nil
}

// We need to copy Go's implementation of tls.Dial (pkg/cryptor/tls/tls.go) in
// order to return our custom tlsClientCon struct which holds both the tls.Conn
// object _and_ its underlying raw connection. The rationale for this is that
// we need to be able to close the write end of the connection when attaching,
// which tls.Conn does not provide.
func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Config) (net.Conn, error) {
	// We want the Timeout and Deadline values from dialer to cover the
	// whole process: TCP connection and TLS handshake. This means that we
	// also need to start our own timers now.
	timeout := dialer.Timeout

	if !dialer.Deadline.IsZero() {
		deadlineTimeout := dialer.Deadline.Sub(time.Now())
		if timeout == 0 || deadlineTimeout < timeout {
			timeout = deadlineTimeout
		}
	}

	var errChannel chan error

	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- errors.New("")
		})
	}

	rawConn, err := dialer.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	// When we set up a TCP connection for hijack, there could be long periods
	// of inactivity (a long running command with no output) that in certain
	// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
	// state. Setting TCP KeepAlive on the socket connection will prohibit
	// ECONNTIMEOUT unless the socket connection truly is broken
	if tcpConn, ok := rawConn.(*net.TCPConn); ok {
		tcpConn.SetKeepAlive(true)
		tcpConn.SetKeepAlivePeriod(30 * time.Second)
	}

	colonPos := strings.LastIndex(addr, ":")
	if colonPos == -1 {
		colonPos = len(addr)
	}
	hostname := addr[:colonPos]

	// If no ServerName is set, infer the ServerName
	// from the hostname we're connecting to.
	if config.ServerName == "" {
		// Make a copy to avoid polluting argument or default.
		c := *config
		c.ServerName = hostname
		config = &c
	}

	conn := tls.Client(rawConn, config)

	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()

		err = <-errChannel
	}

	if err != nil {
		rawConn.Close()
		return nil, err
	}

	// This is Docker difference with standard's crypto/tls package: returned a
	// wrapper which holds both the TLS and raw connections.
	return &tlsClientConn{conn, rawConn}, nil
}

func dialHijack(tlsConfig *tls.Config, addr string) (net.Conn, error) {
	if tlsConfig == nil {
		return net.Dial("tcp", addr)
	}
	return tlsDialWithDialer(new(net.Dialer), "tcp", addr, tlsConfig)
}

func hijack(tlsConfig *tls.Config, addr string, w http.ResponseWriter, r *http.Request) error {
	if parts := strings.SplitN(addr, "://", 2); len(parts) == 2 {
		addr = parts[1]
	}

	log.WithField("addr", addr).Debug("Proxy hijack request")

	var (
		d   net.Conn
		err error
	)

	d, err = dialHijack(tlsConfig, addr)
	if err != nil {
		return err
	}
	hj, ok := w.(http.Hijacker)
	if !ok {
		return err
	}
	nc, _, err := hj.Hijack()
	if err != nil {
		return err
	}
	defer nc.Close()
	defer d.Close()

	err = r.Write(d)
	if err != nil {
		return err
	}

	cp := func(dst io.Writer, src io.Reader, chDone chan struct{}) {
		io.Copy(dst, src)
		if conn, ok := dst.(interface {
			CloseWrite() error
		}); ok {
			conn.CloseWrite()
		}
		close(chDone)
	}
	inDone := make(chan struct{})
	outDone := make(chan struct{})
	go cp(d, nc, inDone)
	go cp(nc, d, outDone)

	// 1. When stdin is done, wait for stdout always
	// 2. When stdout is done, close the stream and wait for stdin to finish
	//
	// On 2, stdin copy should return immediately now since the out stream is closed.
	// Note that we probably don't actually even need to wait here.
	//
	// If we don't close the stream when stdout is done, in some cases stdin will hange
	select {
	case <-inDone:
		// wait for out to be done
		<-outDone
	case <-outDone:
		// close the conn and wait for stdin
		nc.Close()
		<-inDone
	}
	return nil
}

func boolValue(r *http.Request, k string) bool {
	s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
	return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
}

func intValueOrZero(r *http.Request, k string) int {
	val, err := strconv.Atoi(r.FormValue(k))
	if err != nil {
		return 0
	}
	return val
}

func int64ValueOrZero(r *http.Request, k string) int64 {
	val, err := strconv.ParseInt(r.FormValue(k), 10, 64)
	if err != nil {
		return 0
	}
	return val
}

func tagHasDigest(tag string) bool {
	return strings.Contains(tag, ":")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
)

func (db EtcdDB) GetConfig() (*Config, error) {
	fmt.Println("Getting CONFIG")

	etc := db.client

	fmt.Println("precreate")
	etc.CreateDir("config", 0)
	fmt.Println("postcreate")

	cfg := new(Config)

	// Hostname
	{
		var hostname string
		if len(os.Getenv("NETCORE_NAME")) > 0 {
			hostname = os.Getenv("NETCORE_NAME")
		} else if len(os.Getenv("ETCD_NAME")) > 0 {
			re := regexp.MustCompile(`^/([^/]+)/`)
			hostnameParts := re.FindStringSubmatch(os.Getenv("ETCD_NAME"))
			if len(hostnameParts) > 1 && len(hostnameParts[1]) > 0 {
				hostname = hostnameParts[1]
			}
		} else {
			var err error
			hostname, err = getHostname()
			if err != nil {
				return nil, err
			}
		}
		cfg.hostname = hostname
	}

	// Zone
	{
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/zone", *setZone, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/zone", false, false)
		}
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoZone
		}
		cfg.zone = response.Node.Value
	}

	// Domain
	{
		response, err := etc.Get("config/"+cfg.zone+"/domain", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.domain = response.Node.Value
		}
	}

	// Subnet
	{
		response, err := etc.Get("config/"+cfg.zone+"/subnet", false, false)
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoZone
		}
		_, subnet, err := net.ParseCIDR(response.Node.Value)
		if err != nil {
			return nil, err
		}
		cfg.subnet = subnet
	}

	// Gateway
	{
		response, err := etc.Get("config/"+cfg.zone+"/gateway", false, false)
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoGateway
		}
		gateway := net.ParseIP(response.Node.Value).To4()
		cfg.gateway = gateway
	}

	// DHCPIP
	{
		var response *etcd.Response
		var err error
		if setDHCPIP != nil && *setDHCPIP != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcpip", *setDHCPIP, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcpip", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			dhcpIP := net.ParseIP(response.Node.Value).To4()
			cfg.dhcpIP = dhcpIP
		}
	}

	// DHCPNIC
	{
		var response *etcd.Response
		var err error
		if setDHCPNIC != nil && *setDHCPNIC != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcpnic", *setDHCPNIC, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcpnic", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dhcpNIC = response.Node.Value
		}
	}

	// DHCPSubnet
	{
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" && setDHCPSubnet != nil && *setDHCPSubnet != "" {
			response, err = etc.Set("config/"+cfg.zone+"/dhcpsubnet", *setDHCPSubnet, 0)
		} else {
			response, err = etc.Get("config/"+cfg.zone+"/dhcpsubnet", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			_, dhcpSubnet, err := net.ParseCIDR(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dhcpSubnet = dhcpSubnet
		}
	}

	// DHCPLeaseDuration
	{
		cfg.dhcpLeaseDuration = 12 * time.Hour // default setting is 12 hours
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" && setDHCPLeaseDuration != nil && *setDHCPLeaseDuration != "" {
			response, err = etc.Set("config/"+cfg.zone+"/dhcpleaseduration", *setDHCPLeaseDuration, 0)
		} else {
			response, err = etc.Get("config/"+cfg.zone+"/dhcpleaseduration", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dhcpLeaseDuration = time.Duration(value) * time.Minute
		}
	}

	// DHCPTFTP
	{
		var response *etcd.Response
		var err error
		if setDHCPTFTP != nil && *setDHCPTFTP != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcptftp", *setDHCPTFTP, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcptftp", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dhcpTFTP = response.Node.Value
		}
	}

	// DNSForwarders
	{
		cfg.dnsForwarders = []string{"8.8.8.8:53", "8.8.4.4:53"} // default uses Google's Public DNS servers
		response, err := etc.Get("config/"+cfg.zone+"/dnsforwarders", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dnsForwarders = strings.Split(",", response.Node.Value)
		}
	}

	// dnsCacheMaxTTL
	{
		cfg.dnsCacheMaxTTL = 0 // default to no caching
		response, err := etc.Get("config/"+cfg.zone+"/dnscachemaxttl", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dnsCacheMaxTTL = time.Duration(value) * time.Second
		}
	}

	// dnsCacheMissingTTL
	{
		cfg.dnsCacheMissingTTL = 30 * time.Second // default setting is 30 seconds
		response, err := etc.Get("config/"+cfg.zone+"/dnscachemissingttl", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dnsCacheMissingTTL = time.Duration(value) * time.Second
		}
	}

	fmt.Printf("CONFIG: [%+v]\n", cfg)

	return cfg, nil
}
<commit_msg>Added missing db assignment for etcd configuration<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
)

func (db EtcdDB) GetConfig() (*Config, error) {
	fmt.Println("Getting CONFIG")

	etc := db.client

	fmt.Println("precreate")
	etc.CreateDir("config", 0)
	fmt.Println("postcreate")

	cfg := &Config{
		db: db,
	}

	// Hostname
	{
		var hostname string
		if len(os.Getenv("NETCORE_NAME")) > 0 {
			hostname = os.Getenv("NETCORE_NAME")
		} else if len(os.Getenv("ETCD_NAME")) > 0 {
			re := regexp.MustCompile(`^/([^/]+)/`)
			hostnameParts := re.FindStringSubmatch(os.Getenv("ETCD_NAME"))
			if len(hostnameParts) > 1 && len(hostnameParts[1]) > 0 {
				hostname = hostnameParts[1]
			}
		} else {
			var err error
			hostname, err = getHostname()
			if err != nil {
				return nil, err
			}
		}
		cfg.hostname = hostname
	}

	// Zone
	{
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/zone", *setZone, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/zone", false, false)
		}
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoZone
		}
		cfg.zone = response.Node.Value
	}

	// Domain
	{
		response, err := etc.Get("config/"+cfg.zone+"/domain", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.domain = response.Node.Value
		}
	}

	// Subnet
	{
		response, err := etc.Get("config/"+cfg.zone+"/subnet", false, false)
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoZone
		}
		_, subnet, err := net.ParseCIDR(response.Node.Value)
		if err != nil {
			return nil, err
		}
		cfg.subnet = subnet
	}

	// Gateway
	{
		response, err := etc.Get("config/"+cfg.zone+"/gateway", false, false)
		if err != nil {
			return nil, err
		}
		if response == nil || response.Node == nil || response.Node.Value == "" {
			return nil, ErrNoGateway
		}
		gateway := net.ParseIP(response.Node.Value).To4()
		cfg.gateway = gateway
	}

	// DHCPIP
	{
		var response *etcd.Response
		var err error
		if setDHCPIP != nil && *setDHCPIP != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcpip", *setDHCPIP, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcpip", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			dhcpIP := net.ParseIP(response.Node.Value).To4()
			cfg.dhcpIP = dhcpIP
		}
	}

	// DHCPNIC
	{
		var response *etcd.Response
		var err error
		if setDHCPNIC != nil && *setDHCPNIC != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcpnic", *setDHCPNIC, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcpnic", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dhcpNIC = response.Node.Value
		}
	}

	// DHCPSubnet
	{
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" && setDHCPSubnet != nil && *setDHCPSubnet != "" {
			response, err = etc.Set("config/"+cfg.zone+"/dhcpsubnet", *setDHCPSubnet, 0)
		} else {
			response, err = etc.Get("config/"+cfg.zone+"/dhcpsubnet", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			_, dhcpSubnet, err := net.ParseCIDR(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dhcpSubnet = dhcpSubnet
		}
	}

	// DHCPLeaseDuration
	{
		cfg.dhcpLeaseDuration = 12 * time.Hour // default setting is 12 hours
		var response *etcd.Response
		var err error
		if setZone != nil && *setZone != "" && setDHCPLeaseDuration != nil && *setDHCPLeaseDuration != "" {
			response, err = etc.Set("config/"+cfg.zone+"/dhcpleaseduration", *setDHCPLeaseDuration, 0)
		} else {
			response, err = etc.Get("config/"+cfg.zone+"/dhcpleaseduration", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dhcpLeaseDuration = time.Duration(value) * time.Minute
		}
	}

	// DHCPTFTP
	{
		var response *etcd.Response
		var err error
		if setDHCPTFTP != nil && *setDHCPTFTP != "" {
			response, err = etc.Set("config/"+cfg.hostname+"/dhcptftp", *setDHCPTFTP, 0)
		} else {
			response, err = etc.Get("config/"+cfg.hostname+"/dhcptftp", false, false)
		}
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dhcpTFTP = response.Node.Value
		}
	}

	// DNSForwarders
	{
		cfg.dnsForwarders = []string{"8.8.8.8:53", "8.8.4.4:53"} // default uses Google's Public DNS servers
		response, err := etc.Get("config/"+cfg.zone+"/dnsforwarders", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			cfg.dnsForwarders = strings.Split(",", response.Node.Value)
		}
	}

	// dnsCacheMaxTTL
	{
		cfg.dnsCacheMaxTTL = 0 // default to no caching
		response, err := etc.Get("config/"+cfg.zone+"/dnscachemaxttl", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dnsCacheMaxTTL = time.Duration(value) * time.Second
		}
	}

	// dnsCacheMissingTTL
	{
		cfg.dnsCacheMissingTTL = 30 * time.Second // default setting is 30 seconds
		response, err := etc.Get("config/"+cfg.zone+"/dnscachemissingttl", false, false)
		if err != nil && !etcdKeyNotFound(err) {
			return nil, err
		}
		if response != nil && response.Node != nil && response.Node.Value != "" {
			value, err := strconv.Atoi(response.Node.Value)
			if err != nil {
				return nil, err
			}
			cfg.dnsCacheMissingTTL = time.Duration(value) * time.Second
		}
	}

	fmt.Printf("CONFIG: [%+v]\n", cfg)

	return cfg, nil
}
<|endoftext|>