<commit_before>// Copyright (c) 2015, Ben Morgan. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pacman

// Packages is merely a list of packages with support for some
// set and list functions.
type Packages []*Package

// FilterFunc is a function that given a package, returns true if the package
// is ok, and false if it should not be included (filtered out).
//
// It is used with the various Filter* functions to turn one set of Packages
// into another.
//
// FilterFuncs can be combined and negated. The idea is that you implement
// your own filter functions.
type FilterFunc func(p *Package) bool

// And performs a logical AND of f and fs. True is returned only iff
// all the filter functions in fs and f return true.
func (f FilterFunc) And(fs ...FilterFunc) FilterFunc {
	return func(p *Package) bool {
		for _, f := range fs {
			if !f(p) {
				return false
			}
		}
		return f(p)
	}
}

// Or performs a logical OR of f and fs. True is returned as soon
// as any of the filter functions in fs and f return true.
func (f FilterFunc) Or(fs ...FilterFunc) FilterFunc {
	return func(p *Package) bool {
		for _, f := range fs {
			if f(p) {
				return true
			}
		}
		return f(p)
	}
}

// Not negates the effect of the filter. Therefore true becomes false
// and false becomes true.
func (f FilterFunc) Not() FilterFunc {
	return func(p *Package) bool {
		return !f(p)
	}
}

// Filter filters a set of packages with some filter functions.
func Filter(pkgs Packages, f FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		if f(p) {
			fps = append(fps, p)
		}
	}
	return fps
}

// FilterAll filters the packages through all of the filter functions.
func FilterAll(pkgs Packages, fs []FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		keep := true
		for _, f := range fs {
			if !f(p) {
				keep = false
				break
			}
		}
		if keep {
			fps = append(fps, p)
		}
	}
	return fps
}

// FilterAny filters the packages through the filters in fs,
// where at least one must return true for it to be included.
func FilterAny(pkgs Packages, fs []FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		for _, f := range fs {
			if f(p) {
				fps = append(fps, p)
				break
			}
		}
	}
	return fps
}

// Intersect returns the intersection between two sets of Packages.
func Intersect(ps1, ps2 Packages) Packages {
	fps := make(Packages, 0, min(len(ps1), len(ps2)))
	s := make(set)
	s.InsertAll(ps1)
	for _, p := range ps2 {
		if s.Contains(p) {
			fps = append(fps, p)
		}
	}
	return fps
}

// Union returns the union of two sets of Packages.
func Union(ps1, ps2 Packages) Packages {
	s := make(set)
	s.InsertAll(ps1)
	s.InsertAll(ps2)
	return s.All()
}

// Subtract returns ps1 minus all packages that are found in ps2.
func Subtract(ps1, ps2 Packages) Packages {
	s := make(set)
	s.InsertAll(ps1)
	for _, p := range ps2 {
		s.Remove(p)
	}
	return s.All()
}

type set map[string]Packages

func (s set) All() Packages {
	fps := make(Packages, 0, len(s))
	for _, pkgs := range s {
		for _, p := range pkgs {
			fps = append(fps, p)
		}
	}
	return fps
}

func (s set) InsertAll(pkgs Packages) {
	for _, p := range pkgs {
		s.Insert(p)
	}
}

func (s set) Insert(p *Package) {
	m := s[p.Name]
	if m == nil {
		s[p.Name] = Packages{p}
	} else {
		for _, v := range m {
			if p.Equal(v) {
				return
			}
		}
		s[p.Name] = append(m, p)
	}
}

func (s set) Contains(p *Package) bool {
	m := s[p.Name]
	if m == nil {
		return false
	}
	for _, v := range m {
		if p.Equal(v) {
			return true
		}
	}
	return false
}

func (s set) Remove(p *Package) {
	m := s[p.Name]
	if len(m) <= 1 {
		delete(s, p.Name)
	} else {
		i := -1
		for j, v := range m {
			if p.Equal(v) {
				i = j
				break
			}
		}
		if i != -1 {
			if len(s) == i+1 {
				s[p.Name] = m[:i]
			} else {
				s[p.Name] = append(m[:i], m[i+1:]...)
			}
		}
	}
}
<commit_msg>Adding Packages.Map function<commit_after>// Copyright (c) 2015, Ben Morgan. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pacman

import "path"

// Packages is merely a list of packages with support for some
// set and list functions.
type Packages []*Package

type MapFunc func(*Package) string

// Map maps Packages to some string characteristic of a Package.
func (pkgs Packages) Map(f MapFunc) []string {
	results := make([]string, len(pkgs))
	for i, p := range pkgs {
		results[i] = f(p)
	}
	return results
}

func nkgFilename(p *Package) string {
	return p.Filename
}

func PkgBasename(p *Package) string {
	return path.Base(p.Filename)
}

func PkgName(p *Package) string {
	return p.Name
}

// FilterFunc is a function that given a package, returns true if the package
// is ok, and false if it should not be included (filtered out).
//
// It is used with the various Filter* functions to turn one set of Packages
// into another.
//
// FilterFuncs can be combined and negated. The idea is that you implement
// your own filter functions.
type FilterFunc func(p *Package) bool

// And performs a logical AND of f and fs. True is returned only iff
// all the filter functions in fs and f return true.
func (f FilterFunc) And(fs ...FilterFunc) FilterFunc {
	return func(p *Package) bool {
		for _, f := range fs {
			if !f(p) {
				return false
			}
		}
		return f(p)
	}
}

// Or performs a logical OR of f and fs. True is returned as soon
// as any of the filter functions in fs and f return true.
func (f FilterFunc) Or(fs ...FilterFunc) FilterFunc {
	return func(p *Package) bool {
		for _, f := range fs {
			if f(p) {
				return true
			}
		}
		return f(p)
	}
}

// Not negates the effect of the filter. Therefore true becomes false
// and false becomes true.
func (f FilterFunc) Not() FilterFunc {
	return func(p *Package) bool {
		return !f(p)
	}
}

// Filter filters a set of packages with some filter functions.
func Filter(pkgs Packages, f FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		if f(p) {
			fps = append(fps, p)
		}
	}
	return fps
}

// FilterAll filters the packages through all of the filter functions.
func FilterAll(pkgs Packages, fs []FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		keep := true
		for _, f := range fs {
			if !f(p) {
				keep = false
				break
			}
		}
		if keep {
			fps = append(fps, p)
		}
	}
	return fps
}

// FilterAny filters the packages through the filters in fs,
// where at least one must return true for it to be included.
func FilterAny(pkgs Packages, fs []FilterFunc) Packages {
	fps := make(Packages, 0, len(pkgs))
	for _, p := range pkgs {
		for _, f := range fs {
			if f(p) {
				fps = append(fps, p)
				break
			}
		}
	}
	return fps
}

// Intersect returns the intersection between two sets of Packages.
func Intersect(ps1, ps2 Packages) Packages {
	fps := make(Packages, 0, min(len(ps1), len(ps2)))
	s := make(set)
	s.InsertAll(ps1)
	for _, p := range ps2 {
		if s.Contains(p) {
			fps = append(fps, p)
		}
	}
	return fps
}

// Union returns the union of two sets of Packages.
func Union(ps1, ps2 Packages) Packages {
	s := make(set)
	s.InsertAll(ps1)
	s.InsertAll(ps2)
	return s.All()
}

// Subtract returns ps1 minus all packages that are found in ps2.
func Subtract(ps1, ps2 Packages) Packages {
	s := make(set)
	s.InsertAll(ps1)
	for _, p := range ps2 {
		s.Remove(p)
	}
	return s.All()
}

type set map[string]Packages

func (s set) All() Packages {
	fps := make(Packages, 0, len(s))
	for _, pkgs := range s {
		for _, p := range pkgs {
			fps = append(fps, p)
		}
	}
	return fps
}

func (s set) InsertAll(pkgs Packages) {
	for _, p := range pkgs {
		s.Insert(p)
	}
}

func (s set) Insert(p *Package) {
	m := s[p.Name]
	if m == nil {
		s[p.Name] = Packages{p}
	} else {
		for _, v := range m {
			if p.Equal(v) {
				return
			}
		}
		s[p.Name] = append(m, p)
	}
}

func (s set) Contains(p *Package) bool {
	m := s[p.Name]
	if m == nil {
		return false
	}
	for _, v := range m {
		if p.Equal(v) {
			return true
		}
	}
	return false
}

func (s set) Remove(p *Package) {
	m := s[p.Name]
	if len(m) <= 1 {
		delete(s, p.Name)
	} else {
		i := -1
		for j, v := range m {
			if p.Equal(v) {
				i = j
				break
			}
		}
		if i != -1 {
			if len(s) == i+1 {
				s[p.Name] = m[:i]
			} else {
				s[p.Name] = append(m[:i], m[i+1:]...)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"

	"github.com/jackwakefield/gopac"
)

const Name = "pacproxy"
const Version = "0.7.0"

var (
	fPac           string
	fListen        string
	fVerbose       bool
	pac            gopac.Parser
	pacRecordSplit *regexp.Regexp
	pacItemSplit   *regexp.Regexp
)

func init() {
	pacRecordSplit = regexp.MustCompile(`\s*;\s*`)
	pacItemSplit = regexp.MustCompile(`\s+`)
	flag.StringVar(&fPac, "c", "proxy.pac", "PAC file to use")
	flag.StringVar(&fListen, "l", "127.0.0.1:12345", "Interface and port to listen on")
	flag.BoolVar(&fVerbose, "v", false, "send verbose output to STDERR")
}

func main() {
	flag.Parse()
	logWriter := ioutil.Discard
	if fVerbose {
		logWriter = os.Stderr
	}
	log.SetOutput(logWriter)
	log.SetPrefix("")
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	log := log.New(logWriter, "", log.Flags())
	pacLookup := &pacLookup{
		pac: &gopac.Parser{},
		log: log,
	}
	err := pacLookup.pac.Parse(fPac)
	if err != nil {
		log.Fatal(err)
	}
	httpClient := &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives:  true,
			DisableCompression: true,
			Proxy: func(r *http.Request) (*url.URL, error) {
				p, err := pacLookup.fetchOne(r.URL)
				if err != nil {
					log.Printf("Failed to get proxy configuration from pac: %s", err)
					return nil, err
				}
				if p != nil {
					log.Printf("Using proxy %v", p)
				} else {
					log.Printf("Going direct")
				}
				return p, err
			},
		},
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return errors.New("Don't follow redirects")
		},
	}
	handler := &httpHandler{
		client:    httpClient,
		pacLookup: pacLookup,
		log:       log,
	}
	log.Printf("Listening on %q", fListen)
	log.Fatal(http.ListenAndServe(fListen, handler))
}

type pacLookup struct {
	pac *gopac.Parser
	log *log.Logger
}

func (l *pacLookup) fetchString(u *url.URL) string {
	str, err := l.pac.FindProxy(u.String(), u.Host)
	if err != nil {
		return ""
	}
	return str
}

func (l *pacLookup) fetch(u *url.URL) ([]*url.URL, error) {
	var (
		err       error
		pacResult string
		proxyURL  *url.URL
	)
	r := make([]*url.URL, 0, 10)
	if o := strings.Index(u.Host, ":"); o >= 0 {
		pacResult, err = l.pac.FindProxy(u.String(), u.Host[:o])
	} else {
		pacResult, err = l.pac.FindProxy(u.String(), u.Host)
	}
	if err != nil {
		return nil, err
	}
	for _, rSplit := range pacRecordSplit.Split(pacResult, 10) {
		p := pacItemSplit.Split(rSplit, 2)
		switch strings.ToUpper(p[0]) {
		case "DIRECT":
			r = append(r, nil)
		case "PROXY":
			proxyURL, err = url.Parse("http://" + p[1])
			if err != nil {
				return nil, err
			}
			r = append(r, proxyURL)
		case "SOCKS":
			return nil, errors.New("SOCKS is not supported")
		default:
			return nil, fmt.Errorf("Unknown PAC command %q", p[0])
		}
	}
	if len(r) == 0 {
		r = append(r, nil)
	}
	return r, nil
}

func (l *pacLookup) fetchOne(u *url.URL) (*url.URL, error) {
	results, err := l.fetch(u)
	if err != nil {
		return nil, err
	}
	for _, proxyURL := range results {
		// TODO: failover proxy support.
		return proxyURL, nil
	}
	return nil, nil
}

type httpHandler struct {
	client    *http.Client
	log       *log.Logger
	pacLookup *pacLookup
}

func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.log.Printf("Got request %s %s", r.Method, r.URL)
	if strings.ToUpper(r.Method) == "CONNECT" {
		h.doConnect(w, r)
		return
	}
	if !r.URL.IsAbs() {
		h.doNonProxyRequest(w, r)
		return
	}
	h.doProxy(w, r)
}

func (h *httpHandler) doConnect(w http.ResponseWriter, r *http.Request) {
	var (
		clientConn net.Conn
		serverConn net.Conn
		err        error
		proxyURL   *url.URL
	)
	hj, ok := w.(http.Hijacker)
	if !ok {
		h.log.Print("Unable to hijack connection")
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	clientConn, _, err = hj.Hijack()
	if err != nil {
		h.log.Printf("Failed to hijack connection: %s", err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	removeProxyHeaders(r)
	proxyURL, err = h.pacLookup.fetchOne(r.URL)
	if err != nil {
		h.log.Printf("Failed to get proxy configuration from pac: %s", err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	if proxyURL != nil {
		h.log.Printf("Using proxy connect %v", proxyURL)
		h.log.Printf("Dial %v", proxyURL.Host)
		serverConn, err = net.Dial("tcp", proxyURL.Host)
		if err != nil {
			h.log.Printf("Failed to dial: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
		defer serverConn.Close()
		r.WriteProxy(serverConn)
	} else {
		h.log.Print("Using direct connect")
		h.log.Printf("Dial %v", r.URL.Host)
		serverConn, err = net.Dial("tcp", r.URL.Host)
		if err != nil {
			h.log.Printf("Failed to dial: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
		defer serverConn.Close()
		clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
	}
	defer clientConn.Close()
	defer serverConn.Close()
	go io.Copy(clientConn, serverConn)
	io.Copy(serverConn, clientConn)
}

func (h *httpHandler) doProxy(w http.ResponseWriter, r *http.Request) {
	removeProxyHeaders(r)
	resp, err := h.client.Do(r)
	if err != nil {
		if resp == nil {
			h.log.Printf("Client do err: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
	wh := w.Header()
	clearHeaders(wh)
	wh.Add("Via", fmt.Sprintf("%d.%d %s (%s/%s - %s)", r.ProtoMajor, r.ProtoMinor, Name, Name, Version, h.pacLookup.fetchString(r.URL)))
	copyHeaders(wh, resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
	resp.Body.Close()
}

func (h *httpHandler) doNonProxyRequest(w http.ResponseWriter, _ *http.Request) {
	http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", http.StatusBadRequest)
}

func removeProxyHeaders(r *http.Request) {
	// this must be reset when serving a request with the client
	r.RequestURI = ""
	// If no Accept-Encoding header exists, Transport will add the headers it can accept
	// and would wrap the response body with the relevant reader.
	r.Header.Del("Accept-Encoding")
	// curl can add that, see
	// http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
	r.Header.Del("Proxy-Connection")
	// Connection is single hop Header:
	// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
	// 14.10 Connection
	//   The Connection general-header field allows the sender to specify
	//   options that are desired for that particular connection and MUST NOT
	//   be communicated by proxies over further connections.
	r.Header.Del("Connection")
}

func clearHeaders(dst http.Header) {
	for k := range dst {
		dst.Del(k)
	}
}

func copyHeaders(dst, src http.Header) {
	for k, vs := range src {
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}
<commit_msg>Bump version so that I don't forget later.<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"

	"github.com/jackwakefield/gopac"
)

const Name = "pacproxy"
const Version = "0.8.0"

var (
	fPac           string
	fListen        string
	fVerbose       bool
	pac            gopac.Parser
	pacRecordSplit *regexp.Regexp
	pacItemSplit   *regexp.Regexp
)

func init() {
	pacRecordSplit = regexp.MustCompile(`\s*;\s*`)
	pacItemSplit = regexp.MustCompile(`\s+`)
	flag.StringVar(&fPac, "c", "proxy.pac", "PAC file to use")
	flag.StringVar(&fListen, "l", "127.0.0.1:12345", "Interface and port to listen on")
	flag.BoolVar(&fVerbose, "v", false, "send verbose output to STDERR")
}

func main() {
	flag.Parse()
	logWriter := ioutil.Discard
	if fVerbose {
		logWriter = os.Stderr
	}
	log.SetOutput(logWriter)
	log.SetPrefix("")
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	log := log.New(logWriter, "", log.Flags())
	pacLookup := &pacLookup{
		pac: &gopac.Parser{},
		log: log,
	}
	err := pacLookup.pac.Parse(fPac)
	if err != nil {
		log.Fatal(err)
	}
	httpClient := &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives:  true,
			DisableCompression: true,
			Proxy: func(r *http.Request) (*url.URL, error) {
				p, err := pacLookup.fetchOne(r.URL)
				if err != nil {
					log.Printf("Failed to get proxy configuration from pac: %s", err)
					return nil, err
				}
				if p != nil {
					log.Printf("Using proxy %v", p)
				} else {
					log.Printf("Going direct")
				}
				return p, err
			},
		},
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return errors.New("Don't follow redirects")
		},
	}
	handler := &httpHandler{
		client:    httpClient,
		pacLookup: pacLookup,
		log:       log,
	}
	log.Printf("Listening on %q", fListen)
	log.Fatal(http.ListenAndServe(fListen, handler))
}

type pacLookup struct {
	pac *gopac.Parser
	log *log.Logger
}

func (l *pacLookup) fetchString(u *url.URL) string {
	str, err := l.pac.FindProxy(u.String(), u.Host)
	if err != nil {
		return ""
	}
	return str
}

func (l *pacLookup) fetch(u *url.URL) ([]*url.URL, error) {
	var (
		err       error
		pacResult string
		proxyURL  *url.URL
	)
	r := make([]*url.URL, 0, 10)
	if o := strings.Index(u.Host, ":"); o >= 0 {
		pacResult, err = l.pac.FindProxy(u.String(), u.Host[:o])
	} else {
		pacResult, err = l.pac.FindProxy(u.String(), u.Host)
	}
	if err != nil {
		return nil, err
	}
	for _, rSplit := range pacRecordSplit.Split(pacResult, 10) {
		p := pacItemSplit.Split(rSplit, 2)
		switch strings.ToUpper(p[0]) {
		case "DIRECT":
			r = append(r, nil)
		case "PROXY":
			proxyURL, err = url.Parse("http://" + p[1])
			if err != nil {
				return nil, err
			}
			r = append(r, proxyURL)
		case "SOCKS":
			return nil, errors.New("SOCKS is not supported")
		default:
			return nil, fmt.Errorf("Unknown PAC command %q", p[0])
		}
	}
	if len(r) == 0 {
		r = append(r, nil)
	}
	return r, nil
}

func (l *pacLookup) fetchOne(u *url.URL) (*url.URL, error) {
	results, err := l.fetch(u)
	if err != nil {
		return nil, err
	}
	for _, proxyURL := range results {
		// TODO: failover proxy support.
		return proxyURL, nil
	}
	return nil, nil
}

type httpHandler struct {
	client    *http.Client
	log       *log.Logger
	pacLookup *pacLookup
}

func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.log.Printf("Got request %s %s", r.Method, r.URL)
	if strings.ToUpper(r.Method) == "CONNECT" {
		h.doConnect(w, r)
		return
	}
	if !r.URL.IsAbs() {
		h.doNonProxyRequest(w, r)
		return
	}
	h.doProxy(w, r)
}

func (h *httpHandler) doConnect(w http.ResponseWriter, r *http.Request) {
	var (
		clientConn net.Conn
		serverConn net.Conn
		err        error
		proxyURL   *url.URL
	)
	hj, ok := w.(http.Hijacker)
	if !ok {
		h.log.Print("Unable to hijack connection")
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	clientConn, _, err = hj.Hijack()
	if err != nil {
		h.log.Printf("Failed to hijack connection: %s", err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	removeProxyHeaders(r)
	proxyURL, err = h.pacLookup.fetchOne(r.URL)
	if err != nil {
		h.log.Printf("Failed to get proxy configuration from pac: %s", err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	if proxyURL != nil {
		h.log.Printf("Using proxy connect %v", proxyURL)
		h.log.Printf("Dial %v", proxyURL.Host)
		serverConn, err = net.Dial("tcp", proxyURL.Host)
		if err != nil {
			h.log.Printf("Failed to dial: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
		defer serverConn.Close()
		r.WriteProxy(serverConn)
	} else {
		h.log.Print("Using direct connect")
		h.log.Printf("Dial %v", r.URL.Host)
		serverConn, err = net.Dial("tcp", r.URL.Host)
		if err != nil {
			h.log.Printf("Failed to dial: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
		defer serverConn.Close()
		clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
	}
	defer clientConn.Close()
	defer serverConn.Close()
	go io.Copy(clientConn, serverConn)
	io.Copy(serverConn, clientConn)
}

func (h *httpHandler) doProxy(w http.ResponseWriter, r *http.Request) {
	removeProxyHeaders(r)
	resp, err := h.client.Do(r)
	if err != nil {
		if resp == nil {
			h.log.Printf("Client do err: %s", err)
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
	wh := w.Header()
	clearHeaders(wh)
	wh.Add("Via", fmt.Sprintf("%d.%d %s (%s/%s - %s)", r.ProtoMajor, r.ProtoMinor, Name, Name, Version, h.pacLookup.fetchString(r.URL)))
	copyHeaders(wh, resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
	resp.Body.Close()
}

func (h *httpHandler) doNonProxyRequest(w http.ResponseWriter, _ *http.Request) {
	http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", http.StatusBadRequest)
}

func removeProxyHeaders(r *http.Request) {
	// this must be reset when serving a request with the client
	r.RequestURI = ""
	// If no Accept-Encoding header exists, Transport will add the headers it can accept
	// and would wrap the response body with the relevant reader.
	r.Header.Del("Accept-Encoding")
	// curl can add that, see
	// http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
	r.Header.Del("Proxy-Connection")
	// Connection is single hop Header:
	// http://www.w3.org/Protocols/rfc2616/rfc2616.txt
	// 14.10 Connection
	//   The Connection general-header field allows the sender to specify
	//   options that are desired for that particular connection and MUST NOT
	//   be communicated by proxies over further connections.
	r.Header.Del("Connection")
}

func clearHeaders(dst http.Header) {
	for k := range dst {
		dst.Del(k)
	}
}

func copyHeaders(dst, src http.Header) {
	for k, vs := range src {
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}
<|endoftext|>


<commit_before>package store

import (
	"container/list"
	"path"
	"strings"
	"sync"
	"sync/atomic"

	etcdErr "github.com/coreos/etcd/error"
)

// A watcherHub contains all subscribed watchers
// watchers is a map with watched path as key and watcher as value
// EventHistory keeps the old events for watcherHub. It is used to help
// watcher to get a continuous event history. Or a watcher might miss the
// event happens between the end of the first watch command and the start
// of the second command.
type watcherHub struct {
	mutex        sync.Mutex // protect the hash map
	watchers     map[string]*list.List
	count        int64 // current number of watchers.
	EventHistory *EventHistory
}

// newWatchHub creates a watchHub. The capacity determines how many events we will
// keep in the eventHistory.
// Typically, we only need to keep a small size of history[smaller than 20K].
// Ideally, it should smaller than 20K/s[max throughput] * 2 * 50ms[RTT] = 2000
func newWatchHub(capacity int) *watcherHub {
	return &watcherHub{
		watchers:     make(map[string]*list.List),
		EventHistory: newEventHistory(capacity),
	}
}

// Watch function returns a watcher.
// If recursive is true, the first change after index under key will be sent to the event channel of the watcher.
// If recursive is false, the first change after index at key will be sent to the event channel of the watcher.
// If index is zero, watch will start from the current index + 1.
func (wh *watcherHub) watch(key string, recursive, stream bool, index uint64) (*Watcher, *etcdErr.Error) {
	event, err := wh.EventHistory.scan(key, recursive, index)

	if err != nil {
		return nil, err
	}

	w := &Watcher{
		EventChan:  make(chan *Event, 1), // use a buffered channel
		recursive:  recursive,
		stream:     stream,
		sinceIndex: index,
	}

	if event != nil {
		w.EventChan <- event
		return w, nil
	}

	wh.mutex.Lock()
	defer wh.mutex.Unlock()

	l, ok := wh.watchers[key]

	var elem *list.Element

	if ok { // add the new watcher to the back of the list
		elem = l.PushBack(w)

	} else { // create a new list and add the new watcher
		l = list.New()
		elem = l.PushBack(w)
		wh.watchers[key] = l
	}

	w.remove = func() {
		if w.removed { // avoid remove it twice
			return
		}

		wh.mutex.Lock()
		defer wh.mutex.Unlock()

		w.removed = true
		l.Remove(elem)
		atomic.AddInt64(&wh.count, -1)
		if l.Len() == 0 {
			delete(wh.watchers, key)
		}

		// consume all items in the channel
		// unblock all the waiting go routines created by watchHub
		for {
			select {
			case <-w.EventChan:
			default:
				break
			}
		}
	}

	atomic.AddInt64(&wh.count, 1)

	return w, nil
}

// notify function accepts an event and notify to the watchers.
func (wh *watcherHub) notify(e *Event) {
	e = wh.EventHistory.addEvent(e) // add event into the eventHistory

	segments := strings.Split(e.Node.Key, "/")

	currPath := "/"

	// walk through all the segments of the path and notify the watchers
	// if the path is "/foo/bar", it will notify watchers with path "/",
	// "/foo" and "/foo/bar"

	for _, segment := range segments {
		currPath = path.Join(currPath, segment)
		// notify the watchers who interests in the changes of current path
		wh.notifyWatchers(e, currPath, false)
	}
}

func (wh *watcherHub) notifyWatchers(e *Event, path string, deleted bool) {
	wh.mutex.Lock()
	defer wh.mutex.Unlock()

	l, ok := wh.watchers[path]
	if ok {
		curr := l.Front()

		for curr != nil {
			next := curr.Next() // save reference to the next one in the list

			w, _ := curr.Value.(*Watcher)

			if w.notify(e, e.Node.Key == path, deleted) {
				if !w.stream { // do not remove the stream watcher
					// if we successfully notify a watcher
					// we need to remove the watcher from the list
					// and decrease the counter
					l.Remove(curr)
					atomic.AddInt64(&wh.count, -1)
				}
			}

			curr = next // update current to the next element in the list
		}

		if l.Len() == 0 {
			// if we have notified all watcher in the list
			// we can delete the list
			delete(wh.watchers, path)
		}
	}
}

// clone function clones the watcherHub and return the cloned one.
// only clone the static content. do not clone the current watchers.
func (wh *watcherHub) clone() *watcherHub {
	clonedHistory := wh.EventHistory.clone()

	return &watcherHub{
		EventHistory: clonedHistory,
	}
}
<commit_msg>feat(stream watchers) fix locking issue<commit_after>package store

import (
	"container/list"
	"path"
	"strings"
	"sync"
	"sync/atomic"

	etcdErr "github.com/coreos/etcd/error"
)

// A watcherHub contains all subscribed watchers
// watchers is a map with watched path as key and watcher as value
// EventHistory keeps the old events for watcherHub. It is used to help
// watcher to get a continuous event history. Or a watcher might miss the
// event happens between the end of the first watch command and the start
// of the second command.
type watcherHub struct {
	mutex        sync.Mutex // protect the hash map
	watchers     map[string]*list.List
	count        int64 // current number of watchers.
	EventHistory *EventHistory
}

// newWatchHub creates a watchHub. The capacity determines how many events we will
// keep in the eventHistory.
// Typically, we only need to keep a small size of history[smaller than 20K].
// Ideally, it should smaller than 20K/s[max throughput] * 2 * 50ms[RTT] = 2000
func newWatchHub(capacity int) *watcherHub {
	return &watcherHub{
		watchers:     make(map[string]*list.List),
		EventHistory: newEventHistory(capacity),
	}
}

// Watch function returns a watcher.
// If recursive is true, the first change after index under key will be sent to the event channel of the watcher.
// If recursive is false, the first change after index at key will be sent to the event channel of the watcher.
// If index is zero, watch will start from the current index + 1.
func (wh *watcherHub) watch(key string, recursive, stream bool, index uint64) (*Watcher, *etcdErr.Error) {
	event, err := wh.EventHistory.scan(key, recursive, index)

	if err != nil {
		return nil, err
	}

	w := &Watcher{
		EventChan:  make(chan *Event, 1), // use a buffered channel
		recursive:  recursive,
		stream:     stream,
		sinceIndex: index,
	}

	if event != nil {
		w.EventChan <- event
		return w, nil
	}

	wh.mutex.Lock()
	defer wh.mutex.Unlock()

	l, ok := wh.watchers[key]

	var elem *list.Element

	if ok { // add the new watcher to the back of the list
		elem = l.PushBack(w)

	} else { // create a new list and add the new watcher
		l = list.New()
		elem = l.PushBack(w)
		wh.watchers[key] = l
	}

	w.remove = func() {
		if w.removed { // avoid remove it twice
			return
		}

		wh.mutex.Lock()
		defer wh.mutex.Unlock()

		w.removed = true
		l.Remove(elem)
		atomic.AddInt64(&wh.count, -1)
		if l.Len() == 0 {
			delete(wh.watchers, key)
		}
	}

	atomic.AddInt64(&wh.count, 1)

	return w, nil
}

// notify function accepts an event and notify to the watchers.
func (wh *watcherHub) notify(e *Event) {
	e = wh.EventHistory.addEvent(e) // add event into the eventHistory

	segments := strings.Split(e.Node.Key, "/")

	currPath := "/"

	// walk through all the segments of the path and notify the watchers
	// if the path is "/foo/bar", it will notify watchers with path "/",
	// "/foo" and "/foo/bar"

	for _, segment := range segments {
		currPath = path.Join(currPath, segment)
		// notify the watchers who interests in the changes of current path
		wh.notifyWatchers(e, currPath, false)
	}
}

func (wh *watcherHub) notifyWatchers(e *Event, path string, deleted bool) {
	wh.mutex.Lock()
	defer wh.mutex.Unlock()

	l, ok := wh.watchers[path]
	if ok {
		curr := l.Front()

		for curr != nil {
			next := curr.Next() // save reference to the next one in the list

			w, _ := curr.Value.(*Watcher)

			if w.notify(e, e.Node.Key == path, deleted) {
				if !w.stream { // do not remove the stream watcher
					// if we successfully notify a watcher
					// we need to remove the watcher from the list
					// and decrease the counter
					l.Remove(curr)
					atomic.AddInt64(&wh.count, -1)
				}
			}

			curr = next // update current to the next element in the list
		}

		if l.Len() == 0 {
			// if we have notified all watcher in the list
			// we can delete the list
			delete(wh.watchers, path)
		}
	}
}

// clone function clones the watcherHub and return the cloned one.
// only clone the static content. do not clone the current watchers.
func (wh *watcherHub) clone() *watcherHub {
	clonedHistory := wh.EventHistory.clone()

	return &watcherHub{
		EventHistory: clonedHistory,
	}
}
<|endoftext|>


<commit_before>package mixpanel

import (
  "fmt"
  "strings"
  "encoding/json"
  "net/http"
  "io/ioutil"
  "time"
  "sort"
  "bytes"
  "crypto/md5"
  "net/url"
)

const (
  DEFAULT_EXPIRE_IN_DAYS int64 = 5
)

type Mixpanel struct {
  ApiKey string
  Secret string
  Format string
  BaseUrl string
}

type EventQueryResult struct {
  LegendSize int `json:legend_size`
  Data struct {
    Series []string `json:series`
    Values map[string]map[string]int `json:values`
  } `json:data`
}

type ExportQueryResult struct {
  Event string `json:event`
  Properties map[string]interface{} `json:properties`
}

func NewMixpanel(key string, secret string) *Mixpanel {
  m := new(Mixpanel)
  m.Secret = secret
  m.ApiKey = key
  m.Format = "json"
  m.BaseUrl = "http://mixpanel.com/api/2.0"
  return m
}

func (m *Mixpanel) AddExpire(params *map[string]string) {
  if (*params)["expire"] == "" {
    (*params)["expire"] = fmt.Sprintf("%d", ExpireInDays(DEFAULT_EXPIRE_IN_DAYS))
  }
}

func (m *Mixpanel) AddSig(params *map[string]string) {
  keys := make([]string, 0)

  (*params)["api_key"] = m.ApiKey
  (*params)["format"] = m.Format

  for k,_ := range *params {
    keys = append(keys, k)
  }
  sort.StringSlice(keys).Sort()
  // fmt.Println(s)

  var buffer bytes.Buffer
  for _,key := range keys {
    value := (*params)[key]
    buffer.WriteString(fmt.Sprintf("%s=%s", key, value))
  }
  buffer.WriteString(m.Secret)
  // fmt.Println(buffer.String())

  hash := md5.New()
  hash.Write(buffer.Bytes())
  sigHex := fmt.Sprintf("%x", hash.Sum([]byte{}))
  (*params)["sig"] = sigHex
}

func (m *Mixpanel) makeRequest(action string, params map[string]string) ([]byte, error) {
  m.AddExpire(&params)
  m.AddSig(&params)

  var buffer bytes.Buffer
  for key,value := range params {
    value = url.QueryEscape(value)
    buffer.WriteString(fmt.Sprintf("%s=%s&", key, value))
  }

  uri := fmt.Sprintf("%s/%s?%s", m.BaseUrl, action, buffer.String())
  uri = uri[:len(uri)-1]
  // fmt.Println(uri)
  client := new(http.Client)
  req, err := http.NewRequest("GET", uri, nil)
  if err != nil {
  }
  // req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  resp, err := client.Do(req)
  if err != nil {
  }
  // fmt.Println(resp.Header)
  defer resp.Body.Close()
  bytes, err := ioutil.ReadAll(resp.Body)
  return bytes, err
}

func ExpireInDays(days int64) int64 {
  return time.Now().Add(time.Duration(int64(time.Hour) * days * 24)).Unix()
}

func ExpireInHours(hours int64) int64 {
  return time.Now().Add(time.Duration(int64(time.Hour) * hours)).Unix()
}

func (m *Mixpanel) EventQuery(params map[string]string) (EventQueryResult,error) {
  m.BaseUrl = "http://mixpanel.com/api/2.0"
  bytes, err := m.makeRequest("events/properties", params)
  // fmt.Println(string(bytes))
  var result EventQueryResult
  err = json.Unmarshal(bytes, &result)
  return result, err
}

func (m *Mixpanel) ExportQuery(params map[string]string) []ExportQueryResult {
  m.BaseUrl = "http://data.mixpanel.com/api/2.0"
  var results []ExportQueryResult
  bytes, _ := m.makeRequest("export", params)
  str := string(bytes)
  // fmt.Println(str)
  for _, s := range strings.Split(str, "\n") {
    var result ExportQueryResult
    json.Unmarshal([]byte(s),&result)
    results = append(results, result)
  }
  return results
}

func (m *Mixpanel) PeopleQuery(params map[string]string) map[string]interface{} {
  m.BaseUrl = "http://mixpanel.com/api/2.0"
  bytes, _ := m.makeRequest("engage", params)
  str := string(bytes)
  // fmt.Println(str)
  var raw map[string]interface{}
  json.Unmarshal([]byte(str),&raw)
  return raw
}

func (m *Mixpanel) UserInfo(id string) map[string]interface{}{
  params := map[string]string{
    "distinct_id": id,
  }
  raw := m.PeopleQuery(params)
  return raw["results"].([]interface{})[0].(map[string]interface{})["$properties"].(map[string]interface{})
}<commit_msg>go fmt<commit_after>package mixpanel

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"
)

const (
	DEFAULT_EXPIRE_IN_DAYS int64 = 5
)

type Mixpanel struct {
	ApiKey  string
	Secret  string
	Format  string
	BaseUrl string
}

type EventQueryResult struct {
	LegendSize int `json:legend_size`
	Data       struct {
		Series []string                  `json:series`
		Values map[string]map[string]int `json:values`
	} `json:data`
}

type ExportQueryResult struct {
	Event      string                 `json:event`
	Properties map[string]interface{} `json:properties`
}

func NewMixpanel(key string, secret string) *Mixpanel {
	m := new(Mixpanel)
	m.Secret = secret
	m.ApiKey = key
	m.Format = "json"
	m.BaseUrl = "http://mixpanel.com/api/2.0"
	return m
}

func (m *Mixpanel) AddExpire(params *map[string]string) {
	if (*params)["expire"] == "" {
		(*params)["expire"] = fmt.Sprintf("%d", ExpireInDays(DEFAULT_EXPIRE_IN_DAYS))
	}
}

func (m *Mixpanel) AddSig(params *map[string]string) {
	keys := make([]string, 0)

	(*params)["api_key"] = m.ApiKey
	(*params)["format"] = m.Format

	for k, _ := range *params {
		keys = append(keys, k)
	}
	sort.StringSlice(keys).Sort()
	// fmt.Println(s)

	var buffer bytes.Buffer
	for _, key := range keys {
		value := (*params)[key]
		buffer.WriteString(fmt.Sprintf("%s=%s", key, value))
	}
	buffer.WriteString(m.Secret)
	// fmt.Println(buffer.String())

	hash := md5.New()
	hash.Write(buffer.Bytes())
	sigHex := fmt.Sprintf("%x", hash.Sum([]byte{}))
	(*params)["sig"] = sigHex
}

func (m *Mixpanel) makeRequest(action string, params map[string]string) ([]byte, error) {
	m.AddExpire(&params)
	m.AddSig(&params)

	var buffer bytes.Buffer
	for key, value := range params {
		value = url.QueryEscape(value)
		buffer.WriteString(fmt.Sprintf("%s=%s&", key, value))
	}

	uri := fmt.Sprintf("%s/%s?%s", m.BaseUrl, action, buffer.String())
	uri = uri[:len(uri)-1]
	// fmt.Println(uri)
	client := new(http.Client)
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
	}
	// req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	resp, err := client.Do(req)
	if err != nil {
	}
	// fmt.Println(resp.Header)
	defer resp.Body.Close()
	bytes, err := ioutil.ReadAll(resp.Body)
	return bytes, err
}

func ExpireInDays(days int64) int64 {
	return time.Now().Add(time.Duration(int64(time.Hour) * days * 24)).Unix()
}

func ExpireInHours(hours int64) int64 {
	return time.Now().Add(time.Duration(int64(time.Hour) * hours)).Unix()
}

func (m *Mixpanel) EventQuery(params map[string]string) (EventQueryResult, error) {
	m.BaseUrl = "http://mixpanel.com/api/2.0"
	bytes, err := m.makeRequest("events/properties", params)
	// fmt.Println(string(bytes))
	var result EventQueryResult
	err = json.Unmarshal(bytes, &result)
	return result, err
}

func (m *Mixpanel) ExportQuery(params map[string]string) []ExportQueryResult {
	m.BaseUrl = "http://data.mixpanel.com/api/2.0"
	var results []ExportQueryResult
	bytes, _ := m.makeRequest("export", params)
	str := string(bytes)
	// fmt.Println(str)
	for _, s := range strings.Split(str, "\n") {
		var result ExportQueryResult
		json.Unmarshal([]byte(s), &result)
		results = append(results, result)
	}
	return results
}

func (m *Mixpanel) PeopleQuery(params map[string]string) map[string]interface{} {
	m.BaseUrl = "http://mixpanel.com/api/2.0"
	bytes, _ := m.makeRequest("engage", params)
	str := string(bytes)
	// fmt.Println(str)
	var raw map[string]interface{}
	json.Unmarshal([]byte(str), &raw)
	return raw
}

func (m *Mixpanel) UserInfo(id string) map[string]interface{} {
	params := map[string]string{
		"distinct_id": id,
	}
	raw := m.PeopleQuery(params)
	return raw["results"].([]interface{})[0].(map[string]interface{})["$properties"].(map[string]interface{})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/types"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"

	"github.com/gojuno/generator"
)

type (
	options struct {
		InputFile     string
		OutputFile    string
		InterfaceName string
		StructName    string
		Package       string
	}

	visitor struct {
		gen             *generator.Generator
		methods         map[string]*types.Signature
		sourceInterface string
	}
)

func main() {
	opts := processFlags()
	var (
		packagePath = opts.InputFile
		err         error
	)

	if _, err := os.Stat(packagePath); err == nil {
		if packagePath, err = generator.PackageOf(packagePath); err != nil {
			die(err)
		}
	}

	destPackagePath, err := generator.PackageOf(filepath.Dir(opts.OutputFile))
	if err != nil {
		die(err)
	}

	cfg := loader.Config{
		TypeCheckFuncBodies: func(string) bool { return false },
		TypeChecker: types.Config{
			IgnoreFuncBodies:         true,
			FakeImportC:              true,
			DisableUnusedImportCheck: true,
		},
	}
	cfg.Import(packagePath)

	if destPackagePath != packagePath {
		cfg.Import(destPackagePath)
	}

	prog, err := cfg.Load()
	if err != nil {
		die(err)
	}

	gen := generator.New(prog)
	gen.ImportWithAlias(destPackagePath, "")
	gen.SetPackageName(opts.Package)
	gen.SetVar("structName", opts.StructName)
	gen.SetVar("interfaceName", opts.InterfaceName)
	gen.SetHeader(fmt.Sprintf(`DO NOT EDIT!
This is automatically generated code.
Original interface can be found in %s`, packagePath))
	gen.SetDefaultParamsPrefix("p")
	gen.SetDefaultResultsPrefix("r")

	v := &visitor{
		gen:             gen,
		methods:         map[string]*types.Signature{},
		sourceInterface: opts.InterfaceName,
	}

	for _, file := range prog.Package(packagePath).Files {
		ast.Walk(v, file)
	}

	if len(v.methods) == 0 {
		die(fmt.Errorf("interface %s was not found in %s or it's an empty interface", opts.InterfaceName, packagePath))
	}

	if err := gen.ProcessTemplate("interface", template, v.methods); err != nil {
		die(err)
	}

	if err := gen.WriteToFilename(opts.OutputFile); err != nil {
		die(err)
	}
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	switch ts := node.(type) {
	case *ast.FuncDecl:
		return nil
	case *ast.TypeSpec:
		exprType, err := v.gen.ExpressionType(ts.Type)
		if err != nil {
			die(fmt.Errorf("failed to get expression for %T %s", ts.Type, ts.Name.Name, err))
		}

		switch t := exprType.(type) {
		case *types.Interface:
			if ts.Name.Name == v.sourceInterface {
				v.processInterface(t)
			}

			return nil
		}
	}

	return v
}

func (v *visitor) processInterface(t *types.Interface) {
	for i := 0; i < t.NumMethods(); i++ {
		v.methods[t.Method(i).Name()] = t.Method(i).Type().(*types.Signature)
	}
}

const template = `
	type {{$structName}} struct {
		t *testing.T
		m *sync.RWMutex

		{{ range $methodName, $method := . }} {{$methodName}}Func func{{ signature $method }}
		{{ end }}
		{{ range $methodName, $method := . }} {{$methodName}}Counter int
		{{ end }}
		{{ range $methodName, $method := . }} {{$methodName}}Mock {{$structName}}{{$methodName}}
		{{ end }}
	}

	func New{{$structName}}(t *testing.T) *{{$structName}} {
		m := &{{$structName}}{t: t, m: &sync.RWMutex{} }
		{{ range $methodName, $method := . }}m.{{$methodName}}Mock = {{$structName}}{{$methodName}}{mock: m}
		{{ end }}

		return m
	}

	{{ range $methodName, $method := . }}
		type {{$structName}}{{$methodName}} struct {
			mock *{{$structName}}
		}

		func (m {{$structName}}{{$methodName}}) Return({{results $method}}) *{{$structName}} {
			m.mock.{{$methodName}}Func = func({{params $method}}) ({{(results $method).Types}}) {
				return {{ (results $method).Names }}
			}
			return m.mock
		}

		func (m {{$structName}}{{$methodName}}) Set(f func({{params $method}}) ({{results $method}})) *{{$structName}}{
			m.mock.{{$methodName}}Func = f
			return m.mock
		}

		func (m *{{$structName}}) {{$methodName}}{{signature $method}} {
			m.m.Lock()
			m.{{$methodName}}Counter += 1
			m.m.Unlock()

			if m.{{$methodName}}Func == nil {
				m.t.Errorf("Unexpected call to {{$structName}}.{{$methodName}}")
			}

			{{if gt (len (results $method)) 0 }}
			return {{ end }} m.{{$methodName}}Func({{(params $method).Pass}})
		}
	{{ end }}

	func (m *{{$structName}}) ValidateCallCounters() {
		m.t.Log("ValidateCallCounters is deprecated please use CheckMocksCalled")

		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				m.t.Error("Expected call to {{$structName}}.{{$methodName}}")
			}
		{{ end }}
	}

	func (m *{{$structName}}) CheckMocksCalled() {
		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				m.t.Error("Expected call to {{$structName}}.{{$methodName}}")
			}
		{{ end }}
	}

	//AllMocksCalled returns true if all mocked methods were called before the call to AllMocksCalled,
	//it can be used with assert/require, i.e. assert.True(mock.AllMocksCalled())
	func (m *{{$structName}}) AllMocksCalled() bool {
		m.m.RLock()
		defer m.m.RUnlock()

		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				return false
			}
		{{ end }}

		return true
	}`

func processFlags() *options {
	var (
		input  = flag.String("f", "", "input file or import path of the package containing interface declaration")
		name   = flag.String("i", "", "interface name")
		output = flag.String("o", "", "destination file for interface implementation")
		pkg    = flag.String("p", "", "destination package name")
		sname  = flag.String("t", "", "target struct name, default: <interface name>Mock")
	)

	flag.Parse()

	if *pkg == "" || *input == "" || *output == "" || *name == "" || !strings.HasSuffix(*output, ".go") {
		flag.Usage()
		os.Exit(1)
	}

	if *sname == "" {
		*sname = *name + "Mock"
	}

	return &options{
		InputFile:     *input,
		OutputFile:    *output,
		InterfaceName: *name,
		Package:       *pkg,
		StructName:    *sname,
	}
}

func die(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}
<commit_msg>remove old mock before generating the new one<commit_after>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/types"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"

	"github.com/gojuno/generator"
)

type (
	options struct {
		InputFile     string
		OutputFile    string
		InterfaceName string
		StructName    string
		Package       string
	}

	visitor struct {
		gen             *generator.Generator
		methods         map[string]*types.Signature
		sourceInterface string
	}
)

func main() {
	opts := processFlags()
	var (
		packagePath = opts.InputFile
		err         error
	)

	if _, err := os.Stat(packagePath); err == nil {
		if packagePath, err = generator.PackageOf(packagePath); err != nil {
			die(err)
		}
	}

	destPackagePath, err := generator.PackageOf(filepath.Dir(opts.OutputFile))
	if err != nil {
		die(err)
	}

	cfg := loader.Config{
		TypeCheckFuncBodies: func(string) bool { return false },
		TypeChecker: types.Config{
			IgnoreFuncBodies:         true,
			FakeImportC:              true,
			DisableUnusedImportCheck: true,
		},
	}
	cfg.Import(packagePath)

	if err := os.Remove(opts.OutputFile); err != nil && !os.IsNotExist(err) {
		die(err)
	}

	if destPackagePath != packagePath {
		cfg.Import(destPackagePath)
	}

	prog, err := cfg.Load()
	if err != nil {
		die(err)
	}

	gen := generator.New(prog)
	gen.ImportWithAlias(destPackagePath, "")
	gen.SetPackageName(opts.Package)
	gen.SetVar("structName", opts.StructName)
	gen.SetVar("interfaceName", opts.InterfaceName)
	gen.SetHeader(fmt.Sprintf(`DO NOT EDIT!
This is automatically generated code.
Original interface can be found in %s`, packagePath))
	gen.SetDefaultParamsPrefix("p")
	gen.SetDefaultResultsPrefix("r")

	v := &visitor{
		gen:             gen,
		methods:         map[string]*types.Signature{},
		sourceInterface: opts.InterfaceName,
	}

	for _, file := range prog.Package(packagePath).Files {
		ast.Walk(v, file)
	}

	if len(v.methods) == 0 {
		die(fmt.Errorf("interface %s was not found in %s or it's an empty interface", opts.InterfaceName, packagePath))
	}

	if err := gen.ProcessTemplate("interface", template, v.methods); err != nil {
		die(err)
	}

	if err := gen.WriteToFilename(opts.OutputFile); err != nil {
		die(err)
	}
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	switch ts := node.(type) {
	case *ast.FuncDecl:
		return nil
	case *ast.TypeSpec:
		exprType, err := v.gen.ExpressionType(ts.Type)
		if err != nil {
			die(fmt.Errorf("failed to get expression for %T %s", ts.Type, ts.Name.Name, err))
		}

		switch t := exprType.(type) {
		case *types.Interface:
			if ts.Name.Name == v.sourceInterface {
				v.processInterface(t)
			}

			return nil
		}
	}

	return v
}

func (v *visitor) processInterface(t *types.Interface) {
	for i := 0; i < t.NumMethods(); i++ {
		v.methods[t.Method(i).Name()] = t.Method(i).Type().(*types.Signature)
	}
}

const template = `
	type {{$structName}} struct {
		t *testing.T
		m *sync.RWMutex

		{{ range $methodName, $method := . }} {{$methodName}}Func func{{ signature $method }}
		{{ end }}
		{{ range $methodName, $method := . }} {{$methodName}}Counter int
		{{ end }}
		{{ range $methodName, $method := . }} {{$methodName}}Mock {{$structName}}{{$methodName}}
		{{ end }}
	}

	func New{{$structName}}(t *testing.T) *{{$structName}} {
		m := &{{$structName}}{t: t, m: &sync.RWMutex{} }
		{{ range $methodName, $method := . }}m.{{$methodName}}Mock = {{$structName}}{{$methodName}}{mock: m}
		{{ end }}

		return m
	}

	{{ range $methodName, $method := . }}
		type {{$structName}}{{$methodName}} struct {
			mock *{{$structName}}
		}

		func (m {{$structName}}{{$methodName}}) Return({{results $method}}) *{{$structName}} {
			m.mock.{{$methodName}}Func = func({{params $method}}) ({{(results $method).Types}}) {
				return {{ (results $method).Names }}
			}
			return m.mock
		}

		func (m {{$structName}}{{$methodName}}) Set(f func({{params $method}}) ({{results $method}})) *{{$structName}}{
			m.mock.{{$methodName}}Func = f
			return m.mock
		}

		func (m *{{$structName}}) {{$methodName}}{{signature $method}} {
			m.m.Lock()
			m.{{$methodName}}Counter += 1
			m.m.Unlock()

			if m.{{$methodName}}Func == nil {
				m.t.Errorf("Unexpected call to {{$structName}}.{{$methodName}}")
			}

			{{if gt (len (results $method)) 0 }}
			return {{ end }} m.{{$methodName}}Func({{(params $method).Pass}})
		}
	{{ end }}

	func (m *{{$structName}}) ValidateCallCounters() {
		m.t.Log("ValidateCallCounters is deprecated please use CheckMocksCalled")

		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				m.t.Error("Expected call to {{$structName}}.{{$methodName}}")
			}
		{{ end }}
	}

	func (m *{{$structName}}) CheckMocksCalled() {
		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				m.t.Error("Expected call to {{$structName}}.{{$methodName}}")
			}
		{{ end }}
	}

	//AllMocksCalled returns true if all mocked methods were called before the call to AllMocksCalled,
	//it can be used with assert/require, i.e. assert.True(mock.AllMocksCalled())
	func (m *{{$structName}}) AllMocksCalled() bool {
		m.m.RLock()
		defer m.m.RUnlock()

		{{ range $methodName, $method := . }}
			if m.{{$methodName}}Func != nil && m.{{$methodName}}Counter == 0 {
				return false
			}
		{{ end }}

		return true
	}`

func processFlags() *options {
	var (
		input  = flag.String("f", "", "input file or import path of the package containing interface declaration")
		name   = flag.String("i", "", "interface name")
		output = flag.String("o", "", "destination file for interface implementation")
		pkg    = flag.String("p", "", "destination package name")
		sname  = flag.String("t", "", "target struct name, default: <interface name>Mock")
	)

	flag.Parse()

	if *pkg == "" || *input == "" || *output == "" || *name == "" || !strings.HasSuffix(*output, ".go") {
		flag.Usage()
		os.Exit(1)
	}

	if *sname == "" {
		*sname = *name + "Mock"
	}

	return &options{
		InputFile:     *input,
		OutputFile:    *output,
		InterfaceName: *name,
		Package:       *pkg,
		StructName:    *sname,
	}
}

func die(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"

	. "github.com/eaburns/quart/geom"
	"github.com/eaburns/quart/phys"

	"github.com/skelterjohn/go.wde"
)

const (
	width  = 640
	height = 480

	speed         = 5
	gravity       = -3
	stopThreshold = 1
)

var (
	vel    Vector
	circle = Circle{Center: Point{200, 200}, Radius: 50}

	// Sides is the set of polygon sides.
	sides = []Side{
		{{0, height - 1}, {0, 0}},
		{{0, 0}, {width - 1, 0}},
		{{width - 1, 0}, {width - 1, height - 1}},
		{{width - 1, height - 1}, {0, height - 1}},
	}

	// Click is the position of the latest mouse click.
	click = Point{-1, -1}

	// Cursor is the current cursor position.
	cursor Point

	// Stopped is true if the circle has effectively stopped moving.
	stopped bool
)

func main() {
	go mainLoop()
	wde.Run()
}

func mainLoop() {
	win, err := wde.NewWindow(width, height)
	if err != nil {
		panic(err)
	}
	win.SetTitle("geom test")
	win.Show()

	drawScene(win)

	tick := time.NewTicker(40 * time.Millisecond)
	for {
		select {
		case ev, ok := <-win.EventChan():
			if !ok {
				os.Exit(0)
			}
			switch ev := ev.(type) {
			case wde.CloseEvent:
				os.Exit(0)
			case wde.KeyTypedEvent:
				keyTyped(ev)
			case wde.KeyDownEvent:
				keyDown(wde.KeyEvent(ev))
			case wde.KeyUpEvent:
				keyUp(wde.KeyEvent(ev))
			case wde.MouseDraggedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseMovedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseDownEvent:
				mouseDown(wde.MouseButtonEvent(ev))
			case wde.MouseUpEvent:
				mouseUp(wde.MouseButtonEvent(ev))
			}

		case <-tick.C:
			if !stopped {
				start := circle.Center
				circle = phys.MoveCircle(circle, vel, sides)
				circle = phys.MoveCircle(circle, Vector{0, gravity}, sides)
				dist := start.Minus(circle.Center).Magnitude()
				stopped = vel.Equals(Vector{}) && dist < stopThreshold
			}
			drawScene(win)
		}
	}
}

func mouseMove(ev wde.MouseEvent) {
	cursor = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
}

func mouseDown(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		click = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
	}
}

func mouseUp(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		sides = append(sides, Side{click, cursor})
		click = Point{-1, -1}
	}
}

func keyTyped(ev wde.KeyTypedEvent) {
	switch ev.Key {
	case "d":
		if len(sides) > 4 {
			sides = sides[:len(sides)-1]
		}
	}
}

func keyDown(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow":
		vel[0] = -speed
	case "right_arrow":
		vel[0] = speed
	case "up_arrow":
		vel[1] = speed
	case "down_arrow":
		vel[1] = -speed
	}
	stopped = false
}

func keyUp(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow", "right_arrow":
		vel[0] = 0
	case "up_arrow", "down_arrow":
		vel[1] = 0
	}
}

func drawScene(win wde.Window) {
	clear(win)
	cv := ImageCanvas{win.Screen()}

	for _, s := range sides {
		s.Draw(cv, color.Black)
	}
	circle.Draw(cv, color.Black)

	if click[0] >= 0 {
		Side{click, cursor}.Draw(cv, color.RGBA{B: 255, A: 255})
	}

	win.FlushImage()
}

func clear(win wde.Window) {
	img := win.Screen()
	draw.Draw(img, img.Bounds(), image.NewUniform(color.White), image.ZP, draw.Src)
}
<commit_msg>Add gravity directly to velocity.<commit_after>package main

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"

	. "github.com/eaburns/quart/geom"
	"github.com/eaburns/quart/phys"

	"github.com/skelterjohn/go.wde"
)

const (
	width  = 640
	height = 480

	speed         = 5
	gravity       = -3
	stopThreshold = 1
)

var (
	vel    Vector
	circle = Circle{Center: Point{200, 200}, Radius: 50}

	// Sides is the set of polygon sides.
	sides = []Side{
		{{0, height - 1}, {0, 0}},
		{{0, 0}, {width - 1, 0}},
		{{width - 1, 0}, {width - 1, height - 1}},
		{{width - 1, height - 1}, {0, height - 1}},
	}

	// Click is the position of the latest mouse click.
	click = Point{-1, -1}

	// Cursor is the current cursor position.
	cursor Point

	// Stopped is true if the circle has effectively stopped moving.
	stopped bool
)

func main() {
	go mainLoop()
	wde.Run()
}

func mainLoop() {
	win, err := wde.NewWindow(width, height)
	if err != nil {
		panic(err)
	}
	win.SetTitle("geom test")
	win.Show()

	drawScene(win)

	tick := time.NewTicker(40 * time.Millisecond)
	for {
		select {
		case ev, ok := <-win.EventChan():
			if !ok {
				os.Exit(0)
			}
			switch ev := ev.(type) {
			case wde.CloseEvent:
				os.Exit(0)
			case wde.KeyTypedEvent:
				keyTyped(ev)
			case wde.KeyDownEvent:
				keyDown(wde.KeyEvent(ev))
			case wde.KeyUpEvent:
				keyUp(wde.KeyEvent(ev))
			case wde.MouseDraggedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseMovedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseDownEvent:
				mouseDown(wde.MouseButtonEvent(ev))
			case wde.MouseUpEvent:
				mouseUp(wde.MouseButtonEvent(ev))
			}

		case <-tick.C:
			if !stopped {
				start := circle.Center
				circle = phys.MoveCircle(circle, vel.Plus(Vector{0, gravity}), sides)
				dist := start.Minus(circle.Center).Magnitude()
				stopped = vel.Equals(Vector{}) && dist < stopThreshold
			}
			drawScene(win)
		}
	}
}

func mouseMove(ev wde.MouseEvent) {
	cursor = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
}

func mouseDown(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		click = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
	}
}

func mouseUp(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		sides = append(sides, Side{click, cursor})
		click = Point{-1, -1}
	}
}

func keyTyped(ev wde.KeyTypedEvent) {
	switch ev.Key {
	case "d":
		if len(sides) > 4 {
			sides = sides[:len(sides)-1]
		}
	}
}

func keyDown(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow":
		vel[0] = -speed
	case "right_arrow":
		vel[0] = speed
	case "up_arrow":
		vel[1] = speed
	case "down_arrow":
		vel[1] = -speed
	}
	stopped = false
}

func keyUp(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow", "right_arrow":
		vel[0] = 0
	case "up_arrow", "down_arrow":
		vel[1] = 0
	}
}

func drawScene(win wde.Window) {
	clear(win)
	cv := ImageCanvas{win.Screen()}

	for _, s := range sides {
		s.Draw(cv, color.Black)
	}
	circle.Draw(cv, color.Black)

	if click[0] >= 0 {
		Side{click, cursor}.Draw(cv, color.RGBA{B: 255, A: 255})
	}

	win.FlushImage()
}

func clear(win wde.Window) {
	img := win.Screen()
	draw.Draw(img, img.Bounds(), image.NewUniform(color.White), image.ZP, draw.Src)
}
<|endoftext|>


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

package api

import (
	"log"
	"net/http"

	"time"

	router "github.com/gorilla/mux"
	"github.com/minio-io/minio/pkg/api/config"
	"github.com/minio-io/minio/pkg/api/quota"
	"github.com/minio-io/minio/pkg/iodine"
	"github.com/minio-io/minio/pkg/storage/drivers"
)

// private use
type minioAPI struct {
	domain string
	driver drivers.Driver
}

// Path based routing
func pathMux(api minioAPI, mux *router.Router) *router.Router {
	mux.HandleFunc("/", api.listBucketsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT")
	mux.HandleFunc("/{bucket}", api.headBucketHandler).Methods("HEAD")
	mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET")
	mux.HandleFunc("/{bucket}/{object:.*}", api.headObjectHandler).Methods("HEAD")
	mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT")

	return mux
}

// Domain based routing
func domainMux(api minioAPI, mux *router.Router) *router.Router {
	mux.HandleFunc("/",
		api.listObjectsHandler).Host("{bucket}" + "." + api.domain).Methods("GET")
	mux.HandleFunc("/{object:.*}",
		api.getObjectHandler).Host("{bucket}" + "." + api.domain).Methods("GET")
	mux.HandleFunc("/{object:.*}",
		api.headObjectHandler).Host("{bucket}" + "." + api.domain).Methods("HEAD")
	mux.HandleFunc("/{object:.*}",
		api.putObjectHandler).Host("{bucket}" + "." + api.domain).Methods("PUT")
	mux.HandleFunc("/", api.listBucketsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT")
	mux.HandleFunc("/{bucket}", api.headBucketHandler).Methods("HEAD")

	return mux
}

// Get proper router based on domain availability
func getMux(api minioAPI, mux *router.Router) *router.Router {
	switch true {
	case api.domain == "":
		return pathMux(api, mux)
	case api.domain != "":
		s := mux.Host(api.domain).Subrouter()
		return domainMux(api, s)
	}
	return nil
}

// HTTPHandler - http wrapper handler
func HTTPHandler(domain string, driver drivers.Driver) http.Handler {
	var mux *router.Router
	var api = minioAPI{}
	api.driver = driver
	api.domain = domain

	r := router.NewRouter()
	mux = getMux(api, r)

	var conf = config.Config{}
	if err := conf.SetupConfig(); err != nil {
		log.Fatal(iodine.New(err, map[string]string{"domain": domain}))
	}

	h := timeValidityHandler(mux)
	h = ignoreResourcesHandler(h)
	h = validateRequestHandler(conf, h)
	h = quota.BandwidthCap(h, 25*1024*1024, time.Duration(30*time.Minute))
	h = quota.BandwidthCap(h, 100*1024*1024, time.Duration(24*time.Hour))
	h = quota.RequestLimit(h, 100, time.Duration(30*time.Minute))
	h = quota.RequestLimit(h, 1000, time.Duration(24*time.Hour))
	h = quota.ConnectionLimit(h, 5)
	return h
}
<commit_msg>Removing quotas, will handle with iptables<commit_after>/*
 * Minimalist Object Storage, (C) 2014 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package api

import (
	"log"
	"net/http"

	router "github.com/gorilla/mux"
	"github.com/minio-io/minio/pkg/api/config"
	"github.com/minio-io/minio/pkg/api/quota"
	"github.com/minio-io/minio/pkg/iodine"
	"github.com/minio-io/minio/pkg/storage/drivers"
)

// private use
type minioAPI struct {
	domain string
	driver drivers.Driver
}

// Path based routing
func pathMux(api minioAPI, mux *router.Router) *router.Router {
	mux.HandleFunc("/", api.listBucketsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT")
	mux.HandleFunc("/{bucket}", api.headBucketHandler).Methods("HEAD")
	mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET")
	mux.HandleFunc("/{bucket}/{object:.*}", api.headObjectHandler).Methods("HEAD")
	mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT")

	return mux
}

// Domain based routing
func domainMux(api minioAPI, mux *router.Router) *router.Router {
	mux.HandleFunc("/",
		api.listObjectsHandler).Host("{bucket}" + "." + api.domain).Methods("GET")
	mux.HandleFunc("/{object:.*}",
		api.getObjectHandler).Host("{bucket}" + "." + api.domain).Methods("GET")
	mux.HandleFunc("/{object:.*}",
		api.headObjectHandler).Host("{bucket}" + "." + api.domain).Methods("HEAD")
	mux.HandleFunc("/{object:.*}",
		api.putObjectHandler).Host("{bucket}" + "." + api.domain).Methods("PUT")
	mux.HandleFunc("/", api.listBucketsHandler).Methods("GET")
	mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT")
	mux.HandleFunc("/{bucket}", api.headBucketHandler).Methods("HEAD")

	return mux
}

// Get proper router based on domain availability
func getMux(api minioAPI, mux *router.Router) *router.Router {
	switch true {
	case api.domain == "":
		return pathMux(api, mux)
	case api.domain != "":
		s := mux.Host(api.domain).Subrouter()
		return domainMux(api, s)
	}
	return nil
}

// HTTPHandler - http wrapper handler
func HTTPHandler(domain string, driver drivers.Driver) http.Handler {
	var mux *router.Router
	var api = minioAPI{}
	api.driver = driver
	api.domain = domain

	r := router.NewRouter()
	mux = getMux(api, r)

	var conf = config.Config{}
	if err := conf.SetupConfig(); err != nil {
		log.Fatal(iodine.New(err, map[string]string{"domain": domain}))
	}

	h := timeValidityHandler(mux)
	h = ignoreResourcesHandler(h)
	h = validateRequestHandler(conf, h)
	//	h = quota.BandwidthCap(h, 25*1024*1024, time.Duration(30*time.Minute))
	//	h = quota.BandwidthCap(h, 100*1024*1024, time.Duration(24*time.Hour))
	//	h = quota.RequestLimit(h, 100, time.Duration(30*time.Minute))
	//	h = quota.RequestLimit(h, 1000, time.Duration(24*time.Hour))
	h = quota.ConnectionLimit(h, 5)
	return h
}
<|endoftext|>


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

package client

import (
	"bufio"
	"net"

	"macleod.io/bounce/irc"
)

func New(conn net.Conn) *Client {
	client := &Client{
		conn: conn,
		In:   make(chan *irc.Message),
		Out:  make(chan *irc.Message),
	}
	go client.listen()
	go client.scan()
	return client
}

type Capabilities struct {
	Available    []string
	Acknowledged []string
}

type Client struct {
	Capabilities []Capabilities
	conn         net.Conn

	In  chan *irc.Message
	Out chan *irc.Message
}

func (c *Client) Close() error {
	close(c.In)
	return c.conn.Close()
}

func (c *Client) listen() {
	for message := range c.In {
		// TODO : middleware
		message.Buffer().WriteTo(c.conn)
	}
}

func (c *Client) scan() {
	scanner := bufio.NewScanner(c.conn)
	for scanner.Scan() {
		message := irc.ParseMessage(scanner.Text())
		// TODO : middleware
		c.Out <- message
	}
	close(c.Out)
}
<commit_msg>Rename client.listen() to client.accept()<commit_after>//    Copyright 2016 Alex Macleod
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package client

import (
	"bufio"
	"net"

	"macleod.io/bounce/irc"
)

func New(conn net.Conn) *Client {
	client := &Client{
		conn: conn,
		In:   make(chan *irc.Message),
		Out:  make(chan *irc.Message),
	}
	go client.accept()
	go client.scan()
	return client
}

type Capabilities struct {
	Available    []string
	Acknowledged []string
}

type Client struct {
	Capabilities []Capabilities
	conn         net.Conn

	In  chan *irc.Message
	Out chan *irc.Message
}

func (c *Client) Close() error {
	close(c.In)
	return c.conn.Close()
}

func (c *Client) accept() {
	for message := range c.In {
		// TODO : middleware
		message.Buffer().WriteTo(c.conn)
	}
}

func (c *Client) scan() {
	scanner := bufio.NewScanner(c.conn)
	for scanner.Scan() {
		message := irc.ParseMessage(scanner.Text())
		// TODO : middleware
		c.Out <- message
	}
	close(c.Out)
}
<|endoftext|>


<commit_before>package mastodon

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// Config is a setting for access mastodon APIs.
type Config struct {
	Server       string
	ClientID     string
	ClientSecret string
	AccessToken  string
}

// Client is a API client for mastodon.
type Client struct {
	http.Client
	config *Config
}

func (c *Client) doAPI(method string, uri string, params url.Values, res interface{}) error {
	url, err := url.Parse(c.config.Server)
	if err != nil {
		return err
	}
	url.Path = path.Join(url.Path, uri)

	var resp *http.Response
	req, err := http.NewRequest(method, url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
	resp, err = c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if res == nil {
		return nil
	}

	if method == "GET" && resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad request: %v", resp.Status)
	}

	return json.NewDecoder(resp.Body).Decode(&res)
}

// NewClient return new mastodon API client.
func NewClient(config *Config) *Client {
	return &Client{
		Client: *http.DefaultClient,
		config: config,
	}
}

// Authenticate get access-token to the API.
func (c *Client) Authenticate(username, password string) error {
	params := url.Values{}
	params.Set("client_id", c.config.ClientID)
	params.Set("client_secret", c.config.ClientSecret)
	params.Set("grant_type", "password")
	params.Set("username", username)
	params.Set("password", password)
	params.Set("scope", "read write follow")

	url, err := url.Parse(c.config.Server)
	if err != nil {
		return err
	}
	url.Path = path.Join(url.Path, "/oauth/token")

	req, err := http.NewRequest("POST", url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad authorization: %v", resp.Status)
	}

	res := struct {
		AccessToken string `json:"access_token"`
	}{}
	err = json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		return err
	}
	c.config.AccessToken = res.AccessToken
	return nil
}

// AppConfig is a setting for registering applications.
type AppConfig struct {
	http.Client
	Server     string
	ClientName string

	// Where the user should be redirected after authorization (for no redirect, use urn:ietf:wg:oauth:2.0:oob)
	RedirectURIs string

	// This can be a space-separated list of the following items: "read", "write" and "follow".
	Scopes string

	// Optional.
	Website string
}

// Application is mastodon application.
type Application struct {
	ID           int64  `json:"id"`
	RedirectURI  string `json:"redirect_uri"`
	ClientID     string `json:"client_id"`
	ClientSecret string `json:"client_secret"`
}

// RegisterApp returns the mastodon application.
func RegisterApp(appConfig *AppConfig) (*Application, error) {
	params := url.Values{}
	params.Set("client_name", appConfig.ClientName)
	if appConfig.RedirectURIs == "" {
		params.Set("redirect_uris", "urn:ietf:wg:oauth:2.0:oob")
	} else {
		params.Set("redirect_uris", appConfig.RedirectURIs)
	}
	params.Set("scopes", appConfig.Scopes)
	params.Set("website", appConfig.Website)

	url, err := url.Parse(appConfig.Server)
	if err != nil {
		return nil, err
	}
	url.Path = path.Join(url.Path, "/api/v1/apps")

	req, err := http.NewRequest("POST", url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := appConfig.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("bad request: %v", resp.Status)
	}

	var app Application
	err = json.NewDecoder(resp.Body).Decode(&app)
	if err != nil {
		return nil, err
	}

	return &app, nil
}

// Account hold information for mastodon account.
type Account struct {
	ID             int64     `json:"id"`
	Username       string    `json:"username"`
	Acct           string    `json:"acct"`
	DisplayName    string    `json:"display_name"`
	Locked         bool      `json:"locked"`
	CreatedAt      time.Time `json:"created_at"`
	FollowersCount int64     `json:"followers_count"`
	FollowingCount int64     `json:"following_count"`
	StatusesCount  int64     `json:"statuses_count"`
	Note           string    `json:"note"`
	URL            string    `json:"url"`
	Avatar         string    `json:"avatar"`
	AvatarStatic   string    `json:"avatar_static"`
	Header         string    `json:"header"`
	HeaderStatic   string    `json:"header_static"`
}

// Toot is struct to post status.
type Toot struct {
	Status      string  `json:"status"`
	InReplyToID int64   `json:"in_reply_to_id"`
	MediaIDs    []int64 `json:"media_ids"`
	Sensitive   bool    `json:"sensitive"`
	SpoilerText string  `json:"spoiler_text"`
	Visibility  string  `json:"visibility"`
}

// Status is struct to hold status.
type Status struct {
	ID                 int64         `json:"id"`
	CreatedAt          time.Time     `json:"created_at"`
	InReplyToID        interface{}   `json:"in_reply_to_id"`
	InReplyToAccountID interface{}   `json:"in_reply_to_account_id"`
	Sensitive          bool          `json:"sensitive"`
	SpoilerText        string        `json:"spoiler_text"`
	Visibility         string        `json:"visibility"`
	Application        interface{}   `json:"application"`
	Account            Account       `json:"account"`
	MediaAttachments   []interface{} `json:"media_attachments"`
	Mentions           []interface{} `json:"mentions"`
	Tags               []interface{} `json:"tags"`
	URI                string        `json:"uri"`
	Content            string        `json:"content"`
	URL                string        `json:"url"`
	ReblogsCount       int64         `json:"reblogs_count"`
	FavouritesCount    int64         `json:"favourites_count"`
	Reblog             interface{}   `json:"reblog"`
	Favourited         interface{}   `json:"favourited"`
	Reblogged          interface{}   `json:"reblogged"`
}

// GetAccount return Account.
func (c *Client) GetAccount(id int) (*Account, error) {
	var account Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetAccountCurrentUser return Account of current user.
func (c *Client) GetAccountCurrentUser() (*Account, error) {
	var account Account
	err := c.doAPI("GET", "/api/v1/accounts/verify_credentials", nil, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetAccountFollowers return followers list.
func (c *Client) GetAccountFollowers(id int64) ([]*Account, error) {
	var accounts []*Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d/followers", id), nil, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}

// GetAccountFollowing return following list.
func (c *Client) GetAccountFollowing(id int64) ([]*Account, error) {
	var accounts []*Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}

// GetTimelineHome return statuses from home timeline.
func (c *Client) GetTimelineHome() ([]*Status, error) {
	var statuses []*Status
	err := c.doAPI("GET", "/api/v1/timelines/home", nil, &statuses)
	if err != nil {
		return nil, err
	}
	return statuses, nil
}

// PostStatus post the toot.
func (c *Client) PostStatus(toot *Toot) (*Status, error) {
	params := url.Values{}
	params.Set("status", toot.Status)
	if toot.InReplyToID > 0 {
		params.Set("in_reply_to_id", fmt.Sprint(toot.InReplyToID))
	}
	// TODO: media_ids, senstitive, spoiler_text, visibility
	//params.Set("visibility", "public")

	var status Status
	err := c.doAPI("POST", "/api/v1/statuses", params, &status)
	if err != nil {
		return nil, err
	}
	return &status, nil
}

// UpdateEvent is struct for passing status event to app.
type UpdateEvent struct{ Status *Status }

func (e *UpdateEvent) event() {}

// NotificationEvent is struct for passing notification event to app.
type NotificationEvent struct{}

func (e *NotificationEvent) event() {}

// DeleteEvent is struct for passing deletion event to app.
type DeleteEvent struct{ ID int64 }

func (e *DeleteEvent) event() {}

// ErrorEvent is struct for passing errors to app.
type ErrorEvent struct{ err error }

func (e *ErrorEvent) event()        {}
func (e *ErrorEvent) Error() string { return e.err.Error() }

// Event is interface passing events to app.
type Event interface {
	event()
}

// StreamingPublic return channel to read events.
func (c *Client) StreamingPublic(ctx context.Context) (chan Event, error) {
	url, err := url.Parse(c.config.Server)
	if err != nil {
		return nil, err
	}
	url.Path = path.Join(url.Path, "/api/v1/streaming/public")

	var resp *http.Response

	q := make(chan Event, 10)
	go func() {
		defer ctx.Done()

		for {
			req, err := http.NewRequest("GET", url.String(), nil)
			if err == nil {
				req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
				resp, err = c.Do(req)
			}
			if err == nil {
				name := ""
				s := bufio.NewScanner(resp.Body)
				for s.Scan() {
					line := s.Text()
					token := strings.SplitN(line, ":", 2)
					if len(token) != 2 {
						continue
					}
					switch strings.TrimSpace(token[0]) {
					case "event":
						name = strings.TrimSpace(token[1])
					case "data":
						switch name {
						case "update":
							var status Status
							err = json.Unmarshal([]byte(token[1]), &status)
							if err == nil {
								q <- &UpdateEvent{&status}
							}
						case "notification":
						case "delete":
						}
					default:
					}
				}
				resp.Body.Close()
				err = ctx.Err()
				if err == nil {
					break
				}
			} else {
				q <- &ErrorEvent{err}
			}
			time.Sleep(3 * time.Second)
		}
	}()
	go func() {
		<-ctx.Done()
		if resp != nil && resp.Body != nil {
			resp.Body.Close()
		}
	}()
	return q, nil
}

// Follow send follow-request.
func (c *Client) Follow(uri string) (*Account, error) {
	params := url.Values{}
	params.Set("uri", uri)

	var account Account
	err := c.doAPI("POST", "/api/v1/follows", params, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetFollowRequests return follow-requests.
func (c *Client) GetFollowRequests(uri string) ([]*Account, error) {
	params := url.Values{}
	params.Set("uri", uri)

	var accounts []*Account
	err := c.doAPI("GET", "/api/v1/follow_requests", params, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}
<commit_msg>separate func<commit_after>package mastodon

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"
)

// Config is a setting for access mastodon APIs.
type Config struct {
	Server       string
	ClientID     string
	ClientSecret string
	AccessToken  string
}

// Client is a API client for mastodon.
type Client struct {
	http.Client
	config *Config
}

func (c *Client) doAPI(method string, uri string, params url.Values, res interface{}) error {
	url, err := url.Parse(c.config.Server)
	if err != nil {
		return err
	}
	url.Path = path.Join(url.Path, uri)

	var resp *http.Response
	req, err := http.NewRequest(method, url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
	resp, err = c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if res == nil {
		return nil
	}

	if method == "GET" && resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad request: %v", resp.Status)
	}

	return json.NewDecoder(resp.Body).Decode(&res)
}

// NewClient return new mastodon API client.
func NewClient(config *Config) *Client {
	return &Client{
		Client: *http.DefaultClient,
		config: config,
	}
}

// Authenticate get access-token to the API.
func (c *Client) Authenticate(username, password string) error {
	params := url.Values{}
	params.Set("client_id", c.config.ClientID)
	params.Set("client_secret", c.config.ClientSecret)
	params.Set("grant_type", "password")
	params.Set("username", username)
	params.Set("password", password)
	params.Set("scope", "read write follow")

	url, err := url.Parse(c.config.Server)
	if err != nil {
		return err
	}
	url.Path = path.Join(url.Path, "/oauth/token")

	req, err := http.NewRequest("POST", url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad authorization: %v", resp.Status)
	}

	res := struct {
		AccessToken string `json:"access_token"`
	}{}
	err = json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		return err
	}
	c.config.AccessToken = res.AccessToken
	return nil
}

// AppConfig is a setting for registering applications.
type AppConfig struct {
	http.Client
	Server     string
	ClientName string

	// Where the user should be redirected after authorization (for no redirect, use urn:ietf:wg:oauth:2.0:oob)
	RedirectURIs string

	// This can be a space-separated list of the following items: "read", "write" and "follow".
	Scopes string

	// Optional.
	Website string
}

// Application is mastodon application.
type Application struct {
	ID           int64  `json:"id"`
	RedirectURI  string `json:"redirect_uri"`
	ClientID     string `json:"client_id"`
	ClientSecret string `json:"client_secret"`
}

// RegisterApp returns the mastodon application.
func RegisterApp(appConfig *AppConfig) (*Application, error) {
	params := url.Values{}
	params.Set("client_name", appConfig.ClientName)
	if appConfig.RedirectURIs == "" {
		params.Set("redirect_uris", "urn:ietf:wg:oauth:2.0:oob")
	} else {
		params.Set("redirect_uris", appConfig.RedirectURIs)
	}
	params.Set("scopes", appConfig.Scopes)
	params.Set("website", appConfig.Website)

	url, err := url.Parse(appConfig.Server)
	if err != nil {
		return nil, err
	}
	url.Path = path.Join(url.Path, "/api/v1/apps")

	req, err := http.NewRequest("POST", url.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := appConfig.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("bad request: %v", resp.Status)
	}

	var app Application
	err = json.NewDecoder(resp.Body).Decode(&app)
	if err != nil {
		return nil, err
	}

	return &app, nil
}

// Account hold information for mastodon account.
type Account struct {
	ID             int64     `json:"id"`
	Username       string    `json:"username"`
	Acct           string    `json:"acct"`
	DisplayName    string    `json:"display_name"`
	Locked         bool      `json:"locked"`
	CreatedAt      time.Time `json:"created_at"`
	FollowersCount int64     `json:"followers_count"`
	FollowingCount int64     `json:"following_count"`
	StatusesCount  int64     `json:"statuses_count"`
	Note           string    `json:"note"`
	URL            string    `json:"url"`
	Avatar         string    `json:"avatar"`
	AvatarStatic   string    `json:"avatar_static"`
	Header         string    `json:"header"`
	HeaderStatic   string    `json:"header_static"`
}

// Toot is struct to post status.
type Toot struct {
	Status      string  `json:"status"`
	InReplyToID int64   `json:"in_reply_to_id"`
	MediaIDs    []int64 `json:"media_ids"`
	Sensitive   bool    `json:"sensitive"`
	SpoilerText string  `json:"spoiler_text"`
	Visibility  string  `json:"visibility"`
}

// Status is struct to hold status.
type Status struct {
	ID                 int64         `json:"id"`
	CreatedAt          time.Time     `json:"created_at"`
	InReplyToID        interface{}   `json:"in_reply_to_id"`
	InReplyToAccountID interface{}   `json:"in_reply_to_account_id"`
	Sensitive          bool          `json:"sensitive"`
	SpoilerText        string        `json:"spoiler_text"`
	Visibility         string        `json:"visibility"`
	Application        interface{}   `json:"application"`
	Account            Account       `json:"account"`
	MediaAttachments   []interface{} `json:"media_attachments"`
	Mentions           []interface{} `json:"mentions"`
	Tags               []interface{} `json:"tags"`
	URI                string        `json:"uri"`
	Content            string        `json:"content"`
	URL                string        `json:"url"`
	ReblogsCount       int64         `json:"reblogs_count"`
	FavouritesCount    int64         `json:"favourites_count"`
	Reblog             interface{}   `json:"reblog"`
	Favourited         interface{}   `json:"favourited"`
	Reblogged          interface{}   `json:"reblogged"`
}

// GetAccount return Account.
func (c *Client) GetAccount(id int) (*Account, error) {
	var account Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetAccountCurrentUser return Account of current user.
func (c *Client) GetAccountCurrentUser() (*Account, error) {
	var account Account
	err := c.doAPI("GET", "/api/v1/accounts/verify_credentials", nil, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetAccountFollowers return followers list.
func (c *Client) GetAccountFollowers(id int64) ([]*Account, error) {
	var accounts []*Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d/followers", id), nil, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}

// GetAccountFollowing return following list.
func (c *Client) GetAccountFollowing(id int64) ([]*Account, error) {
	var accounts []*Account
	err := c.doAPI("GET", fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}

// GetTimelineHome return statuses from home timeline.
func (c *Client) GetTimelineHome() ([]*Status, error) {
	var statuses []*Status
	err := c.doAPI("GET", "/api/v1/timelines/home", nil, &statuses)
	if err != nil {
		return nil, err
	}
	return statuses, nil
}

// PostStatus post the toot.
func (c *Client) PostStatus(toot *Toot) (*Status, error) {
	params := url.Values{}
	params.Set("status", toot.Status)
	if toot.InReplyToID > 0 {
		params.Set("in_reply_to_id", fmt.Sprint(toot.InReplyToID))
	}
	// TODO: media_ids, senstitive, spoiler_text, visibility
	//params.Set("visibility", "public")

	var status Status
	err := c.doAPI("POST", "/api/v1/statuses", params, &status)
	if err != nil {
		return nil, err
	}
	return &status, nil
}

// UpdateEvent is struct for passing status event to app.
type UpdateEvent struct{ Status *Status }

func (e *UpdateEvent) event() {}

// NotificationEvent is struct for passing notification event to app.
type NotificationEvent struct{}

func (e *NotificationEvent) event() {}

// DeleteEvent is struct for passing deletion event to app.
type DeleteEvent struct{ ID int64 }

func (e *DeleteEvent) event() {}

// ErrorEvent is struct for passing errors to app.
type ErrorEvent struct{ err error }

func (e *ErrorEvent) event()        {}
func (e *ErrorEvent) Error() string { return e.err.Error() }

// Event is interface passing events to app.
type Event interface {
	event()
}

func handleReader(q chan Event, r io.Reader) error {
	name := ""
	s := bufio.NewScanner(r)
	for s.Scan() {
		line := s.Text()
		token := strings.SplitN(line, ":", 2)
		if len(token) != 2 {
			continue
		}
		switch strings.TrimSpace(token[0]) {
		case "event":
			name = strings.TrimSpace(token[1])
		case "data":
			switch name {
			case "update":
				var status Status
				err = json.Unmarshal([]byte(token[1]), &status)
				if err == nil {
					q <- &UpdateEvent{&status}
				}
			case "notification":
			case "delete":
			}
		default:
		}
	}
	return ctx.Err()
}

// StreamingPublic return channel to read events.
func (c *Client) StreamingPublic(ctx context.Context) (chan Event, error) {
	url, err := url.Parse(c.config.Server)
	if err != nil {
		return nil, err
	}
	url.Path = path.Join(url.Path, "/api/v1/streaming/public")

	var resp *http.Response

	q := make(chan Event, 10)
	go func() {
		defer ctx.Done()

		for {
			req, err := http.NewRequest("GET", url.String(), nil)
			if err == nil {
				req.Header.Set("Authorization", "Bearer "+c.config.AccessToken)
				resp, err = c.Do(req)
			}
			if err == nil {
				err = handleReader(resp.Body)
				if err == nil {
					break
				}
				resp.Body.Close()
				return err
			} else {
				q <- &ErrorEvent{err}
			}
			time.Sleep(3 * time.Second)
		}
	}()
	go func() {
		<-ctx.Done()
		if resp != nil && resp.Body != nil {
			resp.Body.Close()
		}
	}()
	return q, nil
}

// Follow send follow-request.
func (c *Client) Follow(uri string) (*Account, error) {
	params := url.Values{}
	params.Set("uri", uri)

	var account Account
	err := c.doAPI("POST", "/api/v1/follows", params, &account)
	if err != nil {
		return nil, err
	}
	return &account, nil
}

// GetFollowRequests return follow-requests.
func (c *Client) GetFollowRequests(uri string) ([]*Account, error) {
	params := url.Values{}
	params.Set("uri", uri)

	var accounts []*Account
	err := c.doAPI("GET", "/api/v1/follow_requests", params, &accounts)
	if err != nil {
		return nil, err
	}
	return accounts, nil
}
<|endoftext|>


<commit_before>package multasgt

import (
	"regexp"
	"strings"

	"golang.org/x/net/html"
)

// Ticket represents the information related to the ticket.
type Ticket struct {
	ID       string
	Entity   string
	Date     string
	Ammount  string
	Discount string
	Total    string
	Location string
	Info     string
	Photo    string
}

// TicketChecker is the interface that all checkers must implement.
type TicketChecker interface {
	Check(plateType, plateNumber string) ([]Ticket, error)
}

func getAttribute(attrName string, n *html.Node) string {
	if n == nil {
		return ""
	}
	for i, a := range n.Attr {
		if a.Key == attrName {
			return n.Attr[i].Val
		}
	}
	return ""
}

func cleanStrings(s string) string {
	clean := regexp.MustCompile(`[\t\n\r]`)
	return clean.ReplaceAllString(strings.TrimSpace(s), "")
}
<commit_msg>Add json meta<commit_after>package multasgt

import (
	"regexp"
	"strings"

	"golang.org/x/net/html"
)

// Ticket represents the information related to the ticket.
type Ticket struct {
	ID       string `json:"id"`
	Entity   string `json:"entity"`
	Date     string `json:"date"`
	Ammount  string `json:"ammount"`
	Discount string `json:"discount"`
	Total    string `json:"total"`
	Location string `json:"location"`
	Info     string `json:"info"`
	Photo    string `json:"photo"`
}

// TicketChecker is the interface that all checkers must implement.
type TicketChecker interface {
	Check(plateType, plateNumber string) ([]Ticket, error)
}

func getAttribute(attrName string, n *html.Node) string {
	if n == nil {
		return ""
	}
	for i, a := range n.Attr {
		if a.Key == attrName {
			return n.Attr[i].Val
		}
	}
	return ""
}

func cleanStrings(s string) string {
	clean := regexp.MustCompile(`[\t\n\r]`)
	return clean.ReplaceAllString(strings.TrimSpace(s), "")
}
<|endoftext|>


<commit_before>package mgopw

import (
	"testing"

	"github.com/klauspost/password/drivers"
	"gopkg.in/mgo.v2"
)

// Test a Mongo database
func TestMongo(t *testing.T) {
	session, err := mgo.Dial("127.0.0.1:27017")
	if err != nil {
		t.Skip("No database: ", err)
	}
	coll := session.DB("testdb").C("password-test")
	_ = coll.DropCollection()

	db := New(session, "testdb", "password-test")
	err = drivers.TestImport(db)
	if err != nil {
		t.Fatal(err)
	}

	// Be sure data is flushed, probably not needed, but we like to be sure
	err = session.Fsync(false)
	if err != nil {
		t.Log("Fsync returned", err, "(ignoring)")
	}

	err = drivers.TestData(db)
	if err != nil {
		t.Fatal(err)
	}

	err = coll.DropCollection()
	if err != nil {
		t.Log("Drop returned", err, "(ignoring)")
	}
	session.Close()
}
<commit_msg>Lower connect timeout.<commit_after>package mgopw

import (
	"testing"
	"time"

	"github.com/klauspost/password/drivers"
	"gopkg.in/mgo.v2"
)

// Test a Mongo database
func TestMongo(t *testing.T) {
	session, err := mgo.DialWithTimeout("127.0.0.1:27017", time.Second)
	if err != nil {
		t.Skip("No database: ", err)
	}
	coll := session.DB("testdb").C("password-test")
	_ = coll.DropCollection()

	db := New(session, "testdb", "password-test")
	err = drivers.TestImport(db)
	if err != nil {
		t.Fatal(err)
	}

	// Be sure data is flushed, probably not needed, but we like to be sure
	err = session.Fsync(false)
	if err != nil {
		t.Log("Fsync returned", err, "(ignoring)")
	}

	err = drivers.TestData(db)
	if err != nil {
		t.Fatal(err)
	}

	err = coll.DropCollection()
	if err != nil {
		t.Log("Drop returned", err, "(ignoring)")
	}
	session.Close()
}
<|endoftext|>


<commit_before>package core

import (
	"reflect"
	"testing"
	"time"

	"github.com/elves/elvish/edit/tty"
	"github.com/elves/elvish/edit/ui"
	"github.com/elves/elvish/styled"
)

var (
	ka     = ui.Key{Rune: 'a'}
	kb     = ui.Key{Rune: 'b'}
	kc     = ui.Key{Rune: 'c'}
	kEnter = ui.Key{Rune: ui.Enter}

	keysABCEnter = []ui.Key{ka, kb, kc, kEnter}
	eventsABC    = []tty.Event{
		tty.KeyEvent(ka), tty.KeyEvent(kb), tty.KeyEvent(kc)}
	eventsABCEnter = []tty.Event{
		tty.KeyEvent(ka), tty.KeyEvent(kb),
		tty.KeyEvent(kc), tty.KeyEvent(kEnter)}
)

func TestRead_PassesInputEventsToMode(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))
	m := newFakeMode(len(eventsABCEnter))
	ed.state.Mode = m

	ed.Read()

	if !reflect.DeepEqual(m.keys, keysABCEnter) {
		t.Errorf("Mode gets keys %v, want %v", m.keys, keysABCEnter)
	}
}

func TestRead_CallsBeforeReadlineOnce(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))

	called := 0
	ed.config.BeforeReadline = []func(){func() { called++ }}

	ed.Read()

	if called != 1 {
		t.Errorf("BeforeReadline hook called %d times, want 1", called)
	}
}

func TestRead_CallsAfterReadlineOnceWithCode(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))

	called := 0
	code := ""
	ed.config.AfterReadline = []func(string){func(s string) {
		called++
		code = s
	}}

	ed.Read()

	if called != 1 {
		t.Errorf("AfterReadline hook called %d times, want 1", called)
	}
	if code != "abc" {
		t.Errorf("AfterReadline hook called with %q, want %q", code, "abc")
	}
}

func TestRead_RespectsMaxHeight(t *testing.T) {
	// TODO
}

var bufChTimeout = 1 * time.Second

func TestRead_RendersHighlightedCode(t *testing.T) {
	terminal := newFakeTTY(eventsABC)
	ed := NewEditor(terminal)
	ed.config.Render.Highlighter = func(code string) (styled.Text, []error) {
		return styled.Text{
			styled.Segment{styled.Style{Foreground: "red"}, code}}, nil
	}

	go ed.Read()

	wantBuf := ui.NewBuffer(80)
	wantBuf.WriteString("abc", "31" /* SGR for red foreground */)
checkBuffer:
	for {
		select {
		case buf := <-terminal.bufCh:
			// Check if the buffer matches out expectation.
			if reflect.DeepEqual(buf.Lines, wantBuf.Lines) {
				break checkBuffer
			}
		case <-time.After(time.Second):
			t.Errorf("Timeout waiting for matching buffer")
			break checkBuffer
		}
	}
	terminal.eventCh <- tty.KeyEvent(kEnter)
}

func TestRead_RendersErrorFromHighlighter(t *testing.T) {
	// TODO
}

func TestRead_RendersPrompt(t *testing.T) {
	// TODO
}

func TestRead_RendersRprompt(t *testing.T) {
	// TODO
}

func TestRead_SupportsPersistentRprompt(t *testing.T) {
	// TODO
}
<commit_msg>newedit/core: Test support for MaxHeight.<commit_after>package core

import (
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/elves/elvish/edit/tty"
	"github.com/elves/elvish/edit/ui"
	"github.com/elves/elvish/styled"
)

var (
	ka     = ui.Key{Rune: 'a'}
	kb     = ui.Key{Rune: 'b'}
	kc     = ui.Key{Rune: 'c'}
	kEnter = ui.Key{Rune: ui.Enter}

	keysABCEnter = []ui.Key{ka, kb, kc, kEnter}
	eventsABC    = []tty.Event{
		tty.KeyEvent(ka), tty.KeyEvent(kb), tty.KeyEvent(kc)}
	eventsABCEnter = []tty.Event{
		tty.KeyEvent(ka), tty.KeyEvent(kb),
		tty.KeyEvent(kc), tty.KeyEvent(kEnter)}
)

func TestRead_PassesInputEventsToMode(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))
	m := newFakeMode(len(eventsABCEnter))
	ed.state.Mode = m

	ed.Read()

	if !reflect.DeepEqual(m.keys, keysABCEnter) {
		t.Errorf("Mode gets keys %v, want %v", m.keys, keysABCEnter)
	}
}

func TestRead_CallsBeforeReadlineOnce(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))

	called := 0
	ed.config.BeforeReadline = []func(){func() { called++ }}

	ed.Read()

	if called != 1 {
		t.Errorf("BeforeReadline hook called %d times, want 1", called)
	}
}

func TestRead_CallsAfterReadlineOnceWithCode(t *testing.T) {
	ed := NewEditor(newFakeTTY(eventsABCEnter))

	called := 0
	code := ""
	ed.config.AfterReadline = []func(string){func(s string) {
		called++
		code = s
	}}

	ed.Read()

	if called != 1 {
		t.Errorf("AfterReadline hook called %d times, want 1", called)
	}
	if code != "abc" {
		t.Errorf("AfterReadline hook called with %q, want %q", code, "abc")
	}
}

func TestRead_RespectsMaxHeight(t *testing.T) {
	maxHeight := 5

	terminal := newFakeTTY(nil)
	ed := NewEditor(terminal)
	// Will fill more than maxHeight but less than terminal height
	ed.state.Code = strings.Repeat("a", 80*10)
	ed.state.Dot = len(ed.state.Code)

	go ed.Read()

	buf1 := <-terminal.bufCh
	// Make sure that normally the height does exceed maxHeight.
	if h := len(buf1.Lines); h <= maxHeight {
		t.Errorf("Buffer height is %d, should > %d", h, maxHeight)
	}

	ed.config.Render.MaxHeight = maxHeight
	ed.loop.Redraw(false)
	buf2 := <-terminal.bufCh
	if h := len(buf2.Lines); h > maxHeight {
		t.Errorf("Buffer height is %d, should <= %d", h, maxHeight)
	}

	terminal.eventCh <- tty.KeyEvent(kEnter)
}

var bufChTimeout = 1 * time.Second

func TestRead_RendersHighlightedCode(t *testing.T) {
	terminal := newFakeTTY(eventsABC)
	ed := NewEditor(terminal)
	ed.config.Render.Highlighter = func(code string) (styled.Text, []error) {
		return styled.Text{
			styled.Segment{styled.Style{Foreground: "red"}, code}}, nil
	}

	go ed.Read()

	wantBuf := ui.NewBuffer(80)
	wantBuf.WriteString("abc", "31" /* SGR for red foreground */)
checkBuffer:
	for {
		select {
		case buf := <-terminal.bufCh:
			// Check if the buffer matches out expectation.
			if reflect.DeepEqual(buf.Lines, wantBuf.Lines) {
				break checkBuffer
			}
		case <-time.After(time.Second):
			t.Errorf("Timeout waiting for matching buffer")
			break checkBuffer
		}
	}
	terminal.eventCh <- tty.KeyEvent(kEnter)
}

func TestRead_RendersErrorFromHighlighter(t *testing.T) {
	// TODO
}

func TestRead_RendersPrompt(t *testing.T) {
	// TODO
}

func TestRead_RendersRprompt(t *testing.T) {
	// TODO
}

func TestRead_SupportsPersistentRprompt(t *testing.T) {
	// TODO
}
<|endoftext|>