<commit_before>// Package csrf generates and validates csrf tokens for martini.
// There are multiple methods of delivery including via a cookie or HTTP
// header.
// Validation occurs via a traditional hidden form key of "_csrf", or via
// a custom HTTP header "X-CSRFToken".
//
// package main
//
// import (
//     "github.com/go-martini/martini"
//     "github.com/martini-contib/csrf"
//     "github.com/martini-contrib/render"
//     "github.com/martini-contib/sessions"
//     "net/http"
// )
//
// func main() {
//     m := martini.Classic()
//     store := sessions.NewCookieStore([]byte("secret123"))
//     m.Use(sessions.Sessions("my_session", store))
//     // Setup generation middleware.
//     m.Use(csrf.Generate(&csrf.Options{
//         Secret:     "token123",
//         SessionKey: "userID",
//     }))
//     m.Use(render.Renderer())
//
//     // Simulate the authentication of a session. If userID exists redirect
//     // to a form that requires csrf protection.
//     m.Get("/", func(s sessions.Session, r render.Render) {
//         if s.Get("userID") == nil {
//             r.Redirect("/login", 302)
//             return
//         }
//         r.Redirect("/protected", 302)
//     })
//
//     // Set userID for the session.
//     m.Get("/login", func(s sessions.Session, r render.Render) {
//         s.Set("userID", "123456")
//         r.Redirect("/", 302)
//     })
//
//     // Render a protected form. Passing a csrf token by calling x.GetToken()
//     m.Get("/protected", func(s sessions.Session, r render.Render, x csrf.CSRF) {
//         if s.Get("userID") == nil {
//             r.Redirect("/login", 401)
//             return
//         }
//         r.HTML(200, "protected", x.GetToken())
//     })
//
//     // Apply csrf validation to route.
//     m.Post("/protected", csrf.Validate, func(s sessions.Session, r render.Render) {
//         if s.Get("userID") != nil {
//             r.HTML(200, "result", "You submitted a valid token")
//             return
//         }
//         r.Redirect("/login", 401)
//     })
//
//     m.Run()
// }
package csrf

import (
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/xsrftoken"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/sessions"
)

// CSRF is used to get the current token and validate a suspect token.
type CSRF interface {
	// Return HTTP header to search for token.
	GetHeaderName() string
	// Return form value to search for token.
	GetFormName() string
	// Return cookie name to search for token.
	GetCookieName() string
	// Return the token.
	GetToken() string
	// Validate by token.
	ValidToken(t string) bool
	// Error replies to the request with a custom function when ValidToken fails.
	Error(w http.ResponseWriter)
}

type csrf struct {
	// Header name value for setting and getting csrf token.
	Header string
	// Form name value for setting and getting csrf token.
	Form string
	// Cookie name value for setting and getting csrf token.
	Cookie string
	// Token generated to pass via header, cookie, or hidden form value.
	Token string
	// This value must be unique per user.
	ID string
	// Secret used along with the unique id above to generate the Token.
	Secret string
	// ErrorFunc is the custom function that replies to the request when ValidToken fails.
	ErrorFunc func(w http.ResponseWriter)
}

// Returns the name of the HTTP header for csrf token.
func (c *csrf) GetHeaderName() string {
	return c.Header
}

// Returns the name of the form value for csrf token.
func (c *csrf) GetFormName() string {
	return c.Form
}

// Returns the name of the cookie for csrf token.
func (c *csrf) GetCookieName() string {
	return c.Cookie
}

// Returns the current token. This is typically used
// to populate a hidden form in an HTML template.
func (c *csrf) GetToken() string {
	return c.Token
}

// Validates the passed token against the existing Secret and ID.
func (c *csrf) ValidToken(t string) bool {
	return xsrftoken.Valid(t, c.Secret, c.ID, "POST")
}

// Error replies to the request when ValidToken fails.
func (c *csrf) Error(w http.ResponseWriter) {
	c.ErrorFunc(w)
}

// Options maintains options to manage behavior of Generate.
type Options struct {
	// The global secret value used to generate Tokens.
	Secret string
	// HTTP header used to set and get token.
	Header string
	// Form value used to set and get token.
	Form string
	// Cookie value used to set and get token.
	Cookie string
	// Key used for getting the unique ID per user.
	SessionKey string
	// If true, send token via X-CSRFToken header.
	SetHeader bool
	// If true, send token via _csrf cookie.
	SetCookie bool
	// Set the Secure flag to true on the cookie.
	Secure bool
	// The function called when Validate fails.
	ErrorFunc func(w http.ResponseWriter)
	// Array of allowed origins. Will be checked during generation from a cross site request.
	// Must be the complete origin. Example: 'https://golang.org'. You will only need to set this
	// if you are supporting CORS.
	AllowedOrigins []string
}

const domainReg = `/^\.?[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d]))(?:\.[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d])))*$/`

// Generate maps CSRF to each request. If this request is a Get request, it will generate a new token.
// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
func Generate(opts *Options) martini.Handler {
	return func(s sessions.Session, c martini.Context, r *http.Request, w http.ResponseWriter) {
		if opts.Header == "" {
			opts.Header = "X-CSRFToken"
		}
		if opts.Form == "" {
			opts.Form = "_csrf"
		}
		if opts.Cookie == "" {
			opts.Cookie = "_csrf"
		}
		if opts.ErrorFunc == nil {
			opts.ErrorFunc = func(w http.ResponseWriter) {
				http.Error(w, "Invalid csrf token.", http.StatusBadRequest)
			}
		}

		x := &csrf{
			Secret:    opts.Secret,
			Header:    opts.Header,
			Form:      opts.Form,
			Cookie:    opts.Cookie,
			ErrorFunc: opts.ErrorFunc,
		}
		c.MapTo(x, (*CSRF)(nil))

		uid := s.Get(opts.SessionKey)
		if uid == nil {
			return
		}
		switch uid.(type) {
		case string:
			x.ID = uid.(string)
		case int64:
			x.ID = strconv.FormatInt(uid.(int64), 10)
		default:
			return
		}

		if r.Header.Get("Origin") != "" {
			originUrl, err := url.Parse(r.Header.Get("Origin"))
			if err != nil {
				return
			}
			if originUrl.Host != r.Host {
				isAllowed := false
				for _, origin := range opts.AllowedOrigins {
					if originUrl.String() == origin {
						isAllowed = true
						break
					}
				}
				if !isAllowed {
					return
				}
			}
		}

		// If cookie present, map existing token, else generate a new one.
		if ex, err := r.Cookie(opts.Cookie); err == nil && ex.Value != "" {
			x.Token = ex.Value
		} else {
			x.Token = xsrftoken.Generate(x.Secret, x.ID, "POST")
			if opts.SetCookie {
				expire := time.Now().AddDate(0, 0, 1)
				// Verify the domain is valid. If it is not, set as empty.
				domain := strings.Split(r.Host, ":")[0]
				if ok, err := regexp.Match(domainReg, []byte(domain)); !ok || err != nil {
					domain = ""
				}

				cookie := &http.Cookie{
					Name:       opts.Cookie,
					Value:      x.Token,
					Path:       "/",
					Domain:     domain,
					Expires:    expire,
					RawExpires: expire.Format(time.UnixDate),
					MaxAge:     0,
					Secure:     opts.Secure,
					HttpOnly:   false,
					Raw:        fmt.Sprintf("%s=%s", opts.Cookie, x.Token),
					Unparsed:   []string{fmt.Sprintf("token=%s", x.Token)},
				}
				http.SetCookie(w, cookie)
			}
		}

		if opts.SetHeader {
			w.Header().Add(opts.Header, x.Token)
		}
	}

}

// Validate should be used as a per route middleware. It attempts to get a token from a "X-CSRFToken"
// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated
// using ValidToken. If this validation fails, custom Error is sent in the reply.
// If neither a header or form value is found, http.StatusBadRequest is sent.
func Validate(r *http.Request, w http.ResponseWriter, x CSRF) {
	if token := r.Header.Get(x.GetHeaderName()); token != "" {
		if !x.ValidToken(token) {
			x.Error(w)
		}
		return
	}
	if token := r.FormValue(x.GetFormName()); token != "" {
		if !x.ValidToken(token) {
			x.Error(w)
		}
		return
	}

	http.Error(w, "Bad Request", http.StatusBadRequest)
	return
}
<commit_msg>Fix regex<commit_after>// Package csrf generates and validates csrf tokens for martini.
// There are multiple methods of delivery including via a cookie or HTTP
// header.
// Validation occurs via a traditional hidden form key of "_csrf", or via
// a custom HTTP header "X-CSRFToken".
//
// package main
//
// import (
//     "github.com/go-martini/martini"
//     "github.com/martini-contib/csrf"
//     "github.com/martini-contrib/render"
//     "github.com/martini-contib/sessions"
//     "net/http"
// )
//
// func main() {
//     m := martini.Classic()
//     store := sessions.NewCookieStore([]byte("secret123"))
//     m.Use(sessions.Sessions("my_session", store))
//     // Setup generation middleware.
//     m.Use(csrf.Generate(&csrf.Options{
//         Secret:     "token123",
//         SessionKey: "userID",
//     }))
//     m.Use(render.Renderer())
//
//     // Simulate the authentication of a session. If userID exists redirect
//     // to a form that requires csrf protection.
//     m.Get("/", func(s sessions.Session, r render.Render) {
//         if s.Get("userID") == nil {
//             r.Redirect("/login", 302)
//             return
//         }
//         r.Redirect("/protected", 302)
//     })
//
//     // Set userID for the session.
//     m.Get("/login", func(s sessions.Session, r render.Render) {
//         s.Set("userID", "123456")
//         r.Redirect("/", 302)
//     })
//
//     // Render a protected form. Passing a csrf token by calling x.GetToken()
//     m.Get("/protected", func(s sessions.Session, r render.Render, x csrf.CSRF) {
//         if s.Get("userID") == nil {
//             r.Redirect("/login", 401)
//             return
//         }
//         r.HTML(200, "protected", x.GetToken())
//     })
//
//     // Apply csrf validation to route.
//     m.Post("/protected", csrf.Validate, func(s sessions.Session, r render.Render) {
//         if s.Get("userID") != nil {
//             r.HTML(200, "result", "You submitted a valid token")
//             return
//         }
//         r.Redirect("/login", 401)
//     })
//
//     m.Run()
// }
package csrf

import (
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/xsrftoken"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/sessions"
)

// CSRF is used to get the current token and validate a suspect token.
type CSRF interface {
	// Return HTTP header to search for token.
	GetHeaderName() string
	// Return form value to search for token.
	GetFormName() string
	// Return cookie name to search for token.
	GetCookieName() string
	// Return the token.
	GetToken() string
	// Validate by token.
	ValidToken(t string) bool
	// Error replies to the request with a custom function when ValidToken fails.
	Error(w http.ResponseWriter)
}

type csrf struct {
	// Header name value for setting and getting csrf token.
	Header string
	// Form name value for setting and getting csrf token.
	Form string
	// Cookie name value for setting and getting csrf token.
	Cookie string
	// Token generated to pass via header, cookie, or hidden form value.
	Token string
	// This value must be unique per user.
	ID string
	// Secret used along with the unique id above to generate the Token.
	Secret string
	// ErrorFunc is the custom function that replies to the request when ValidToken fails.
	ErrorFunc func(w http.ResponseWriter)
}

// Returns the name of the HTTP header for csrf token.
func (c *csrf) GetHeaderName() string {
	return c.Header
}

// Returns the name of the form value for csrf token.
func (c *csrf) GetFormName() string {
	return c.Form
}

// Returns the name of the cookie for csrf token.
func (c *csrf) GetCookieName() string {
	return c.Cookie
}

// Returns the current token. This is typically used
// to populate a hidden form in an HTML template.
func (c *csrf) GetToken() string {
	return c.Token
}

// Validates the passed token against the existing Secret and ID.
func (c *csrf) ValidToken(t string) bool {
	return xsrftoken.Valid(t, c.Secret, c.ID, "POST")
}

// Error replies to the request when ValidToken fails.
func (c *csrf) Error(w http.ResponseWriter) {
	c.ErrorFunc(w)
}

// Options maintains options to manage behavior of Generate.
type Options struct {
	// The global secret value used to generate Tokens.
	Secret string
	// HTTP header used to set and get token.
	Header string
	// Form value used to set and get token.
	Form string
	// Cookie value used to set and get token.
	Cookie string
	// Key used for getting the unique ID per user.
	SessionKey string
	// If true, send token via X-CSRFToken header.
	SetHeader bool
	// If true, send token via _csrf cookie.
	SetCookie bool
	// Set the Secure flag to true on the cookie.
	Secure bool
	// The function called when Validate fails.
	ErrorFunc func(w http.ResponseWriter)
	// Array of allowed origins. Will be checked during generation from a cross site request.
	// Must be the complete origin. Example: 'https://golang.org'. You will only need to set this
	// if you are supporting CORS.
	AllowedOrigins []string
}

const domainReg = `^\.?[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d]))(?:\.[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d])))*$`

// Generate maps CSRF to each request. If this request is a Get request, it will generate a new token.
// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
func Generate(opts *Options) martini.Handler {
	return func(s sessions.Session, c martini.Context, r *http.Request, w http.ResponseWriter) {
		if opts.Header == "" {
			opts.Header = "X-CSRFToken"
		}
		if opts.Form == "" {
			opts.Form = "_csrf"
		}
		if opts.Cookie == "" {
			opts.Cookie = "_csrf"
		}
		if opts.ErrorFunc == nil {
			opts.ErrorFunc = func(w http.ResponseWriter) {
				http.Error(w, "Invalid csrf token.", http.StatusBadRequest)
			}
		}

		x := &csrf{
			Secret:    opts.Secret,
			Header:    opts.Header,
			Form:      opts.Form,
			Cookie:    opts.Cookie,
			ErrorFunc: opts.ErrorFunc,
		}
		c.MapTo(x, (*CSRF)(nil))

		uid := s.Get(opts.SessionKey)
		if uid == nil {
			return
		}
		switch uid.(type) {
		case string:
			x.ID = uid.(string)
		case int64:
			x.ID = strconv.FormatInt(uid.(int64), 10)
		default:
			return
		}

		if r.Header.Get("Origin") != "" {
			originUrl, err := url.Parse(r.Header.Get("Origin"))
			if err != nil {
				return
			}
			if originUrl.Host != r.Host {
				isAllowed := false
				for _, origin := range opts.AllowedOrigins {
					if originUrl.String() == origin {
						isAllowed = true
						break
					}
				}
				if !isAllowed {
					return
				}
			}
		}

		// If cookie present, map existing token, else generate a new one.
		if ex, err := r.Cookie(opts.Cookie); err == nil && ex.Value != "" {
			x.Token = ex.Value
		} else {
			x.Token = xsrftoken.Generate(x.Secret, x.ID, "POST")
			if opts.SetCookie {
				expire := time.Now().AddDate(0, 0, 1)
				// Verify the domain is valid. If it is not, set as empty.
				domain := strings.Split(r.Host, ":")[0]
				if ok, err := regexp.Match(domainReg, []byte(domain)); !ok || err != nil {
					domain = ""
				}

				cookie := &http.Cookie{
					Name:       opts.Cookie,
					Value:      x.Token,
					Path:       "/",
					Domain:     domain,
					Expires:    expire,
					RawExpires: expire.Format(time.UnixDate),
					MaxAge:     0,
					Secure:     opts.Secure,
					HttpOnly:   false,
					Raw:        fmt.Sprintf("%s=%s", opts.Cookie, x.Token),
					Unparsed:   []string{fmt.Sprintf("token=%s", x.Token)},
				}
				http.SetCookie(w, cookie)
			}
		}

		if opts.SetHeader {
			w.Header().Add(opts.Header, x.Token)
		}
	}

}

// Validate should be used as a per route middleware. It attempts to get a token from a "X-CSRFToken"
// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated
// using ValidToken. If this validation fails, custom Error is sent in the reply.
// If neither a header or form value is found, http.StatusBadRequest is sent.
func Validate(r *http.Request, w http.ResponseWriter, x CSRF) {
	if token := r.Header.Get(x.GetHeaderName()); token != "" {
		if !x.ValidToken(token) {
			x.Error(w)
		}
		return
	}
	if token := r.FormValue(x.GetFormName()); token != "" {
		if !x.ValidToken(token) {
			x.Error(w)
		}
		return
	}

	http.Error(w, "Bad Request", http.StatusBadRequest)
	return
}
<|endoftext|>


<commit_before>package daemon

import (
	"errors"
	"net"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"src.elv.sh/pkg/daemon/internal/api"
	"src.elv.sh/pkg/rpc"
	"src.elv.sh/pkg/store"
)

// Serve runs the daemon service, listening on the socket specified by sockpath
// and serving data from dbpath. It quits upon receiving SIGTERM, SIGINT or when
// all active clients have disconnected.
func Serve(sockpath, dbpath string) {
	logger.Println("pid is", syscall.Getpid())
	logger.Println("going to listen", sockpath)
	listener, err := listen(sockpath)
	if err != nil {
		logger.Printf("failed to listen on %s: %v", sockpath, err)
		logger.Println("aborting")
		os.Exit(2)
	}

	st, err := store.NewStore(dbpath)
	if err != nil {
		logger.Printf("failed to create storage: %v", err)
		logger.Printf("serving anyway")
	}

	quitSignals := make(chan os.Signal)
	quitChan := make(chan struct{})
	signal.Notify(quitSignals, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		select {
		case sig := <-quitSignals:
			logger.Printf("received signal %s", sig)
		case <-quitChan:
			logger.Printf("all clients exited")
		}
		err := os.Remove(sockpath)
		if err != nil {
			logger.Printf("failed to remove socket %s: %v", sockpath, err)
		}
		err = st.Close()
		if err != nil {
			logger.Printf("failed to close storage: %v", err)
		}
		err = listener.Close()
		if err != nil {
			logger.Printf("failed to close listener: %v", err)
		}
	}()

	svc := &service{st, err}
	rpc.RegisterName(api.ServiceName, svc)

	logger.Println("starting to serve RPC calls")

	firstClient := true
	activeClient := sync.WaitGroup{}
	// prevent daemon exit before serving first client
	activeClient.Add(1)
	go func() {
		activeClient.Wait()
		close(quitChan)
	}()

	for {
		conn, err := listener.Accept()
		if err != nil {
			if !errors.Is(err, net.ErrClosed) {
				logger.Printf("Failed to accept: %v", err)
			}
			break
		}

		if firstClient {
			firstClient = false
		} else {
			activeClient.Add(1)
		}
		go func() {
			rpc.DefaultServer.ServeConn(conn)
			activeClient.Done()
		}()
	}

	logger.Println("exiting")
}
<commit_msg>pkg/daemon: Don't depend on net.ErrClosed.<commit_after>package daemon

import (
	"os"
	"os/signal"
	"sync"
	"syscall"

	"src.elv.sh/pkg/daemon/internal/api"
	"src.elv.sh/pkg/rpc"
	"src.elv.sh/pkg/store"
)

// Serve runs the daemon service, listening on the socket specified by sockpath
// and serving data from dbpath. It quits upon receiving SIGTERM, SIGINT or when
// all active clients have disconnected.
func Serve(sockpath, dbpath string) {
	logger.Println("pid is", syscall.Getpid())
	logger.Println("going to listen", sockpath)
	listener, err := listen(sockpath)
	if err != nil {
		logger.Printf("failed to listen on %s: %v", sockpath, err)
		logger.Println("aborting")
		os.Exit(2)
	}

	st, err := store.NewStore(dbpath)
	if err != nil {
		logger.Printf("failed to create storage: %v", err)
		logger.Printf("serving anyway")
	}

	quitSignals := make(chan os.Signal)
	quitChan := make(chan struct{})
	signal.Notify(quitSignals, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		select {
		case sig := <-quitSignals:
			logger.Printf("received signal %s", sig)
		case <-quitChan:
			logger.Printf("all clients exited")
		}
		err := os.Remove(sockpath)
		if err != nil {
			logger.Printf("failed to remove socket %s: %v", sockpath, err)
		}
		err = st.Close()
		if err != nil {
			logger.Printf("failed to close storage: %v", err)
		}
		err = listener.Close()
		if err != nil {
			logger.Printf("failed to close listener: %v", err)
		}
	}()

	svc := &service{st, err}
	rpc.RegisterName(api.ServiceName, svc)

	logger.Println("starting to serve RPC calls")

	firstClient := true
	activeClient := sync.WaitGroup{}
	// prevent daemon exit before serving first client
	activeClient.Add(1)
	go func() {
		activeClient.Wait()
		close(quitChan)
	}()

	for {
		conn, err := listener.Accept()
		if err != nil {
			select {
			case <-quitChan:
				// listener was closed explicitly; don't complain.
			default:
				logger.Printf("Failed to accept: %v", err)
			}
			break
		}

		if firstClient {
			firstClient = false
		} else {
			activeClient.Add(1)
		}
		go func() {
			rpc.DefaultServer.ServeConn(conn)
			activeClient.Done()
		}()
	}

	logger.Println("exiting")
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/smancke/guble/protocol"
	"github.com/smancke/guble/store"

	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"github.com/smancke/guble/server/auth"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type WSHandler struct {
	Router        Router
	prefix        string
	messageStore  store.MessageStore
	accessManager auth.AccessManager
}

func NewWSHandler(router Router, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}

	messageStore, err := router.MessageStore()
	if err != nil {
		return nil, err
	}

	return &WSHandler{
		Router:        router,
		prefix:        prefix,
		accessManager: accessManager,
		messageStore:  messageStore,
	}, nil
}

func (handle *WSHandler) GetPrefix() string {
	return handle.prefix
}

func (handle *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		protocol.Warn("error on upgrading %v", err.Error())
		return
	}
	defer c.Close()

	NewWebSocket(handle, &wsconn{c}, extractUserId(r.RequestURI)).Start()
}

// WSConnection is a wrapper interface for the needed functions of the websocket.Conn
// It is introduced for testability of the WSHandler
type WSConnection interface {
	Close()
	Send(bytes []byte) (err error)
	Receive(bytes *[]byte) (err error)
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

func (conn *wsconn) Close() {
	conn.Close()
}

func (conn *wsconn) Send(bytes []byte) (err error) {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// WebSocket struct represents a websocket
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationId string
	userId        string
	sendChannel   chan []byte
	receivers     map[protocol.Path]*Receiver
}

func NewWebSocket(handler *WSHandler, wsConn WSConnection, userID string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationId: xid.New().String(),
		userId:        userID,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[protocol.Path]*Receiver),
	}
}

func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for {
		select {
		case raw := <-ws.sendChannel:

			if ws.checkAccess(raw) {
				if protocol.DebugEnabled() {
					if len(raw) < 80 {
						protocol.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v", ws.userId, ws.applicationId, len(raw), string(raw))
					} else {
						protocol.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v...", ws.userId, ws.applicationId, len(raw), string(raw[0:79]))
					}
				}

				if err := ws.Send(raw); err != nil {
					protocol.Info("applicationId=%v closed the connection", ws.applicationId)
					ws.cleanAndClose()
					break
				}
			}
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	protocol.Debug("raw message: %v", string(raw))
	if raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)
		protocol.Debug("Received msg %v %v", ws.userId, path)
		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userId, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) protocol.Path {
	i := strings.Index(string(raw), ",")
	return protocol.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {
			protocol.Info("applicationId=%v closed the connection", ws.applicationId)
			ws.cleanAndClose()
			break
		}

		//protocol.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := protocol.ParseCmd(message)
		if err != nil {
			ws.sendError(protocol.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case protocol.CmdSend:
			ws.handleSendCmd(cmd)
		case protocol.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case protocol.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(protocol.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &protocol.NotificationMessage{
		Name: protocol.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationId, ws.userId, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *protocol.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationId,
		cmd,
		ws.sendChannel,
		ws.Router,
		ws.messageStore,
		ws.userId,
	)
	if err != nil {
		protocol.Info("client error in handleReceiveCmd: %v", err.Error())
		ws.sendError(protocol.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *protocol.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "- command requires a path argument, but non given")
		return
	}
	path := protocol.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *protocol.Cmd) {
	protocol.Debug("sending %v", string(cmd.Bytes()))
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "send command requires a path argument, but non given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &protocol.Message{
		Path:          protocol.Path(args[0]),
		ApplicationID: ws.applicationId,
		UserID:        ws.userId,
		HeaderJSON:    cmd.HeaderJSON,
		Body:          cmd.Body,
	}
	if len(args) == 2 {
		msg.MessageID = args[1]
	}

	ws.Router.HandleMessage(msg)

	ws.sendOK(protocol.SUCCESS_SEND, msg.MessageID)
}

func (ws *WebSocket) cleanAndClose() {
	protocol.Info("closing applicationId=%v", ws.applicationId)

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}
<commit_msg>adding health-check in websocket<commit_after>package server

import (
	"github.com/smancke/guble/protocol"
	"github.com/smancke/guble/store"

	"github.com/gorilla/websocket"
	"github.com/rs/xid"

	"fmt"
	"github.com/smancke/guble/server/auth"
	"net/http"
	"strings"
	"time"
)

var webSocketUpgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

type WSHandler struct {
	Router        Router
	prefix        string
	messageStore  store.MessageStore
	accessManager auth.AccessManager
}

func NewWSHandler(router Router, prefix string) (*WSHandler, error) {
	accessManager, err := router.AccessManager()
	if err != nil {
		return nil, err
	}

	messageStore, err := router.MessageStore()
	if err != nil {
		return nil, err
	}

	return &WSHandler{
		Router:        router,
		prefix:        prefix,
		accessManager: accessManager,
		messageStore:  messageStore,
	}, nil
}

func (handle *WSHandler) GetPrefix() string {
	return handle.prefix
}

func (handle *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c, err := webSocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		protocol.Warn("error on upgrading %v", err.Error())
		return
	}
	defer c.Close()

	NewWebSocket(handle, &wsconn{c}, extractUserId(r.RequestURI)).Start()
}

func (handle *WSHandler) Check() error {
	return nil
}

// WSConnection is a wrapper interface for the needed functions of the websocket.Conn
// It is introduced for testability of the WSHandler
type WSConnection interface {
	Close()
	Send(bytes []byte) (err error)
	Receive(bytes *[]byte) (err error)
}

// wsconnImpl is a Wrapper of the websocket.Conn
// implementing the interface WSConn for better testability
type wsconn struct {
	*websocket.Conn
}

func (conn *wsconn) Close() {
	conn.Close()
}

func (conn *wsconn) Send(bytes []byte) (err error) {
	return conn.WriteMessage(websocket.BinaryMessage, bytes)
}

func (conn *wsconn) Receive(bytes *[]byte) (err error) {
	_, *bytes, err = conn.ReadMessage()
	return err
}

// WebSocket struct represents a websocket
type WebSocket struct {
	*WSHandler
	WSConnection
	applicationId string
	userId        string
	sendChannel   chan []byte
	receivers     map[protocol.Path]*Receiver
}

func NewWebSocket(handler *WSHandler, wsConn WSConnection, userID string) *WebSocket {
	return &WebSocket{
		WSHandler:     handler,
		WSConnection:  wsConn,
		applicationId: xid.New().String(),
		userId:        userID,
		sendChannel:   make(chan []byte, 10),
		receivers:     make(map[protocol.Path]*Receiver),
	}
}

func (ws *WebSocket) Start() error {
	ws.sendConnectionMessage()
	go ws.sendLoop()
	ws.receiveLoop()
	return nil
}

func (ws *WebSocket) sendLoop() {
	for {
		select {
		case raw := <-ws.sendChannel:

			if ws.checkAccess(raw) {
				if protocol.DebugEnabled() {
					if len(raw) < 80 {
						protocol.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v", ws.userId, ws.applicationId, len(raw), string(raw))
					} else {
						protocol.Debug("send to client (userId=%v, applicationId=%v, totalSize=%v): %v...", ws.userId, ws.applicationId, len(raw), string(raw[0:79]))
					}
				}

				if err := ws.Send(raw); err != nil {
					protocol.Info("applicationId=%v closed the connection", ws.applicationId)
					ws.cleanAndClose()
					break
				}
			}
		}
	}
}

func (ws *WebSocket) checkAccess(raw []byte) bool {
	protocol.Debug("raw message: %v", string(raw))
	if raw[0] == byte('/') {
		path := getPathFromRawMessage(raw)
		protocol.Debug("Received msg %v %v", ws.userId, path)
		return len(path) == 0 || ws.accessManager.IsAllowed(auth.READ, ws.userId, path)

	}
	return true
}

func getPathFromRawMessage(raw []byte) protocol.Path {
	i := strings.Index(string(raw), ",")
	return protocol.Path(raw[:i])
}

func (ws *WebSocket) receiveLoop() {
	var message []byte
	for {
		err := ws.Receive(&message)
		if err != nil {
			protocol.Info("applicationId=%v closed the connection", ws.applicationId)
			ws.cleanAndClose()
			break
		}

		//protocol.Debug("websocket_connector, raw message received: %v", string(message))
		cmd, err := protocol.ParseCmd(message)
		if err != nil {
			ws.sendError(protocol.ERROR_BAD_REQUEST, "error parsing command. %v", err.Error())
			continue
		}
		switch cmd.Name {
		case protocol.CmdSend:
			ws.handleSendCmd(cmd)
		case protocol.CmdReceive:
			ws.handleReceiveCmd(cmd)
		case protocol.CmdCancel:
			ws.handleCancelCmd(cmd)
		default:
			ws.sendError(protocol.ERROR_BAD_REQUEST, "unknown command %v", cmd.Name)
		}
	}
}

func (ws *WebSocket) sendConnectionMessage() {
	n := &protocol.NotificationMessage{
		Name: protocol.SUCCESS_CONNECTED,
		Arg:  "You are connected to the server.",
		Json: fmt.Sprintf(`{"ApplicationId": "%s", "UserId": "%s", "Time": "%s"}`, ws.applicationId, ws.userId, time.Now().Format(time.RFC3339)),
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) handleReceiveCmd(cmd *protocol.Cmd) {
	rec, err := NewReceiverFromCmd(
		ws.applicationId,
		cmd,
		ws.sendChannel,
		ws.Router,
		ws.messageStore,
		ws.userId,
	)
	if err != nil {
		protocol.Info("client error in handleReceiveCmd: %v", err.Error())
		ws.sendError(protocol.ERROR_BAD_REQUEST, err.Error())
		return
	}
	ws.receivers[rec.path] = rec
	rec.Start()
}

func (ws *WebSocket) handleCancelCmd(cmd *protocol.Cmd) {
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "- command requires a path argument, but non given")
		return
	}
	path := protocol.Path(cmd.Arg)
	rec, exist := ws.receivers[path]
	if exist {
		rec.Stop()
		delete(ws.receivers, path)
	}
}

func (ws *WebSocket) handleSendCmd(cmd *protocol.Cmd) {
	protocol.Debug("sending %v", string(cmd.Bytes()))
	if len(cmd.Arg) == 0 {
		ws.sendError(protocol.ERROR_BAD_REQUEST, "send command requires a path argument, but non given")
		return
	}

	args := strings.SplitN(cmd.Arg, " ", 2)
	msg := &protocol.Message{
		Path:          protocol.Path(args[0]),
		ApplicationID: ws.applicationId,
		UserID:        ws.userId,
		HeaderJSON:    cmd.HeaderJSON,
		Body:          cmd.Body,
	}
	if len(args) == 2 {
		msg.MessageID = args[1]
	}

	ws.Router.HandleMessage(msg)

	ws.sendOK(protocol.SUCCESS_SEND, msg.MessageID)
}

func (ws *WebSocket) cleanAndClose() {
	protocol.Info("closing applicationId=%v", ws.applicationId)

	for path, rec := range ws.receivers {
		rec.Stop()
		delete(ws.receivers, path)
	}

	ws.Close()
}

func (ws *WebSocket) sendError(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: true,
	}
	ws.sendChannel <- n.Bytes()
}

func (ws *WebSocket) sendOK(name string, argPattern string, params ...interface{}) {
	n := &protocol.NotificationMessage{
		Name:    name,
		Arg:     fmt.Sprintf(argPattern, params...),
		IsError: false,
	}
	ws.sendChannel <- n.Bytes()
}
<|endoftext|>


<commit_before>// Package tar is a wrapper around archive/tar, it's used for archiving and unarchiving source from
// and into folders on the host. Because runtime has many cases where it streams source via RPC,
// this package encapsulates the shared logic.
package tar

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// Unarchive decodes the source in a tar and writes it to a directory
func Unarchive(src io.Reader, dir string) error {
	tr := tar.NewReader(src)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		path := filepath.Join(dir, hdr.Name)
		bytes, err := ioutil.ReadAll(tr)
		if err != nil {
			return err
		}

		switch hdr.Typeflag {
		case tar.TypeDir:
			if _, verr := os.Stat(path); os.IsNotExist(verr) {
				err = os.Mkdir(path, os.ModePerm)
			}
		case tar.TypeReg:
			err = ioutil.WriteFile(path, bytes, os.ModePerm)
		default:
			err = fmt.Errorf("Unknown tar header type flag: %v", string(hdr.Typeflag))
		}

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

// Archive a local directory into a tar gzip
func Archive(dir string) (io.Reader, error) {
	// Create a tar writer and a buffer to store the archive
	tf := bytes.NewBuffer(nil)
	tw := tar.NewWriter(tf)
	defer tw.Close()

	// walkFn archives each file in the directory
	walkFn := func(path string, info os.FileInfo, err error) error {
		// get the relative path, e.g. cmd/main.go
		relpath, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		// skip git files
		if filepath.HasPrefix(relpath, ".git") {
			return nil
		}

		// skip irrelevent files
		if !info.IsDir() && !shouldArchive(relpath) {
			return nil
		}

		// generate and write tar header
		header, err := tar.FileInfoHeader(info, relpath)
		if err != nil {
			return err
		}

		// Since os.FileInfo's Name method only returns the base name of the file it describes, it is
		// necessary to modify Header.Name to provide the full path name of the file. See:
		// https://golang.org/src/archive/tar/common.go?s=22088:22153#L626
		header.Name = relpath

		// write the header to the archive
		if err := tw.WriteHeader(header); err != nil {
			return err
		}

		// there is no body if it's a directory
		if info.IsDir() {
			return nil
		}

		// read the contents of the file
		bytes, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		// write the contents of the file to the tar
		_, err = tw.Write([]byte(bytes))
		return err
	}

	// Add the files to the archive
	if err := filepath.Walk(dir, walkFn); err != nil {
		return nil, err
	}

	// Return the archive
	return tf, nil
}

// shouldArchive is a helper func which indicates if a file should be archived. TODO: implement a
// smarter check which just excludes executables
func shouldArchive(file string) bool {
	if filepath.HasPrefix(file, "vendor") {
		return true
	}
	if strings.HasSuffix(file, ".go") {
		return true
	}
	if strings.HasSuffix(file, "go.sum") {
		return true
	}
	if strings.HasSuffix(file, "go.mod") {
		return true
	}
	return false
}
<commit_msg>service/build: handle walkpath error in tar util (#1532)<commit_after>// Package tar is a wrapper around archive/tar, it's used for archiving and unarchiving source from
// and into folders on the host. Because runtime has many cases where it streams source via RPC,
// this package encapsulates the shared logic.
package tar

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// Unarchive decodes the source in a tar and writes it to a directory
func Unarchive(src io.Reader, dir string) error {
	tr := tar.NewReader(src)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		path := filepath.Join(dir, hdr.Name)
		bytes, err := ioutil.ReadAll(tr)
		if err != nil {
			return err
		}

		switch hdr.Typeflag {
		case tar.TypeDir:
			if _, verr := os.Stat(path); os.IsNotExist(verr) {
				err = os.Mkdir(path, os.ModePerm)
			}
		case tar.TypeReg:
			err = ioutil.WriteFile(path, bytes, os.ModePerm)
		default:
			err = fmt.Errorf("Unknown tar header type flag: %v", string(hdr.Typeflag))
		}

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

// Archive a local directory into a tar gzip
func Archive(dir string) (io.Reader, error) {
	// Create a tar writer and a buffer to store the archive
	tf := bytes.NewBuffer(nil)
	tw := tar.NewWriter(tf)
	defer tw.Close()

	// walkFn archives each file in the directory
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// get the relative path, e.g. cmd/main.go
		relpath, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		// skip git files
		if filepath.HasPrefix(relpath, ".git") {
			return nil
		}

		// skip irrelevent files
		if !info.IsDir() && !shouldArchive(relpath) {
			return nil
		}

		// generate and write tar header
		header, err := tar.FileInfoHeader(info, relpath)
		if err != nil {
			return err
		}

		// Since os.FileInfo's Name method only returns the base name of the file it describes, it is
		// necessary to modify Header.Name to provide the full path name of the file. See:
		// https://golang.org/src/archive/tar/common.go?s=22088:22153#L626
		header.Name = relpath

		// write the header to the archive
		if err := tw.WriteHeader(header); err != nil {
			return err
		}

		// there is no body if it's a directory
		if info.IsDir() {
			return nil
		}

		// read the contents of the file
		bytes, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		// write the contents of the file to the tar
		_, err = tw.Write([]byte(bytes))
		return err
	}

	// Add the files to the archive
	if err := filepath.Walk(dir, walkFn); err != nil {
		return nil, err
	}

	// Return the archive
	return tf, nil
}

// shouldArchive is a helper func which indicates if a file should be archived. TODO: implement a
// smarter check which just excludes executables
func shouldArchive(file string) bool {
	if filepath.HasPrefix(file, "vendor") {
		return true
	}
	if strings.HasSuffix(file, ".go") {
		return true
	}
	if strings.HasSuffix(file, "go.sum") {
		return true
	}
	if strings.HasSuffix(file, "go.mod") {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package auth

import (
	"github.com/MG-RAST/Shock/shock-server/user"
	"time"
)

type cache struct {
	m map[string]cacheValue
}

type cacheValue struct {
	expires time.Time
	user    *user.User
}

func (c *cache) lookup(header string) *user.User {
	if v, ok := c.m[header]; ok {
		if time.Now().Before(v.expires) {
			return v.user
		} else {
			delete(c.m, header)
		}
	}
	return nil
}

func (c *cache) add(header string, u *user.User) {
	c.m[header] = cacheValue{
		expires: time.Now().Add(1 * time.Hour),
		user:    u,
	}
	return
}
<commit_msg>Making Shock auth cache thread safe.<commit_after>package auth

import (
	"github.com/MG-RAST/Shock/shock-server/user"
	"sync"
	"time"
)

type cache struct {
	sync.Mutex
	m map[string]cacheValue
}

type cacheValue struct {
	expires time.Time
	user    *user.User
}

func (c *cache) lookup(header string) *user.User {
	if v, ok := c.m[header]; ok {
		if time.Now().Before(v.expires) {
			return v.user
		} else {
			c.Lock()
			defer c.Unlock()
			delete(c.m, header)
		}
	}
	return nil
}

func (c *cache) add(header string, u *user.User) {
	c.Lock()
	defer c.Unlock()
	c.m[header] = cacheValue{
		expires: time.Now().Add(1 * time.Hour),
		user:    u,
	}
	return
}
<|endoftext|>


<commit_before>package opsgenie2

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"sync/atomic"
	"time"

	"github.com/influxdata/kapacitor/alert"
	"github.com/influxdata/kapacitor/keyvalue"
	"github.com/influxdata/kapacitor/models"
	"github.com/pkg/errors"
)

type Diagnostic interface {
	WithContext(ctx ...keyvalue.T) Diagnostic

	Error(msg string, err error)
}

type Service struct {
	configValue atomic.Value
	diag        Diagnostic
}

func NewService(c Config, d Diagnostic) *Service {
	s := &Service{
		diag: d,
	}
	s.configValue.Store(c)
	return s
}

func (s *Service) Open() error {
	return nil
}

func (s *Service) Close() error {
	return nil
}

func (s *Service) config() Config {
	return s.configValue.Load().(Config)
}

func (s *Service) Update(newConfig []interface{}) error {
	if l := len(newConfig); l != 1 {
		return fmt.Errorf("expected only one new config object, got %d", l)
	}
	if c, ok := newConfig[0].(Config); !ok {
		return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
	} else {
		s.configValue.Store(c)
	}
	return nil
}

func (s *Service) Global() bool {
	c := s.config()
	return c.Global
}

type testOptions struct {
	Teams       []string `json:"teams"`
	Recipients  []string `json:"recipients"`
	MessageType string   `json:"message-type"`
	Message     string   `json:"message"`
	EntityID    string   `json:"entity-id"`
}

func (s *Service) TestOptions() interface{} {
	c := s.config()
	return &testOptions{
		Teams:       c.Teams,
		Recipients:  c.Recipients,
		MessageType: "CRITICAL",
		Message:     "test opsgenie message",
		EntityID:    "testEntityID",
	}
}

func (s *Service) Test(options interface{}) error {
	o, ok := options.(*testOptions)
	if !ok {
		return fmt.Errorf("unexpected options type %T", options)
	}
	var level alert.Level
	if o.MessageType == "RECOVERY" {
		level = alert.OK
	} else {
		l, err := alert.ParseLevel(o.MessageType)
		if err != nil {
			return err
		}
		level = l
	}
	return s.Alert(
		o.Teams,
		o.Recipients,
		level,
		o.Message,
		o.EntityID,
		time.Now(),
		models.Result{},
	)
}

func (s *Service) Alert(teams []string, recipients []string, level alert.Level, message, entityID string, t time.Time, details models.Result) error {
	req, err := s.preparePost(teams, recipients, level, message, entityID, t, details)
	if err != nil {
		return errors.Wrap(err, "failed to prepare API request")
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.Wrap(err, "failed to execute API request")
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusAccepted {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return errors.Wrap(err, "failed to read API response")
		}
		type response struct {
			Message string `json:"message"`
		}
		r := &response{Message: fmt.Sprintf("failed to understand OpsGenie response. code: %d content: %s", resp.StatusCode, string(body))}
		b := bytes.NewReader(body)
		dec := json.NewDecoder(b)
		dec.Decode(r)
		return fmt.Errorf("opsgenie error: %s", r.Message)
	}
	return nil
}

func (s *Service) preparePost(teams []string, recipients []string, level alert.Level, message, entityID string, t time.Time, details models.Result) (*http.Request, error) {
	c := s.config()
	if !c.Enabled {
		return nil, errors.New("service is not enabled")
	}

	alias := base64.URLEncoding.EncodeToString([]byte(entityID))

	ogData := make(map[string]interface{})
	u := c.URL
	switch level {
	case alert.OK:
		recoveryURL, err := url.Parse(c.URL)
		if err != nil {
			return nil, err
		}
		recoveryURL.Path = path.Join(recoveryURL.Path, alias, c.RecoveryAction)
		recoveryURL.RawQuery = "identifierType=alias"
		u = recoveryURL.String()
		ogData["note"] = message
	default:
		var priority string
		switch level {
		case alert.Info:
			priority = "P5"
		case alert.Warning:
			priority = "P3"
		case alert.Critical:
			priority = "P1"
		}

		ogData["entity"] = entityID
		ogData["alias"] = alias
		ogData["message"] = message
		ogData["note"] = ""
		ogData["priority"] = priority

		// Encode details as description
		b, err := json.Marshal(details)
		if err != nil {
			return nil, err
		}
		ogData["description"] = string(b)

		//Extra Fields (can be used for filtering)
		ogDetails := make(map[string]string)
		ogDetails["Monitoring Tool"] = "Kapacitor"
		ogDetails["Level"] = level.String()

		row := details.Series[0]
		for k, v := range row.Tags {
			ogDetails[k] = v
		}
		ogDetails["Kapacitor Task Name"] = row.Name

		ogData["details"] = ogDetails

		// Create responders list
		var responders []map[string]string
		if len(teams) == 0 {
			teams = c.Teams
		}
		if len(teams) > 0 {
			for _, t := range teams {
				responders = append(responders, map[string]string{
					"name": t,
					"type": "team",
				})
			}
		}

		if len(recipients) == 0 {
			recipients = c.Recipients
		}
		if len(recipients) > 0 {
			for _, u := range recipients {
				responders = append(responders, map[string]string{
					"username": u,
					"type":     "user",
				})
			}
		}

		if len(responders) > 0 {
			ogData["responders"] = responders
		}
	}

	var post bytes.Buffer
	enc := json.NewEncoder(&post)
	if err := enc.Encode(ogData); err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", u, &post)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "GenieKey "+c.APIKey)

	return req, nil
}

type HandlerConfig struct {
	// OpsGenie Teams.
	TeamsList []string `mapstructure:"teams-list"`

	// OpsGenie Recipients.
	RecipientsList []string `mapstructure:"recipients-list"`
}

type handler struct {
	s    *Service
	c    HandlerConfig
	diag Diagnostic
}

func (s *Service) Handler(c HandlerConfig, ctx ...keyvalue.T) alert.Handler {
	return &handler{
		s:    s,
		c:    c,
		diag: s.diag.WithContext(ctx...),
	}
}

func (h *handler) Handle(event alert.Event) {
	if err := h.s.Alert(
		h.c.TeamsList,
		h.c.RecipientsList,
		event.State.Level,
		event.State.Message,
		event.State.ID,
		event.State.Time,
		event.Data.Result,
	); err != nil {
		h.diag.Error("failed to send event to OpsGenie", err)
	}
}
<commit_msg>fix #1865<commit_after>package opsgenie2

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"sync/atomic"
	"time"

	"github.com/influxdata/kapacitor/alert"
	"github.com/influxdata/kapacitor/keyvalue"
	"github.com/influxdata/kapacitor/models"
	"github.com/pkg/errors"
)

type Diagnostic interface {
	WithContext(ctx ...keyvalue.T) Diagnostic

	Error(msg string, err error)
}

type Service struct {
	configValue atomic.Value
	diag        Diagnostic
}

func NewService(c Config, d Diagnostic) *Service {
	s := &Service{
		diag: d,
	}
	s.configValue.Store(c)
	return s
}

func (s *Service) Open() error {
	return nil
}

func (s *Service) Close() error {
	return nil
}

func (s *Service) config() Config {
	return s.configValue.Load().(Config)
}

func (s *Service) Update(newConfig []interface{}) error {
	if l := len(newConfig); l != 1 {
		return fmt.Errorf("expected only one new config object, got %d", l)
	}
	if c, ok := newConfig[0].(Config); !ok {
		return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
	} else {
		s.configValue.Store(c)
	}
	return nil
}

func (s *Service) Global() bool {
	c := s.config()
	return c.Global
}

type testOptions struct {
	Teams       []string `json:"teams"`
	Recipients  []string `json:"recipients"`
	MessageType string   `json:"message-type"`
	Message     string   `json:"message"`
	EntityID    string   `json:"entity-id"`
}

func (s *Service) TestOptions() interface{} {
	c := s.config()
	return &testOptions{
		Teams:       c.Teams,
		Recipients:  c.Recipients,
		MessageType: "CRITICAL",
		Message:     "test opsgenie message",
		EntityID:    "testEntityID",
	}
}

func (s *Service) Test(options interface{}) error {
	o, ok := options.(*testOptions)
	if !ok {
		return fmt.Errorf("unexpected options type %T", options)
	}
	var level alert.Level
	if o.MessageType == "RECOVERY" {
		level = alert.OK
	} else {
		l, err := alert.ParseLevel(o.MessageType)
		if err != nil {
			return err
		}
		level = l
	}
	return s.Alert(
		o.Teams,
		o.Recipients,
		level,
		o.Message,
		o.EntityID,
		time.Now(),
		models.Result{},
	)
}

func (s *Service) Alert(teams []string, recipients []string, level alert.Level, message, entityID string, t time.Time, details models.Result) error {
	req, err := s.preparePost(teams, recipients, level, message, entityID, t, details)
	if err != nil {
		return errors.Wrap(err, "failed to prepare API request")
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.Wrap(err, "failed to execute API request")
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusAccepted {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return errors.Wrap(err, "failed to read API response")
		}
		type response struct {
			Message string `json:"message"`
		}
		r := &response{Message: fmt.Sprintf("failed to understand OpsGenie response. code: %d content: %s", resp.StatusCode, string(body))}
		b := bytes.NewReader(body)
		dec := json.NewDecoder(b)
		dec.Decode(r)
		return fmt.Errorf("opsgenie error: %s", r.Message)
	}
	return nil
}

func (s *Service) preparePost(teams []string, recipients []string, level alert.Level, message, entityID string, t time.Time, details models.Result) (*http.Request, error) {
	c := s.config()
	if !c.Enabled {
		return nil, errors.New("service is not enabled")
	}

	alias := base64.URLEncoding.EncodeToString([]byte(entityID))

	ogData := make(map[string]interface{})
	u := c.URL
	switch level {
	case alert.OK:
		recoveryURL, err := url.Parse(c.URL)
		if err != nil {
			return nil, err
		}
		recoveryURL.Path = path.Join(recoveryURL.Path, alias, c.RecoveryAction)
		recoveryURL.RawQuery = "identifierType=alias"
		u = recoveryURL.String()
		ogData["note"] = message
	default:
		var priority string
		switch level {
		case alert.Info:
			priority = "P5"
		case alert.Warning:
			priority = "P3"
		case alert.Critical:
			priority = "P1"
		}

		ogData["entity"] = entityID
		ogData["alias"] = alias
		ogData["message"] = message
		ogData["note"] = ""
		ogData["priority"] = priority

		// Encode details as description
		b, err := json.Marshal(details)
		if err != nil {
			return nil, err
		}
		ogData["description"] = string(b)

		//Extra Fields (can be used for filtering)
		ogDetails := make(map[string]string)
		ogDetails["Monitoring Tool"] = "Kapacitor"
		ogDetails["Level"] = level.String()

		if len(details.Series) > 0 {
			row := details.Series[0]
			for k, v := range row.Tags {
				ogDetails[k] = v
			}
			ogDetails["Kapacitor Task Name"] = row.Name
		}

		ogData["details"] = ogDetails

		// Create responders list
		var responders []map[string]string
		if len(teams) == 0 {
			teams = c.Teams
		}
		if len(teams) > 0 {
			for _, t := range teams {
				responders = append(responders, map[string]string{
					"name": t,
					"type": "team",
				})
			}
		}

		if len(recipients) == 0 {
			recipients = c.Recipients
		}
		if len(recipients) > 0 {
			for _, u := range recipients {
				responders = append(responders, map[string]string{
					"username": u,
					"type":     "user",
				})
			}
		}

		if len(responders) > 0 {
			ogData["responders"] = responders
		}
	}

	var post bytes.Buffer
	enc := json.NewEncoder(&post)
	if err := enc.Encode(ogData); err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", u, &post)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "GenieKey "+c.APIKey)

	return req, nil
}

type HandlerConfig struct {
	// OpsGenie Teams.
	TeamsList []string `mapstructure:"teams-list"`

	// OpsGenie Recipients.
	RecipientsList []string `mapstructure:"recipients-list"`
}

type handler struct {
	s    *Service
	c    HandlerConfig
	diag Diagnostic
}

func (s *Service) Handler(c HandlerConfig, ctx ...keyvalue.T) alert.Handler {
	return &handler{
		s:    s,
		c:    c,
		diag: s.diag.WithContext(ctx...),
	}
}

func (h *handler) Handle(event alert.Event) {
	if err := h.s.Alert(
		h.c.TeamsList,
		h.c.RecipientsList,
		event.State.Level,
		event.State.Message,
		event.State.ID,
		event.State.Time,
		event.Data.Result,
	); err != nil {
		h.diag.Error("failed to send event to OpsGenie", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
        "fmt"
        "labix.org/v2/mgo"
        "labix.org/v2/mgo/bson"
)

type Person struct {
        Name string
        Phone string
}

func main() {
        session, err := mgo.Dial("localhost")
        if err != nil {
                panic(err)
        }
        defer session.Close()

        // Optional. Switch the session to a monotonic behavior.
        session.SetMode(mgo.Monotonic, true)

        c := session.DB("test").C("people")
        err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
                       &Person{"Cla", "+55 53 8402 8510"})
        if err != nil {
                panic(err)
        }

        result := Person{}
        err = c.Find(bson.M{"name": "Ale"}).One(&result)
        if err != nil {
                panic(err)
        }

        fmt.Println("Phone:", result.Phone)
}
~ <commit_msg>fixing the damn spacing issues that go likes to have formatting like it likes to have.<commit_after>package main

import (
        "fmt"
        "labix.org/v2/mgo"
        "labix.org/v2/mgo/bson"
)

type Person struct {
        Name string
        Phone string
}

func main() {
        session, err := mgo.Dial("localhost")
        if err != nil {
                panic(err)
        }
        defer session.Close()

        // Optional. Switch the session to a monotonic behavior.
        session.SetMode(mgo.Monotonic, true)

        c := session.DB("test").C("people")
        err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
	               &Person{"Cla", "+55 53 8402 8510"})
        if err != nil {
                panic(err)
        }

        result := Person{}
        err = c.Find(bson.M{"name": "Ale"}).One(&result)
        if err != nil {
                panic(err)
        }

        fmt.Println("Phone:", result.Phone)
}
<|endoftext|>


<commit_before>package node

type srmentry struct {
	address  NodeAddress
	distance uint8
}

type SimpleReachabilityMap map[NodeAddress]srmentry

func NewSimpleReachabilityMap() ReachabilityMap {
	m := make(map[NodeAddress]srmentry)
	return SimpleReachabilityMap(m)
}

func (m SimpleReachabilityMap) IsReachable(n NodeAddress) bool {
	_, ok := m[n]
	return ok
}

func (m SimpleReachabilityMap) AddEntry(n NodeAddress) {
	m[n] = srmentry{n, 0}
}

func (m SimpleReachabilityMap) Increment() {
	for k, v := range m {
		v.distance += 1
		m[k] = v
	}
}

func (m SimpleReachabilityMap) Merge(nr ReachabilityMap) {
	n := nr.(SimpleReachabilityMap)
	for k, v := range n {
		m[k] = v
	}
}
<commit_msg>minor type fix<commit_after>package node

type srmentry struct {
	address  NodeAddress
	distance uint8
}

type SimpleReachabilityMap map[NodeAddress]srmentry

func NewSimpleReachabilityMap() ReachabilityMap {
	m := make(SimpleReachabilityMap)
	return m
}

func (m SimpleReachabilityMap) IsReachable(n NodeAddress) bool {
	_, ok := m[n]
	return ok
}

func (m SimpleReachabilityMap) AddEntry(n NodeAddress) {
	m[n] = srmentry{n, 0}
}

func (m SimpleReachabilityMap) Increment() {
	for k, v := range m {
		v.distance += 1
		m[k] = v
	}
}

func (m SimpleReachabilityMap) Merge(nr ReachabilityMap) {
	n := nr.(SimpleReachabilityMap)
	for k, v := range n {
		m[k] = v
	}
}
<|endoftext|>


<commit_before>package stack

import (
	"runtime"
	"testing"
)

func TestFindSigpanic(t *testing.T) {
	t.Parallel()
	sp := findSigpanic()
	if got, want := sp.Name(), "runtime.sigpanic"; got != want {
		t.Errorf("got == %v, want == %v", got, want)
	}
}

func TestCaller(t *testing.T) {
	t.Parallel()

	c := Caller(0)
	_, file, line, ok := runtime.Caller(0)
	line--
	if !ok {
		t.Fatal("runtime.Caller(0) failed")
	}

	if got, want := c.file(), file; got != want {
		t.Errorf("got file == %v, want file == %v", got, want)
	}

	if got, want := c.line(), line; got != want {
		t.Errorf("got line == %v, want line == %v", got, want)
	}
}

type fholder struct {
	f func() CallStack
}

func (fh *fholder) labyrinth() CallStack {
	for {
		return fh.f()
	}
	panic("this line only needed for go 1.0")
}

func TestTrace(t *testing.T) {
	t.Parallel()

	fh := fholder{
		f: func() CallStack {
			cs := Trace()
			return cs
		},
	}

	cs := fh.labyrinth()

	lines := []int{50, 41, 56}

	for i, line := range lines {
		if got, want := cs[i].line(), line; got != want {
			t.Errorf("got line[%d] == %v, want line[%d] == %v", i, got, i, want)
		}
	}
}
<commit_msg>Fix test.<commit_after>package stack

import (
	"runtime"
	"testing"
)

func TestFindSigpanic(t *testing.T) {
	t.Parallel()
	sp := findSigpanic()
	if got, want := sp.Name(), "runtime.sigpanic"; got != want {
		t.Errorf("got == %v, want == %v", got, want)
	}
}

func TestCaller(t *testing.T) {
	t.Parallel()

	c := Caller(0)
	_, file, line, ok := runtime.Caller(0)
	line--
	if !ok {
		t.Fatal("runtime.Caller(0) failed")
	}

	if got, want := c.file(), file; got != want {
		t.Errorf("got file == %v, want file == %v", got, want)
	}

	if got, want := c.line(), line; got != want {
		t.Errorf("got line == %v, want line == %v", got, want)
	}
}

type fholder struct {
	f func() CallStack
}

func (fh *fholder) labyrinth() CallStack {
	for {
		return fh.f()
	}
	panic("this line only needed for go 1.0")
}

func TestTrace(t *testing.T) {
	t.Parallel()

	fh := fholder{
		f: func() CallStack {
			cs := Trace()
			return cs
		},
	}

	cs := fh.labyrinth()

	lines := []int{51, 41, 56}

	for i, line := range lines {
		if got, want := cs[i].line(), line; got != want {
			t.Errorf("got line[%d] == %v, want line[%d] == %v", i, got, i, want)
		}
	}
}
<|endoftext|>


<commit_before>package main

func (this *SingleProducerSequencer) Next(slotCount int64) int64 {
	nextValue := this.pad.Load()
	nextSequence := nextValue + slotCount
	wrapPoint := nextSequence - this.ringSize
	cachedGatingSequence := this.pad[cachedGatingSequencePadIndex]

	if wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue {
		minSequence := int64(0)
		for wrapPoint > minSequence {
			minSequence = this.last.Load()
		}

		this.pad[cachedGatingSequencePadIndex] = minSequence
	}

	this.pad.Store(nextSequence)
	return nextSequence
}

func (this *SingleProducerSequencer) Publish(sequence int64) {
	this.cursor[0] = sequence
}

func NewSingleProducerSequencer(cursor *Sequence, ringSize int32, last Barrier) *SingleProducerSequencer {
	pad := NewSequence()
	pad[cachedGatingSequencePadIndex] = InitialSequenceValue

	return &SingleProducerSequencer{
		pad:      pad,
		cursor:   cursor,
		ringSize: int64(ringSize),
		last:     last,
	}
}

type SingleProducerSequencer struct {
	pad      *Sequence
	cursor   *Sequence
	ringSize int64
	last     Barrier
}

const cachedGatingSequencePadIndex = 1
<commit_msg>Calling directly into sequence.<commit_after>package main

func (this *SingleProducerSequencer) Next(slotCount int64) int64 {
	nextValue := this.pad.Load()
	nextSequence := nextValue + slotCount
	wrapPoint := nextSequence - this.ringSize
	cachedGatingSequence := this.pad[cachedGatingSequencePadIndex]

	if wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue {
		minSequence := int64(0)
		for wrapPoint > minSequence {
			minSequence = this.last.Load()
		}

		this.pad[cachedGatingSequencePadIndex] = minSequence
	}

	this.pad.Store(nextSequence)
	return nextSequence
}

func (this *SingleProducerSequencer) Publish(sequence int64) {
	// this.cursor.Store(sequence)
	this.cursor[0] = sequence
}

func NewSingleProducerSequencer(cursor *Sequence, ringSize int32, last Barrier) *SingleProducerSequencer {
	pad := NewSequence()
	pad[cachedGatingSequencePadIndex] = InitialSequenceValue

	return &SingleProducerSequencer{
		pad:      pad,
		cursor:   cursor,
		ringSize: int64(ringSize),
		last:     last,
	}
}

type SingleProducerSequencer struct {
	pad      *Sequence
	cursor   *Sequence
	ringSize int64
	last     Barrier
}

const cachedGatingSequencePadIndex = 1
<|endoftext|>


<commit_before>package catalogue

// service.go contains the definition and implementation (business logic) of the
// catalogue service. Everything here is agnostic to the transport (HTTP).

import (
	"errors"
	"strings"

	"github.com/go-kit/kit/log"
	"github.com/jmoiron/sqlx"
)

// Service is the catalogue service, providing read operations on a saleable
// catalogue of sock products.
type Service interface {
	List(tags []string, order string, pageNum, pageSize int) ([]Sock, error) // GET /catalogue
	Count(tags []string) (int, error)                                        // GET /catalogue/size
	Get(id string) (Sock, error)                                             // GET /catalogue/{id}
	Tags() ([]string, error)                                                 // GET /tags
}

// Sock describes the thing on offer in the catalogue.
type Sock struct {
	ID          string   `json:"id" db:"id"`
	Name        string   `json:"name" db:"name"`
	Description string   `json:"description" db:"description"`
	ImageURL    []string `json:"imageUrl" db:"-"`
	ImageURL_1  string   `json:"-" db:"image_url_1"`
	ImageURL_2  string   `json:"-" db:"image_url_2"`
	Price       float32  `json:"price" db:"price"`
	Count       int      `json:"count" db:"count"`
	Tags        []string `json:"tag" db:"-"`
	TagString   string   `json:"-" db:"tag_name"`
}

// ErrNotFound is returned when there is no sock for a given ID.
var ErrNotFound = errors.New("not found")

// ErrDBConnection is returned when connection with the database fails.
var ErrDBConnection = errors.New("database connection error")

var baseQuery = "SELECT sock.sock_id AS id, sock.name, sock.description, sock.price, sock.count, sock.image_url_1, sock.image_url_2, GROUP_CONCAT(tag.name) AS tag_name FROM sock JOIN sock_tag ON sock.sock_id=sock_tag.sock_id JOIN tag ON sock_tag.tag_id=tag.tag_id"

// NewCatalogueService returns an implementation of the Service interface,
// with connection to an SQL database.
func NewCatalogueService(db *sqlx.DB, logger log.Logger) Service {
	return &catalogueService{
		db: db,
		logger: logger,
	}
}

type catalogueService struct {
	db *sqlx.DB
	logger log.Logger
}

func (s *catalogueService) List(tags []string, order string, pageNum, pageSize int) ([]Sock, error) {
	var socks []Sock
	query := baseQuery

	var args []interface{}

	for i, t := range tags {
		if i == 0 {
			query += " WHERE tag.name=?"
			args = append(args, t)
		} else {
			query += " OR tag.name=?"
			args = append(args, t)
		}
	}

	query += " GROUP BY id"

	if order != "" {
		query += " ORDER BY ?"
		args = append(args, order)
	}

	query += ";"

	err := s.db.Select(&socks, query, args...)
	if err != nil {
		s.logger.Log("database error", err)
		return []Sock{}, ErrDBConnection
	}
	for i, s := range socks {
		socks[i].ImageURL = []string{s.ImageURL_1, s.ImageURL_2}
		socks[i].Tags = strings.Split(s.TagString, ",")
	}

	socks = cut(socks, pageNum, pageSize)

	return socks, nil
}

func (s *catalogueService) Count(tags []string) (int, error) {
	query := "SELECT COUNT(DISTINCT sock.sock_id) FROM sock JOIN sock_tag ON sock.sock_id=sock_tag.sock_id JOIN tag ON sock_tag.tag_id=tag.tag_id"

	var args []interface{}

	for i, t := range tags {
		if i == 0 {
			query += " WHERE tag.name=?"
			args = append(args, t)
		} else {
			query += " OR tag.name=?"
			args = append(args, t)
		}
	}

	query += ";"

	sel, err := s.db.Prepare(query)

	if err != nil {
		s.logger.Log("database error", err)
		return 0, ErrDBConnection
	}
	defer sel.Close()

	var count int
	err = sel.QueryRow(args...).Scan(&count)

	if err != nil {
		s.logger.Log("database error", err)
		return 0, ErrDBConnection
	}

	return count, nil
}

func (s *catalogueService) Get(id string) (Sock, error) {
	query := baseQuery + " WHERE sock.sock_id =? GROUP BY sock.sock_id;"

	var sock Sock
	err := s.db.Get(&sock, query, id)
	if err != nil {
		s.logger.Log("database error", err)
		return Sock{}, ErrNotFound
	}

	sock.ImageURL = []string{sock.ImageURL_1, sock.ImageURL_2}
	sock.Tags = strings.Split(sock.TagString, ",")

	return sock, nil
}

func (s *catalogueService) Tags() ([]string, error) {
	var tags []string
	query := "SELECT name FROM tag;"
	rows, err := s.db.Query(query)
	if err != nil {
		s.logger.Log("database error", err)
		return []string{}, ErrDBConnection
	}
	var tag string
	for rows.Next() {
		rows.Scan(&tag)
		tags = append(tags, tag)
	}
	return tags, nil
}

func cut(socks []Sock, pageNum, pageSize int) []Sock {
	if pageNum == 0 || pageSize == 0 {
		return []Sock{} // pageNum is 1-indexed
	}
	start := (pageNum * pageSize) - pageSize
	if start > len(socks) {
		return []Sock{}
	}
	end := (pageNum * pageSize)
	if end > len(socks) {
		end = len(socks)
	}
	return socks[start:end]
}

func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<commit_msg>handle error<commit_after>package catalogue

// service.go contains the definition and implementation (business logic) of the
// catalogue service. Everything here is agnostic to the transport (HTTP).

import (
	"errors"
	"strings"

	"github.com/go-kit/kit/log"
	"github.com/jmoiron/sqlx"
)

// Service is the catalogue service, providing read operations on a saleable
// catalogue of sock products.
type Service interface {
	List(tags []string, order string, pageNum, pageSize int) ([]Sock, error) // GET /catalogue
	Count(tags []string) (int, error)                                        // GET /catalogue/size
	Get(id string) (Sock, error)                                             // GET /catalogue/{id}
	Tags() ([]string, error)                                                 // GET /tags
}

// Sock describes the thing on offer in the catalogue.
type Sock struct {
	ID          string   `json:"id" db:"id"`
	Name        string   `json:"name" db:"name"`
	Description string   `json:"description" db:"description"`
	ImageURL    []string `json:"imageUrl" db:"-"`
	ImageURL_1  string   `json:"-" db:"image_url_1"`
	ImageURL_2  string   `json:"-" db:"image_url_2"`
	Price       float32  `json:"price" db:"price"`
	Count       int      `json:"count" db:"count"`
	Tags        []string `json:"tag" db:"-"`
	TagString   string   `json:"-" db:"tag_name"`
}

// ErrNotFound is returned when there is no sock for a given ID.
var ErrNotFound = errors.New("not found")

// ErrDBConnection is returned when connection with the database fails.
var ErrDBConnection = errors.New("database connection error")

var baseQuery = "SELECT sock.sock_id AS id, sock.name, sock.description, sock.price, sock.count, sock.image_url_1, sock.image_url_2, GROUP_CONCAT(tag.name) AS tag_name FROM sock JOIN sock_tag ON sock.sock_id=sock_tag.sock_id JOIN tag ON sock_tag.tag_id=tag.tag_id"

// NewCatalogueService returns an implementation of the Service interface,
// with connection to an SQL database.
func NewCatalogueService(db *sqlx.DB, logger log.Logger) Service {
	return &catalogueService{
		db: db,
		logger: logger,
	}
}

type catalogueService struct {
	db *sqlx.DB
	logger log.Logger
}

func (s *catalogueService) List(tags []string, order string, pageNum, pageSize int) ([]Sock, error) {
	var socks []Sock
	query := baseQuery

	var args []interface{}

	for i, t := range tags {
		if i == 0 {
			query += " WHERE tag.name=?"
			args = append(args, t)
		} else {
			query += " OR tag.name=?"
			args = append(args, t)
		}
	}

	query += " GROUP BY id"

	if order != "" {
		query += " ORDER BY ?"
		args = append(args, order)
	}

	query += ";"

	err := s.db.Select(&socks, query, args...)
	if err != nil {
		s.logger.Log("database error", err)
		return []Sock{}, ErrDBConnection
	}
	for i, s := range socks {
		socks[i].ImageURL = []string{s.ImageURL_1, s.ImageURL_2}
		socks[i].Tags = strings.Split(s.TagString, ",")
	}

	socks = cut(socks, pageNum, pageSize)

	return socks, nil
}

func (s *catalogueService) Count(tags []string) (int, error) {
	query := "SELECT COUNT(DISTINCT sock.sock_id) FROM sock JOIN sock_tag ON sock.sock_id=sock_tag.sock_id JOIN tag ON sock_tag.tag_id=tag.tag_id"

	var args []interface{}

	for i, t := range tags {
		if i == 0 {
			query += " WHERE tag.name=?"
			args = append(args, t)
		} else {
			query += " OR tag.name=?"
			args = append(args, t)
		}
	}

	query += ";"

	sel, err := s.db.Prepare(query)

	if err != nil {
		s.logger.Log("database error", err)
		return 0, ErrDBConnection
	}
	defer sel.Close()

	var count int
	err = sel.QueryRow(args...).Scan(&count)

	if err != nil {
		s.logger.Log("database error", err)
		return 0, ErrDBConnection
	}

	return count, nil
}

func (s *catalogueService) Get(id string) (Sock, error) {
	query := baseQuery + " WHERE sock.sock_id =? GROUP BY sock.sock_id;"

	var sock Sock
	err := s.db.Get(&sock, query, id)
	if err != nil {
		s.logger.Log("database error", err)
		return Sock{}, ErrNotFound
	}

	sock.ImageURL = []string{sock.ImageURL_1, sock.ImageURL_2}
	sock.Tags = strings.Split(sock.TagString, ",")

	return sock, nil
}

func (s *catalogueService) Tags() ([]string, error) {
	var tags []string
	query := "SELECT name FROM tag;"
	rows, err := s.db.Query(query)
	if err != nil {
		s.logger.Log("database error", err)
		return []string{}, ErrDBConnection
	}
	var tag string
	for rows.Next() {
		err = rows.Scan(&tag)
		if err != nil {
			s.logger.Log("database error", err)
			continue
		}
		tags = append(tags, tag)
	}
	return tags, nil
}

func cut(socks []Sock, pageNum, pageSize int) []Sock {
	if pageNum == 0 || pageSize == 0 {
		return []Sock{} // pageNum is 1-indexed
	}
	start := (pageNum * pageSize) - pageSize
	if start > len(socks) {
		return []Sock{}
	}
	end := (pageNum * pageSize)
	if end > len(socks) {
		end = len(socks)
	}
	return socks[start:end]
}

func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}
<|endoftext|>


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

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
package ecdsa

// References:
//   [NSA]: Suite B implementer's guide to FIPS 186-3,
//     http://www.nsa.gov/ia/_files/ecdsa.pdf
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/sha512"
	"encoding/asn1"
	"errors"
	"io"
	"math/big"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

type ecdsaSignature struct {
	R, S *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Sign signs msg with priv, reading randomness from rand. This method is
// intended to support keys where the private part is kept in, for example, a
// hardware module. Common uses should use the Sign function in this package
// directly.
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, msg)
	if err != nil {
		return nil, err
	}

	return asn1.Marshal(ecdsaSignature{r, s})
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length.  It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// Get max(log2(q) / 2, 256) bits of entropy from rand.
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	e := hashToInt(hash, c)

	var w *big.Int
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<commit_msg>crypto/ecdsa: correct code comment.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
package ecdsa

// References:
//   [NSA]: Suite B implementer's guide to FIPS 186-3,
//     http://www.nsa.gov/ia/_files/ecdsa.pdf
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/sha512"
	"encoding/asn1"
	"errors"
	"io"
	"math/big"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

type ecdsaSignature struct {
	R, S *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Sign signs msg with priv, reading randomness from rand. This method is
// intended to support keys where the private part is kept in, for example, a
// hardware module. Common uses should use the Sign function in this package
// directly.
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, msg)
	if err != nil {
		return nil, err
	}

	return asn1.Marshal(ecdsaSignature{r, s})
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length.  It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// Get min(log2(q) / 2, 256) bits of entropy from rand.
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	e := hashToInt(hash, c)

	var w *big.Int
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<|endoftext|>


<commit_before>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tests verifying the semantics of the select statement
// for basic empty/non-empty cases.

package main

import "time"

const always = "function did not"
const never = "function did"

func unreachable() {
	panic("control flow shouldn't reach here")
}

// Calls f and verifies that f always/never panics depending on signal.
func testPanic(signal string, f func()) {
	defer func() {
		s := never
		if recover() != nil {
			s = always // f panicked
		}
		if s != signal {
			panic(signal + " panic")
		}
	}()
	f()
}

// Calls f and empirically verifies that f always/never blocks depending on signal.
func testBlock(signal string, f func()) {
	c := make(chan string)
	go func() {
		f()
		c <- never // f didn't block
	}()
	go func() {
		time.Sleep(1e8) // 0.1s seems plenty long
		c <- always     // f blocked always
	}()
	if <-c != signal {
		panic(signal + " block")
	}
}

func main() {
	const async = 1 // asynchronous channels
	var nilch chan int
	closedch := make(chan int)
	close(closedch)

	// sending/receiving from a nil channel blocks
	testBlock(always, func() {
		nilch <- 7
	})
	testBlock(always, func() {
		<-nilch
	})

	// sending/receiving from a nil channel inside a select is never selected
	testPanic(never, func() {
		select {
		case nilch <- 7:
			unreachable()
		default:
		}
	})
	testPanic(never, func() {
		select {
		case <-nilch:
			unreachable()
		default:
		}
	})

	// sending to an async channel with free buffer space never blocks
	testBlock(never, func() {
		ch := make(chan int, async)
		ch <- 7
	})

	// receiving from a closed channel never blocks
	testBlock(never, func() {
		for i := 0; i < 10; i++ {
			if <-closedch != 0 {
				panic("expected zero value when reading from closed channel")
			}
			if x, ok := <-closedch; x != 0 || ok {
				println("closedch:", x, ok)
				panic("expected 0, false from closed channel")
			}
		}
	})

	// sending to a closed channel panics.
	testPanic(always, func() {
		closedch <- 7
	})

	// receiving from a non-ready channel always blocks
	testBlock(always, func() {
		ch := make(chan int)
		<-ch
	})

	// empty selects always block
	testBlock(always, func() {
		select {
		}
	})

	// selects with only nil channels always block
	testBlock(always, func() {
		select {
		case <-nilch:
			unreachable()
		}
	})
	testBlock(always, func() {
		select {
		case nilch <- 7:
			unreachable()
		}
	})
	testBlock(always, func() {
		select {
		case <-nilch:
			unreachable()
		case nilch <- 7:
			unreachable()
		}
	})

	// selects with non-ready non-nil channels always block
	testBlock(always, func() {
		ch := make(chan int)
		select {
		case <-ch:
			unreachable()
		}
	})

	// selects with default cases don't block
	testBlock(never, func() {
		select {
		default:
		}
	})
	testBlock(never, func() {
		select {
		case <-nilch:
			unreachable()
		default:
		}
	})
	testBlock(never, func() {
		select {
		case nilch <- 7:
			unreachable()
		default:
		}
	})

	// selects with ready channels don't block
	testBlock(never, func() {
		ch := make(chan int, async)
		select {
		case ch <- 7:
		default:
			unreachable()
		}
	})
	testBlock(never, func() {
		ch := make(chan int, async)
		ch <- 7
		select {
		case <-ch:
		default:
			unreachable()
		}
	})

	// selects with closed channels behave like ordinary operations
	testBlock(never, func() {
		select {
		case <-closedch:
		}
	})
	testBlock(never, func() {
		select {
		case x := <-closedch:
			_ = x
		}
	})
	testBlock(never, func() {
		select {
		case x, ok := <-closedch:
			_, _ = x, ok
		}
	})
	testPanic(always, func() {
		select {
		case closedch <- 7:
		}
	})

	// select should not get confused if it sees itself
	testBlock(always, func() {
		c := make(chan int)
		select {
		case c <- 1:
		case <-c:
		}
	})
}
<commit_msg>test: test that x := <-c accepts a general expression<commit_after>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tests verifying the semantics of the select statement
// for basic empty/non-empty cases.

package main

import "time"

const always = "function did not"
const never = "function did"

func unreachable() {
	panic("control flow shouldn't reach here")
}

// Calls f and verifies that f always/never panics depending on signal.
func testPanic(signal string, f func()) {
	defer func() {
		s := never
		if recover() != nil {
			s = always // f panicked
		}
		if s != signal {
			panic(signal + " panic")
		}
	}()
	f()
}

// Calls f and empirically verifies that f always/never blocks depending on signal.
func testBlock(signal string, f func()) {
	c := make(chan string)
	go func() {
		f()
		c <- never // f didn't block
	}()
	go func() {
		time.Sleep(1e8) // 0.1s seems plenty long
		c <- always     // f blocked always
	}()
	if <-c != signal {
		panic(signal + " block")
	}
}

func main() {
	const async = 1 // asynchronous channels
	var nilch chan int
	closedch := make(chan int)
	close(closedch)

	// sending/receiving from a nil channel blocks
	testBlock(always, func() {
		nilch <- 7
	})
	testBlock(always, func() {
		<-nilch
	})

	// sending/receiving from a nil channel inside a select is never selected
	testPanic(never, func() {
		select {
		case nilch <- 7:
			unreachable()
		default:
		}
	})
	testPanic(never, func() {
		select {
		case <-nilch:
			unreachable()
		default:
		}
	})

	// sending to an async channel with free buffer space never blocks
	testBlock(never, func() {
		ch := make(chan int, async)
		ch <- 7
	})

	// receiving from a closed channel never blocks
	testBlock(never, func() {
		for i := 0; i < 10; i++ {
			if <-closedch != 0 {
				panic("expected zero value when reading from closed channel")
			}
			if x, ok := <-closedch; x != 0 || ok {
				println("closedch:", x, ok)
				panic("expected 0, false from closed channel")
			}
		}
	})

	// sending to a closed channel panics.
	testPanic(always, func() {
		closedch <- 7
	})

	// receiving from a non-ready channel always blocks
	testBlock(always, func() {
		ch := make(chan int)
		<-ch
	})

	// empty selects always block
	testBlock(always, func() {
		select {
		}
	})

	// selects with only nil channels always block
	testBlock(always, func() {
		select {
		case <-nilch:
			unreachable()
		}
	})
	testBlock(always, func() {
		select {
		case nilch <- 7:
			unreachable()
		}
	})
	testBlock(always, func() {
		select {
		case <-nilch:
			unreachable()
		case nilch <- 7:
			unreachable()
		}
	})

	// selects with non-ready non-nil channels always block
	testBlock(always, func() {
		ch := make(chan int)
		select {
		case <-ch:
			unreachable()
		}
	})

	// selects with default cases don't block
	testBlock(never, func() {
		select {
		default:
		}
	})
	testBlock(never, func() {
		select {
		case <-nilch:
			unreachable()
		default:
		}
	})
	testBlock(never, func() {
		select {
		case nilch <- 7:
			unreachable()
		default:
		}
	})

	// selects with ready channels don't block
	testBlock(never, func() {
		ch := make(chan int, async)
		select {
		case ch <- 7:
		default:
			unreachable()
		}
	})
	testBlock(never, func() {
		ch := make(chan int, async)
		ch <- 7
		select {
		case <-ch:
		default:
			unreachable()
		}
	})

	// selects with closed channels behave like ordinary operations
	testBlock(never, func() {
		select {
		case <-closedch:
		}
	})
	testBlock(never, func() {
		select {
		case x := (<-closedch):
			_ = x
		}
	})
	testBlock(never, func() {
		select {
		case x, ok := (<-closedch):
			_, _ = x, ok
		}
	})
	testPanic(always, func() {
		select {
		case closedch <- 7:
		}
	})

	// select should not get confused if it sees itself
	testBlock(always, func() {
		c := make(chan int)
		select {
		case c <- 1:
		case <-c:
		}
	})
}
<|endoftext|>