<commit_before>package ambrosio

import (
	"fmt"
	"net/http"
    "regexp"
    "github.com/codegangsta/negroni"
    "github.com/gorilla/mux"
)

type Listener interface {
	Listen(port int)
    NewAction()
}

type Ambrosio struct {
	name    string
    router  *mux.Router
	negroni *negroni.Negroni
    Behaviours []Behaviour
}

type Behaviour struct {
    Pattern string
    Handler func([]string) (string, bool)
}

type Handler func(http.ResponseWriter, *http.Request)

func NewAmbrosio(name string) *Ambrosio {
    /*helpBehaviour := Behaviour {
        "/help",
        func(matches []string, w http.ResponseWriter, req *http.Request) {
            fmt.Println("help")
        },
    }*/
	ambrosio := Ambrosio{
		name,
        mux.NewRouter(),
		negroni.Classic(),
        []Behaviour{},//helpBehaviour inside brackets
	}
	return &ambrosio
}

func (a Ambrosio) Listen(port int) {

	a.router.HandleFunc("/ask", func(w http.ResponseWriter, req *http.Request) {
        var handledOnce = false
		var actionResult string
		var actionError bool
        action := req.FormValue("action")

        for _, b := range a.Behaviours {

            matched, _ := regexp.MatchString(b.Pattern, action)

            if (matched == true) {
				matches := regexp.MustCompile(b.Pattern).FindStringSubmatch(action)
                handledOnce = true
				actionResult, actionError = b.Handler(matches)
            }

        }
        if(!handledOnce) {
            fmt.Fprintf(w, "Unkown command")
        } else if(actionError == false){
			fmt.Fprintf(w, actionResult)
		} else {
			fmt.Fprintf(w, actionResult)
		}

	})

	// start the server
	n := negroni.Classic()
	n.UseHandler(a.router)
	n.Run(fmt.Sprintf(":%d", port))
}

func (a *Ambrosio) NewBehaviour(b Behaviour) {
    a.Behaviours = append(a.Behaviours, b)
}
<commit_msg>receiving second return value as error type instead of bool<commit_after>package ambrosio

import (
	"fmt"
	"net/http"
    "regexp"
    "github.com/codegangsta/negroni"
    "github.com/gorilla/mux"
)

type Listener interface {
	Listen(port int)
    NewAction()
}

type Ambrosio struct {
	name    string
    router  *mux.Router
	negroni *negroni.Negroni
    Behaviours []Behaviour
}

type Behaviour struct {
    Pattern string
    Handler func([]string) (string, error)
}

type Handler func(http.ResponseWriter, *http.Request)

func NewAmbrosio(name string) *Ambrosio {
    /*helpBehaviour := Behaviour {
        "/help",
        func(matches []string, w http.ResponseWriter, req *http.Request) {
            fmt.Println("help")
        },
    }*/
	ambrosio := Ambrosio{
		name,
        mux.NewRouter(),
		negroni.Classic(),
        []Behaviour{},//helpBehaviour inside brackets
	}
	return &ambrosio
}

func (a Ambrosio) Listen(port int) {

	a.router.HandleFunc("/ask", func(w http.ResponseWriter, req *http.Request) {
        var handledOnce = false
		var actionResult string
		var actionError error
        action := req.FormValue("action")

        for _, b := range a.Behaviours {

            matched, _ := regexp.MatchString(b.Pattern, action)

            if (matched == true) {
				matches := regexp.MustCompile(b.Pattern).FindStringSubmatch(action)
                handledOnce = true
				actionResult, actionError = b.Handler(matches)
            }

        }
        if(!handledOnce) {
            fmt.Fprintf(w, "Unkown command")
        } else if(actionError == nil){
			fmt.Fprintf(w, actionResult)
		} else {
			fmt.Fprintf(w, actionResult)
		}

	})

	// start the server
	n := negroni.Classic()
	n.UseHandler(a.router)
	n.Run(fmt.Sprintf(":%d", port))
}

func (a *Ambrosio) NewBehaviour(b Behaviour) {
    a.Behaviours = append(a.Behaviours, b)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"
)

var start = flag.Int("start", 0, "character position to start from")
var step = flag.Int("step", 1, "number of characters to step by")
var size = flag.Int("size", 80, "number of characters to display")
var delay = flag.Int("delay", 600, "delay in miliseconds between line outputs")

var input string

type circularStringReader struct {
	input    string
	position int
}

func (c *circularStringReader) read() (rune, bool) {
	wrapped := false

	if c.position < 0 || c.position >= len(c.input) {
		wrapped = true
		c.position = c.position % len(c.input)
	}
	ch := c.input[c.position]
	c.position++
	return rune(ch), wrapped
}

func (c *circularStringReader) readString(start, size int) string {
	var result string

	c.position = start

	for i := 0; i < size; i++ {
		ch, _ := c.read()
		result = result + string(ch)

	}

	return result
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:\n\n  %s [OPTIONS] input string\n\nOptions:\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
}

func main() {

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(0)
	}

	csr := circularStringReader{input: strings.Join(flag.Args(), " "), position: 0}

	for i := *start; true; i++ {
		fmt.Println(csr.readString(i*(*step), *size))
		time.Sleep(time.Duration(*delay) * time.Millisecond)
	}
}
<commit_msg>usage<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"
)

var start = flag.Int("start", 0, "character position to start from")
var step = flag.Int("step", 1, "number of characters to step by")
var size = flag.Int("size", 80, "number of characters to display")
var delay = flag.Int("delay", 600, "delay in miliseconds between line outputs")

var input string

type circularStringReader struct {
	input    string
	position int
}

func (c *circularStringReader) read() (rune, bool) {
	wrapped := false

	if c.position < 0 || c.position >= len(c.input) {
		wrapped = true
		c.position = c.position % len(c.input)
	}
	ch := c.input[c.position]
	c.position++
	return rune(ch), wrapped
}

func (c *circularStringReader) readString(start, size int) string {
	var result string

	c.position = start

	for i := 0; i < size; i++ {
		ch, _ := c.read()
		result = result + string(ch)

	}

	return result
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:\n\n  %s [OPTIONS] input string\n\nOptions:\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()
}

func main() {

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	csr := circularStringReader{input: strings.Join(flag.Args(), " "), position: 0}

	for i := *start; true; i++ {
		fmt.Println(csr.readString(i*(*step), *size))
		time.Sleep(time.Duration(*delay) * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package chevalier

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/mattbaird/elastigo/api"
	es "github.com/mattbaird/elastigo/core"
	"github.com/mattbaird/elastigo/search"
	"log"
	"strings"
	"time"
)

// QueryEngine presents an interface for running queries for sources
// against Elasticsearch.
type QueryEngine struct {
	indexName      string
	dataType       string
	nSources       int64
	updateInterval time.Duration
}

// NewQueryEngine initializes a QueryEngine with the supplied
// Elasticsearch metadata. indexName and dataType can be anything as
// long as they're consistent.
func NewQueryEngine(host, indexName, dataType string) *QueryEngine {
	e := new(QueryEngine)
	e.indexName = indexName
	e.dataType = dataType
	api.Domain = host
	e.updateSourceCount()
	e.updateInterval = time.Second * 10
	go e.updateForever()
	return e
}

// sanitizeField takes an input field specifier (from a
// SourceRequest_Tag) and munges it so Elasticsearch likes it more. In
// particular, it makes single-wildcard queries work correctly.
//
// FIXME: mid-field wildcards still aren't working.
func (e *QueryEngine) sanitizeField(f string) string {
	f = strings.TrimSpace(f)
	if f == "*" {
		return fmt.Sprintf("%s._all", e.dataType)
	}
	f = fmt.Sprintf("%s.%s", e.dataType, f)
	return f
}

// sanitizeTag escapes assorted Elasticsearch wildcards.
//
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#_reserved_characters
func (e *QueryEngine) sanitizeTag(field, value string) (string, string) {
	// * is normally in this list, but is not included here because
	// we want it to act as a wildcard.
	// Also, this can be made a lot faster.
	reservedChars := `\ + - && || ! ( ) { } [ ] ^ " ~ ? : /`
	for _, char := range strings.Split(reservedChars, " ") {
		escapedChar := fmt.Sprintf(`\%s`, char)
		field = strings.Replace(field, char, escapedChar, -1)
		value = strings.Replace(value, char, escapedChar, -1)
	}
	field = e.sanitizeField(field)
	return field, value
}

// buildTagQuery constructs an elastigo query object (search.QueryDsl)
// from a SourceRequest_Tag, designed to be plugged into a
// query-string-type[0] query later on. Returns error on empty query.
//
// [0]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
func (e *QueryEngine) buildTagQuery(tag *SourceRequest_Tag) (*search.QueryDsl, error) {
	field, value := e.sanitizeTag(*tag.Field, *tag.Value)
	// Don't bother running empty queries.
	if value == "" {
		return nil, errors.New("empty query string")
	}
	qs := new(search.QueryString)
	qs.Fields = make([]string, 0)
	qs.Fields = append(qs.Fields, field)
	qs.Query = value
	q := search.Query().Qs(qs)
	return q, nil
}

// buildOriginQuery returns the origin-matching part of the complete
// query.
func (e *QueryEngine) buildOriginQuery(origin string) *search.QueryDsl {
	qs := new(search.QueryString)
	qs.Fields = make([]string, 1)
	qs.Fields[0] = "Origin"
	qs.Query = origin
	q := search.Query().Qs(qs)
	return q
}

// SourceQuery is a multi-level map type representing an Elasticsearch
// query-string-type query. Suitable for marshalling as JSON and feeding
// to Elasticsearch.
type SourceQuery map[string]interface{}

func (e *QueryEngine) getStartResult(req *SourceRequest) int64 {
	startPage := req.GetStartPage()
	pageSize := req.GetSourcesPerPage()
	if pageSize == 0 {
		return int64(0)
	}
	return startPage * pageSize
}

// getResultCount returns the number of results to return for a
// request.
func (e *QueryEngine) getResultCount(req *SourceRequest) int64 {
	pageSize := req.GetSourcesPerPage()
	if pageSize <= 0 {
		return e.nSources
	}
	return pageSize
}

// BuildQuery takes a SourceRequest and turns it into a multi-level
// map suitable for marshalling to JSON and sending to Elasticsearch.
func (e *QueryEngine) BuildQuery(origin string, req *SourceRequest) (SourceQuery, error) {
	_ = search.Search(e.indexName).Type(e.dataType)
	tags := req.GetTags()
	tagQueries := make([]*search.QueryDsl, 0)
	for _, tag := range tags {
		q, err := e.buildTagQuery(tag)
		if q != nil && err == nil {
			tagQueries = append(tagQueries, q)
		}
	}
	originTag := e.buildOriginQuery(origin)
	tagQueries = append(tagQueries, originTag)
	if len(tagQueries) == 0 {
		return nil, errors.New("No valid query strings found.")
	}
	fromResult := e.getStartResult(req)
	resultCount := e.getResultCount(req)
	query := map[string]interface{}{
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": tagQueries,
			},
		},
		"from": fromResult,
		"size": resultCount,
	}
	return SourceQuery(query), nil
}

// runSourceRequest takes a request object and returns an elastigo-type
// (i.e., intermediate) result.
func (e *QueryEngine) runSourceRequest(origin string, req *SourceRequest) (*es.SearchResult, error) {
	q, err := e.BuildQuery(origin, req)
	if err != nil {
		return nil, err
	}
	res, err := es.SearchRequest(false, e.indexName, e.dataType, q, "", 0)
	return &res, err
}

// GetSources takes a request object and returns the DataSourceBurst of
// the sources it gets back from Elasticsearch. If error is not nil,
// then a valid DataSourceBurst will still be returned, with the Error
// field set.
func (e *QueryEngine) GetSources(origin string, req *SourceRequest) (*DataSourceBurst, error) {
	res, err := e.runSourceRequest(origin, req)
	if err != nil {
		msg := fmt.Sprintf("Request error: %v", err)
		burst := new(DataSourceBurst)
		burst.Error = &msg
		return burst, err
	}
	sources := make([]*DataSource, len(res.Hits.Hits))
	for i, hit := range res.Hits.Hits {
		source := new(ElasticsearchSource)
		err = json.Unmarshal(hit.Source, source)
		if err != nil {
			msg := fmt.Sprintf("Response decoding error: %v", err)
			burst := new(DataSourceBurst)
			burst.Error = &msg
			return burst, err
		}
		sources[i] = source.Unmarshal()
	}
	burst := BuildSourceBurst(sources)
	return burst, nil
}

// FmtResult returns a string from a SearchResult by interpreting it in
// the most naive manner possible. For debugging.
func FmtResult(result *es.SearchResult) []string {
	results := make([]string, len(result.Hits.Hits))
	for i, hit := range result.Hits.Hits {
		results[i] = string(hit.Source[:])
	}
	return results
}

// GetSourceCount returns the number of sources we currently think exist
// in the index.
func (e *QueryEngine) GetSourceCount() int64 {
	return e.nSources
}

// updateSourceCount updates our running total of documents-in-index
// (by asking Elasticsearch).
func (e *QueryEngine) updateSourceCount() error {
	resp, err := es.Count(false, e.indexName, e.dataType)
	e.nSources = int64(resp.Count)
	return err
}

// updateForever updates the source counter on a regular basis.
func (e *QueryEngine) updateForever() {
	for true {
		time.Sleep(e.updateInterval)
		err := e.updateSourceCount()
		if err != nil {
			log.Printf("Error updating source count: %v", err)
		}
	}
}
<commit_msg>Account for breaking changes in elastigo/core<commit_after>package chevalier

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/mattbaird/elastigo/api"
	es "github.com/mattbaird/elastigo/core"
	"github.com/mattbaird/elastigo/search"
	"log"
	"strings"
	"time"
)

// QueryEngine presents an interface for running queries for sources
// against Elasticsearch.
type QueryEngine struct {
	indexName      string
	dataType       string
	nSources       int64
	updateInterval time.Duration
}

// NewQueryEngine initializes a QueryEngine with the supplied
// Elasticsearch metadata. indexName and dataType can be anything as
// long as they're consistent.
func NewQueryEngine(host, indexName, dataType string) *QueryEngine {
	e := new(QueryEngine)
	e.indexName = indexName
	e.dataType = dataType
	api.Domain = host
	e.updateSourceCount()
	e.updateInterval = time.Second * 10
	go e.updateForever()
	return e
}

// sanitizeField takes an input field specifier (from a
// SourceRequest_Tag) and munges it so Elasticsearch likes it more. In
// particular, it makes single-wildcard queries work correctly.
//
// FIXME: mid-field wildcards still aren't working.
func (e *QueryEngine) sanitizeField(f string) string {
	f = strings.TrimSpace(f)
	if f == "*" {
		return fmt.Sprintf("%s._all", e.dataType)
	}
	f = fmt.Sprintf("%s.%s", e.dataType, f)
	return f
}

// sanitizeTag escapes assorted Elasticsearch wildcards.
//
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#_reserved_characters
func (e *QueryEngine) sanitizeTag(field, value string) (string, string) {
	// * is normally in this list, but is not included here because
	// we want it to act as a wildcard.
	// Also, this can be made a lot faster.
	reservedChars := `\ + - && || ! ( ) { } [ ] ^ " ~ ? : /`
	for _, char := range strings.Split(reservedChars, " ") {
		escapedChar := fmt.Sprintf(`\%s`, char)
		field = strings.Replace(field, char, escapedChar, -1)
		value = strings.Replace(value, char, escapedChar, -1)
	}
	field = e.sanitizeField(field)
	return field, value
}

// buildTagQuery constructs an elastigo query object (search.QueryDsl)
// from a SourceRequest_Tag, designed to be plugged into a
// query-string-type[0] query later on. Returns error on empty query.
//
// [0]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
func (e *QueryEngine) buildTagQuery(tag *SourceRequest_Tag) (*search.QueryDsl, error) {
	field, value := e.sanitizeTag(*tag.Field, *tag.Value)
	// Don't bother running empty queries.
	if value == "" {
		return nil, errors.New("empty query string")
	}
	qs := new(search.QueryString)
	qs.Fields = make([]string, 0)
	qs.Fields = append(qs.Fields, field)
	qs.Query = value
	q := search.Query().Qs(qs)
	return q, nil
}

// buildOriginQuery returns the origin-matching part of the complete
// query.
func (e *QueryEngine) buildOriginQuery(origin string) *search.QueryDsl {
	qs := new(search.QueryString)
	qs.Fields = make([]string, 1)
	qs.Fields[0] = "Origin"
	qs.Query = origin
	q := search.Query().Qs(qs)
	return q
}

// SourceQuery is a multi-level map type representing an Elasticsearch
// query-string-type query. Suitable for marshalling as JSON and feeding
// to Elasticsearch.
type SourceQuery map[string]interface{}

func (e *QueryEngine) getStartResult(req *SourceRequest) int64 {
	startPage := req.GetStartPage()
	pageSize := req.GetSourcesPerPage()
	if pageSize == 0 {
		return int64(0)
	}
	return startPage * pageSize
}

// getResultCount returns the number of results to return for a
// request.
func (e *QueryEngine) getResultCount(req *SourceRequest) int64 {
	pageSize := req.GetSourcesPerPage()
	if pageSize <= 0 {
		return e.nSources
	}
	return pageSize
}

// BuildQuery takes a SourceRequest and turns it into a multi-level
// map suitable for marshalling to JSON and sending to Elasticsearch.
func (e *QueryEngine) BuildQuery(origin string, req *SourceRequest) (SourceQuery, error) {
	_ = search.Search(e.indexName).Type(e.dataType)
	tags := req.GetTags()
	tagQueries := make([]*search.QueryDsl, 0)
	for _, tag := range tags {
		q, err := e.buildTagQuery(tag)
		if q != nil && err == nil {
			tagQueries = append(tagQueries, q)
		}
	}
	originTag := e.buildOriginQuery(origin)
	tagQueries = append(tagQueries, originTag)
	if len(tagQueries) == 0 {
		return nil, errors.New("No valid query strings found.")
	}
	fromResult := e.getStartResult(req)
	resultCount := e.getResultCount(req)
	query := map[string]interface{}{
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"must": tagQueries,
			},
		},
		"from": fromResult,
		"size": resultCount,
	}
	return SourceQuery(query), nil
}

// runSourceRequest takes a request object and returns an elastigo-type
// (i.e., intermediate) result.
func (e *QueryEngine) runSourceRequest(origin string, req *SourceRequest) (*es.SearchResult, error) {
	q, err := e.BuildQuery(origin, req)
	if err != nil {
		return nil, err
	}
	var args map[string]interface{}
	res, err := es.SearchRequest(e.indexName, e.dataType, args, q)
	return &res, err
}

// GetSources takes a request object and returns the DataSourceBurst of
// the sources it gets back from Elasticsearch. If error is not nil,
// then a valid DataSourceBurst will still be returned, with the Error
// field set.
func (e *QueryEngine) GetSources(origin string, req *SourceRequest) (*DataSourceBurst, error) {
	res, err := e.runSourceRequest(origin, req)
	if err != nil {
		msg := fmt.Sprintf("Request error: %v", err)
		burst := new(DataSourceBurst)
		burst.Error = &msg
		return burst, err
	}
	sources := make([]*DataSource, len(res.Hits.Hits))
	for i, hit := range res.Hits.Hits {
		source := new(ElasticsearchSource)
		err = json.Unmarshal(*hit.Source, source)
		if err != nil {
			msg := fmt.Sprintf("Response decoding error: %v", err)
			burst := new(DataSourceBurst)
			burst.Error = &msg
			return burst, err
		}
		sources[i] = source.Unmarshal()
	}
	burst := BuildSourceBurst(sources)
	return burst, nil
}

// FmtResult returns a string from a SearchResult by interpreting it in
// the most naive manner possible. For debugging.
func FmtResult(result *es.SearchResult) []string {
	results := make([]string, len(result.Hits.Hits))
	for i, hit := range result.Hits.Hits {
		results[i] = string((*hit.Source)[:])
	}
	return results
}

// GetSourceCount returns the number of sources we currently think exist
// in the index.
func (e *QueryEngine) GetSourceCount() int64 {
	return e.nSources
}

// updateSourceCount updates our running total of documents-in-index
// (by asking Elasticsearch).
func (e *QueryEngine) updateSourceCount() error {
	var args map[string]interface{}
	resp, err := es.Count(e.indexName, e.dataType, args)
	e.nSources = int64(resp.Count)
	return err
}

// updateForever updates the source counter on a regular basis.
func (e *QueryEngine) updateForever() {
	for true {
		time.Sleep(e.updateInterval)
		err := e.updateSourceCount()
		if err != nil {
			log.Printf("Error updating source count: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>package gojekyll

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/jaschaephraim/lrserver"
	"github.com/pkg/browser"
)

// Server serves the site on HTTP.
type Server struct {
	Site *Site
	mu   sync.Mutex
	lr   *lrserver.Server
}

// Run runs the server.
func (s *Server) Run(open bool, logger func(label, value string)) error {
	address := "localhost:4000"
	if err := s.watchFiles(); err != nil {
		return err
	}
	s.lr = lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
	logger("Server address:", "http://"+address+"/")
	http.HandleFunc("/", s.handler)
	c := make(chan error)
	go s.lr.ListenAndServe() // nolint: errcheck
	go func() {
		c <- http.ListenAndServe(address, nil)
	}()
	logger("Server running...", "press ctrl-c to stop.")
	if open {
		browser.OpenURL("http://localhost:4000")
	}
	return <-c
}

func (s *Server) handler(rw http.ResponseWriter, r *http.Request) {
	s.mu.Lock()
	defer s.mu.Unlock()

	site := s.Site
	urlpath := r.URL.Path

	page, found := site.PageForURL(urlpath)
	if !found {
		rw.WriteHeader(http.StatusNotFound)
		page, found = site.Paths["404.html"]
	}
	if !found {
		fmt.Fprintf(rw, "404 page not found: %s", urlpath)
		return
	}

	mimeType := mime.TypeByExtension(page.OutputExt())
	if mimeType != "" {
		rw.Header().Set("Content-Type", mimeType)
	}
	var w io.Writer = rw
	if strings.HasPrefix(mimeType, "text/html;") {
		w = scriptTagInjector{w}
	}
	err := page.Write(w)
	if err != nil {
		fmt.Printf("Error rendering %s: %s", urlpath, err)
	}
}

type scriptTagInjector struct {
	w io.Writer
}

var liveReloadScriptTag = []byte(`<script src="http://localhost:35729/livereload.js"></script>`)
var liveReloadSearchBytes = []byte(`</head>`)
var liveReloadReplacementBytes = append(liveReloadScriptTag, liveReloadSearchBytes...)

// Write injects a livereload script tag at the end of the HTML head, if present,
// else at the beginning of the document.
// It depends on the fact that dynamic page rendering makes a single Write call,
// so that it's guaranteed to find the marker within a single invocation argument.
// It doesn't parse HTML, so it could be spoofed but probably only intentionally.
func (i scriptTagInjector) Write(content []byte) (n int, err error) {
	if !bytes.Contains(content, liveReloadScriptTag) && bytes.Contains(content, liveReloadSearchBytes) {
		content = bytes.Replace(content, liveReloadSearchBytes, liveReloadReplacementBytes, 1)
	}
	if !bytes.Contains(content, liveReloadScriptTag) {
		content = append(liveReloadScriptTag, content...)
	}
	return i.w.Write(content)
}

func (s *Server) syncReloadSite() {
	s.mu.Lock()
	defer s.mu.Unlock()

	start := time.Now()
	fmt.Printf("%s Reloading site...", start.Format(time.Stamp))
	if err := s.Site.Reload(); err != nil {
		fmt.Println()
		fmt.Println(err.Error())
	}
	fmt.Printf("reloaded in %.2fs\n", time.Since(start).Seconds())
}

func (s *Server) watchFiles() error {
	var (
		site      = s.Site
		events    = make(chan string)
		debounced = debounce(time.Second, events)
	)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				events <- event.Name
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()

	go func() {
		for {
			names := <-debounced
			// Resolve to URLS *before* reloading the site, in case the latter
			// remaps permalinks.
			urls := map[string]bool{}
			for _, name := range names {
				relpath, err := filepath.Rel(site.Source, name)
				if err != nil {
					log.Println("error:", err)
					continue
				}
				url, found := site.GetFileURL(relpath)
				if !found {
					log.Println("error:", name, "does not match a site URL")
				}
				urls[url] = true
			}
			s.syncReloadSite()
			for url := range urls {
				s.lr.Reload(url)
			}
		}
	}()

	return watcher.Add(site.Source)
}

// debounce relays values from input to output, merging successive values within interval
// TODO consider https://github.com/ReactiveX/RxGo
func debounce(interval time.Duration, input chan string) (output chan []string) {
	output = make(chan []string)
	var (
		pending = []string{}
		ticker  = time.Tick(interval) // nolint: staticcheck
	)
	go func() {
		for {
			select {
			case value := <-input:
				pending = append(pending, value)
			case <-ticker:
				if len(pending) > 0 {
					output <- pending
					pending = []string{}
				}
			}
		}
	}()
	return
}
<commit_msg>Silence the live-reload status log<commit_after>package gojekyll

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/jaschaephraim/lrserver"
	"github.com/pkg/browser"
)

// Server serves the site on HTTP.
type Server struct {
	Site *Site
	mu   sync.Mutex
	lr   *lrserver.Server
}

// Run runs the server.
func (s *Server) Run(open bool, logger func(label, value string)) error {
	address := "localhost:4000"
	if err := s.watchFiles(); err != nil {
		return err
	}
	s.lr = lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
	s.lr.SetStatusLog(nil)
	logger("Server address:", "http://"+address+"/")
	http.HandleFunc("/", s.handler)
	c := make(chan error)
	go s.lr.ListenAndServe() // nolint: errcheck
	go func() {
		c <- http.ListenAndServe(address, nil)
	}()
	logger("Server running...", "press ctrl-c to stop.")
	if open {
		browser.OpenURL("http://localhost:4000")
	}
	return <-c
}

func (s *Server) handler(rw http.ResponseWriter, r *http.Request) {
	s.mu.Lock()
	defer s.mu.Unlock()

	site := s.Site
	urlpath := r.URL.Path

	page, found := site.PageForURL(urlpath)
	if !found {
		rw.WriteHeader(http.StatusNotFound)
		page, found = site.Paths["404.html"]
	}
	if !found {
		fmt.Fprintf(rw, "404 page not found: %s", urlpath)
		return
	}

	mimeType := mime.TypeByExtension(page.OutputExt())
	if mimeType != "" {
		rw.Header().Set("Content-Type", mimeType)
	}
	var w io.Writer = rw
	if strings.HasPrefix(mimeType, "text/html;") {
		w = scriptTagInjector{w}
	}
	err := page.Write(w)
	if err != nil {
		fmt.Printf("Error rendering %s: %s", urlpath, err)
	}
}

type scriptTagInjector struct {
	w io.Writer
}

var liveReloadScriptTag = []byte(`<script src="http://localhost:35729/livereload.js"></script>`)
var liveReloadSearchBytes = []byte(`</head>`)
var liveReloadReplacementBytes = append(liveReloadScriptTag, liveReloadSearchBytes...)

// Write injects a livereload script tag at the end of the HTML head, if present,
// else at the beginning of the document.
// It depends on the fact that dynamic page rendering makes a single Write call,
// so that it's guaranteed to find the marker within a single invocation argument.
// It doesn't parse HTML, so it could be spoofed but probably only intentionally.
func (i scriptTagInjector) Write(content []byte) (n int, err error) {
	if !bytes.Contains(content, liveReloadScriptTag) && bytes.Contains(content, liveReloadSearchBytes) {
		content = bytes.Replace(content, liveReloadSearchBytes, liveReloadReplacementBytes, 1)
	}
	if !bytes.Contains(content, liveReloadScriptTag) {
		content = append(liveReloadScriptTag, content...)
	}
	return i.w.Write(content)
}

func (s *Server) syncReloadSite() {
	s.mu.Lock()
	defer s.mu.Unlock()

	start := time.Now()
	fmt.Printf("%s Reloading site...", start.Format(time.Stamp))
	if err := s.Site.Reload(); err != nil {
		fmt.Println()
		fmt.Println(err.Error())
	}
	fmt.Printf("reloaded in %.2fs\n", time.Since(start).Seconds())
}

func (s *Server) watchFiles() error {
	var (
		site      = s.Site
		events    = make(chan string)
		debounced = debounce(time.Second, events)
	)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				events <- event.Name
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()

	go func() {
		for {
			names := <-debounced
			// Resolve to URLS *before* reloading the site, in case the latter
			// remaps permalinks.
			urls := map[string]bool{}
			for _, name := range names {
				relpath, err := filepath.Rel(site.Source, name)
				if err != nil {
					log.Println("error:", err)
					continue
				}
				url, found := site.GetFileURL(relpath)
				if !found {
					log.Println("error:", name, "does not match a site URL")
				}
				urls[url] = true
			}
			s.syncReloadSite()
			for url := range urls {
				s.lr.Reload(url)
			}
		}
	}()

	return watcher.Add(site.Source)
}

// debounce relays values from input to output, merging successive values within interval
// TODO consider https://github.com/ReactiveX/RxGo
func debounce(interval time.Duration, input chan string) (output chan []string) {
	output = make(chan []string)
	var (
		pending = []string{}
		ticker  = time.Tick(interval) // nolint: staticcheck
	)
	go func() {
		for {
			select {
			case value := <-input:
				pending = append(pending, value)
			case <-ticker:
				if len(pending) > 0 {
					output <- pending
					pending = []string{}
				}
			}
		}
	}()
	return
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"fmt"
	"io"
	"log"
	"net"
	"regexp"
	"strings"
)

var (
	nickRegexp    = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`)
	channelRegexp = regexp.MustCompile(`^#[a-zA-Z0-9_\-]+$`)
)

func NewServer() *Server {
	return &Server{eventChan: make(chan Event),
		name:        "rosella",
		clientMap:   make(map[string]*Client),
		channelMap:  make(map[string]*Channel),
		operatorMap: make(map[string]string)}
}

func (s *Server) Run() {
	for event := range s.eventChan {
		s.handleEvent(event)
	}
}

func (s *Server) HandleConnection(conn net.Conn) {
	client := &Client{server: s,
		connection: conn,
		outputChan: make(chan string),
		signalChan: make(chan signalCode, 3),
		channelMap: make(map[string]*Channel),
		connected:  true}

	go client.clientThread()
}

func (s *Server) handleEvent(e Event) {
	defer func(event Event) {
		err := recover()
		if err != nil {
			log.Printf("Recovered from errer when handling event: %+v", event)
			log.Println(err)
		}
	}(e)
	fields := strings.Fields(e.input)

	if len(fields) < 1 {
		return
	}

	if strings.HasPrefix(fields[0], ":") {
		fields = fields[1:]
	}

	command := strings.ToUpper(fields[0])
	args := fields[1:]

	switch {
	case command == "NICK":
		if len(args) < 1 {
			e.client.reply(errNoNick)
			return
		}

		newNick := args[0]

		//Check newNick is of valid formatting (regex)
		if nickRegexp.MatchString(newNick) == false {
			e.client.reply(errInvalidNick, newNick)
			return
		}

		if _, exists := s.clientMap[strings.ToLower(newNick)]; exists {
			e.client.reply(errNickInUse, newNick)
			return
		}

		//Protect the server name from being used
		if strings.ToLower(newNick) == strings.ToLower(s.name) {
			e.client.reply(errNickInUse, newNick)
			return
		}

		e.client.setNick(newNick)

	case command == "USER":
		if e.client.nick == "" {
			e.client.reply(rplKill, "Your nickname is already being used")
			e.client.disconnect()
		} else {
			e.client.reply(rplWelcome)
			e.client.registered = true
		}

	case command == "JOIN":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		if args[0] == "0" {
			//Quit all channels
			for channel := range e.client.channelMap {
				e.client.partChannel(channel)
			}
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Join the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				e.client.joinChannel(channel)
			}
		}

	case command == "PART":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Part the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				e.client.partChannel(channel)
			}
		}

	case command == "PRIVMSG":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		message := strings.Join(args[1:], " ")

		channel, chanExists := s.channelMap[strings.ToLower(args[0])]
		client, clientExists := s.clientMap[strings.ToLower(args[0])]

		if chanExists {
			if channel.mode.noExternal {
				if _, inChannel := channel.clientMap[strings.ToLower(e.client.nick)]; !inChannel {
					//Not in channel, not allowed to send
					e.client.reply(errCannotSend, args[0])
					return
				}
			}
			if channel.mode.moderated {
				clientMode := channel.modeMap[strings.ToLower(e.client.nick)]
				if !clientMode.operator && !clientMode.voice {
					//It's moderated and we're not +v or +o, do nothing
					e.client.reply(errCannotSend, args[0])
					return
				}
			}
			for _, c := range channel.clientMap {
				if c != e.client {
					c.reply(rplMsg, e.client.nick, args[0], message)
				}
			}
		} else if clientExists {
			client.reply(rplMsg, e.client.nick, client.nick, message)
		} else {
			e.client.reply(errNoSuchNick, args[0])
		}

	case command == "QUIT":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		e.client.disconnect()

	case command == "TOPIC":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channel, exists := s.channelMap[strings.ToLower(args[0])]
		if exists == false {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		channelName := args[0]

		if len(args) == 1 {
			e.client.reply(rplTopic, channelName, channel.topic)
			return
		}

		clientMode := channel.modeMap[strings.ToLower(e.client.nick)]
		if channel.mode.topicLocked && !clientMode.operator {
			e.client.reply(errNoPriv)
			return
		}

		if args[1] == ":" {
			channel.topic = ""
			for _, client := range channel.clientMap {
				client.reply(rplNoTopic, channelName)
			}
		} else {
			topic := strings.Join(args[1:], " ")
			topic = strings.TrimPrefix(topic, ":")
			channel.topic = topic

			for _, client := range channel.clientMap {
				client.reply(rplTopic, channelName, channel.topic)
			}
		}

	case command == "LIST":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) == 0 {
			chanList := make([]string, 0, len(s.channelMap))

			for channelName, channel := range s.channelMap {
				if channel.mode.secret {
					if _, inChannel := channel.clientMap[strings.ToLower(e.client.nick)]; !inChannel {
						//Not in the channel, skip
						continue
					}
				}
				listItem := fmt.Sprintf("%s %d :%s", channelName, len(channel.clientMap), channel.topic)
				chanList = append(chanList, listItem)
			}

			e.client.reply(rplList, chanList...)

		} else {
			channels := strings.Split(args[0], ",")
			chanList := make([]string, 0, len(channels))

			for _, channelName := range channels {
				if channel, exists := s.channelMap[strings.ToLower(channelName)]; exists {
					listItem := fmt.Sprintf("%s %d :%s", channelName, len(channel.clientMap), channel.topic)
					chanList = append(chanList, listItem)
				}
			}

			e.client.reply(rplList, chanList...)
		}
	case command == "OPER":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		username := args[0]
		password := args[1]

		if hashedPassword, exists := s.operatorMap[username]; exists {
			h := sha1.New()
			io.WriteString(h, password)
			pass := fmt.Sprintf("%x", h.Sum(nil))
			if hashedPassword == pass {
				e.client.operator = true
				e.client.reply(rplOper)
				return
			}
		}
		e.client.reply(errPassword)

	case command == "KILL":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if e.client.operator == false {
			e.client.reply(errNoPriv)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		nick := args[0]

		if client, exists := s.clientMap[strings.ToLower(nick)]; exists {
			client.reply(rplKill, "An operator has disconnected you.")
			client.disconnect()
		} else {
			e.client.reply(errNoSuchNick, nick)
		}

	case command == "KICK":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		channelKey := strings.ToLower(args[0])
		targetKey := strings.ToLower(args[1])

		channel, channelExists := s.channelMap[channelKey]
		if !channelExists {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		target, targetExists := channel.clientMap[targetKey]
		if !targetExists {
			e.client.reply(errNoSuchNick, args[1])
			return
		}

		clientMode := channel.modeMap[e.client.key]
		if !clientMode.operator {
			e.client.reply(errNoPriv)
			return
		}

		reason := strings.Join(args[2:], " ")

		//It worked
		for _, client := range channel.clientMap {
			client.reply(rplKick, e.client.nick, channel.name, target.nick, reason)
		}

		delete(channel.clientMap, targetKey)
		delete(channel.modeMap, targetKey)
		delete(target.channelMap, channelKey)

	case command == "MODE":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channelKey := strings.ToLower(args[0])

		channel, channelExists := s.channelMap[channelKey]
		if !channelExists {
			e.client.reply(errNoSuchNick, args[0])
			return
		}
		mode := channel.mode

		if len(args) == 1 {
			//No more args, they just want the mode
			e.client.reply(rplChannelModeIs, args[0], mode.String(), "")
			return
		}

		if cm, ok := channel.modeMap[strings.ToLower(e.client.nick)]; !ok || !cm.operator {
			//Not a channel operator.

			//If they're not an irc operator either, they'll fail
			if !e.client.operator {
				e.client.reply(errNoPriv)
				return
			}
		}

		hasClient := false
		var oldClientMode, newClientMode *ClientMode
		var targetClient *Client
		if len(args) >= 3 {
			clientKey := strings.ToLower(args[2])
			oldClientMode, hasClient = channel.modeMap[clientKey]
			if hasClient {
				targetClient = channel.clientMap[clientKey]
				newClientMode = new(ClientMode)
				*newClientMode = *oldClientMode
			}
		}

		mod := strings.ToLower(args[1])
		if strings.HasPrefix(mod, "+") {
			for _, char := range mod {
				switch char {
				case 's':
					mode.secret = true
				case 't':
					mode.topicLocked = true
				case 'm':
					mode.moderated = true
				case 'n':
					mode.noExternal = true
				case 'o':
					if hasClient {
						newClientMode.operator = true
					}
				case 'v':
					if hasClient {
						newClientMode.voice = true
					}
				}
			}
		} else if strings.HasPrefix(mod, "-") {
			for _, char := range mod {
				switch char {
				case 's':
					mode.secret = false
				case 't':
					mode.topicLocked = false
				case 'm':
					mode.moderated = false
				case 'n':
					mode.noExternal = false
				case 'o':
					if hasClient {
						newClientMode.operator = false
					}
				case 'v':
					if hasClient {
						newClientMode.voice = false
					}
				}
			}
		}

		if hasClient {
			*oldClientMode = *newClientMode
		}
		channel.mode = mode

		for _, client := range channel.clientMap {
			if hasClient {
				client.reply(rplChannelModeIs, args[0], args[1], targetClient.nick)
			} else {
				client.reply(rplChannelModeIs, args[0], args[1], "")
			}
		}

	default:
		e.client.reply(errUnknownCommand, command)
	}
}
<commit_msg>IRC operators can always use /KICK now<commit_after>package main

import (
	"crypto/sha1"
	"fmt"
	"io"
	"log"
	"net"
	"regexp"
	"strings"
)

var (
	nickRegexp    = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`)
	channelRegexp = regexp.MustCompile(`^#[a-zA-Z0-9_\-]+$`)
)

func NewServer() *Server {
	return &Server{eventChan: make(chan Event),
		name:        "rosella",
		clientMap:   make(map[string]*Client),
		channelMap:  make(map[string]*Channel),
		operatorMap: make(map[string]string)}
}

func (s *Server) Run() {
	for event := range s.eventChan {
		s.handleEvent(event)
	}
}

func (s *Server) HandleConnection(conn net.Conn) {
	client := &Client{server: s,
		connection: conn,
		outputChan: make(chan string),
		signalChan: make(chan signalCode, 3),
		channelMap: make(map[string]*Channel),
		connected:  true}

	go client.clientThread()
}

func (s *Server) handleEvent(e Event) {
	defer func(event Event) {
		err := recover()
		if err != nil {
			log.Printf("Recovered from errer when handling event: %+v", event)
			log.Println(err)
		}
	}(e)
	fields := strings.Fields(e.input)

	if len(fields) < 1 {
		return
	}

	if strings.HasPrefix(fields[0], ":") {
		fields = fields[1:]
	}

	command := strings.ToUpper(fields[0])
	args := fields[1:]

	switch {
	case command == "NICK":
		if len(args) < 1 {
			e.client.reply(errNoNick)
			return
		}

		newNick := args[0]

		//Check newNick is of valid formatting (regex)
		if nickRegexp.MatchString(newNick) == false {
			e.client.reply(errInvalidNick, newNick)
			return
		}

		if _, exists := s.clientMap[strings.ToLower(newNick)]; exists {
			e.client.reply(errNickInUse, newNick)
			return
		}

		//Protect the server name from being used
		if strings.ToLower(newNick) == strings.ToLower(s.name) {
			e.client.reply(errNickInUse, newNick)
			return
		}

		e.client.setNick(newNick)

	case command == "USER":
		if e.client.nick == "" {
			e.client.reply(rplKill, "Your nickname is already being used")
			e.client.disconnect()
		} else {
			e.client.reply(rplWelcome)
			e.client.registered = true
		}

	case command == "JOIN":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		if args[0] == "0" {
			//Quit all channels
			for channel := range e.client.channelMap {
				e.client.partChannel(channel)
			}
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Join the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				e.client.joinChannel(channel)
			}
		}

	case command == "PART":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channels := strings.Split(args[0], ",")
		for _, channel := range channels {
			//Part the channel if it's valid
			if channelRegexp.Match([]byte(channel)) {
				e.client.partChannel(channel)
			}
		}

	case command == "PRIVMSG":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		message := strings.Join(args[1:], " ")

		channel, chanExists := s.channelMap[strings.ToLower(args[0])]
		client, clientExists := s.clientMap[strings.ToLower(args[0])]

		if chanExists {
			if channel.mode.noExternal {
				if _, inChannel := channel.clientMap[strings.ToLower(e.client.nick)]; !inChannel {
					//Not in channel, not allowed to send
					e.client.reply(errCannotSend, args[0])
					return
				}
			}
			if channel.mode.moderated {
				clientMode := channel.modeMap[strings.ToLower(e.client.nick)]
				if !clientMode.operator && !clientMode.voice {
					//It's moderated and we're not +v or +o, do nothing
					e.client.reply(errCannotSend, args[0])
					return
				}
			}
			for _, c := range channel.clientMap {
				if c != e.client {
					c.reply(rplMsg, e.client.nick, args[0], message)
				}
			}
		} else if clientExists {
			client.reply(rplMsg, e.client.nick, client.nick, message)
		} else {
			e.client.reply(errNoSuchNick, args[0])
		}

	case command == "QUIT":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		e.client.disconnect()

	case command == "TOPIC":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channel, exists := s.channelMap[strings.ToLower(args[0])]
		if exists == false {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		channelName := args[0]

		if len(args) == 1 {
			e.client.reply(rplTopic, channelName, channel.topic)
			return
		}

		clientMode := channel.modeMap[strings.ToLower(e.client.nick)]
		if channel.mode.topicLocked && !clientMode.operator {
			e.client.reply(errNoPriv)
			return
		}

		if args[1] == ":" {
			channel.topic = ""
			for _, client := range channel.clientMap {
				client.reply(rplNoTopic, channelName)
			}
		} else {
			topic := strings.Join(args[1:], " ")
			topic = strings.TrimPrefix(topic, ":")
			channel.topic = topic

			for _, client := range channel.clientMap {
				client.reply(rplTopic, channelName, channel.topic)
			}
		}

	case command == "LIST":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) == 0 {
			chanList := make([]string, 0, len(s.channelMap))

			for channelName, channel := range s.channelMap {
				if channel.mode.secret {
					if _, inChannel := channel.clientMap[strings.ToLower(e.client.nick)]; !inChannel {
						//Not in the channel, skip
						continue
					}
				}
				listItem := fmt.Sprintf("%s %d :%s", channelName, len(channel.clientMap), channel.topic)
				chanList = append(chanList, listItem)
			}

			e.client.reply(rplList, chanList...)

		} else {
			channels := strings.Split(args[0], ",")
			chanList := make([]string, 0, len(channels))

			for _, channelName := range channels {
				if channel, exists := s.channelMap[strings.ToLower(channelName)]; exists {
					listItem := fmt.Sprintf("%s %d :%s", channelName, len(channel.clientMap), channel.topic)
					chanList = append(chanList, listItem)
				}
			}

			e.client.reply(rplList, chanList...)
		}
	case command == "OPER":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		username := args[0]
		password := args[1]

		if hashedPassword, exists := s.operatorMap[username]; exists {
			h := sha1.New()
			io.WriteString(h, password)
			pass := fmt.Sprintf("%x", h.Sum(nil))
			if hashedPassword == pass {
				e.client.operator = true
				e.client.reply(rplOper)
				return
			}
		}
		e.client.reply(errPassword)

	case command == "KILL":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if e.client.operator == false {
			e.client.reply(errNoPriv)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		nick := args[0]

		if client, exists := s.clientMap[strings.ToLower(nick)]; exists {
			client.reply(rplKill, "An operator has disconnected you.")
			client.disconnect()
		} else {
			e.client.reply(errNoSuchNick, nick)
		}

	case command == "KICK":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 2 {
			e.client.reply(errMoreArgs)
			return
		}

		channelKey := strings.ToLower(args[0])
		targetKey := strings.ToLower(args[1])

		channel, channelExists := s.channelMap[channelKey]
		if !channelExists {
			e.client.reply(errNoSuchNick, args[0])
			return
		}

		target, targetExists := channel.clientMap[targetKey]
		if !targetExists {
			e.client.reply(errNoSuchNick, args[1])
			return
		}

		clientMode := channel.modeMap[e.client.key]
		if !clientMode.operator && !e.client.operator {
			e.client.reply(errNoPriv)
			return
		}

		reason := strings.Join(args[2:], " ")

		//It worked
		for _, client := range channel.clientMap {
			client.reply(rplKick, e.client.nick, channel.name, target.nick, reason)
		}

		delete(channel.clientMap, targetKey)
		delete(channel.modeMap, targetKey)
		delete(target.channelMap, channelKey)

	case command == "MODE":
		if e.client.registered == false {
			e.client.reply(errNotReg)
			return
		}

		if len(args) < 1 {
			e.client.reply(errMoreArgs)
			return
		}

		channelKey := strings.ToLower(args[0])

		channel, channelExists := s.channelMap[channelKey]
		if !channelExists {
			e.client.reply(errNoSuchNick, args[0])
			return
		}
		mode := channel.mode

		if len(args) == 1 {
			//No more args, they just want the mode
			e.client.reply(rplChannelModeIs, args[0], mode.String(), "")
			return
		}

		if cm, ok := channel.modeMap[strings.ToLower(e.client.nick)]; !ok || !cm.operator {
			//Not a channel operator.

			//If they're not an irc operator either, they'll fail
			if !e.client.operator {
				e.client.reply(errNoPriv)
				return
			}
		}

		hasClient := false
		var oldClientMode, newClientMode *ClientMode
		var targetClient *Client
		if len(args) >= 3 {
			clientKey := strings.ToLower(args[2])
			oldClientMode, hasClient = channel.modeMap[clientKey]
			if hasClient {
				targetClient = channel.clientMap[clientKey]
				newClientMode = new(ClientMode)
				*newClientMode = *oldClientMode
			}
		}

		mod := strings.ToLower(args[1])
		if strings.HasPrefix(mod, "+") {
			for _, char := range mod {
				switch char {
				case 's':
					mode.secret = true
				case 't':
					mode.topicLocked = true
				case 'm':
					mode.moderated = true
				case 'n':
					mode.noExternal = true
				case 'o':
					if hasClient {
						newClientMode.operator = true
					}
				case 'v':
					if hasClient {
						newClientMode.voice = true
					}
				}
			}
		} else if strings.HasPrefix(mod, "-") {
			for _, char := range mod {
				switch char {
				case 's':
					mode.secret = false
				case 't':
					mode.topicLocked = false
				case 'm':
					mode.moderated = false
				case 'n':
					mode.noExternal = false
				case 'o':
					if hasClient {
						newClientMode.operator = false
					}
				case 'v':
					if hasClient {
						newClientMode.voice = false
					}
				}
			}
		}

		if hasClient {
			*oldClientMode = *newClientMode
		}
		channel.mode = mode

		for _, client := range channel.clientMap {
			if hasClient {
				client.reply(rplChannelModeIs, args[0], args[1], targetClient.nick)
			} else {
				client.reply(rplChannelModeIs, args[0], args[1], "")
			}
		}

	default:
		e.client.reply(errUnknownCommand, command)
	}
}
<|endoftext|>


<commit_before>package oauth

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/satori/go.uuid"
)

const (
	TOKEN_TYPE = "Bearer"
)

type Any interface{}

// CredentialsVerifier defines the interface of the user and client credentials verifier.
type CredentialsVerifier interface {
	// Validate username and password returning an error if the user credentials are wrong
	ValidateUser(username, password, scope string, req *http.Request) error
	// Validate clientId and secret returning an error if the client credentials are wrong
	ValidateClient(clientID, clientSecret, scope string, req *http.Request) error
	// Provide additional claims to the token
	AddClaims(credential, tokenID, tokenType, scope string) (map[string]string, error)
	// Optionally store the tokenID generated for the user
	StoreTokenId(credential, tokenID, refreshTokenID, tokenType string) error
	// Provide additional information to the authorization server response
	AddProperties(credential, tokenID, tokenType string) (map[string]string, error)
	// Optionally validate previously stored tokenID during refresh request
	ValidateTokenId(credential, tokenID, refreshTokenID, tokenType string) error
}

// AuthorizationCodeVerifier defines the interface of the Authorization Code verifier
type AuthorizationCodeVerifier interface {
	// ValidateCode checks the authorization code and returns the user credential
	ValidateCode(clientID, clientSecret, code, redirectURI string, req *http.Request) (string, error)
}

// OAuthBearerServer is the OAuth 2 Bearer Server implementation.
type OAuthBearerServer struct {
	secretKey string
	TokenTTL  time.Duration
	verifier  CredentialsVerifier
	provider  *TokenProvider
}

// NewOAuthBearerServer creates new OAuth 2 Bearer Server
func NewOAuthBearerServer(secretKey string,
	ttl time.Duration,
	verifier CredentialsVerifier,
	formatter TokenSecureFormatter) *OAuthBearerServer {
	if formatter == nil {
		formatter = NewSHA256RC4TokenSecurityProvider([]byte(secretKey))
	}
	obs := &OAuthBearerServer{
		secretKey: secretKey,
		TokenTTL:  ttl,
		verifier:  verifier,
		provider:  NewTokenProvider(formatter)}
	return obs
}

// UserCredentials manages password grant type requests
func (s *OAuthBearerServer) UserCredentials(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type password variables
	username := ctx.PostForm("username")
	password := ctx.PostForm("password")
	scope := ctx.PostForm("scope")
	if username == "" || password == "" {
		// get username and password from basic authorization header
		var err error
		username, password, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	// grant_type refresh_token
	refreshToken := ctx.PostForm("refresh_token")
	code, resp := s.generateTokenResponse(grantType, username, password, refreshToken, scope, "", "", ctx.Request)
	ctx.JSON(code, resp)
}

// ClientCredentials manages client credentials grant type requests
func (s *OAuthBearerServer) ClientCredentials(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type client_credentials variables
	clientId := ctx.PostForm("client_id")
	clientSecret := ctx.PostForm("client_secret")
	if clientId == "" || clientSecret == "" {
		// get clientId and secret from basic authorization header
		var err error
		clientId, clientSecret, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	scope := ctx.PostForm("scope")
	// grant_type refresh_token
	refreshToken := ctx.PostForm("refresh_token")
	code, resp := s.generateTokenResponse(grantType, clientId, clientSecret, refreshToken, scope, "", "", ctx.Request)
	ctx.JSON(code, resp)
}

// AuthorizationCode manages authorization code grant type requests for the phase two of the authorization process
func (s *OAuthBearerServer) AuthorizationCode(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type client_credentials variables
	clientId := ctx.PostForm("client_id")
	clientSecret := ctx.PostForm("client_secret") // not mandatory
	code := ctx.PostForm("code")
	redirectURI := ctx.PostForm("redirect_uri") // not mandatory
	scope := ctx.PostForm("scope")              // not mandatory
	if clientId == "" {
		// get clientId and secret from basic authorization header
		var err error
		clientId, clientSecret, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	status, resp := s.generateTokenResponse(grantType, clientId, clientSecret, "", scope, code, redirectURI, ctx.Request)
	ctx.JSON(status, resp)
}

// Generate token response
func (s *OAuthBearerServer) generateTokenResponse(grantType, credential, secret, refreshToken, scope, code, redirectURI string, req *http.Request) (int, Any) {
	// check grant_Type
	if grantType == "password" {
		err := s.verifier.ValidateUser(credential, secret, scope, req)
		if err == nil {
			token, refresh, err := s.generateTokens(credential, "U", scope)
			if err == nil {
				// Store token id
				err = s.verifier.StoreTokenId(credential, token.Id, refresh.RefreshTokenId, token.TokenType)
				if err != nil {
					return http.StatusInternalServerError, "Storing Token Id failed"
				}
				resp, err := s.cryptTokens(token, refresh)
				if err == nil {
					return http.StatusOK, resp
				} else {
					return http.StatusInternalServerError, "Token generation failed, check security provider"
				}
			} else {
				return http.StatusInternalServerError, "Token generation failed, check claims"
			}

		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else if grantType == "client_credentials" {
		err := s.verifier.ValidateClient(credential, secret, scope, req)
		if err == nil {
			token, refresh, err := s.generateTokens(credential, "C", scope)
			if err == nil {
				// Store token id
				err = s.verifier.StoreTokenId(credential, token.Id, refresh.RefreshTokenId, token.TokenType)
				if err != nil {
					return http.StatusInternalServerError, "Storing Token Id failed"
				}
				resp, err := s.cryptTokens(token, refresh)
				if err == nil {
					return http.StatusOK, resp
				} else {
					return http.StatusInternalServerError, "Token generation failed, check security provider"
				}
			} else {
				return http.StatusInternalServerError, "Token generation failed, check claims"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else if grantType == "authorization_code" {
		if codeVerifier, ok := s.verifier.(AuthorizationCodeVerifier); ok {
			user, err := codeVerifier.ValidateCode(credential, secret, code, redirectURI, req)
			if err == nil {
				token, refresh, err := s.generateTokens(user, "A", scope)
				if err == nil {
					// Store token id
					err = s.verifier.StoreTokenId(user, token.Id, refresh.RefreshTokenId, token.TokenType)
					if err != nil {
						return http.StatusInternalServerError, "Storing Token Id failed"
					}
					resp, err := s.cryptTokens(token, refresh)
					if err == nil {
						return http.StatusOK, resp
					} else {
						return http.StatusInternalServerError, "Token generation failed, check security provider"
					}
				} else {
					return http.StatusInternalServerError, "Token generation failed, check claims"
				}
			} else {
				//not autorized
				return http.StatusUnauthorized, "Not authorized"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized, grant type not supported"
		}
	} else if grantType == "refresh_token" {
		// refresh token
		refresh, err := s.provider.DecryptRefreshTokens(refreshToken)
		if err == nil {
			err = s.verifier.ValidateTokenId(refresh.Credential, refresh.TokenId, refresh.RefreshTokenId, refresh.TokenType)
			if err == nil {
				// generate new token
				token, refresh, err := s.generateTokens(refresh.Credential, refresh.TokenType, refresh.Scope)
				if err == nil {
					// Store token id
					err = s.verifier.StoreTokenId(refresh.Credential, token.Id, refresh.RefreshTokenId, token.TokenType)
					if err != nil {
						return http.StatusInternalServerError, "Storing Token Id failed"
					}
					resp, err := s.cryptTokens(token, refresh)
					if err == nil {
						return http.StatusOK, resp
					} else {
						return http.StatusInternalServerError, "Token generation failed"
					}
				} else {
					return http.StatusInternalServerError, "Token generation failed"
				}
			} else {
				//not autorized invalid token Id
				return http.StatusUnauthorized, "Not authorized invalid token"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else {
		// Invalid request
		return http.StatusBadRequest, "Invalid grant_type"
	}
}

func (s *OAuthBearerServer) generateTokens(username, tokenType, scope string) (token *Token, refresh *RefreshToken, err error) {
	token = &Token{Credential: username, ExperesIn: s.TokenTTL, CreationDate: time.Now().UTC(), TokenType: tokenType, Scope: scope}
	// generate token Id
	token.Id = uuid.NewV4().String()
	if s.verifier != nil {
		claims, err := s.verifier.AddClaims(username, token.Id, token.TokenType, token.Scope)
		if err == nil {
			token.Claims = claims
		} else {
			// claims error
			return nil, nil, err
		}
	}
	// create refresh token
	refresh = &RefreshToken{RefreshTokenId: uuid.NewV4().String(), TokenId: token.Id, CreationDate: time.Now().UTC(), Credential: username, TokenType: tokenType, Scope: scope}

	return token, refresh, nil
}

func (s *OAuthBearerServer) cryptTokens(token *Token, refresh *RefreshToken) (resp *TokenResponse, err error) {
	ctoken, err := s.provider.CryptToken(token)
	if err != nil {
		return nil, err
	}
	crefresh, err := s.provider.CryptRefreshToken(refresh)
	if err != nil {
		return nil, err
	}
	resp = &TokenResponse{Token: ctoken, RefreshToken: crefresh, TokenType: TOKEN_TYPE, ExperesIn: (int64)(s.TokenTTL / time.Second)}

	if s.verifier != nil {
		// add properties
		props, err := s.verifier.AddProperties(token.Credential, token.Id, token.TokenType)
		if err == nil {
			resp.Properties = props
		}
	}
	return resp, nil
}
<commit_msg>fix go.uuid NewV4 method call after signature update<commit_after>package oauth

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/satori/go.uuid"
)

const (
	TOKEN_TYPE = "Bearer"
)

type Any interface{}

// CredentialsVerifier defines the interface of the user and client credentials verifier.
type CredentialsVerifier interface {
	// Validate username and password returning an error if the user credentials are wrong
	ValidateUser(username, password, scope string, req *http.Request) error
	// Validate clientId and secret returning an error if the client credentials are wrong
	ValidateClient(clientID, clientSecret, scope string, req *http.Request) error
	// Provide additional claims to the token
	AddClaims(credential, tokenID, tokenType, scope string) (map[string]string, error)
	// Optionally store the tokenID generated for the user
	StoreTokenId(credential, tokenID, refreshTokenID, tokenType string) error
	// Provide additional information to the authorization server response
	AddProperties(credential, tokenID, tokenType string) (map[string]string, error)
	// Optionally validate previously stored tokenID during refresh request
	ValidateTokenId(credential, tokenID, refreshTokenID, tokenType string) error
}

// AuthorizationCodeVerifier defines the interface of the Authorization Code verifier
type AuthorizationCodeVerifier interface {
	// ValidateCode checks the authorization code and returns the user credential
	ValidateCode(clientID, clientSecret, code, redirectURI string, req *http.Request) (string, error)
}

// OAuthBearerServer is the OAuth 2 Bearer Server implementation.
type OAuthBearerServer struct {
	secretKey string
	TokenTTL  time.Duration
	verifier  CredentialsVerifier
	provider  *TokenProvider
}

// NewOAuthBearerServer creates new OAuth 2 Bearer Server
func NewOAuthBearerServer(secretKey string,
	ttl time.Duration,
	verifier CredentialsVerifier,
	formatter TokenSecureFormatter) *OAuthBearerServer {
	if formatter == nil {
		formatter = NewSHA256RC4TokenSecurityProvider([]byte(secretKey))
	}
	obs := &OAuthBearerServer{
		secretKey: secretKey,
		TokenTTL:  ttl,
		verifier:  verifier,
		provider:  NewTokenProvider(formatter)}
	return obs
}

// UserCredentials manages password grant type requests
func (s *OAuthBearerServer) UserCredentials(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type password variables
	username := ctx.PostForm("username")
	password := ctx.PostForm("password")
	scope := ctx.PostForm("scope")
	if username == "" || password == "" {
		// get username and password from basic authorization header
		var err error
		username, password, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	// grant_type refresh_token
	refreshToken := ctx.PostForm("refresh_token")
	code, resp := s.generateTokenResponse(grantType, username, password, refreshToken, scope, "", "", ctx.Request)
	ctx.JSON(code, resp)
}

// ClientCredentials manages client credentials grant type requests
func (s *OAuthBearerServer) ClientCredentials(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type client_credentials variables
	clientId := ctx.PostForm("client_id")
	clientSecret := ctx.PostForm("client_secret")
	if clientId == "" || clientSecret == "" {
		// get clientId and secret from basic authorization header
		var err error
		clientId, clientSecret, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	scope := ctx.PostForm("scope")
	// grant_type refresh_token
	refreshToken := ctx.PostForm("refresh_token")
	code, resp := s.generateTokenResponse(grantType, clientId, clientSecret, refreshToken, scope, "", "", ctx.Request)
	ctx.JSON(code, resp)
}

// AuthorizationCode manages authorization code grant type requests for the phase two of the authorization process
func (s *OAuthBearerServer) AuthorizationCode(ctx *gin.Context) {
	grantType := ctx.PostForm("grant_type")
	// grant_type client_credentials variables
	clientId := ctx.PostForm("client_id")
	clientSecret := ctx.PostForm("client_secret") // not mandatory
	code := ctx.PostForm("code")
	redirectURI := ctx.PostForm("redirect_uri") // not mandatory
	scope := ctx.PostForm("scope")              // not mandatory
	if clientId == "" {
		// get clientId and secret from basic authorization header
		var err error
		clientId, clientSecret, err = GetBasicAuthentication(ctx)
		if err != nil {
			ctx.JSON(http.StatusUnauthorized, "Not authorized")
			return
		}
	}
	status, resp := s.generateTokenResponse(grantType, clientId, clientSecret, "", scope, code, redirectURI, ctx.Request)
	ctx.JSON(status, resp)
}

// Generate token response
func (s *OAuthBearerServer) generateTokenResponse(grantType, credential, secret, refreshToken, scope, code, redirectURI string, req *http.Request) (int, Any) {
	// check grant_Type
	if grantType == "password" {
		err := s.verifier.ValidateUser(credential, secret, scope, req)
		if err == nil {
			token, refresh, err := s.generateTokens(credential, "U", scope)
			if err == nil {
				// Store token id
				err = s.verifier.StoreTokenId(credential, token.Id, refresh.RefreshTokenId, token.TokenType)
				if err != nil {
					return http.StatusInternalServerError, "Storing Token Id failed"
				}
				resp, err := s.cryptTokens(token, refresh)
				if err == nil {
					return http.StatusOK, resp
				} else {
					return http.StatusInternalServerError, "Token generation failed, check security provider"
				}
			} else {
				return http.StatusInternalServerError, "Token generation failed, check claims"
			}

		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else if grantType == "client_credentials" {
		err := s.verifier.ValidateClient(credential, secret, scope, req)
		if err == nil {
			token, refresh, err := s.generateTokens(credential, "C", scope)
			if err == nil {
				// Store token id
				err = s.verifier.StoreTokenId(credential, token.Id, refresh.RefreshTokenId, token.TokenType)
				if err != nil {
					return http.StatusInternalServerError, "Storing Token Id failed"
				}
				resp, err := s.cryptTokens(token, refresh)
				if err == nil {
					return http.StatusOK, resp
				} else {
					return http.StatusInternalServerError, "Token generation failed, check security provider"
				}
			} else {
				return http.StatusInternalServerError, "Token generation failed, check claims"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else if grantType == "authorization_code" {
		if codeVerifier, ok := s.verifier.(AuthorizationCodeVerifier); ok {
			user, err := codeVerifier.ValidateCode(credential, secret, code, redirectURI, req)
			if err == nil {
				token, refresh, err := s.generateTokens(user, "A", scope)
				if err == nil {
					// Store token id
					err = s.verifier.StoreTokenId(user, token.Id, refresh.RefreshTokenId, token.TokenType)
					if err != nil {
						return http.StatusInternalServerError, "Storing Token Id failed"
					}
					resp, err := s.cryptTokens(token, refresh)
					if err == nil {
						return http.StatusOK, resp
					} else {
						return http.StatusInternalServerError, "Token generation failed, check security provider"
					}
				} else {
					return http.StatusInternalServerError, "Token generation failed, check claims"
				}
			} else {
				//not autorized
				return http.StatusUnauthorized, "Not authorized"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized, grant type not supported"
		}
	} else if grantType == "refresh_token" {
		// refresh token
		refresh, err := s.provider.DecryptRefreshTokens(refreshToken)
		if err == nil {
			err = s.verifier.ValidateTokenId(refresh.Credential, refresh.TokenId, refresh.RefreshTokenId, refresh.TokenType)
			if err == nil {
				// generate new token
				token, refresh, err := s.generateTokens(refresh.Credential, refresh.TokenType, refresh.Scope)
				if err == nil {
					// Store token id
					err = s.verifier.StoreTokenId(refresh.Credential, token.Id, refresh.RefreshTokenId, token.TokenType)
					if err != nil {
						return http.StatusInternalServerError, "Storing Token Id failed"
					}
					resp, err := s.cryptTokens(token, refresh)
					if err == nil {
						return http.StatusOK, resp
					} else {
						return http.StatusInternalServerError, "Token generation failed"
					}
				} else {
					return http.StatusInternalServerError, "Token generation failed"
				}
			} else {
				//not autorized invalid token Id
				return http.StatusUnauthorized, "Not authorized invalid token"
			}
		} else {
			//not autorized
			return http.StatusUnauthorized, "Not authorized"
		}
	} else {
		// Invalid request
		return http.StatusBadRequest, "Invalid grant_type"
	}
}

func (s *OAuthBearerServer) generateTokens(username, tokenType, scope string) (token *Token, refresh *RefreshToken, err error) {
	token = &Token{Credential: username, ExperesIn: s.TokenTTL, CreationDate: time.Now().UTC(), TokenType: tokenType, Scope: scope}
	// generate token Id
	token.Id = uuid.Must(uuid.NewV4()).String()
	if s.verifier != nil {
		claims, err := s.verifier.AddClaims(username, token.Id, token.TokenType, token.Scope)
		if err == nil {
			token.Claims = claims
		} else {
			// claims error
			return nil, nil, err
		}
	}
	// create refresh token
	refresh = &RefreshToken{RefreshTokenId: uuid.Must(uuid.NewV4()).String(), TokenId: token.Id, CreationDate: time.Now().UTC(), Credential: username, TokenType: tokenType, Scope: scope}

	return token, refresh, nil
}

func (s *OAuthBearerServer) cryptTokens(token *Token, refresh *RefreshToken) (resp *TokenResponse, err error) {
	ctoken, err := s.provider.CryptToken(token)
	if err != nil {
		return nil, err
	}
	crefresh, err := s.provider.CryptRefreshToken(refresh)
	if err != nil {
		return nil, err
	}
	resp = &TokenResponse{Token: ctoken, RefreshToken: crefresh, TokenType: TOKEN_TYPE, ExperesIn: (int64)(s.TokenTTL / time.Second)}

	if s.verifier != nil {
		// add properties
		props, err := s.verifier.AddProperties(token.Credential, token.Id, token.TokenType)
		if err == nil {
			resp.Properties = props
		}
	}
	return resp, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string
var dbUrl string

var rootMetrics = map[string]string{
	"system.load.1":       "system.load.1",
	"system.load.5":       "system.load.5",
	"system.load.15":      "system.load.15",
	"system.load.norm.1":  "system.load.norm.1",
	"system.load.norm.5":  "system.load.norm.5",
	"system.load.norm.15": "system.load.norm.15",

	"cpuIdle":   "system.cpu.idle",
	"cpuUser":   "system.cpu.user",
	"cpuWait":   "system.cpu.iowait",
	"cpuSystem": "system.cpu.system",
	"cpuStolen": "system.cpu.stolen",

	"memBuffers":       "system.mem.buffered",
	"memPhysPctUsable": "system.mem.pct_usable",
	"memShared":        "system.mem.shared",
	"memPhysTotal":     "system.mem.total",
	"memPhysUsable":    "system.mem.usable",
	"memCached":        "system.mem.cached",
	"memPhysUsed":      "system.mem.used",
	"memPhysFree":      "system.mem.free",

	"memSwapFree":    "system.swap.free",
	"memSwapTotal":   "system.swap.total",
	"memSwapUsed":    "system.swap.used",
	"memSwapPctFree": "system.swap.pct_free",
}

type Metric struct {
	Name    string          `json:"name"`
	Columns []string        `json:"columns"`
	Points  [][]interface{} `json:"points"`
}

func NewMetric(host, name string, timestamp, value interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "value", "hostname"}
	points := [][]interface{}{{timestamp, value, host}}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][2] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func PushMetrics(metrics []*Metric) {
	if len(metrics) == 0 {
		return
	}
	log.Printf("Pushing %d metrics to InfluxDB", len(metrics))

	body, err := json.Marshal(metrics)
	if err != nil {
		log.Println(err)
		return
	}

	log.Println(string(body))

	resp, err := http.Post(dbUrl, "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Println(err)
	} else {
		log.Println(resp)
	}
}

func mapMetrics(data map[string]interface{}) []*Metric {
	metrics := []*Metric{}
	host := data["internalHostname"].(string)
	timestamp := data["collection_timestamp"].(float64)

	fmt.Printf("Unmapped metrics (%s):\n", host)
	for key, value := range data {
		name, ok := rootMetrics[key]
		if ok {
			metrics = append(metrics, NewMetric(host, name, uint64(timestamp), value, nil))
		} else {
			fmt.Println(key)
		}
	}
	return metrics
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	data := make(map[string]interface{})
	err = json.Unmarshal(buf.Bytes(), &data)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	metrics := mapMetrics(data)
	go PushMetrics(metrics)

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	} else {
		log.Println(buf.String())
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "STILL-ALIVE\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}
	dbUrl = os.Getenv("DB_URL")
	if len(dbUrl) == 0 {
		dbUrl = "http://localhost:8086/db/datadog/series?u=root&p=root"
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<commit_msg>Fix timestamp again<commit_after>package main

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string
var dbUrl string

var rootMetrics = map[string]string{
	"system.load.1":       "system.load.1",
	"system.load.5":       "system.load.5",
	"system.load.15":      "system.load.15",
	"system.load.norm.1":  "system.load.norm.1",
	"system.load.norm.5":  "system.load.norm.5",
	"system.load.norm.15": "system.load.norm.15",

	"cpuIdle":   "system.cpu.idle",
	"cpuUser":   "system.cpu.user",
	"cpuWait":   "system.cpu.iowait",
	"cpuSystem": "system.cpu.system",
	"cpuStolen": "system.cpu.stolen",

	"memBuffers":       "system.mem.buffered",
	"memPhysPctUsable": "system.mem.pct_usable",
	"memShared":        "system.mem.shared",
	"memPhysTotal":     "system.mem.total",
	"memPhysUsable":    "system.mem.usable",
	"memCached":        "system.mem.cached",
	"memPhysUsed":      "system.mem.used",
	"memPhysFree":      "system.mem.free",

	"memSwapFree":    "system.swap.free",
	"memSwapTotal":   "system.swap.total",
	"memSwapUsed":    "system.swap.used",
	"memSwapPctFree": "system.swap.pct_free",
}

type Metric struct {
	Name    string          `json:"name"`
	Columns []string        `json:"columns"`
	Points  [][]interface{} `json:"points"`
}

func NewMetric(host, name string, timestamp, value interface{}, tags map[string]string) *Metric {
	columns := []string{"time", "value", "hostname"}
	points := [][]interface{}{{timestamp, value, host}}
	if tags != nil {
		for k, v := range tags {
			if k == "hostname" {
				points[0][2] = v
			} else {
				columns = append(columns, k)
				points[0] = append(points[0], v)
			}
		}
	}
	return &Metric{name, columns, points}
}

func PushMetrics(metrics []*Metric) {
	if len(metrics) == 0 {
		return
	}
	log.Printf("Pushing %d metrics to InfluxDB", len(metrics))

	body, err := json.Marshal(metrics)
	if err != nil {
		log.Println(err)
		return
	}

	log.Println(string(body))

	resp, err := http.Post(dbUrl, "application/json", bytes.NewBuffer(body))
	if err != nil {
		log.Println(err)
	} else {
		log.Println(resp)
	}
}

func mapMetrics(data map[string]interface{}) []*Metric {
	metrics := []*Metric{}
	host := data["internalHostname"].(string)
	timestamp := data["collection_timestamp"].(float64)

	fmt.Printf("Unmapped metrics (%s):\n", host)
	for key, value := range data {
		name, ok := rootMetrics[key]
		if ok {
			metrics = append(metrics, NewMetric(host, name, uint64(timestamp*1000), value, nil))
		} else {
			fmt.Println(key)
		}
	}
	return metrics
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	data := make(map[string]interface{})
	err = json.Unmarshal(buf.Bytes(), &data)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	metrics := mapMetrics(data)
	go PushMetrics(metrics)

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	log.Println(req.Method, req.URL.Path)

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	} else {
		log.Println(buf.String())
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "STILL-ALIVE\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}
	dbUrl = os.Getenv("DB_URL")
	if len(dbUrl) == 0 {
		dbUrl = "http://localhost:8086/db/datadog/series?u=root&p=root"
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<|endoftext|>


<commit_before>// Copyright 2015 The httpserver 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 httpserver

import (
	"fmt"
	"net/http"
	"text/template"

	"github.com/gorilla/mux"
)

const (
	SkipCheckHttpMethod = ""
	GetMethod           = "GET"
	PutMethod           = "PUT"
	PostMethod          = "POST"
	DeleteMethod        = "DELETE"
)

type HttpServer struct {
	port             string
	address          string
	errTemplate      *template.Template
	notFoundTemplate *template.Template
	router           *mux.Router
}

func NewHttpServer(a string, p string) *HttpServer {
	r := mux.NewRouter()
	s := &HttpServer{router: r, address: a, port: p}
	return s
}

func (s *HttpServer) SetErrTemplate(t *template.Template) {
	s.errTemplate = t
}

func (s *HttpServer) SetNotFoundTemplate(t *template.Template) {
	s.notFoundTemplate = t
}

func (s *HttpServer) errorHandler(route *Route) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if recoverErr := recover(); recoverErr != nil {
				error := NewError(fmt.Sprintf("\"%v\"", recoverErr))
				w.WriteHeader(500)
				if s.errTemplate != nil {
					s.errTemplate.Execute(w, error)
				} else {
					fmt.Fprintf(w, fmt.Sprintf("\"%v\"", recoverErr))
				}
			}
		}()
		if route.HasIncorrectHttpMethod(r.Method) {
			http.Error(w, "Method not allowed", 405)
			return
		}
		route.HandleFunc(w, r)
	}
}
func (s *HttpServer) NotFound(w http.ResponseWriter, r *http.Request) {

	w.WriteHeader(404)
	if s.notFoundTemplate != nil {
		s.notFoundTemplate.Execute(w, nil)
	} else {
		fmt.Fprintf(w, "Not found")
	}

}

func (s *HttpServer) DeployAtBase(h RouteHandler) {
	s.Deploy("", h)
}

func (s *HttpServer) Deploy(context string, h RouteHandler) {
	routes := h.GetRoutes()
	for _, r := range routes {
		s.router.HandleFunc(fmt.Sprintf("%s/%s", context, r.Path), s.errorHandler(r))
	}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	http.Handle("/", s.router)
	s.router.NotFoundHandler = http.HandlerFunc(s.NotFound)
}

func (s *HttpServer) Start() error {
	return http.ListenAndServe(fmt.Sprintf("%s:%s", s.address, s.port), nil)
}
<commit_msg>refactoring<commit_after>// Copyright 2015 The httpserver 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 httpserver

import (
	"fmt"
	"net/http"
	"text/template"

	"github.com/gorilla/mux"
)

const (
	SkipCheckHttpMethod = ""
	GetMethod           = "GET"
	PutMethod           = "PUT"
	PostMethod          = "POST"
	DeleteMethod        = "DELETE"
)

type HttpServer struct {
	port             string
	address          string
	errTemplate      *template.Template
	notFoundTemplate *template.Template
	router           *mux.Router
}

func NewHttpServer(a string, p string) *HttpServer {
	r := mux.NewRouter()
	s := &HttpServer{router: r, address: a, port: p}
	return s
}

func (s *HttpServer) SetErrTemplate(t *template.Template) {
	s.errTemplate = t
}

func (s *HttpServer) SetNotFoundTemplate(t *template.Template) {
	s.notFoundTemplate = t
}

func (s *HttpServer) errorHandler(route *httpserver.Route) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if recoverErr := recover(); recoverErr != nil {
				error := NewError(fmt.Sprintf("\"%v\"", recoverErr))
				w.WriteHeader(500)
				if s.errTemplate != nil {
					s.errTemplate.Execute(w, error)
				} else {
					fmt.Fprintf(w, fmt.Sprintf("\"%v\"", recoverErr))
				}
			}
		}()
		if route.HasIncorrectHttpMethod(r.Method) {
			http.Error(w, "Method not allowed", 405)
			return
		}
		route.HandleFunc(w, r)
	}
}
func (s *HttpServer) NotFound(w http.ResponseWriter, r *http.Request) {

	w.WriteHeader(404)
	if s.notFoundTemplate != nil {
		s.notFoundTemplate.Execute(w, nil)
	} else {
		fmt.Fprintf(w, "Not found")
	}

}

func (s *HttpServer) DeployAtBase(h RouteHandler) {
	s.Deploy("", h)
}

func (s *HttpServer) Deploy(context string, h RouteHandler) {
	routes := h.GetRoutes()
	for _, r := range routes {
		s.router.HandleFunc(fmt.Sprintf("%s/%s", context, r.Path), s.errorHandler(r))
	}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	http.Handle("/", s.router)
	s.router.NotFoundHandler = http.HandlerFunc(s.NotFound)
}

func (s *HttpServer) Start() error {
	return http.ListenAndServe(fmt.Sprintf("%s:%s", s.address, s.port), nil)
}
<|endoftext|>


<commit_before>package dsunit

import (
	"fmt"
	"log"
	"net/http"
	"github.com/viant/toolbox"
)

var version = "/v1/"
var initURI = version + "init"
var executeURI = version + "execute"
var prepareURI = version + "prepare"
var expectURI = version + "expect"

var errorHandler = func(router *toolbox.ServiceRouter, responseWriter http.ResponseWriter, httpRequest *http.Request, message string) {

	responseWriter.WriteHeader(http.StatusInternalServerError)
	responseWriter.Header().Set("Error", message)
	err := router.WriteResponse(toolbox.NewJSONEncoderFactory(), &Response{Status: "error", Message: message}, httpRequest, responseWriter)
	if err != nil {
		log.Fatalf("Failed to write response :%v", err)
	}
}

//StartServer start dsunit server
func StartServer(port string) {
	var service = NewServiceLocal("")
	serviceRouter := toolbox.NewServiceRouter(
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        initURI,
			Handler:    service.Init,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        executeURI,
			Handler:    service.ExecuteScripts,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        prepareURI,
			Handler:    service.PrepareDatastore,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        expectURI,
			Handler:    service.ExpectDatasets,
			Parameters: []string{"request"},
		},
	)

	http.HandleFunc("/", func(responseWriter http.ResponseWriter, httpRequest *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				errorHandler(serviceRouter, responseWriter, httpRequest, fmt.Sprintf("%v", err))
			}
		}()
		err := serviceRouter.Route(responseWriter, httpRequest)
		if err != nil {
			errorHandler(serviceRouter, responseWriter, httpRequest, fmt.Sprintf("%v", err))
		}
	})

	fmt.Printf("Started dsunit server on port %v\n", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<commit_msg>patch error handling with json<commit_after>package dsunit

import (
	"fmt"
	"log"
	"net/http"
	"github.com/viant/toolbox"
)

var version = "/v1/"
var initURI = version + "init"
var executeURI = version + "execute"
var prepareURI = version + "prepare"
var expectURI = version + "expect"

var errorHandler = func(router *toolbox.ServiceRouter, responseWriter http.ResponseWriter, httpRequest *http.Request, message string) {
	err := router.WriteResponse(toolbox.NewJSONEncoderFactory(), &Response{Status: "error", Message: message}, httpRequest, responseWriter)
	if err != nil {
		log.Fatalf("Failed to write response :%v", err)
	}
}

//StartServer start dsunit server
func StartServer(port string) {
	var service = NewServiceLocal("")
	serviceRouter := toolbox.NewServiceRouter(
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        initURI,
			Handler:    service.Init,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        executeURI,
			Handler:    service.ExecuteScripts,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        prepareURI,
			Handler:    service.PrepareDatastore,
			Parameters: []string{"request"},
		},
		toolbox.ServiceRouting{
			HTTPMethod: "POST",
			URI:        expectURI,
			Handler:    service.ExpectDatasets,
			Parameters: []string{"request"},
		},
	)

	http.HandleFunc("/", func(responseWriter http.ResponseWriter, httpRequest *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				errorHandler(serviceRouter, responseWriter, httpRequest, fmt.Sprintf("%v", err))
			}
		}()
		err := serviceRouter.Route(responseWriter, httpRequest)
		if err != nil {
			errorHandler(serviceRouter, responseWriter, httpRequest, fmt.Sprintf("%v", err))
		}
	})

	fmt.Printf("Started dsunit server on port %v\n", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gorilla/websocket"
	"fmt"
	"net"
	"net/http"
	"time"
	"sync"
	"html"
	"strconv"
)

//############ CHATROOM TYPE AND METHODS

type ChatRoom struct {
	clients map[int]Client
	clientsMtx sync.Mutex
	queue   chan string
	curId   int
}

//initializing the chatroom
func (cr *ChatRoom) Init() {
	// fmt.Println("Chatroom init")
	cr.queue = make(chan string, 5)
	cr.clients = make(map[int]Client)

	//the "heartbeat" for broadcasting messages
	go func() {
		for {
			cr.BroadCast()
			time.Sleep(100 * time.Millisecond)
		}
	}()
}

//registering a new client
//returns pointer to a Client, or Nil, if the name is already taken
func (cr *ChatRoom) Join(conn *websocket.Conn) *Client {
	defer cr.clientsMtx.Unlock();

	cr.clientsMtx.Lock(); //preventing simultaneous access to the `clients` map
	cr.curId = cr.curId + 1
	id := cr.curId
	client := Client{
	        id:        id,
		conn:      conn,
		belongsTo: cr,
	}
	cr.clients[id] = client

	cr.AddMsg("
anon" + " has joined the chat. (" +
	strconv.Itoa(len(cr.clients)) + " anons in the chat)
")
	return &client
}

//leaving the chatroom
func (cr *ChatRoom) Leave(cl *Client) {
	cr.clientsMtx.Lock(); //preventing simultaneous access to the `clients` map
	delete(cr.clients, cl.id)
	cr.clientsMtx.Unlock();
	cr.AddMsg("
anon" + " has left the chat.
")
}

//adding message to queue
func (cr *ChatRoom) AddMsg(msg string) {
	cr.queue <- msg
}

//broadcasting all the messages in the queue in one block
func (cr *ChatRoom) BroadCast() {
	msgBlock := ""
infLoop:
	for {
		select {
		case m := <-cr.queue:
			msgBlock += m
		default:
			break infLoop
		}
	}
	if len(msgBlock) > 0 {
		for _, client := range cr.clients {
			client.Send(msgBlock)
		}
	}
}

//################CLIENT TYPE AND METHODS

type Client struct {
	id        int
	conn      *websocket.Conn
	belongsTo *ChatRoom
}

//Client has a new message to broadcast
func (cl *Client) NewMsg(msg string) {
	if len(msg) > 0 {
		cl.belongsTo.AddMsg("
anon" + ": " + html.EscapeString(msg) + "
")
	}
}

//Exiting out
func (cl *Client) Exit() {
	cl.belongsTo.Leave(cl)
}

//Sending message block to the client
func (cl *Client) Send(msgs string) {
	cl.conn.WriteMessage(websocket.TextMessage, []byte(msgs))
}

//global variable for handling all chat traffic
var chat ChatRoom

//##############SERVING STATIC FILES
func staticFiles(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./static/"+r.URL.Path)
}

//##############HANDLING THE WEBSOCKET
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true }, //not checking origin
}

//this is also the handler for joining to the chat
func wsHandler(w http.ResponseWriter, r *http.Request) {
	oldMsg := ""

	conn, err := upgrader.Upgrade(w, r, nil)

	if err != nil {
		fmt.Println("Error upgrading to websocket:", err)
		return
	}
	go func() {
		client := chat.Join(  conn)
		if client == nil || err != nil {
			conn.Close() //closing connection to indicate failed Join
			return
		}

		//then watch for incoming messages
		for {
			_, msg, err := conn.ReadMessage()
			if err != nil { //if error then assuming that the connection is closed
				client.Exit()
				return
			}
			if (string(msg) != oldMsg){
				client.NewMsg(string(msg))
			}
			oldMsg = string(msg)
		}

	}()
}

//Printing out the various ways the server can be reached by the clients
func printClientConnInfo() {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		fmt.Println("Oops: " + err.Error())
		return
	}

	fmt.Println("Chat clients can connect at the following addresses:\n")

	for _, a := range addrs {
		if a.String() != "0.0.0.0" {
			fmt.Println("http://" + a.String() + ":8000/chat.html\n")
		}
	}
}

//#############MAIN FUNCTION and INITIALIZATIONS

func main() {
	printClientConnInfo()
	http.HandleFunc("/ws", wsHandler)
	http.HandleFunc("/", staticFiles)
	chat.Init()
	//err := http.ListenAndServe(":8000", nil) //uncomment if you don't have a tls certificate
	err := http.ListenAndServeTLS(":8000", "cert.pem", "key.pem", nil)
	fmt.Println(err)
}
<commit_msg>Moved format-related features to a single function<commit_after>package main

import (
	"github.com/gorilla/websocket"
	"fmt"
	"net"
	"net/http"
	"time"
	"sync"
	"html"
	"strconv"
)

//############ CHATROOM TYPE AND METHODS

type ChatRoom struct {
	clients map[int]Client
	clientsMtx sync.Mutex
	queue   chan string
	curId   int
}

//initializing the chatroom
func (cr *ChatRoom) Init() {
	// fmt.Println("Chatroom init")
	cr.queue = make(chan string, 5)
	cr.clients = make(map[int]Client)

	//the "heartbeat" for broadcasting messages
	go func() {
		for {
			cr.BroadCast()
			time.Sleep(100 * time.Millisecond)
		}
	}()
}

//registering a new client
//returns pointer to a Client, or Nil, if the name is already taken
func (cr *ChatRoom) Join(conn *websocket.Conn) *Client {
	defer cr.clientsMtx.Unlock();

	cr.clientsMtx.Lock(); //preventing simultaneous access to the `clients` map
	cr.curId = cr.curId + 1
	id := cr.curId
	client := Client{
	        id:        id,
		conn:      conn,
		belongsTo: cr,
	}
	cr.clients[id] = client

	cr.AddMsg(" has joined the chat. (" +
		     strconv.Itoa(len(cr.clients)) + " anons in the chat)", true)
	return &client
}

//leaving the chatroom
func (cr *ChatRoom) Leave(cl *Client) {
	cr.clientsMtx.Lock(); //preventing simultaneous access to the `clients` map
	delete(cr.clients, cl.id)
	cr.clientsMtx.Unlock();
    cr.AddMsg(" has left the chat.", true)
}

//formating a message
func FormatMsg(msg string, sys bool) string {
    format := "
%s%s
"

    if (sys) { //If the message is a system message (join, leave, etc.)
	format = fmt.Sprintf(format, "anon", "%s")
    } else {
	format = fmt.Sprintf(format, "anon:", "%s")
    }

    return fmt.Sprintf(format, msg)
}

//formating and adding message to queue
func (cr *ChatRoom) AddMsg(msg string, sys bool) {
    cr.queue <- FormatMsg(msg, sys)
}

//broadcasting all the messages in the queue in one block
func (cr *ChatRoom) BroadCast() {
	msgBlock := ""
infLoop:
	for {
		select {
		case m := <-cr.queue:
			msgBlock += m
		default:
			break infLoop
		}
	}
	if len(msgBlock) > 0 {
		for _, client := range cr.clients {
			client.Send(msgBlock)
		}
	}
}

//################CLIENT TYPE AND METHODS

type Client struct {
	id        int
	conn      *websocket.Conn
	belongsTo *ChatRoom
}

//Client has a new message to broadcast
func (cl *Client) NewMsg(msg string) {
	if len(msg) > 0 {
	    cl.belongsTo.AddMsg(html.EscapeString(msg), false)
	}
}

//Exiting out
func (cl *Client) Exit() {
	cl.belongsTo.Leave(cl)
}

//Sending message block to the client
func (cl *Client) Send(msgs string) {
	cl.conn.WriteMessage(websocket.TextMessage, []byte(msgs))
}

//global variable for handling all chat traffic
var chat ChatRoom

//##############SERVING STATIC FILES
func staticFiles(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./static/"+r.URL.Path)
}

//##############HANDLING THE WEBSOCKET
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true }, //not checking origin
}

//this is also the handler for joining to the chat
func wsHandler(w http.ResponseWriter, r *http.Request) {
	oldMsg := ""

	conn, err := upgrader.Upgrade(w, r, nil)

	if err != nil {
		fmt.Println("Error upgrading to websocket:", err)
		return
	}
	go func() {
		client := chat.Join(  conn)
		if client == nil || err != nil {
			conn.Close() //closing connection to indicate failed Join
			return
		}

		//then watch for incoming messages
		for {
			_, msg, err := conn.ReadMessage()
			if err != nil { //if error then assuming that the connection is closed
				client.Exit()
				return
			}
			if (string(msg) != oldMsg){
				client.NewMsg(string(msg))
			}
			oldMsg = string(msg)
		}

	}()
}

//Printing out the various ways the server can be reached by the clients
func printClientConnInfo() {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		fmt.Println("Oops: " + err.Error())
		return
	}

	fmt.Println("Chat clients can connect at the following addresses:\n")

	for _, a := range addrs {
		if a.String() != "0.0.0.0" {
			fmt.Println("http://" + a.String() + ":8000/chat.html\n")
		}
	}
}

//#############MAIN FUNCTION and INITIALIZATIONS

func main() {
	printClientConnInfo()
	http.HandleFunc("/ws", wsHandler)
	http.HandleFunc("/", staticFiles)
	chat.Init()
	//err := http.ListenAndServe(":8000", nil) //uncomment if you don't have a tls certificate
	err := http.ListenAndServeTLS(":8000", "cert.pem", "key.pem", nil)
	fmt.Println(err)
}
<|endoftext|>