<commit_before>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

type Broker struct {
	Name               string
	ServiceGenericName string
	IP                 string
	Port               int
	CertFile           string
	KeyFile            string
	AuthExchange       string
	AuthAllExchange    string
	WebProtocol        string
}

type Config struct {
	BuildNumber     int
	Environment     string
	ProjectRoot     string
	UserSitesDomain string
	Version         string
	Client          struct {
		StaticFilesBaseUrl string
		RuntimeOptions     RuntimeOptions
	}
	Mongo string
	Mq    struct {
		Host     string
		Port     int
		Login    string
		Password string
		Vhost    string
		LogLevel string
	}
	Broker            Broker
	PremiumBroker     Broker
	BrokerKite        Broker
	PremiumBrokerKite Broker
	Slack             struct {
		Token   string
		Channel string
	}
	LogLevel map[string]string
	Redis    struct {
		Url string
	}
	SubscriptionEndpoint string
	Gowebserver          struct {
		Port int
	}
	Rerouting struct {
		Port int
	}
	SocialApi struct {
		ProxyUrl     string
		CustomDomain struct {
			Public string
			Local  string
		}
	}
	Vmwatcher struct {
		Port           string
		AwsKey         string
		AwsSecret      string
		KloudSecretKey string
		KloudAddr      string
	}
	Segment        string
	GatherIngestor struct {
		Port int
	}
	Mailgun struct {
		Domain     string
		PrivateKey string
		PublicKey  string
	}
}

type RuntimeOptions struct {
	Kites struct {
		DisableWebSocketByDefault bool `json:"disableWebSocketByDefault"`
		Kontrol                   struct {
			Username string `json:"username"`
		} `json:"kontrol"`
		Os struct {
			Version string `json:"version"`
		} `json:"os"`
		Terminal struct {
			Version string `json:"version"`
		} `json:"terminal"`
		Klient struct {
			Version string `json:"version"`
		} `json:"klient"`
		Kloud struct {
			Version string `json:"version"`
		} `json:"kloud"`
	} `json:"kites"`
	Algolia struct {
		AppId       string `json:"appId"`
		ApiKey      string `json:"apiKey"`
		IndexSuffix string `json:"indexSuffix"`
	} `json:"algolia"`
	SuppressLogs    bool   `json:"suppressLogs"`
	AuthExchange    string `json:"authExchange"`
	Environment     string `json:"environment"`
	Version         string `json:"version"`
	ResourceName    string `json:"resourceName"`
	UserSitesDomain string `json:"userSitesDomain"`
	LogResourceName string `json:"logResourceName"`
	SocialApiUri    string `json:"socialApiUri"`
	ApiUri          string `json:"apiUri"`
	MainUri         string `json:"mainUri"`
	SourceMapsUri   string `json:"sourceMapsUri"`
	Broker          struct {
		Uri string `json:"uri"`
	} `json:"broker"`
	AppsUri            string `json:"appsUri"`
	UploadsUri         string `json:"uploadsUri"`
	UploadsUriForGroup string `json:"uploadsUriForGroup"`
	FileFetchTimeout   int    `json:"fileFetchTimeout"`
	UserIdleMs         int    `json:"userIdleMs"`
	Embedly            struct {
		ApiKey string `json:"apiKey"`
	} `json:"embedly"`
	Github struct {
		ClientId string `json:"clientId"`
	} `json:"github"`
	Newkontrol struct {
		Url string `json:"url"`
	} `json:"newkontrol"`
	SessionCookie struct {
		MaxAge int  `json:"maxAge"`
		Secure bool `json:"secure"`
	} `json:"sessionCookie"`
	Stripe struct {
		Token string `json:"token"`
	} `json:"stripe"`
	ExternalProfiles struct {
		Google struct {
			Nicename string `json:"nicename"`
		} `json:"google"`
		Linkedin struct {
			Nicename string `json:"nicename"`
		} `json:"linkedin"`
		Twitter struct {
			Nicename string `json:"nicename"`
		} `json:"twitter"`
		Facebook struct {
			Nicename    string `json:"nicename"`
			UrlLocation string `json:"urlLocation"`
		} `json:"facebook"`
		Github struct {
			Nicename    string `json:"nicename"`
			UrlLocation string `json:"urlLocation"`
		} `json:"github"`
	} `json:"externalProfiles"`
	EntryPoint struct {
		Slug string `json:"slug"`
		Type string `json:"type"`
	} `json:"entryPoint"`
	Roles       []string      `json:"roles"`
	Permissions []interface{} `json:"permissions"`
	SiftScience string        `json:"siftScience"`
	Paypal      struct {
		FormUrl string `json:"formUrl"`
	} `json:"paypal"`
	Pubnub struct {
		SubscribeKey string `json:"subscribekey"`
		Enabled      bool   `json:"enabled"`
		SSL          bool   `json:"ssl"`
	} `json:"pubnub"`
	Collaboration struct {
		Timeout int `json:"timeout"`
	} `json:"collaboration"`
	PaymentBlockDuration float64 `json:"paymentBlockDuration"`
	DisabledFeatures     struct {
		Moderation bool `json:"moderation"`
		Teams      bool `json:"teams"`
		BotChannel bool `json:"botchannel"`
	} `json:"disabledFeatures"`
	ContentRotatorUrl string `json:"contentRotatorUrl"`
	Integration       struct {
		Url string `json:"url"`
	} `json:"integration"`
	WebhookMiddleware struct {
		Url string `json:"url"`
	} `json:"webhookMiddleware"`
	Google struct {
		ApiKey string `json:"apiKey"`
	} `json:"google"`
	Recaptcha struct {
		Key     string `json:"key"`
		Enabled bool   `json:"enabled"`
	} `json:"recaptcha"`
	Domains struct {
		Base string `json:"base"`
		Mail string `json:"mail"`
		Main string `json:"main"`
		Port string `json:"port"`
	} `json:"domains"`
}

// TODO: THIS IS ADDED SO ALL GO PACKAGES CLEANLY EXIT EVEN WHEN
// RUN WITH RERUN

func init() {

	go func() {
		signals := make(chan os.Signal, 1)
		signal.Notify(signals)
		for {
			signal := <-signals
			switch signal {
			case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGSTOP:
				os.Exit(0)
			}
		}
	}()
}

func MustConfig(profile string) *Config {
	conf, err := readConfig("", profile)
	if err != nil {
		panic(err)
	}

	return conf
}

// MustEnv is like Env, but panics if the Config cannot be read successfully.
func MustEnv() *Config {
	conf, err := Env()
	if err != nil {
		panic(err)
	}

	return conf
}

// Env reads from the KONFIG_JSON environment variable and intitializes the
// Config struct
func Env() (*Config, error) {
	return readConfig("", "")
}

func readConfig(configDir, profile string) (*Config, error) {
	jsonData := os.Getenv("KONFIG_JSON")
	if jsonData == "" {
		return nil, errors.New("KONFIG_JSON is not set")
	}

	conf := new(Config)
	err := json.Unmarshal([]byte(jsonData), &conf)
	if err != nil {
		return nil, fmt.Errorf("Configuration error, make sure KONFIG_JSON is set: %s\nConfiguration source output:\n%s\n",
			err.Error(), string(jsonData))
	}

	return conf, nil
}
<commit_msg>go/webserver: add intercom app key in client runtime opts<commit_after>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

type Broker struct {
	Name               string
	ServiceGenericName string
	IP                 string
	Port               int
	CertFile           string
	KeyFile            string
	AuthExchange       string
	AuthAllExchange    string
	WebProtocol        string
}

type Config struct {
	BuildNumber     int
	Environment     string
	ProjectRoot     string
	UserSitesDomain string
	Version         string
	Client          struct {
		StaticFilesBaseUrl string
		RuntimeOptions     RuntimeOptions
	}
	Mongo string
	Mq    struct {
		Host     string
		Port     int
		Login    string
		Password string
		Vhost    string
		LogLevel string
	}
	Broker            Broker
	PremiumBroker     Broker
	BrokerKite        Broker
	PremiumBrokerKite Broker
	Slack             struct {
		Token   string
		Channel string
	}
	LogLevel map[string]string
	Redis    struct {
		Url string
	}
	SubscriptionEndpoint string
	Gowebserver          struct {
		Port int
	}
	Rerouting struct {
		Port int
	}
	SocialApi struct {
		ProxyUrl     string
		CustomDomain struct {
			Public string
			Local  string
		}
	}
	Vmwatcher struct {
		Port           string
		AwsKey         string
		AwsSecret      string
		KloudSecretKey string
		KloudAddr      string
	}
	Segment        string
	GatherIngestor struct {
		Port int
	}
	Mailgun struct {
		Domain     string
		PrivateKey string
		PublicKey  string
	}
}

type RuntimeOptions struct {
	Kites struct {
		DisableWebSocketByDefault bool `json:"disableWebSocketByDefault"`
		Kontrol                   struct {
			Username string `json:"username"`
		} `json:"kontrol"`
		Os struct {
			Version string `json:"version"`
		} `json:"os"`
		Terminal struct {
			Version string `json:"version"`
		} `json:"terminal"`
		Klient struct {
			Version string `json:"version"`
		} `json:"klient"`
		Kloud struct {
			Version string `json:"version"`
		} `json:"kloud"`
	} `json:"kites"`
	Algolia struct {
		AppId       string `json:"appId"`
		ApiKey      string `json:"apiKey"`
		IndexSuffix string `json:"indexSuffix"`
	} `json:"algolia"`
	SuppressLogs    bool   `json:"suppressLogs"`
	AuthExchange    string `json:"authExchange"`
	Environment     string `json:"environment"`
	Version         string `json:"version"`
	ResourceName    string `json:"resourceName"`
	UserSitesDomain string `json:"userSitesDomain"`
	LogResourceName string `json:"logResourceName"`
	SocialApiUri    string `json:"socialApiUri"`
	ApiUri          string `json:"apiUri"`
	MainUri         string `json:"mainUri"`
	SourceMapsUri   string `json:"sourceMapsUri"`
	Broker          struct {
		Uri string `json:"uri"`
	} `json:"broker"`
	AppsUri            string `json:"appsUri"`
	UploadsUri         string `json:"uploadsUri"`
	UploadsUriForGroup string `json:"uploadsUriForGroup"`
	FileFetchTimeout   int    `json:"fileFetchTimeout"`
	UserIdleMs         int    `json:"userIdleMs"`
	IntercomAppId      string `json:"intercomAppId"`
	Embedly            struct {
		ApiKey string `json:"apiKey"`
	} `json:"embedly"`
	Github struct {
		ClientId string `json:"clientId"`
	} `json:"github"`
	Newkontrol struct {
		Url string `json:"url"`
	} `json:"newkontrol"`
	SessionCookie struct {
		MaxAge int  `json:"maxAge"`
		Secure bool `json:"secure"`
	} `json:"sessionCookie"`
	Stripe struct {
		Token string `json:"token"`
	} `json:"stripe"`
	ExternalProfiles struct {
		Google struct {
			Nicename string `json:"nicename"`
		} `json:"google"`
		Linkedin struct {
			Nicename string `json:"nicename"`
		} `json:"linkedin"`
		Twitter struct {
			Nicename string `json:"nicename"`
		} `json:"twitter"`
		Facebook struct {
			Nicename    string `json:"nicename"`
			UrlLocation string `json:"urlLocation"`
		} `json:"facebook"`
		Github struct {
			Nicename    string `json:"nicename"`
			UrlLocation string `json:"urlLocation"`
		} `json:"github"`
	} `json:"externalProfiles"`
	EntryPoint struct {
		Slug string `json:"slug"`
		Type string `json:"type"`
	} `json:"entryPoint"`
	Roles       []string      `json:"roles"`
	Permissions []interface{} `json:"permissions"`
	SiftScience string        `json:"siftScience"`
	Paypal      struct {
		FormUrl string `json:"formUrl"`
	} `json:"paypal"`
	Pubnub struct {
		SubscribeKey string `json:"subscribekey"`
		Enabled      bool   `json:"enabled"`
		SSL          bool   `json:"ssl"`
	} `json:"pubnub"`
	Collaboration struct {
		Timeout int `json:"timeout"`
	} `json:"collaboration"`
	PaymentBlockDuration float64 `json:"paymentBlockDuration"`
	DisabledFeatures     struct {
		Moderation bool `json:"moderation"`
		Teams      bool `json:"teams"`
		BotChannel bool `json:"botchannel"`
	} `json:"disabledFeatures"`
	ContentRotatorUrl string `json:"contentRotatorUrl"`
	Integration       struct {
		Url string `json:"url"`
	} `json:"integration"`
	WebhookMiddleware struct {
		Url string `json:"url"`
	} `json:"webhookMiddleware"`
	Google struct {
		ApiKey string `json:"apiKey"`
	} `json:"google"`
	Recaptcha struct {
		Key     string `json:"key"`
		Enabled bool   `json:"enabled"`
	} `json:"recaptcha"`
	Domains struct {
		Base string `json:"base"`
		Mail string `json:"mail"`
		Main string `json:"main"`
		Port string `json:"port"`
	} `json:"domains"`
}

// TODO: THIS IS ADDED SO ALL GO PACKAGES CLEANLY EXIT EVEN WHEN
// RUN WITH RERUN

func init() {

	go func() {
		signals := make(chan os.Signal, 1)
		signal.Notify(signals)
		for {
			signal := <-signals
			switch signal {
			case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGSTOP:
				os.Exit(0)
			}
		}
	}()
}

func MustConfig(profile string) *Config {
	conf, err := readConfig("", profile)
	if err != nil {
		panic(err)
	}

	return conf
}

// MustEnv is like Env, but panics if the Config cannot be read successfully.
func MustEnv() *Config {
	conf, err := Env()
	if err != nil {
		panic(err)
	}

	return conf
}

// Env reads from the KONFIG_JSON environment variable and intitializes the
// Config struct
func Env() (*Config, error) {
	return readConfig("", "")
}

func readConfig(configDir, profile string) (*Config, error) {
	jsonData := os.Getenv("KONFIG_JSON")
	if jsonData == "" {
		return nil, errors.New("KONFIG_JSON is not set")
	}

	conf := new(Config)
	err := json.Unmarshal([]byte(jsonData), &conf)
	if err != nil {
		return nil, fmt.Errorf("Configuration error, make sure KONFIG_JSON is set: %s\nConfiguration source output:\n%s\n",
			err.Error(), string(jsonData))
	}

	return conf, nil
}
<|endoftext|>


<commit_before>package http

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"

	cmds "github.com/ipfs/go-ipfs/commands"
	u "github.com/ipfs/go-ipfs/util"
)

var log = u.Logger("commands/http")

// the internal handler for the API
type internalHandler struct {
	ctx  cmds.Context
	root *cmds.Command
}

// The Handler struct is funny because we want to wrap our internal handler
// with CORS while keeping our fields.
type Handler struct {
	internalHandler
	corsHandler http.Handler
}

var ErrNotFound = errors.New("404 page not found")

const (
	StreamErrHeader        = "X-Stream-Error"
	streamHeader           = "X-Stream-Output"
	channelHeader          = "X-Chunked-Output"
	uaHeader               = "User-Agent"
	contentTypeHeader      = "Content-Type"
	contentLengthHeader    = "Content-Length"
	contentDispHeader      = "Content-Disposition"
	transferEncodingHeader = "Transfer-Encoding"
	applicationJson        = "application/json"
	applicationOctetStream = "application/octet-stream"
	plainText              = "text/plain"
)

var mimeTypes = map[string]string{
	cmds.JSON: "application/json",
	cmds.XML:  "application/xml",
	cmds.Text: "text/plain",
}

func NewHandler(ctx cmds.Context, root *cmds.Command, allowedOrigin string) *Handler {
	// allow whitelisted origins (so we can make API requests from the browser)
	if len(allowedOrigin) > 0 {
		log.Info("Allowing API requests from origin: " + allowedOrigin)
	}

	// Create a handler for the API.
	internal := internalHandler{ctx, root}

	// Create a CORS object for wrapping the internal handler.
	c := cors.New(cors.Options{
		AllowedMethods: []string{"GET", "POST", "PUT"},

		// use AllowOriginFunc instead of AllowedOrigins because we want to be
		// restrictive by default.
		AllowOriginFunc: func(origin string) bool {
			return (allowedOrigin == "*") || (origin == allowedOrigin)
		},
	})

	// Wrap the internal handler with CORS handling-middleware.
	return &Handler{internal, c.Handler(internal)}
}

func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Call the CORS handler which wraps the internal handler.
	i.corsHandler.ServeHTTP(w, r)
}

func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Debug("Incoming API request: ", r.URL)

	// error on external referers (to prevent CSRF attacks)
	referer := r.Referer()
	scheme := r.URL.Scheme
	if len(scheme) == 0 {
		scheme = "http"
	}
	host := fmt.Sprintf("%s://%s/", scheme, r.Host)
	// empty string means the user isn't following a link (they are directly typing in the url)
	if referer != "" && !strings.HasPrefix(referer, host) {
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("403 - Forbidden"))
		return
	}

	req, err := Parse(r, i.root)
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(http.StatusNotFound)
		} else {
			w.WriteHeader(http.StatusBadRequest)
		}
		w.Write([]byte(err.Error()))
		return
	}

	// get the node's context to pass into the commands.
	node, err := i.ctx.GetNode()
	if err != nil {
		s := fmt.Sprintf("cmds/http: couldn't GetNode(): %s", err)
		http.Error(w, s, http.StatusInternalServerError)
		return
	}

	//ps: take note of the name clash - commands.Context != context.Context
	req.SetInvocContext(i.ctx)
	err = req.SetRootContext(node.Context())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// call the command
	res := i.root.Call(req)

	// now handle responding to the client properly
	sendResponse(w, req, res)
}

func guessMimeType(res cmds.Response) (string, error) {
	if _, ok := res.Output().(io.Reader); ok {
		// we don't set the Content-Type for streams, so that browsers can MIME-sniff the type themselves
		// we set this header so clients have a way to know this is an output stream
		// (not marshalled command output)
		// TODO: set a specific Content-Type if the command response needs it to be a certain type
		return "", nil
	}

	// Try to guess mimeType from the encoding option
	enc, found, err := res.Request().Option(cmds.EncShort).String()
	if err != nil {
		return "", err
	}
	if !found {
		return "", errors.New("no encoding option set")
	}

	return mimeTypes[enc], nil
}

func sendResponse(w http.ResponseWriter, req cmds.Request, res cmds.Response) {
	mime, err := guessMimeType(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	status := http.StatusOK
	// if response contains an error, write an HTTP error status code
	if e := res.Error(); e != nil {
		if e.Code == cmds.ErrClient {
			status = http.StatusBadRequest
		} else {
			status = http.StatusInternalServerError
		}
		// NOTE: The error will actually be written out by the reader below
	}

	out, err := res.Reader()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	h := w.Header()
	if res.Length() > 0 {
		h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
	}

	// if output is a channel and user requested streaming channels,
	// use chunk copier for the output
	_, isChan := res.Output().(chan interface{})
	if !isChan {
		_, isChan = res.Output().(<-chan interface{})
	}

	streamChans, _, _ := req.Option("stream-channels").Bool()
	if isChan {
		h.Set(channelHeader, "1")
		if streamChans {
			// streaming output from a channel will always be json objects
			mime = applicationJson
		}
	}

	if mime != "" {
		h.Set(contentTypeHeader, mime)
	}
	h.Set(streamHeader, "1")
	h.Set(transferEncodingHeader, "chunked")

	if err := writeResponse(status, w, out); err != nil {
		log.Error("error while writing stream", err)
	}
}

// Copies from an io.Reader to a http.ResponseWriter.
// Flushes chunks over HTTP stream as they are read (if supported by transport).
func writeResponse(status int, w http.ResponseWriter, out io.Reader) error {
	// hijack the connection so we can write our own chunked output and trailers
	hijacker, ok := w.(http.Hijacker)
	if !ok {
		log.Error("Failed to create hijacker! cannot continue!")
		return errors.New("Could not create hijacker")
	}
	conn, writer, err := hijacker.Hijack()
	if err != nil {
		return err
	}
	defer conn.Close()

	// write status
	writer.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", status, http.StatusText(status)))

	// Write out headers
	w.Header().Write(writer)

	// end of headers
	writer.WriteString("\r\n")

	// write body
	streamErr := writeChunks(out, writer)

	// close body
	writer.WriteString("0\r\n")

	// if there was a stream error, write out an error trailer. hopefully
	// the client will pick it up!
	if streamErr != nil {
		writer.WriteString(StreamErrHeader + ": " + sanitizedErrStr(streamErr) + "\r\n")
	}
	writer.WriteString("\r\n") // close response
	writer.Flush()
	return streamErr
}

func writeChunks(r io.Reader, w *bufio.ReadWriter) error {
	buf := make([]byte, 32*1024)
	for {
		n, err := r.Read(buf)

		if n > 0 {
			length := fmt.Sprintf("%x\r\n", n)
			w.WriteString(length)

			_, err := w.Write(buf[0:n])
			if err != nil {
				return err
			}

			w.WriteString("\r\n")
			w.Flush()
		}

		if err != nil && err != io.EOF {
			return err
		}
		if err == io.EOF {
			break
		}
	}
	return nil
}

func sanitizedErrStr(err error) string {
	s := err.Error()
	s = strings.Split(s, "\n")[0]
	s = strings.Split(s, "\r")[0]
	return s
}
<commit_msg>only set stream header on streamed output<commit_after>package http

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"

	cmds "github.com/ipfs/go-ipfs/commands"
	u "github.com/ipfs/go-ipfs/util"
)

var log = u.Logger("commands/http")

// the internal handler for the API
type internalHandler struct {
	ctx  cmds.Context
	root *cmds.Command
}

// The Handler struct is funny because we want to wrap our internal handler
// with CORS while keeping our fields.
type Handler struct {
	internalHandler
	corsHandler http.Handler
}

var ErrNotFound = errors.New("404 page not found")

const (
	StreamErrHeader        = "X-Stream-Error"
	streamHeader           = "X-Stream-Output"
	channelHeader          = "X-Chunked-Output"
	uaHeader               = "User-Agent"
	contentTypeHeader      = "Content-Type"
	contentLengthHeader    = "Content-Length"
	contentDispHeader      = "Content-Disposition"
	transferEncodingHeader = "Transfer-Encoding"
	applicationJson        = "application/json"
	applicationOctetStream = "application/octet-stream"
	plainText              = "text/plain"
)

var mimeTypes = map[string]string{
	cmds.JSON: "application/json",
	cmds.XML:  "application/xml",
	cmds.Text: "text/plain",
}

func NewHandler(ctx cmds.Context, root *cmds.Command, allowedOrigin string) *Handler {
	// allow whitelisted origins (so we can make API requests from the browser)
	if len(allowedOrigin) > 0 {
		log.Info("Allowing API requests from origin: " + allowedOrigin)
	}

	// Create a handler for the API.
	internal := internalHandler{ctx, root}

	// Create a CORS object for wrapping the internal handler.
	c := cors.New(cors.Options{
		AllowedMethods: []string{"GET", "POST", "PUT"},

		// use AllowOriginFunc instead of AllowedOrigins because we want to be
		// restrictive by default.
		AllowOriginFunc: func(origin string) bool {
			return (allowedOrigin == "*") || (origin == allowedOrigin)
		},
	})

	// Wrap the internal handler with CORS handling-middleware.
	return &Handler{internal, c.Handler(internal)}
}

func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Call the CORS handler which wraps the internal handler.
	i.corsHandler.ServeHTTP(w, r)
}

func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Debug("Incoming API request: ", r.URL)

	// error on external referers (to prevent CSRF attacks)
	referer := r.Referer()
	scheme := r.URL.Scheme
	if len(scheme) == 0 {
		scheme = "http"
	}
	host := fmt.Sprintf("%s://%s/", scheme, r.Host)
	// empty string means the user isn't following a link (they are directly typing in the url)
	if referer != "" && !strings.HasPrefix(referer, host) {
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("403 - Forbidden"))
		return
	}

	req, err := Parse(r, i.root)
	if err != nil {
		if err == ErrNotFound {
			w.WriteHeader(http.StatusNotFound)
		} else {
			w.WriteHeader(http.StatusBadRequest)
		}
		w.Write([]byte(err.Error()))
		return
	}

	// get the node's context to pass into the commands.
	node, err := i.ctx.GetNode()
	if err != nil {
		s := fmt.Sprintf("cmds/http: couldn't GetNode(): %s", err)
		http.Error(w, s, http.StatusInternalServerError)
		return
	}

	//ps: take note of the name clash - commands.Context != context.Context
	req.SetInvocContext(i.ctx)
	err = req.SetRootContext(node.Context())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// call the command
	res := i.root.Call(req)

	// now handle responding to the client properly
	sendResponse(w, req, res)
}

func guessMimeType(res cmds.Response) (string, error) {
	// Try to guess mimeType from the encoding option
	enc, found, err := res.Request().Option(cmds.EncShort).String()
	if err != nil {
		return "", err
	}
	if !found {
		return "", errors.New("no encoding option set")
	}

	return mimeTypes[enc], nil
}

func sendResponse(w http.ResponseWriter, req cmds.Request, res cmds.Response) {
	mime, err := guessMimeType(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	status := http.StatusOK
	// if response contains an error, write an HTTP error status code
	if e := res.Error(); e != nil {
		if e.Code == cmds.ErrClient {
			status = http.StatusBadRequest
		} else {
			status = http.StatusInternalServerError
		}
		// NOTE: The error will actually be written out by the reader below
	}

	out, err := res.Reader()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	h := w.Header()
	if res.Length() > 0 {
		h.Set(contentLengthHeader, strconv.FormatUint(res.Length(), 10))
	}

	if _, ok := res.Output().(io.Reader); ok {
		mime = ""
		h.Set(streamHeader, "1")
	}

	// if output is a channel and user requested streaming channels,
	// use chunk copier for the output
	_, isChan := res.Output().(chan interface{})
	if !isChan {
		_, isChan = res.Output().(<-chan interface{})
	}

	streamChans, _, _ := req.Option("stream-channels").Bool()
	if isChan {
		h.Set(channelHeader, "1")
		if streamChans {
			// streaming output from a channel will always be json objects
			mime = applicationJson
		}
	}

	if mime != "" {
		h.Set(contentTypeHeader, mime)
	}
	h.Set(transferEncodingHeader, "chunked")

	if err := writeResponse(status, w, out); err != nil {
		log.Error("error while writing stream", err)
	}
}

// Copies from an io.Reader to a http.ResponseWriter.
// Flushes chunks over HTTP stream as they are read (if supported by transport).
func writeResponse(status int, w http.ResponseWriter, out io.Reader) error {
	// hijack the connection so we can write our own chunked output and trailers
	hijacker, ok := w.(http.Hijacker)
	if !ok {
		log.Error("Failed to create hijacker! cannot continue!")
		return errors.New("Could not create hijacker")
	}
	conn, writer, err := hijacker.Hijack()
	if err != nil {
		return err
	}
	defer conn.Close()

	// write status
	writer.WriteString(fmt.Sprintf("HTTP/1.1 %d %s\r\n", status, http.StatusText(status)))

	// Write out headers
	w.Header().Write(writer)

	// end of headers
	writer.WriteString("\r\n")

	// write body
	streamErr := writeChunks(out, writer)

	// close body
	writer.WriteString("0\r\n")

	// if there was a stream error, write out an error trailer. hopefully
	// the client will pick it up!
	if streamErr != nil {
		writer.WriteString(StreamErrHeader + ": " + sanitizedErrStr(streamErr) + "\r\n")
	}
	writer.WriteString("\r\n") // close response
	writer.Flush()
	return streamErr
}

func writeChunks(r io.Reader, w *bufio.ReadWriter) error {
	buf := make([]byte, 32*1024)
	for {
		n, err := r.Read(buf)

		if n > 0 {
			length := fmt.Sprintf("%x\r\n", n)
			w.WriteString(length)

			_, err := w.Write(buf[0:n])
			if err != nil {
				return err
			}

			w.WriteString("\r\n")
			w.Flush()
		}

		if err != nil && err != io.EOF {
			return err
		}
		if err == io.EOF {
			break
		}
	}
	return nil
}

func sanitizedErrStr(err error) string {
	s := err.Error()
	s = strings.Split(s, "\n")[0]
	s = strings.Split(s, "\r")[0]
	return s
}
<|endoftext|>


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

package testlib

import (
	"flag"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"testing"
	"time"

	"google.golang.org/grpc"

	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/servenv"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/vtctl/grpcvtctlserver"
	"github.com/youtube/vitess/go/vt/vtctl/vtctlclient"
	"golang.org/x/net/context"

	// we need to import the grpcvtctlclient library so the gRPC
	// vtctl client is registered and can be used.
	_ "github.com/youtube/vitess/go/vt/vtctl/grpcvtctlclient"
)

var servenvInitialized sync.Once

// VtctlPipe is a vtctl server based on a topo server, and a client that
// is connected to it via gRPC.
type VtctlPipe struct {
	listener net.Listener
	client   vtctlclient.VtctlClient
	t        *testing.T
}

// NewVtctlPipe creates a new VtctlPipe based on the given topo server.
func NewVtctlPipe(t *testing.T, ts topo.Server) *VtctlPipe {
	// Register all vtctl commands
	servenvInitialized.Do(func() {
		// make sure we use the right protocol
		flag.Set("vtctl_client_protocol", "grpc")

		// Enable all query groups
		flag.Set("enable_queries", "true")
		servenv.FireRunHooks()
	})

	// Listen on a random port
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatalf("Cannot listen: %v", err)
	}

	// Create a gRPC server and listen on the port
	server := grpc.NewServer()
	grpcvtctlserver.StartServer(server, ts)
	go server.Serve(listener)

	// Create a VtctlClient gRPC client to talk to the fake server
	client, err := vtctlclient.New(listener.Addr().String(), 30*time.Second)
	if err != nil {
		t.Fatalf("Cannot create client: %v", err)
	}

	return &VtctlPipe{
		listener: listener,
		client:   client,
		t:        t,
	}
}

// Close will stop listening and free up all resources.
func (vp *VtctlPipe) Close() {
	vp.client.Close()
	vp.listener.Close()
}

// Run executes the provided command remotely, logs the output in the
// test logs, and returns the command error.
func (vp *VtctlPipe) Run(args []string) error {
	return vp.run(args, func(line string) {
		vp.t.Log(line)
	})
}

// RunAndOutput is similar to Run, but returns the output as a multi-line string
// instead of logging it.
func (vp *VtctlPipe) RunAndOutput(args []string) (string, error) {
	var output []string
	err := vp.run(args, func(line string) {
		output = append(output, line)
	})
	return strings.Join(output, ""), err
}

func (vp *VtctlPipe) run(args []string, outputFunc func(string)) error {
	actionTimeout := 30 * time.Second
	ctx := context.Background()

	stream, err := vp.client.ExecuteVtctlCommand(ctx, args, actionTimeout)
	if err != nil {
		return fmt.Errorf("VtctlPipe.Run() failed: %v", err)
	}
	for {
		le, err := stream.Recv()
		switch err {
		case nil:
			outputFunc(logutil.EventString(le))
		case io.EOF:
			return nil
		default:
			return err
		}
	}
}

// RunAndStreamOutput returns the output of the vtctl command as a channel.
// When the channcel is closed, the command did finish.
func (vp *VtctlPipe) RunAndStreamOutput(args []string) (logutil.EventStream, error) {
	actionTimeout := 30 * time.Second
	ctx := context.Background()

	return vp.client.ExecuteVtctlCommand(ctx, args, actionTimeout)
}
<commit_msg>VtctlPipe: Use buffer instead of strings.Join().<commit_after>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testlib

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net"
	"sync"
	"testing"
	"time"

	"google.golang.org/grpc"

	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/servenv"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/vtctl/grpcvtctlserver"
	"github.com/youtube/vitess/go/vt/vtctl/vtctlclient"
	"golang.org/x/net/context"

	// we need to import the grpcvtctlclient library so the gRPC
	// vtctl client is registered and can be used.
	_ "github.com/youtube/vitess/go/vt/vtctl/grpcvtctlclient"
)

var servenvInitialized sync.Once

// VtctlPipe is a vtctl server based on a topo server, and a client that
// is connected to it via gRPC.
type VtctlPipe struct {
	listener net.Listener
	client   vtctlclient.VtctlClient
	t        *testing.T
}

// NewVtctlPipe creates a new VtctlPipe based on the given topo server.
func NewVtctlPipe(t *testing.T, ts topo.Server) *VtctlPipe {
	// Register all vtctl commands
	servenvInitialized.Do(func() {
		// make sure we use the right protocol
		flag.Set("vtctl_client_protocol", "grpc")

		// Enable all query groups
		flag.Set("enable_queries", "true")
		servenv.FireRunHooks()
	})

	// Listen on a random port
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatalf("Cannot listen: %v", err)
	}

	// Create a gRPC server and listen on the port
	server := grpc.NewServer()
	grpcvtctlserver.StartServer(server, ts)
	go server.Serve(listener)

	// Create a VtctlClient gRPC client to talk to the fake server
	client, err := vtctlclient.New(listener.Addr().String(), 30*time.Second)
	if err != nil {
		t.Fatalf("Cannot create client: %v", err)
	}

	return &VtctlPipe{
		listener: listener,
		client:   client,
		t:        t,
	}
}

// Close will stop listening and free up all resources.
func (vp *VtctlPipe) Close() {
	vp.client.Close()
	vp.listener.Close()
}

// Run executes the provided command remotely, logs the output in the
// test logs, and returns the command error.
func (vp *VtctlPipe) Run(args []string) error {
	return vp.run(args, func(line string) {
		vp.t.Log(line)
	})
}

// RunAndOutput is similar to Run, but returns the output as a multi-line string
// instead of logging it.
func (vp *VtctlPipe) RunAndOutput(args []string) (string, error) {
	var output bytes.Buffer
	err := vp.run(args, func(line string) {
		output.WriteString(line)
	})
	return output.String(), err
}

func (vp *VtctlPipe) run(args []string, outputFunc func(string)) error {
	actionTimeout := 30 * time.Second
	ctx := context.Background()

	stream, err := vp.client.ExecuteVtctlCommand(ctx, args, actionTimeout)
	if err != nil {
		return fmt.Errorf("VtctlPipe.Run() failed: %v", err)
	}
	for {
		le, err := stream.Recv()
		switch err {
		case nil:
			outputFunc(logutil.EventString(le))
		case io.EOF:
			return nil
		default:
			return err
		}
	}
}

// RunAndStreamOutput returns the output of the vtctl command as a channel.
// When the channcel is closed, the command did finish.
func (vp *VtctlPipe) RunAndStreamOutput(args []string) (logutil.EventStream, error) {
	actionTimeout := 30 * time.Second
	ctx := context.Background()

	return vp.client.ExecuteVtctlCommand(ctx, args, actionTimeout)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

type mockIncomingCall struct {
	callerName string
}

func (m *mockIncomingCall) CallerName() string {
	return m.callerName
}

var (
	cn = "hello"
)

func TestWrapContextForTest(t *testing.T) {
	call := &mockIncomingCall{callerName: cn}
	ctx, cancel := NewContext(time.Second)
	defer cancel()
	actual := WrapContextForTest(ctx, call)
	assert.Equal(t, call, CurrentCall(actual), "Incorrect call object returned.")
}

func TestCurrentCallWithNilResult(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()
	call := CurrentCall(ctx)
	assert.Nil(t, call, "Should return nil.")
}
<commit_msg>Update context_test to use testutils/FakeIncomingCall<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel_test

import (
	"testing"
	"time"

	. "github.com/uber/tchannel/golang"

	"github.com/stretchr/testify/assert"
	"github.com/uber/tchannel/golang/testutils"
)

var cn = "hello"

func TestWrapContextForTest(t *testing.T) {
	call := testutils.NewIncomingCall(cn)
	ctx, cancel := NewContext(time.Second)
	defer cancel()
	actual := WrapContextForTest(ctx, call)
	assert.Equal(t, call, CurrentCall(actual), "Incorrect call object returned.")
}

func TestCurrentCallWithNilResult(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()
	call := CurrentCall(ctx)
	assert.Nil(t, call, "Should return nil.")
}
<|endoftext|>


<commit_before>/*
 * 2013-06-29
 * will@summercat.com
 *
 * rss fetcher.
 *
 * - find rss feeds from a database.
 * - for every rss feed, if it was last fetched less than its update
 *   frequency ago, record that a retrieval was done, and retrieve
 *   its content.
 * - for every item, add information about that item into the database.
 *
 * this script is intended to be run periodically through something like
 * cron.
 *
 * we try to ensure that we do not poll the rss feeds too much by
 * recording a last update time and update frequency if the feed includes
 * such data.
 */

package main

import (
	"crypto/tls"
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	_ "github.com/lib/pq"
	"summercat.com/config"
	"summercat.com/gorse/gorselib"
)

type GorsePollConfig struct {
	DbUser string
	DbPass string
	DbName string
	DbHost string
	Quiet  int64
}

// retrieveFeed fetches the raw feed content.
func retrieveFeed(feed *gorselib.RssFeed) ([]byte, error) {
	// Retrieve the feed via an HTTP call.

	// NOTE: We set up a http.Transport to use TLS settings (we do not want
	//   to check certificates because my site does not have a valid one
	//   right now), and then set the transport on the http.Client, and then
	//   make the request.
	//
	//   We have to do it in this round about way rather than simply
	//   http.Get() or the like in order to pass through the TLS setting it
	//   appears.
	//
	//   TODO: Enable verification...

	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
	}

	httpTransport := &http.Transport{
		TLSClientConfig: tlsConfig,
	}

	httpClient := &http.Client{
		Transport: httpTransport,
		Timeout:   time.Second * 10,
	}

	httpResponse, err := httpClient.Get(feed.Uri)

	if err != nil {
		log.Printf("HTTP request for feed failed. (%s): %s", feed.Name, err.Error())

		// It appears we do not need to call Body.Close() here - if we try
		// then we get a runtime error about nil pointer dereference.
		return nil, err
	}

	// while we will be decoding xml, and the xml package can read directly
	// from an io.reader, I read it all in here for simplicity so that this
	// fetch function does not need to worry about anything to do with xml.
	body, err := ioutil.ReadAll(httpResponse.Body)
	httpResponse.Body.Close()
	if err != nil {
		log.Print("Failed to read all: " + err.Error())
		return nil, err
	}
	return body, nil
}

// feedItemExists checks if this item is already recorded in the database.
// it does this by checking if the uri exists for the given feed id.
func feedItemExists(db *sql.DB, feed *gorselib.RssFeed, item *gorselib.Item) (bool, error) {
	query := `
SELECT id
FROM rss_item
WHERE rss_feed_id = $1
	AND link = $2
`
	rows, err := db.Query(query, feed.ID, item.Link)
	if err != nil {
		log.Printf("Failed to check if item title [%s] exists for feed [%s]: %s",
			item.Title, feed.Name, err.Error())
		return false, err
	}

	// if we have a row, then the item exists.
	count := 0
	for rows.Next() {
		count++
	}
	return count > 0, nil
}

// recordFeedItem inserts the feed item information into the database if it
// is not already present.
// we return whether we actually performed an insert and if there was an
// error.
func recordFeedItem(config *GorsePollConfig, db *sql.DB,
	feed *gorselib.RssFeed, item *gorselib.Item) (bool, error) {
	// sanity check the item's information.
	// we require at least a link to be set.
	// description may be blank. we also permit title to be blank.
	if item.Link == "" {
		log.Printf("Item with title [%s] has no link. Skipping",
			item.Title)
		return false, errors.New("Item has blank link")
	}
	// we need to ensure we have a publication date, and that it is in utc.
	// if we do not have it, we default to using the current time.
	pubDateTime := gorselib.GetItemPubDate(item.PubDate)
	// convert the pub date time to a string suitable for passing to
	// postgres.
	var pubDateDb string = pubDateTime.Format(time.RFC3339)

	// if the item is already recorded, then we don't do anything.
	exists, err := feedItemExists(db, feed, item)
	if err != nil {
		log.Printf("Failed to check if feed item title [%s] exists: %s",
			item.Title, err.Error())
		return false, err
	}
	if exists {
		return false, nil
	}

	// we need to record it.
	var query string = `
INSERT INTO rss_item
(title, description, link, publication_date, rss_feed_id)
VALUES($1, $2, $3, $4, $5)
`
	// TODO: we could check if a single row was affected. the variable
	//   I am dropping here is of type Result which tells us such
	//   information.
	_, err = db.Exec(query, item.Title, item.Description,
		item.Link, pubDateDb, feed.ID)
	if err != nil {
		log.Printf("Failed to add item with title [%s]: %s",
			item.Title, err.Error())
		return false, err
	}
	if config.Quiet == 0 {
		log.Printf("Added item with title [%s] to feed [%s]",
			item.Title, feed.Name)
	}
	return true, nil
}

// updateFeed performs a new request to retrieve the feed.
// we record what items we saw.
// at this point we have determined we need to perform an update.
// we return a nil error if no problems occurred.
func updateFeed(config *GorsePollConfig, db *sql.DB,
	feed *gorselib.RssFeed) error {
	// retrieve the feed body.
	xmlData, err := retrieveFeed(feed)
	if err != nil {
		log.Print("Failed to retrieve feed: " + err.Error())
		return err
	}

	// parse the XML response.
	channel, err := gorselib.ParseFeedXML(xmlData)
	if err != nil {
		return fmt.Errorf("Failed to parse XML of feed: %v", err.Error())
	}

	// record information about each item we parsed.
	if config.Quiet == 0 {
		log.Printf("Fetched %d item(s) for feed [%s]", len(channel.Items),
			feed.Name)
	}
	var recorded_count int = 0
	for _, item := range channel.Items {
		recorded, err := recordFeedItem(config, db, feed, &item)
		if err != nil {
			log.Printf("Failed to record feed item title [%s] for feed [%s]: %s",
				item.Title, feed.Name, err.Error())
			return err
		}
		if recorded {
			recorded_count++
		}
	}
	if config.Quiet == 0 {
		log.Printf("Added %d/%d item(s) from feed [%s]",
			recorded_count, len(channel.Items), feed.Name)
	}

	// raise a message if we had to record all items we received. why? because
	// this may indicate that we missed some through not updating frequently
	// enough.
	if recorded_count == len(channel.Items) {
		log.Printf("Warning: recorded all items from feed [%s] (%d/%d)",
			feed.Name, recorded_count, len(channel.Items))
	}
	return nil
}

// recordFeedUpdate sets the last feed update time to right now.
func recordFeedUpdate(db *sql.DB, feed *gorselib.RssFeed) error {
	var query string = `
UPDATE rss_feed
SET last_update_time = NOW()
WHERE id = $1
`
	_, err := db.Exec(query, feed.ID)
	if err != nil {
		log.Printf("Failed to record feed update for feed id [%d] name [%s]: %s",
			feed.ID, feed.Name, err)
		return err
	}
	feed.LastUpdateTime = time.Now()
	return nil
}

// processFeeds processes each feed in turn.
// we look at every feed, and retrieve it anew if it needs to be updated.
// we store the new retrieved information and update the feed's
// details if we retrieved it.
// if there was an error, we return an error, otherwise we return nil.
func processFeeds(config *GorsePollConfig, db *sql.DB,
	feeds []gorselib.RssFeed, forceUpdate bool) error {

	feedsUpdated := 0

	for _, feed := range feeds {
		// Check if we need to update.
		// We may be always forcing an update.
		// If not, we decide based on when we last updated the feed.
		if !forceUpdate {
			var timeSince time.Duration = time.Since(feed.LastUpdateTime)

			if config.Quiet == 0 {
				log.Printf("Feed [%s] was updated [%d] second(s) ago, and stored update frequency is %d second(s).",
					feed.Name, int64(timeSince.Seconds()), feed.UpdateFrequencySeconds)
			}

			if int64(timeSince.Seconds()) < feed.UpdateFrequencySeconds {
				if config.Quiet == 0 {
					log.Print("Skipping update.")
				}
				continue
			}
		}

		// Perform our update.

		if config.Quiet == 0 {
			log.Printf("Updating feed [%s]", feed.Name)
		}

		err := updateFeed(config, db, &feed)
		if err != nil {
			log.Print("Failed to update feed: " + feed.Name + ": " + err.Error())
			continue
		}

		if config.Quiet == 0 {
			log.Printf("Updated feed [%s]", feed.Name)
		}

		// record that we have performed an update of this feed.
		// do this after we have successfully updated the feed so as to
		// ensure we try repeatedly in case of transient errors e.g. if
		// network is down.
		err = recordFeedUpdate(db, &feed)
		if err != nil {
			log.Printf("Failed to record update on feed [%s]: %s", feed.Name,
				err.Error())
			return err
		}

		feedsUpdated++
	}
	if config.Quiet == 0 {
		log.Printf("Updated %d/%d feed(s).", feedsUpdated, len(feeds))
	}
	return nil
}

// main is the entry point to the program
func main() {
	// we may be given a single argument - a feed name to process. this means
	// we process the single feed only and ignore all others.
	singleFeed := flag.String("feed-name", "",
		"Single feed name to process. Process all feeds if not given.")
	configPath := flag.String("config-file", "",
		"Path to a configuration file.")
	forceUpdate := flag.Bool("force-update", false, "Force updates by ignoring the last update time on feeds.")
	flag.Parse()

	if len(*configPath) == 0 {
		log.Print("You must specify a configuration file.")
		flag.PrintDefaults()
		os.Exit(1)
	}

	// load up our settings.
	var settings GorsePollConfig
	err := config.GetConfig(*configPath, &settings)
	if err != nil {
		log.Fatalf("Failed to retrieve config: %s", err.Error())
	}

	// set up the standard logger. we want to set flags to make it give
	// more information.
	log.SetFlags(log.Ltime)

	// connect to the database.
	dsn := fmt.Sprintf("user=%s password=%s dbname=%s host=%s connect_timeout=10",
		settings.DbUser, settings.DbPass, settings.DbName, settings.DbHost)
	db, err := sql.Open("postgres", dsn)
	if err != nil {
		log.Fatal("Failed to connect to the database: " + err.Error())
	}
	defer db.Close()

	// set gorselib settings.
	gorselib.SetQuiet(settings.Quiet != 0)

	// Retrieve our feeds from the database.
	feeds, err := gorselib.RetrieveFeeds(db)
	if err != nil {
		log.Fatal("Failed to retrieve feeds: " + err.Error())
	}

	// we limit ourselves to the one feed. find it and make a new slice with
	// only this feed in it.
	if len(*singleFeed) > 0 {
		feedsSingle := make([]gorselib.RssFeed, 0)
		for _, feed := range feeds {
			if feed.Name == *singleFeed {
				feedsSingle = append(feedsSingle, feed)
				break
			}
		}
		if len(feedsSingle) == 0 {
			log.Fatalf("Feed with name [%s] not found!", *singleFeed)
		}
		if settings.Quiet == 0 {
			log.Printf("Using only feed [%s]", *singleFeed)
		}
		feeds = feedsSingle
	}

	// process & update our feeds.
	err = processFeeds(&settings, db, feeds, *forceUpdate)
	if err != nil {
		log.Fatal("Failed to process feed(s)")
	}
}
<commit_msg>gorsepoll: Style and linter updates<commit_after>//
// RSS feed fetcher.
//
// This program roughly works as follows:
// - Find RSS feeds from a database.
// - For every RSS feed, if it was last fetched less than its update
//   frequency ago, record that a retrieval was done, and retrieve
//   its content.
// - For every item, add information about that item into the database.
//
// This script is intended to be run periodically through something like cron.
//
// We try to ensure that we do not poll the rss feeds too much by recording a
// last update time and update frequency if the feed includes such data.
//
package main

import (
	"crypto/tls"
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	_ "github.com/lib/pq"
	"summercat.com/config"
	"summercat.com/gorse/gorselib"
)

// Config holds runtime configuration info.
type Config struct {
	DBUser string
	DBPass string
	DBName string
	DBHost string
	Quiet  int64
}

// retrieveFeed fetches the raw feed content.
func retrieveFeed(feed *gorselib.RSSFeed) ([]byte, error) {
	// Retrieve the feed via an HTTP call.

	// NOTE: We set up a http.Transport to use TLS settings. Then we set the
	// transport on the http.Client, and then make the request.
	//
	// We have to do it in this round about way rather than simply http.Get()
	// or the like in order to pass through the TLS setting it appears.
	//
	// I don't actually have any TLS settings any more. I used to disable
	// verification before one of my sites had a valid certificate.

	tlsConfig := &tls.Config{}

	httpTransport := &http.Transport{
		TLSClientConfig: tlsConfig,
	}

	httpClient := &http.Client{
		Transport: httpTransport,
		Timeout:   time.Second * 10,
	}

	httpResponse, err := httpClient.Get(feed.URI)

	if err != nil {
		log.Printf("HTTP request for feed failed. (%s): %s", feed.Name, err.Error())

		// It appears we do not need to call Body.Close() here - if we try
		// then we get a runtime error about nil pointer dereference.
		return nil, err
	}
	defer httpResponse.Body.Close()

	// while we will be decoding xml, and the xml package can read directly
	// from an io.reader, I read it all in here for simplicity so that this
	// fetch function does not need to worry about anything to do with xml.
	body, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		log.Print("Failed to read all: " + err.Error())
		return nil, err
	}
	return body, nil
}

// feedItemExists checks if this item is already recorded in the database.
// it does this by checking if the uri exists for the given feed id.
func feedItemExists(db *sql.DB, feed *gorselib.RSSFeed,
	item *gorselib.Item) (bool, error) {
	query := `
SELECT id
FROM rss_item
WHERE rss_feed_id = $1
	AND link = $2
`
	rows, err := db.Query(query, feed.ID, item.Link)
	if err != nil {
		log.Printf("Failed to check if item title [%s] exists for feed [%s]: %s",
			item.Title, feed.Name, err.Error())
		return false, err
	}

	// if we have a row, then the item exists.
	count := 0
	for rows.Next() {
		count++
	}
	return count > 0, nil
}

// recordFeedItem inserts the feed item information into the database if it
// is not already present.
// we return whether we actually performed an insert and if there was an
// error.
func recordFeedItem(config *Config, db *sql.DB, feed *gorselib.RSSFeed,
	item *gorselib.Item) (bool, error) {
	// sanity check the item's information.
	// we require at least a link to be set.
	// description may be blank. we also permit title to be blank.
	if item.Link == "" {
		log.Printf("Item with title [%s] has no link. Skipping",
			item.Title)
		return false, errors.New("Item has blank link")
	}
	// we need to ensure we have a publication date, and that it is in utc.
	// if we do not have it, we default to using the current time.
	pubDateTime := gorselib.GetItemPubDate(item.PubDate)
	// convert the pub date time to a string suitable for passing to
	// postgres.
	var pubDateDb string = pubDateTime.Format(time.RFC3339)

	// if the item is already recorded, then we don't do anything.
	exists, err := feedItemExists(db, feed, item)
	if err != nil {
		log.Printf("Failed to check if feed item title [%s] exists: %s",
			item.Title, err.Error())
		return false, err
	}
	if exists {
		return false, nil
	}

	// we need to record it.
	query := `
INSERT INTO rss_item
(title, description, link, publication_date, rss_feed_id)
VALUES($1, $2, $3, $4, $5)
`
	// TODO: we could check if a single row was affected. the variable
	//   I am dropping here is of type Result which tells us such
	//   information.
	_, err = db.Exec(query, item.Title, item.Description,
		item.Link, pubDateDb, feed.ID)
	if err != nil {
		log.Printf("Failed to add item with title [%s]: %s",
			item.Title, err.Error())
		return false, err
	}
	if config.Quiet == 0 {
		log.Printf("Added item with title [%s] to feed [%s]",
			item.Title, feed.Name)
	}
	return true, nil
}

// updateFeed performs a new request to retrieve the feed.
// we record what items we saw.
// at this point we have determined we need to perform an update.
// we return a nil error if no problems occurred.
func updateFeed(config *Config, db *sql.DB, feed *gorselib.RSSFeed) error {
	// retrieve the feed body.
	xmlData, err := retrieveFeed(feed)
	if err != nil {
		log.Print("Failed to retrieve feed: " + err.Error())
		return err
	}

	// parse the XML response.
	channel, err := gorselib.ParseFeedXML(xmlData)
	if err != nil {
		return fmt.Errorf("Failed to parse XML of feed: %v", err.Error())
	}

	// record information about each item we parsed.
	if config.Quiet == 0 {
		log.Printf("Fetched %d item(s) for feed [%s]", len(channel.Items),
			feed.Name)
	}
	recordedCount := 0
	for _, item := range channel.Items {
		recorded, err := recordFeedItem(config, db, feed, &item)
		if err != nil {
			log.Printf("Failed to record feed item title [%s] for feed [%s]: %s",
				item.Title, feed.Name, err.Error())
			return err
		}
		if recorded {
			recordedCount++
		}
	}
	if config.Quiet == 0 {
		log.Printf("Added %d/%d item(s) from feed [%s]",
			recordedCount, len(channel.Items), feed.Name)
	}

	// raise a message if we had to record all items we received. why? because
	// this may indicate that we missed some through not updating frequently
	// enough.
	if recordedCount == len(channel.Items) {
		log.Printf("Warning: recorded all items from feed [%s] (%d/%d)",
			feed.Name, recordedCount, len(channel.Items))
	}
	return nil
}

// recordFeedUpdate sets the last feed update time to right now.
func recordFeedUpdate(db *sql.DB, feed *gorselib.RSSFeed) error {
	query := `
UPDATE rss_feed
SET last_update_time = NOW()
WHERE id = $1
`
	_, err := db.Exec(query, feed.ID)
	if err != nil {
		log.Printf("Failed to record feed update for feed id [%d] name [%s]: %s",
			feed.ID, feed.Name, err)
		return err
	}
	feed.LastUpdateTime = time.Now()
	return nil
}

// processFeeds processes each feed in turn.
// we look at every feed, and retrieve it anew if it needs to be updated.
// we store the new retrieved information and update the feed's
// details if we retrieved it.
// if there was an error, we return an error, otherwise we return nil.
func processFeeds(config *Config, db *sql.DB, feeds []gorselib.RSSFeed,
	forceUpdate bool) error {

	feedsUpdated := 0

	for _, feed := range feeds {
		// Check if we need to update.
		// We may be always forcing an update.
		// If not, we decide based on when we last updated the feed.
		if !forceUpdate {
			timeSince := time.Since(feed.LastUpdateTime)

			if config.Quiet == 0 {
				log.Printf("Feed [%s] was updated [%d] second(s) ago, and stored update frequency is %d second(s).",
					feed.Name, int64(timeSince.Seconds()), feed.UpdateFrequencySeconds)
			}

			if int64(timeSince.Seconds()) < feed.UpdateFrequencySeconds {
				if config.Quiet == 0 {
					log.Print("Skipping update.")
				}
				continue
			}
		}

		// Perform our update.

		if config.Quiet == 0 {
			log.Printf("Updating feed [%s]", feed.Name)
		}

		err := updateFeed(config, db, &feed)
		if err != nil {
			log.Print("Failed to update feed: " + feed.Name + ": " + err.Error())
			continue
		}

		if config.Quiet == 0 {
			log.Printf("Updated feed [%s]", feed.Name)
		}

		// record that we have performed an update of this feed.
		// do this after we have successfully updated the feed so as to
		// ensure we try repeatedly in case of transient errors e.g. if
		// network is down.
		err = recordFeedUpdate(db, &feed)
		if err != nil {
			log.Printf("Failed to record update on feed [%s]: %s", feed.Name,
				err.Error())
			return err
		}

		feedsUpdated++
	}
	if config.Quiet == 0 {
		log.Printf("Updated %d/%d feed(s).", feedsUpdated, len(feeds))
	}
	return nil
}

// main is the entry point to the program
func main() {
	// we may be given a single argument - a feed name to process. this means
	// we process the single feed only and ignore all others.
	singleFeed := flag.String("feed-name", "",
		"Single feed name to process. Process all feeds if not given.")
	configPath := flag.String("config-file", "",
		"Path to a configuration file.")
	forceUpdate := flag.Bool("force-update", false, "Force updates by ignoring the last update time on feeds.")
	flag.Parse()

	if len(*configPath) == 0 {
		log.Print("You must specify a configuration file.")
		flag.PrintDefaults()
		os.Exit(1)
	}

	// load up our settings.
	var settings Config
	err := config.GetConfig(*configPath, &settings)
	if err != nil {
		log.Fatalf("Failed to retrieve config: %s", err.Error())
	}

	// set up the standard logger. we want to set flags to make it give
	// more information.
	log.SetFlags(log.Ltime)

	// connect to the database.
	dsn := fmt.Sprintf("user=%s password=%s dbname=%s host=%s connect_timeout=10",
		settings.DBUser, settings.DBPass, settings.DBName, settings.DBHost)
	db, err := sql.Open("postgres", dsn)
	if err != nil {
		log.Fatalf("Failed to connect to the database: %s", err)
	}
	defer db.Close()

	// set gorselib settings.
	gorselib.SetQuiet(settings.Quiet != 0)

	// Retrieve our feeds from the database.
	feeds, err := gorselib.RetrieveFeeds(db)
	if err != nil {
		log.Fatalf("Failed to retrieve feeds: %s", err)
	}

	// we limit ourselves to the one feed. find it and make a new slice with
	// only this feed in it.
	if len(*singleFeed) > 0 {
		feedsSingle := make([]gorselib.RSSFeed, 0)
		for _, feed := range feeds {
			if feed.Name == *singleFeed {
				feedsSingle = append(feedsSingle, feed)
				break
			}
		}
		if len(feedsSingle) == 0 {
			log.Fatalf("Feed with name [%s] not found!", *singleFeed)
		}
		if settings.Quiet == 0 {
			log.Printf("Using only feed [%s]", *singleFeed)
		}
		feeds = feedsSingle
	}

	// process & update our feeds.
	err = processFeeds(&settings, db, feeds, *forceUpdate)
	if err != nil {
		log.Fatal("Failed to process feed(s)")
	}
}
<|endoftext|>


<commit_before>package orm

import (
	"reflect"
)

type record struct {
	client *Client
	table  *table
}

func (r *record) initialized() bool {
	if r.client == nil {
		return false
	} else if r.table == nil {
		return false
	}

	return true
}

type Model interface {
	Save() error
}

type Record struct {
	record  *record
	parentV reflect.Value
}

func (r *Record) initialized() bool {
	if r.record == nil || !r.record.initialized() {
		return false
	}

	return true
}

func (r *Record) Save() (err error) {
	if r.record == nil {
		/*
			r.record = &record{
				client: client,
			}
		*/
	} else {
		if r.record.client == nil {
			err = ErrUnsuitableRecord
			return
		}
	}

	return
}
<commit_msg>remove Save method from Model and Record<commit_after>package orm

import (
	"reflect"
)

type record struct {
	client *Client
	table  *table
}

func (r *record) initialized() bool {
	if r.client == nil {
		return false
	} else if r.table == nil {
		return false
	}

	return true
}

type Model interface {
}

type Record struct {
	record  *record
	parentV reflect.Value
}

func (r *Record) initialized() bool {
	if r.record == nil || !r.record.initialized() {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package core

//go:generate go get -u github.com/golang/mock/gomock
//go:generate go install github.com/golang/mock/mockgen

//go:generate mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
//go:generate mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler v2ray.com/core/common/log Handler
//go:generate mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory
//go:generate mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client
//go:generate mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector
//go:generate mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound v2ray.com/core/proxy Inbound,Outbound
<commit_msg>Mock: refine go generate command<commit_after>package core

//go:generate go install github.com/golang/mock/gomock
//go:generate go install github.com/golang/mock/mockgen

//go:generate mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
//go:generate mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler v2ray.com/core/common/log Handler
//go:generate mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory v2ray.com/core/common/mux ClientWorkerFactory
//go:generate mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient v2ray.com/core/features/dns Client
//go:generate mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector v2ray.com/core/features/outbound Manager,HandlerSelector
//go:generate mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound v2ray.com/core/proxy Inbound,Outbound
<|endoftext|>


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

package gitea

import (
	"fmt"
)

// User represents a API user.
type User struct {
	ID        int64  `json:"id"`
	UserName  string `json:"login"`
	FullName  string `json:"full_name"`
	Email     string `json:"email"`
	AvatarURL string `json:"avatar_url"`
}

// GetUserInfo get user info by user's name
func (c *Client) GetUserInfo(user string) (*User, error) {
	u := new(User)
	err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u)
	return u, err
}
<commit_msg>Backward compatibility (username vs. login)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gitea

import (
	"encoding/json"
	"fmt"
)

// User represents a API user.
type User struct {
	ID        int64  `json:"id"`
	UserName  string `json:"login"`
	FullName  string `json:"full_name"`
	Email     string `json:"email"`
	AvatarURL string `json:"avatar_url"`
}

// MarshalJSON implements the json.Marshaler interface for User, adding field(s) for backward compatibility
func (u User) MarshalJSON() ([]byte, error) {
	// Re-declaring User to avoid recursion
	type shadow User
	return json.Marshal(struct {
		shadow
		CompatUserName string `json:"username"`
	}{shadow(u), u.UserName})
}

// GetUserInfo get user info by user's name
func (c *Client) GetUserInfo(user string) (*User, error) {
	u := new(User)
	err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u)
	return u, err
}
<|endoftext|>


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

package isolated

import (
	"bytes"
	"compress/zlib"
	"errors"
	"fmt"
	"io/ioutil"
)

// Pack returns a deflate'd buffer of delta encoded varints.
func Pack(values []int64) ([]byte, error) {
	if len(values) == 0 {
		return nil, nil
	}
	if values[0] < 0 {
		return nil, errors.New("values must be between 0 and 2**63")
	}
	if values[len(values)-1] < 0 {
		return nil, errors.New("values must be between 0 and 2**63")
	}

	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	var last int64
	for _, value := range values {
		v := value
		value -= last
		if value < 0 {
			return nil, errors.New("list must be sorted ascending")
		}
		last = v
		for value > 127 {
			if _, err := w.Write([]byte{byte(1<<7 | value&0x7f)}); err != nil {
				return nil, fmt.Errorf("failed to write: %v", err)
			}
			value >>= 7
		}
		if _, err := w.Write([]byte{byte(value)}); err != nil {
			return nil, fmt.Errorf("failed to write: %v", err)
		}

	}
	if err := w.Close(); err != nil {
		return nil, fmt.Errorf("failed to close zlib writer: %v", err)
	}

	return b.Bytes(), nil
}

// Unpack decompresses a deflate'd delta encoded list of varints.
func Unpack(data []byte) ([]int64, error) {
	if len(data) == 0 {
		return nil, nil
	}

	var ret []int64
	var value int64
	var base int64 = 1
	var last int64

	r, err := zlib.NewReader(bytes.NewReader(data))
	if err != nil {
		return nil, fmt.Errorf("failed to get zlib reader: %v", err)
	}
	defer r.Close()

	data, err = ioutil.ReadAll(r)
	if err != nil {
		return nil, fmt.Errorf("failed to read all: %v", err)
	}

	for _, valByte := range data {
		value += int64(valByte&0x7f) * base
		if valByte&0x80 > 0 {
			base <<= 7
			continue
		}
		ret = append(ret, value+last)
		last += value
		value = 0
		base = 1
	}

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

package isolated

import (
	"bytes"
	"compress/zlib"
	"io/ioutil"

	"go.chromium.org/luci/common/errors"
)

// Pack returns a deflate'd buffer of delta encoded varints.
func Pack(values []int64) ([]byte, error) {
	if len(values) == 0 {
		return nil, nil
	}
	if values[0] < 0 {
		return nil, errors.Reason("values must be between 0 and 2**63").Err()
	}
	if values[len(values)-1] < 0 {
		return nil, errors.Reason("values must be between 0 and 2**63").Err()
	}

	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	var last int64
	for _, value := range values {
		v := value
		value -= last
		if value < 0 {
			return nil, errors.Reason("list must be sorted ascending").Err()
		}
		last = v
		for value > 127 {
			if _, err := w.Write([]byte{byte(1<<7 | value&0x7f)}); err != nil {
				return nil, errors.Annotate(err, "failed to write").Err()
			}
			value >>= 7
		}
		if _, err := w.Write([]byte{byte(value)}); err != nil {
			return nil, errors.Annotate(err, "failed to write").Err()
		}

	}
	if err := w.Close(); err != nil {
		return nil, errors.Annotate(err, "failed to close zlib writer").Err()
	}

	return b.Bytes(), nil
}

// Unpack decompresses a deflate'd delta encoded list of varints.
func Unpack(data []byte) ([]int64, error) {
	if len(data) == 0 {
		return nil, nil
	}

	var ret []int64
	var value int64
	var base int64 = 1
	var last int64

	r, err := zlib.NewReader(bytes.NewReader(data))
	if err != nil {
		return nil, errors.Annotate(err, "failed to get zlib reader").Err()
	}
	defer r.Close()

	data, err = ioutil.ReadAll(r)
	if err != nil {
		return nil, errors.Annotate(err, "failed to read all").Err()
	}

	for _, valByte := range data {
		value += int64(valByte&0x7f) * base
		if valByte&0x80 > 0 {
			base <<= 7
			continue
		}
		ret = append(ret, value+last)
		last += value
		value = 0
		base = 1
	}

	return ret, nil
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"regexp"
	"time"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common/errors"
)

// Constants directly related to interacting with the package model in the
// cassandra database.
const (
	// TableNamePackages is the name of the table containing the package model.
	TableNamePackages = "packages"
	// IndexNamePackages is the name of the lucene index
	IndexNamePackages             = "packages_index"
	ColumnNamePackagesRepo        = "repo"
	ColumnNamePackagesStars       = "stars"
	ColumnNamePackagesExists      = "exists"
	ColumnNamePackagesAuthor      = "author"
	ColumnNamePackagesVersions    = "versions"
	ColumnNamePackagesGodocURL    = "godoc_url"
	ColumnNamePackagesIndexTime   = "index_time"
	ColumnNamePackagesAwesomeGo   = "awesome_go"
	ColumnNamePackagesSearchBlob  = "search_blob"
	ColumnNamePackagesDescription = "description"
)

const (
	packagesSearchBlobTemplate = "%s %s %s"
)

var (
	cqlQueryFuzzySearchPackagesTemplate = fmt.Sprintf(
		`SELECT %s,%s,%s FROM %s WHERE expr(%s,'{query:{type:"fuzzy",field:"%s",value:"%s"}}') LIMIT 10`,
		ColumnNamePackagesRepo,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesDescription,
		TableNamePackages,
		IndexNamePackages,
		ColumnNamePackagesSearchBlob,
		"%s",
	)

	cqlQuerySelectPackageVersions = fmt.Sprintf(
		`SELECT %s FROM %s WHERE %s = ? AND %s = ? LIMIT 1`,
		ColumnNamePackagesVersions,
		TableNamePackages,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesRepo,
	)

	cqlQueryInsertPackage = fmt.Sprintf(
		`INSERT INTO %s (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) VALUES (?,?,?,?,?,?,?,?,?,?)`,
		TableNamePackages,
		ColumnNamePackagesRepo,
		ColumnNamePackagesStars,
		ColumnNamePackagesExists,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesVersions,
		ColumnNamePackagesGodocURL,
		ColumnNamePackagesIndexTime,
		ColumnNamePackagesAwesomeGo,
		ColumnNamePackagesSearchBlob,
		ColumnNamePackagesDescription,
	)
)

var (
	alphanumericFilterRegex = regexp.MustCompile(`[^\sa-zA-Z0-9\-_]+`)
)

// PackageModel is a struct representing one individual package in the database.
type PackageModel struct {
	Repo        *string
	Stars       *int
	Exists      *bool
	Author      *string
	Versions    []string
	GodocURL    *string
	IndexTime   *time.Time
	AwesomeGo   *bool
	SearchBlob  *string
	Description *string
}

// NewPackageModelForInsert creates an instance of PackageModel that is
// optimized and validated for the insert operation in the database.
func NewPackageModelForInsert(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	indexTime time.Time,
	awesomeGo bool,
	description string,
	stars int,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	searchBlob := fmt.Sprintf(
		packagesSearchBlobTemplate,
		author,
		repo,
		description,
	)

	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		IndexTime:   &indexTime,
		AwesomeGo:   &awesomeGo,
		SearchBlob:  &searchBlob,
		Description: &description,
	}, nil
}

// NewPackageModelFromBulkSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// multiple packages from the database.
func NewPackageModelFromBulkSelect(
	author string,
	repo string,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}

	return &PackageModel{
		Repo:        &repo,
		Author:      &author,
		Description: &description,
	}, nil
}

func NewPackageModelTest(
	author string,
	repo string,
	awesome_go bool,
	description string,
	exists bool,
	godoc_url string,
	index_time time.Time,
	search_blob string,
	versions []string,
	stars int,
) *PackageModel {
	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godoc_url,
		IndexTime:   &index_time,
		AwesomeGo:   &awesome_go,
		SearchBlob:  &search_blob,
		Description: &description,
	}
}

// NewPackageModelFromSingleSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// a single package from the database.
func NewPackageModelFromSingleSelect(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	awesomeGo bool,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	return &PackageModel{
		Repo:        &repo,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		AwesomeGo:   &awesomeGo,
		Description: &description,
	}, nil
}

// FindPackageVersions gets the versions of a package from the database. If
// no such package exists, or there were no versions for said package, then nil
// is returned.
func FindPackageVersions(session *gocql.Session, author string, repo string) ([]string, error) {
	var (
		err      error
		versions []string
	)

	iter := session.Query(cqlQuerySelectPackageVersions, author, repo).Iter()

	if !iter.Scan(&versions) {
		return nil, nil
	}

	if err = iter.Close(); err != nil {
		return nil, errors.NewQueryScanError(nil, err)
	}

	return versions, nil
}

// FuzzySearchPackages finds a list of packages relevant to a query phrase
// string. The search takes author, package and description into account.
func FuzzySearchPackages(
	session *gocql.Session,
	searchText string,
) ([]*PackageModel, error) {
	// First, remove all non-essential characters
	searchText = alphanumericFilterRegex.ReplaceAllString(searchText, "")
	// Next put the search text into a query string
	query := fmt.Sprintf(cqlQueryFuzzySearchPackagesTemplate, searchText)
	// Return the processed results of the query
	return scanPackageModels(session.Query(query))
}

// InsertPackage inserts an individual package into the database.
func InsertPackage(
	session *gocql.Session,
	packageModel *PackageModel,
) error {
	err := session.Query(cqlQueryInsertPackage,
		*packageModel.Repo,
		*packageModel.Stars,
		*packageModel.Exists,
		*packageModel.Author,
		packageModel.Versions,
		*packageModel.GodocURL,
		*packageModel.IndexTime,
		*packageModel.AwesomeGo,
		*packageModel.SearchBlob,
		*packageModel.Description,
	).Exec()

	return err
}

// InsertPackages inserts a slice of package models into the database.
func InsertPackages(
	session *gocql.Session,
	packageModels []*PackageModel,
) error {
	batch := gocql.NewBatch(gocql.LoggedBatch)

	if packageModels == nil || len(packageModels) == 0 {
		return errors.NewInvalidParameterError("packageModels", packageModels)
	}

	for _, packageModel := range packageModels {
		if packageModel != nil &&
			packageModel.Repo != nil &&
			packageModel.Exists != nil &&
			packageModel.Author != nil &&
			packageModel.GodocURL != nil &&
			packageModel.IndexTime != nil &&
			packageModel.AwesomeGo != nil &&
			packageModel.SearchBlob != nil &&
			packageModel.Description != nil {
			batch.Query(
				cqlQueryInsertPackage,
				*packageModel.Repo,
				*packageModel.Exists,
				*packageModel.Author,
				packageModel.Versions,
				*packageModel.GodocURL,
				*packageModel.IndexTime,
				*packageModel.AwesomeGo,
				*packageModel.SearchBlob,
				*packageModel.Description,
			)
		} else {
			return errors.NewInvalidParameterError(
				"packageModels",
				fmt.Sprintf("[ ..., %v, ... ]", packageModel),
			)
		}
	}

	err := session.ExecuteBatch(batch)
	if err != nil {
		return err
	}

	return nil
}

/********************************** HELPERS ***********************************/

// TODO(skeswa): implement this for querying single packages
func scanPackageModel(query *gocql.Query) ([]*PackageModel, error) {
	return nil, nil
}

func scanPackageModels(query *gocql.Query) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		repo        string
		author      string
		description string

		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&repo, &author, &description) {
		packageModel, err = NewPackageModelFromBulkSelect(author, repo, description)
		if err != nil {
			scanError = err
			break
		} else {
			packageModels = append(packageModels, packageModel)
		}
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}

func ScanAllPackageModels(session *gocql.Session) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		author      string
		repo        string
		awesome_go  bool
		description string
		exists      bool
		godoc_url   string
		index_time  time.Time
		search_blob string
		versions    []string
		stars       int

		query = session.Query(`SELECT
			author,
			repo,
			awesome_go,
			description,
			exists,
			godoc_url,
			index_time,
			search_blob,
			versions,
			stars
			FROM packages`)
		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&author, &repo, &awesome_go, &description, &exists, &godoc_url, &index_time, &search_blob, &versions, &stars) {
		packageModel = NewPackageModelTest(author, repo, awesome_go, description, exists, godoc_url, index_time, search_blob, versions, stars)
		packageModels = append(packageModels, packageModel)
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}
<commit_msg>fix error ref<commit_after>package models

import (
	"fmt"
	"regexp"
	"time"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common/errors"
)

// Constants directly related to interacting with the package model in the
// cassandra database.
const (
	// TableNamePackages is the name of the table containing the package model.
	TableNamePackages = "packages"
	// IndexNamePackages is the name of the lucene index
	IndexNamePackages             = "packages_index"
	ColumnNamePackagesRepo        = "repo"
	ColumnNamePackagesStars       = "stars"
	ColumnNamePackagesExists      = "exists"
	ColumnNamePackagesAuthor      = "author"
	ColumnNamePackagesVersions    = "versions"
	ColumnNamePackagesGodocURL    = "godoc_url"
	ColumnNamePackagesIndexTime   = "index_time"
	ColumnNamePackagesAwesomeGo   = "awesome_go"
	ColumnNamePackagesSearchBlob  = "search_blob"
	ColumnNamePackagesDescription = "description"
)

const (
	packagesSearchBlobTemplate = "%s %s %s"
)

var (
	cqlQueryFuzzySearchPackagesTemplate = fmt.Sprintf(
		`SELECT %s,%s,%s FROM %s WHERE expr(%s,'{query:{type:"fuzzy",field:"%s",value:"%s"}}') LIMIT 10`,
		ColumnNamePackagesRepo,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesDescription,
		TableNamePackages,
		IndexNamePackages,
		ColumnNamePackagesSearchBlob,
		"%s",
	)

	cqlQuerySelectPackageVersions = fmt.Sprintf(
		`SELECT %s FROM %s WHERE %s = ? AND %s = ? LIMIT 1`,
		ColumnNamePackagesVersions,
		TableNamePackages,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesRepo,
	)

	cqlQueryInsertPackage = fmt.Sprintf(
		`INSERT INTO %s (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) VALUES (?,?,?,?,?,?,?,?,?,?)`,
		TableNamePackages,
		ColumnNamePackagesRepo,
		ColumnNamePackagesStars,
		ColumnNamePackagesExists,
		ColumnNamePackagesAuthor,
		ColumnNamePackagesVersions,
		ColumnNamePackagesGodocURL,
		ColumnNamePackagesIndexTime,
		ColumnNamePackagesAwesomeGo,
		ColumnNamePackagesSearchBlob,
		ColumnNamePackagesDescription,
	)
)

var (
	alphanumericFilterRegex = regexp.MustCompile(`[^\sa-zA-Z0-9\-_]+`)
)

// PackageModel is a struct representing one individual package in the database.
type PackageModel struct {
	Repo        *string
	Stars       *int
	Exists      *bool
	Author      *string
	Versions    []string
	GodocURL    *string
	IndexTime   *time.Time
	AwesomeGo   *bool
	SearchBlob  *string
	Description *string
}

// NewPackageModelForInsert creates an instance of PackageModel that is
// optimized and validated for the insert operation in the database.
func NewPackageModelForInsert(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	indexTime time.Time,
	awesomeGo bool,
	description string,
	stars int,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	searchBlob := fmt.Sprintf(
		packagesSearchBlobTemplate,
		author,
		repo,
		description,
	)

	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		IndexTime:   &indexTime,
		AwesomeGo:   &awesomeGo,
		SearchBlob:  &searchBlob,
		Description: &description,
	}, nil
}

// NewPackageModelFromBulkSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// multiple packages from the database.
func NewPackageModelFromBulkSelect(
	author string,
	repo string,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}

	return &PackageModel{
		Repo:        &repo,
		Author:      &author,
		Description: &description,
	}, nil
}

func NewPackageModelTest(
	author string,
	repo string,
	awesome_go bool,
	description string,
	exists bool,
	godoc_url string,
	index_time time.Time,
	search_blob string,
	versions []string,
	stars int,
) *PackageModel {
	return &PackageModel{
		Repo:        &repo,
		Stars:       &stars,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godoc_url,
		IndexTime:   &index_time,
		AwesomeGo:   &awesome_go,
		SearchBlob:  &search_blob,
		Description: &description,
	}
}

// NewPackageModelFromSingleSelect creates an instance of PackageModel that is
// optimized and validated for a select operation designed to get data about
// a single package from the database.
func NewPackageModelFromSingleSelect(
	author string,
	exists bool,
	repo string,
	versions []string,
	godocURL string,
	awesomeGo bool,
	description string,
) (*PackageModel, error) {
	if len(repo) < 1 {
		return nil, errors.NewInvalidParameterError("repo", repo)
	}
	if len(author) < 1 {
		return nil, errors.NewInvalidParameterError("author", author)
	}
	if len(godocURL) < 1 {
		return nil, errors.NewInvalidParameterError("godocURL", godocURL)
	}

	return &PackageModel{
		Repo:        &repo,
		Exists:      &exists,
		Author:      &author,
		Versions:    versions,
		GodocURL:    &godocURL,
		AwesomeGo:   &awesomeGo,
		Description: &description,
	}, nil
}

// FindPackageVersions gets the versions of a package from the database. If
// no such package exists, or there were no versions for said package, then nil
// is returned.
func FindPackageVersions(session *gocql.Session, author string, repo string) ([]string, error) {
	var (
		err      error
		versions []string
	)

	iter := session.Query(cqlQuerySelectPackageVersions, author, repo).Iter()

	if !iter.Scan(&versions) {
		return nil, nil
	}

	if err = iter.Close(); err != nil {
		return nil, errors.NewQueryScanError(nil, err)
	}

	return versions, nil
}

// FuzzySearchPackages finds a list of packages relevant to a query phrase
// string. The search takes author, package and description into account.
func FuzzySearchPackages(
	session *gocql.Session,
	searchText string,
) ([]*PackageModel, error) {
	// First, remove all non-essential characters
	searchText = alphanumericFilterRegex.ReplaceAllString(searchText, "")
	// Next put the search text into a query string
	query := fmt.Sprintf(cqlQueryFuzzySearchPackagesTemplate, searchText)
	// Return the processed results of the query
	return scanPackageModels(session.Query(query))
}

// InsertPackage inserts an individual package into the database.
func InsertPackage(
	session *gocql.Session,
	packageModel *PackageModel,
) error {
	err := session.Query(cqlQueryInsertPackage,
		*packageModel.Repo,
		*packageModel.Stars,
		*packageModel.Exists,
		*packageModel.Author,
		packageModel.Versions,
		*packageModel.GodocURL,
		*packageModel.IndexTime,
		*packageModel.AwesomeGo,
		*packageModel.SearchBlob,
		*packageModel.Description,
	).Exec()

	return err
}

// InsertPackages inserts a slice of package models into the database.
func InsertPackages(
	session *gocql.Session,
	packageModels []*PackageModel,
) error {
	batch := gocql.NewBatch(gocql.LoggedBatch)

	if packageModels == nil || len(packageModels) == 0 {
		return errors.NewInvalidParameterError("packageModels", packageModels)
	}

	for _, packageModel := range packageModels {
		if packageModel != nil &&
			packageModel.Repo != nil &&
			packageModel.Exists != nil &&
			packageModel.Author != nil &&
			packageModel.GodocURL != nil &&
			packageModel.IndexTime != nil &&
			packageModel.AwesomeGo != nil &&
			packageModel.SearchBlob != nil &&
			packageModel.Description != nil {
			batch.Query(
				cqlQueryInsertPackage,
				*packageModel.Repo,
				*packageModel.Exists,
				*packageModel.Author,
				packageModel.Versions,
				*packageModel.GodocURL,
				*packageModel.IndexTime,
				*packageModel.AwesomeGo,
				*packageModel.SearchBlob,
				*packageModel.Description,
			)
		} else {
			return errors.NewInvalidParameterError(
				"packageModels",
				fmt.Sprintf("[ ..., %v, ... ]", packageModel),
			)
		}
	}

	err := session.ExecuteBatch(batch)
	if err != nil {
		return err
	}

	return nil
}

/********************************** HELPERS ***********************************/

// TODO(skeswa): implement this for querying single packages
func scanPackageModel(query *gocql.Query) ([]*PackageModel, error) {
	return nil, nil
}

func scanPackageModels(query *gocql.Query) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		repo        string
		author      string
		description string

		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&repo, &author, &description) {
		packageModel, err = NewPackageModelFromBulkSelect(author, repo, description)
		if err != nil {
			scanError = err
			break
		} else {
			packageModels = append(packageModels, packageModel)
		}
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}

func ScanAllPackageModels(session *gocql.Session) ([]*PackageModel, error) {
	var (
		err          error
		scanError    error
		closeError   error
		packageModel *PackageModel

		author      string
		repo        string
		awesome_go  bool
		description string
		exists      bool
		godoc_url   string
		index_time  time.Time
		search_blob string
		versions    []string
		stars       int

		query = session.Query(`SELECT
			author,
			repo,
			awesome_go,
			description,
			exists,
			godoc_url,
			index_time,
			search_blob,
			versions,
			stars
			FROM packages`)
		iter          = query.Iter()
		packageModels = make([]*PackageModel, 0)
	)

	for iter.Scan(&author, &repo, &awesome_go, &description, &exists, &godoc_url, &index_time, &search_blob, &versions, &stars) {
		packageModel = NewPackageModelTest(author, repo, awesome_go, description, exists, godoc_url, index_time, search_blob, versions, stars)
		packageModels = append(packageModels, packageModel)
	}

	if err = iter.Close(); err != nil {
		closeError = err
	}

	if scanError != nil || closeError != nil {
		return nil, errors.NewQueryScanError(scanError, closeError)
	}

	return packageModels, nil
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "strings"
    "errors"

    "code.google.com/p/go.net/websocket"
)

const listenAddr = "localhost:4000"

type Socket struct {
    ws     *websocket.Conn
    UID    string
    Page   string
    buff   chan *Message
    done   chan bool
    Server *Server
}

func newSocket(ws *websocket.Conn, server *Server) *Socket {
    return &Socket{ws, "", "", make(chan *Message, 1000), make(chan bool), server}
}

func (this *Socket) Close() error {
    this.Server.Store.Remove(this.UID)
    this.done <- true

    return nil
}

func Authenticate(sock *Socket) error {
    var message Message
    err := websocket.JSON.Receive(sock.ws, &message)

    log.Println(message.Event)
    if err != nil {
        return err
    }

    if strings.ToLower(message.Event) != "authenticate" {
        return errors.New("Error: Authenticate Expected.\n")
    }

    UID, ok := message.Body["UID"].(string)
    if !ok {
        return errors.New("Error on Authenticate: Bad Input.\n")
    }

    log.Printf("saving UID as %s", UID)
    sock.UID = UID
    sock.Server.Store.Save(UID, sock)

    log.Printf("saving UID as %s", sock.UID)

    return nil
}

func listenForMessages(sock *Socket) {

    for {

        select {
            case <- sock.done:
                sock.Close()
                return

            default:
                var message *Message
                err := websocket.JSON.Receive(sock.ws, message)
                log.Println("Waiting...\n")
                if err != nil {
                    log.Printf("Error: %s\n", err.Error())

                    sock.Close()
                    return
                }
                log.Println(message)

                go message.FromSocket(sock)
        }

    }
}

func listenForWrites(sock *Socket) {
    for {
        select {
            case message := <-sock.buff:
                log.Println("Send:", message)
                if err := websocket.JSON.Send(sock.ws, message); err != nil {
                    sock.Close()
                }

            case <-sock.done:
                sock.Close()
                return
        }
    }
}<commit_msg>added extra check to make sure certain functions were only being called once<commit_after>package main

import (
    "log"
    "strings"
    "errors"

    "code.google.com/p/go.net/websocket"
)

const listenAddr = "localhost:4000"
var i = 0
type Socket struct {
    ws     *websocket.Conn
    UID    string
    Page   string
    buff   chan *Message
    done   chan bool
    Server *Server
}

func newSocket(ws *websocket.Conn, server *Server) *Socket {
    return &Socket{ws, "", "", make(chan *Message, 1000), make(chan bool), server}
}

func (this *Socket) Close() error {
    i++
    log.Printf("CLOSING SOCK %s -- %v", this.Page, i)
    if this.Page != "" {
        this.Server.Store.UnsetPage(this.UID, this.Page)
        this.Page = ""
    }

    this.Server.Store.Remove(this.UID)
    this.done <- true

    return nil
}

func Authenticate(sock *Socket) error {
    var message Message
    err := websocket.JSON.Receive(sock.ws, &message)

    log.Println(message.Event)
    if err != nil {
        return err
    }

    if strings.ToLower(message.Event) != "authenticate" {
        return errors.New("Error: Authenticate Expected.\n")
    }

    UID, ok := message.Body["UID"].(string)
    if !ok {
        return errors.New("Error on Authenticate: Bad Input.\n")
    }

    log.Printf("saving UID as %s", UID)
    sock.UID = UID
    sock.Server.Store.Save(UID, sock)

    log.Printf("saving UID as %s", sock.UID)

    return nil
}

func listenForMessages(sock *Socket) {

    for {

        select {
            case <- sock.done:
                sock.Close()
                return

            default:
                var message Message
                err := websocket.JSON.Receive(sock.ws, &message)
                log.Println("Waiting...\n")
                if err != nil {
                    log.Printf("Error: %s\n", err.Error())

                    sock.Close()
                    return
                }
                log.Println(message)

                go message.FromSocket(sock)
        }

    }
}

func listenForWrites(sock *Socket) {
    for {
        select {
            case message := <-sock.buff:
                log.Println("Send:", message)
                if err := websocket.JSON.Send(sock.ws, message); err != nil {
                    sock.Close()
                }

            case <-sock.done:
                sock.Close()
                return
        }
    }
}<|endoftext|>