<commit_before>package kafka_httpcat

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"time"
)

type HTTPSender struct {
	hosts             []string
	contextPath       string
	method            string
	parsedContextPath *url.URL
	headers           map[string][]string
	currentHost       int
	expectedRespCodes map[int]bool

	client *http.Client
}

func NewHTTPSender(hosts []string, contextPath string, method string, headers map[string][]string, expectedRespCodes []int) *HTTPSender {
	//Random host
	if len(hosts) == 0 {
		log.Fatal("Need at least one host defined.")
	}
	cur := rand.Int() % len(hosts)
	if u, err := url.Parse(contextPath); err != nil {
		log.Fatalf("Unable to parse context path: %s", err)
		return nil
	} else {
		u.Scheme = "http"
		respMap := make(map[int]bool)
		for _, expectedRespCode := range expectedRespCodes {
			respMap[expectedRespCode] = true
		}

		return &HTTPSender{hosts: hosts, contextPath: contextPath, method: method, headers: headers,
			parsedContextPath: u, expectedRespCodes: respMap, currentHost: cur, client: &http.Client{Timeout: time.Duration(2 * time.Second)}}
	}
}

func (h *HTTPSender) buildBaseRequest(contextPath string, method string, headers map[string][]string, bodyReader *bytes.Reader) *http.Request {
	var req http.Request
	req.Method = h.method
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	req.Close = false
	req.Header = h.headers
	req.URL = h.parsedContextPath
	req.URL.Host = h.hosts[h.currentHost]
	req.Body = ioutil.NopCloser(bodyReader)
	req.ContentLength = int64(bodyReader.Len())
	return &req
}

func (h *HTTPSender) send(bodyReader *bytes.Reader) error {
	req := h.buildBaseRequest(h.contextPath, h.method, h.headers, bodyReader)
	//io.Copy(os.Stdout, req.Body)

	if resp, err := h.client.Do(req); err != nil {
		log.Printf("Not sent!: %s", err)
		return err
	} else {
		defer resp.Body.Close()
		if _, ok := h.expectedRespCodes[resp.StatusCode]; !ok {
			msg, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return fmt.Errorf("Unexpected http code: %d", resp.StatusCode)
			} else {
				return fmt.Errorf("Unexpected http code: %d. %s", string(msg))
			}
		}
	}

	return nil
}

func (h *HTTPSender) RRSend(body []byte) error {
	retries := 0

	for {
		bodyReader := bytes.NewReader(body)
		if err := h.send(bodyReader); err != nil {
			log.Printf("Backing off sending: %s", err)
			return nil
			//Round robin
			h.currentHost = (h.currentHost + 1) % len(h.hosts)

			retries++

			if retries < 10 {
				time.Sleep(100 * time.Millisecond)
			} else {
				log.Printf("Backing off sending: %s", err)
				log.Printf("%s\n", string(body))
				time.Sleep(time.Second)
			}
		} else {
			return nil
		}
	}
}
<commit_msg>higher timeout<commit_after>package kafka_httpcat

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"time"
)

type HTTPSender struct {
	hosts             []string
	contextPath       string
	method            string
	parsedContextPath *url.URL
	headers           map[string][]string
	currentHost       int
	expectedRespCodes map[int]bool

	client *http.Client
}

func NewHTTPSender(hosts []string, contextPath string, method string, headers map[string][]string, expectedRespCodes []int) *HTTPSender {
	//Random host
	if len(hosts) == 0 {
		log.Fatal("Need at least one host defined.")
	}
	cur := rand.Int() % len(hosts)
	if u, err := url.Parse(contextPath); err != nil {
		log.Fatalf("Unable to parse context path: %s", err)
		return nil
	} else {
		u.Scheme = "http"
		respMap := make(map[int]bool)
		for _, expectedRespCode := range expectedRespCodes {
			respMap[expectedRespCode] = true
		}

		return &HTTPSender{hosts: hosts, contextPath: contextPath, method: method, headers: headers,
			parsedContextPath: u, expectedRespCodes: respMap, currentHost: cur, client: &http.Client{Timeout: time.Duration(15 * time.Second)}}
	}
}

func (h *HTTPSender) buildBaseRequest(contextPath string, method string, headers map[string][]string, bodyReader *bytes.Reader) *http.Request {
	var req http.Request
	req.Method = h.method
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	req.Close = false
	req.Header = h.headers
	req.URL = h.parsedContextPath
	req.URL.Host = h.hosts[h.currentHost]
	req.Body = ioutil.NopCloser(bodyReader)
	req.ContentLength = int64(bodyReader.Len())
	return &req
}

func (h *HTTPSender) send(bodyReader *bytes.Reader) error {
	req := h.buildBaseRequest(h.contextPath, h.method, h.headers, bodyReader)
	//io.Copy(os.Stdout, req.Body)

	if resp, err := h.client.Do(req); err != nil {
		log.Printf("Not sent!: %s", err)
		return err
	} else {
		defer resp.Body.Close()
		if _, ok := h.expectedRespCodes[resp.StatusCode]; !ok {
			msg, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return fmt.Errorf("Unexpected http code: %d", resp.StatusCode)
			} else {
				return fmt.Errorf("Unexpected http code: %d. %s", string(msg))
			}
		}
	}

	return nil
}

func (h *HTTPSender) RRSend(body []byte) error {
	retries := 0

	for {
		bodyReader := bytes.NewReader(body)
		if err := h.send(bodyReader); err != nil {
			log.Printf("Backing off sending: %s", err)
			return nil
			//Round robin
			h.currentHost = (h.currentHost + 1) % len(h.hosts)

			retries++

			if retries < 10 {
				time.Sleep(100 * time.Millisecond)
			} else {
				log.Printf("Backing off sending: %s", err)
				log.Printf("%s\n", string(body))
				time.Sleep(time.Second)
			}
		} else {
			return nil
		}
	}
}
<|endoftext|>


<commit_before>/* Principals functions */

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

package main

import (
	"net/http"
	"encoding/json"
	"github.com/ctdk/goiardi/actor"
)

func principal_handler(w http.ResponseWriter, r *http.Request){
	w.Header().Set("Content-Type", "application/json")
	principal_name := r.URL.Path[11:]
	switch r.Method {
		case "GET":
			chef_actor, err := actor.Get(principal_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			json_principal := map[string]interface{}{
				"name": chef_actor.Name,
				"type": chef_actor.ChefType,
				"public_key": chef_actor.PublicKey,
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_principal); err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		default:
			JsonErrorReport(w, r, "Unrecognized method for principals!", http.StatusMethodNotAllowed)
	}
}
<commit_msg>/principals, not /principal.<commit_after>/* Principals functions */

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

package main

import (
	"net/http"
	"encoding/json"
	"github.com/ctdk/goiardi/actor"
)

func principal_handler(w http.ResponseWriter, r *http.Request){
	w.Header().Set("Content-Type", "application/json")
	principal_name := r.URL.Path[12:]
	switch r.Method {
		case "GET":
			chef_actor, err := actor.Get(principal_name)
			if err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusNotFound)
				return
			}
			json_principal := map[string]interface{}{
				"name": chef_actor.Name,
				"type": chef_actor.ChefType,
				"public_key": chef_actor.PublicKey,
			}
			enc := json.NewEncoder(w)
			if err = enc.Encode(&json_principal); err != nil {
				JsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
				return
			}
		default:
			JsonErrorReport(w, r, "Unrecognized method for principals!", http.StatusMethodNotAllowed)
	}
}
<|endoftext|>


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

// Package filevar provides a runtimevar.Driver implementation that reads
// variables from local files.
//
// User can update a configuration file using any commands (cp, mv) or tools/editors. This package
// does not guarantee read consistency since it does not have control over the writes. It is highly
// advisable to use this package only for local development or testing purposes and not in
// production applications/services.
//
// Known Issues:
//
// * On Mac OSX, if user copies an empty file into a configuration file, Watch will not be able to
// detect the change since event.Op is Chmod only.
//
// * Saving a configuration file in vim using :w will incur events Rename and Create. When the
// Rename event occurs, the file is temporarily removed and hence Watch will return error.  A
// follow-up Watch call will then detect the Create event.
package filevar

import (
	"bytes"
	"context"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/google/go-cloud/runtimevar"
	"github.com/google/go-cloud/runtimevar/driver"

	"github.com/fsnotify/fsnotify"
)

// New constructs a runtimevar.Variable object with this package as the driver
// implementation.  The decoder argument allows users to dictate the decoding function to parse the
// file as well as the type to unmarshal into.
func New(file string, decoder *runtimevar.Decoder, opts *Options) (*runtimevar.Variable, error) {
	w, err := newWatcher(file, decoder, opts)
	if err != nil {
		return nil, err
	}
	return runtimevar.New(w), nil
}

func newWatcher(file string, decoder *runtimevar.Decoder, opts *Options) (*watcher, error) {
	if opts == nil {
		opts = &Options{}
	}

	// Use absolute file path.
	file, err := filepath.Abs(file)
	if err != nil {
		return nil, err
	}

	// Construct a fsnotify.Watcher.
	notifier, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	// Create a ctx for the background goroutine that does all of the reading.
	// The cancel function will be used to shut it down during Close, with the
	// result being passed back via closeCh.
	ctx, cancel := context.WithCancel(context.Background())
	w := &watcher{
		// See struct comments for why it's buffered.
		ch:       make(chan *state, 1),
		closeCh:  make(chan error),
		shutdown: cancel,
	}
	go w.watch(ctx, notifier, file, decoder, driver.WaitDuration(opts.WaitDuration))
	return w, nil
}

// state implements driver.State.
type state struct {
	val        interface{}
	updateTime time.Time
	raw        []byte
	err        error
}

func (s *state) Value() (interface{}, error) {
	return s.val, s.err
}

func (s *state) UpdateTime() time.Time {
	return s.updateTime
}

// watcher implements driver.Watcher for configurations stored in files.
type watcher struct {
	// The background goroutine writes new *state values to ch.
	// It is buffered so that the background goroutine can write without
	// blocking; it always drains the buffer before writing so that the latest
	// write is buffered. If writes could block, the background goroutine could be
	// blocked indefinitely from reading fsnotify events.
	ch chan *state
	// closeCh is used to return any errors from closing the notifier
	// back to watcher.Close.
	closeCh chan error
	// shutdown tells the background goroutine to exit.
	shutdown func()
}

// WatchVariable implements driver.WatchVariable.
func (w *watcher) WatchVariable(ctx context.Context, _ driver.State) (driver.State, time.Duration) {
	select {
	case <-ctx.Done():
		return &state{err: ctx.Err()}, 0
	case cur := <-w.ch:
		return cur, 0
	}
}

// updateState checks to see if s and prev both represent the same error.
// If not, it drains any previous state buffered in w.ch, then writes s to it.
// It always return s.
func (w *watcher) updateState(s, prev *state) *state {
	if s.err != nil && prev != nil && prev.err != nil && (s.err == prev.err || (os.IsNotExist(s.err) && os.IsNotExist(prev.err))) {
		// s represents the same error as prev.
		return s
	}
	// Drain any buffered value on ch; it is now stale.
	select {
	case <-w.ch:
	default:
	}
	// This write can't block, since we're the only writer, ch has a buffer
	// size of 1, and we just read anything that was buffered.
	w.ch <- s
	return s
}

// watch is run by a background goroutine.
// It watches file using notifier, and writes new states to w.ch.
// If it can't read or watch the file, it re-checks every wait.
// It exits when ctx is canceled, and writes any shutdown errors (or
// nil if there weren't any) to w.closeCh.
func (w *watcher) watch(ctx context.Context, notifier *fsnotify.Watcher, file string, decoder *runtimevar.Decoder, wait time.Duration) {
	// addedToNotifier is true iff file has been added to the notifier.
	addedToNotifier := false
	var cur *state

	for {
		// If the current state is an error, pause between attempts
		// to avoid spin loops. In particular, this happens when the file
		// doesn't exist.
		if cur != nil && cur.err != nil {
			select {
			case <-ctx.Done():
				w.closeCh <- notifier.Close()
				return
			case <-time.After(wait):
			}
		}

		// If needed, add the file to the notifier to be watched.
		if !addedToNotifier {
			if err := notifier.Add(file); err != nil {
				// File probably does not exist. Try again later.
				cur = w.updateState(&state{err: err}, cur)
				continue
			}
			addedToNotifier = true
		}

		// Read the file.
		b, err := ioutil.ReadFile(file)
		if err != nil {
			cur = w.updateState(&state{err: err}, cur)
			// It's likely that the file was deleted. fsnotifier
			// stops watching a deleted file, so we'll need to
			// re-add the file once it exists again.
			notifier.Remove(file)
			addedToNotifier = false
			continue
		}

		// If it's a new value, decode and return it.
		if cur == nil || cur.err != nil || !bytes.Equal(cur.raw, b) {
			if val, err := decoder.Decode(b); err != nil {
				cur = w.updateState(&state{err: err}, cur)
			} else {
				cur = w.updateState(&state{val: val, updateTime: time.Now(), raw: b}, cur)
			}
		}

		// Block until notifier tells us something relevant changed.
		wait := true
		for wait {
			select {
			case <-ctx.Done():
				w.closeCh <- notifier.Close()
				return

			case event := <-notifier.Events:
				if event.Name != file {
					continue
				}
				// Ignore if not one of the following operations.
				if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Remove|fsnotify.Rename) == 0 {
					continue
				}
				wait = false

			case err := <-notifier.Errors:
				cur = w.updateState(&state{err: err}, cur)
			}
		}
	}
}

// Options sets options.
type Options struct {
	// WaitDuration controls the frequency of retries after an error. For example,
	// if the file does not exist. Defaults to 30 seconds.
	WaitDuration time.Duration
}

// Close implements driver.WatchVariable.
func (w *watcher) Close() error {
	// Tell the background goroutine to shut down by canceling its ctx.
	w.shutdown()
	// Wait for it to return the result of closing the notifier.
	err := <-w.closeCh
	// Cleanup our channels.
	close(w.ch)
	close(w.closeCh)
	return err
}
<commit_msg>runtimevar/filevar: always add files to the notifier after errors<commit_after>// Copyright 2018 The Go Cloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package filevar provides a runtimevar.Driver implementation that reads
// variables from local files.
//
// User can update a configuration file using any commands (cp, mv) or tools/editors. This package
// does not guarantee read consistency since it does not have control over the writes. It is highly
// advisable to use this package only for local development or testing purposes and not in
// production applications/services.
//
// Known Issues:
//
// * On Mac OSX, if user copies an empty file into a configuration file, Watch will not be able to
// detect the change since event.Op is Chmod only.
//
// * Saving a configuration file in vim using :w will incur events Rename and Create. When the
// Rename event occurs, the file is temporarily removed and hence Watch will return error.  A
// follow-up Watch call will then detect the Create event.
package filevar

import (
	"bytes"
	"context"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/google/go-cloud/runtimevar"
	"github.com/google/go-cloud/runtimevar/driver"

	"github.com/fsnotify/fsnotify"
)

// New constructs a runtimevar.Variable object with this package as the driver
// implementation.  The decoder argument allows users to dictate the decoding function to parse the
// file as well as the type to unmarshal into.
func New(file string, decoder *runtimevar.Decoder, opts *Options) (*runtimevar.Variable, error) {
	w, err := newWatcher(file, decoder, opts)
	if err != nil {
		return nil, err
	}
	return runtimevar.New(w), nil
}

func newWatcher(file string, decoder *runtimevar.Decoder, opts *Options) (*watcher, error) {
	if opts == nil {
		opts = &Options{}
	}

	// Use absolute file path.
	file, err := filepath.Abs(file)
	if err != nil {
		return nil, err
	}

	// Construct a fsnotify.Watcher.
	notifier, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	// Create a ctx for the background goroutine that does all of the reading.
	// The cancel function will be used to shut it down during Close, with the
	// result being passed back via closeCh.
	ctx, cancel := context.WithCancel(context.Background())
	w := &watcher{
		// See struct comments for why it's buffered.
		ch:       make(chan *state, 1),
		closeCh:  make(chan error),
		shutdown: cancel,
	}
	go w.watch(ctx, notifier, file, decoder, driver.WaitDuration(opts.WaitDuration))
	return w, nil
}

// state implements driver.State.
type state struct {
	val        interface{}
	updateTime time.Time
	raw        []byte
	err        error
}

func (s *state) Value() (interface{}, error) {
	return s.val, s.err
}

func (s *state) UpdateTime() time.Time {
	return s.updateTime
}

// watcher implements driver.Watcher for configurations stored in files.
type watcher struct {
	// The background goroutine writes new *state values to ch.
	// It is buffered so that the background goroutine can write without
	// blocking; it always drains the buffer before writing so that the latest
	// write is buffered. If writes could block, the background goroutine could be
	// blocked indefinitely from reading fsnotify events.
	ch chan *state
	// closeCh is used to return any errors from closing the notifier
	// back to watcher.Close.
	closeCh chan error
	// shutdown tells the background goroutine to exit.
	shutdown func()
}

// WatchVariable implements driver.WatchVariable.
func (w *watcher) WatchVariable(ctx context.Context, _ driver.State) (driver.State, time.Duration) {
	select {
	case <-ctx.Done():
		return &state{err: ctx.Err()}, 0
	case cur := <-w.ch:
		return cur, 0
	}
}

// updateState checks to see if s and prev both represent the same error.
// If not, it drains any previous state buffered in w.ch, then writes s to it.
// It always return s.
func (w *watcher) updateState(s, prev *state) *state {
	if s.err != nil && prev != nil && prev.err != nil && (s.err == prev.err || (os.IsNotExist(s.err) && os.IsNotExist(prev.err))) {
		// s represents the same error as prev.
		return s
	}
	// Drain any buffered value on ch; it is now stale.
	select {
	case <-w.ch:
	default:
	}
	// This write can't block, since we're the only writer, ch has a buffer
	// size of 1, and we just read anything that was buffered.
	w.ch <- s
	return s
}

// watch is run by a background goroutine.
// It watches file using notifier, and writes new states to w.ch.
// If it can't read or watch the file, it re-checks every wait.
// It exits when ctx is canceled, and writes any shutdown errors (or
// nil if there weren't any) to w.closeCh.
func (w *watcher) watch(ctx context.Context, notifier *fsnotify.Watcher, file string, decoder *runtimevar.Decoder, wait time.Duration) {
	var cur *state

	for {
		// If the current state is an error, pause between attempts
		// to avoid spin loops. In particular, this happens when the file
		// doesn't exist.
		if cur != nil && cur.err != nil {
			select {
			case <-ctx.Done():
				w.closeCh <- notifier.Close()
				return
			case <-time.After(wait):
			}
		}

		// Add the file to the notifier to be watched. It's fine to be
		// added multiple times, and fsnotifier is a bit flaky about when
		// it's needed during renames, so just always try.
		if err := notifier.Add(file); err != nil {
			// File probably does not exist. Try again later.
			cur = w.updateState(&state{err: err}, cur)
			continue
		}

		// Read the file.
		b, err := ioutil.ReadFile(file)
		if err != nil {
			// It's likely that the file was deleted.
			cur = w.updateState(&state{err: err}, cur)
			continue
		}

		// If it's a new value, decode and return it.
		if cur == nil || cur.err != nil || !bytes.Equal(cur.raw, b) {
			if val, err := decoder.Decode(b); err != nil {
				cur = w.updateState(&state{err: err}, cur)
			} else {
				cur = w.updateState(&state{val: val, updateTime: time.Now(), raw: b}, cur)
			}
		}

		// Block until notifier tells us something relevant changed.
		wait := true
		for wait {
			select {
			case <-ctx.Done():
				w.closeCh <- notifier.Close()
				return

			case event := <-notifier.Events:
				if event.Name != file {
					continue
				}
				// Ignore if not one of the following operations.
				if event.Op&(fsnotify.Create|fsnotify.Write|fsnotify.Remove|fsnotify.Rename) == 0 {
					continue
				}
				wait = false

			case err := <-notifier.Errors:
				cur = w.updateState(&state{err: err}, cur)
			}
		}
	}
}

// Options sets options.
type Options struct {
	// WaitDuration controls the frequency of retries after an error. For example,
	// if the file does not exist. Defaults to 30 seconds.
	WaitDuration time.Duration
}

// Close implements driver.WatchVariable.
func (w *watcher) Close() error {
	// Tell the background goroutine to shut down by canceling its ctx.
	w.shutdown()
	// Wait for it to return the result of closing the notifier.
	err := <-w.closeCh
	// Cleanup our channels.
	close(w.ch)
	close(w.closeCh)
	return err
}
<|endoftext|>


<commit_before>package socketio

import (
	"github.com/googollee/go-engine.io"
	"net/http"
	"time"
)

// Server is the server of socket.io.
type Server struct {
	*namespace
	broadcast BroadcastAdaptor
	eio       *engineio.Server
}

// NewServer returns the server supported given transports. If transports is nil, server will use ["polling", "websocket"] as default.
func NewServer(transportNames []string) (*Server, error) {
	eio, err := engineio.NewServer(transportNames)
	if err != nil {
		return nil, err
	}
	ret := &Server{
		namespace: newNamespace(newBroadcastDefault()),
		eio:       eio,
	}
	go ret.loop()
	return ret, nil
}

// SetPingTimeout sets the timeout of ping. When time out, server will close connection. Default is 60s.
func (s *Server) SetPingTimeout(t time.Duration) {
	s.eio.SetPingTimeout(t)
}

// SetPingInterval sets the interval of ping. Default is 25s.
func (s *Server) SetPingInterval(t time.Duration) {
	s.eio.SetPingInterval(t)
}

// SetAllowRequest sets the middleware function when establish connection. If it return non-nil, connection won't be established. Default will allow all request.
func (s *Server) SetAllowRequest(f func(*http.Request) error) {
	s.eio.SetAllowRequest(f)
}

// SetAllowUpgrades sets whether server allows transport upgrade. Default is true.
func (s *Server) SetAllowUpgrades(allow bool) {
	s.eio.SetAllowUpgrades(allow)
}

// SetCookie sets the name of cookie which used by engine.io. Default is "io".
func (s *Server) SetCookie(prefix string) {
	s.eio.SetCookie(prefix)
}

// SetAdaptor sets the adaptor of broadcast. Default is in-process broadcast implement.
func (s *Server) SetAdaptor(adaptor BroadcastAdaptor) {
	s.namespace = newNamespace(adaptor)
}

// ServeHTTP handles http request.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.eio.ServeHTTP(w, r)
}

// Server level broadcasts function.
func (s *Server) BroadcastTo(room, message string, args ...interface{}) {
	s.namespace.BroadcastTo(room, message, args...)
}

func (s *Server) loop() {
	for {
		conn, err := s.eio.Accept()
		if err != nil {
			return
		}
		s := newSocket(conn, s.baseHandler)
		go func(s *socket) {
			s.loop()
		}(s)
	}
}
<commit_msg>added feature to allow custom connection id generator<commit_after>package socketio

import (
	"github.com/googollee/go-engine.io"
	"net/http"
	"time"
)

// Server is the server of socket.io.
type Server struct {
	*namespace
	broadcast BroadcastAdaptor
	eio       *engineio.Server
}

// NewServer returns the server supported given transports. If transports is nil, server will use ["polling", "websocket"] as default.
func NewServer(transportNames []string) (*Server, error) {
	eio, err := engineio.NewServer(transportNames)
	if err != nil {
		return nil, err
	}
	ret := &Server{
		namespace: newNamespace(newBroadcastDefault()),
		eio:       eio,
	}
	go ret.loop()
	return ret, nil
}

// SetPingTimeout sets the timeout of ping. When time out, server will close connection. Default is 60s.
func (s *Server) SetPingTimeout(t time.Duration) {
	s.eio.SetPingTimeout(t)
}

// SetPingInterval sets the interval of ping. Default is 25s.
func (s *Server) SetPingInterval(t time.Duration) {
	s.eio.SetPingInterval(t)
}

// SetAllowRequest sets the middleware function when establish connection. If it return non-nil, connection won't be established. Default will allow all request.
func (s *Server) SetAllowRequest(f func(*http.Request) error) {
	s.eio.SetAllowRequest(f)
}

// SetAllowUpgrades sets whether server allows transport upgrade. Default is true.
func (s *Server) SetAllowUpgrades(allow bool) {
	s.eio.SetAllowUpgrades(allow)
}

// SetCookie sets the name of cookie which used by engine.io. Default is "io".
func (s *Server) SetCookie(prefix string) {
	s.eio.SetCookie(prefix)
}

// SetNewId sets the callback func to generate new connection id. By default, id is generated from remote addr + current time stamp
func (s *Server) SetNewId(f func(*http.Request) string) {
	s.eio.SetNewId(f)
}

// SetAdaptor sets the adaptor of broadcast. Default is in-process broadcast implement.
func (s *Server) SetAdaptor(adaptor BroadcastAdaptor) {
	s.namespace = newNamespace(adaptor)
}

// ServeHTTP handles http request.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.eio.ServeHTTP(w, r)
}

// Server level broadcasts function.
func (s *Server) BroadcastTo(room, message string, args ...interface{}) {
	s.namespace.BroadcastTo(room, message, args...)
}

func (s *Server) loop() {
	for {
		conn, err := s.eio.Accept()
		if err != nil {
			return
		}
		s := newSocket(conn, s.baseHandler)
		go func(s *socket) {
			s.loop()
		}(s)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discoverd"
	rpc "github.com/flynn/rpcplus/comborpc"
)

type Server struct {
	*HTTPFrontend
}

func (s *Server) ListenAndServe(quit <-chan struct{}) {
	go s.HTTPFrontend.serve()
	go s.HTTPFrontend.syncDatabase()
	<-quit
	// TODO: unregister from service discovery
	// TODO: stop frontends gracefully
}

func main() {
	rpcAddr := flag.String("rpcaddr", ":1115", "rpc listen address")
	httpAddr := flag.String("httpaddr", ":8080", "http frontend listen address")
	flag.Parse()

	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	var s Server
	s.HTTPFrontend = NewHTTPFrontend(*httpAddr, etcd.NewClient(nil), d)
	rpc.Register(&Router{s})
	rpc.HandleHTTP()
	go http.ListenAndServe(*rpcAddr, nil)

	if err = d.Register("flynn-strowger-rpc", *rpcAddr); err != nil {
		log.Fatal(err)
	}

	s.ListenAndServe(nil)
}
<commit_msg>Support ETCD env variable, analogous to DISCOVERD.<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/coreos/go-etcd/etcd"
	"github.com/flynn/go-discoverd"
	rpc "github.com/flynn/rpcplus/comborpc"
)

type Server struct {
	*HTTPFrontend
}

func (s *Server) ListenAndServe(quit <-chan struct{}) {
	go s.HTTPFrontend.serve()
	go s.HTTPFrontend.syncDatabase()
	<-quit
	// TODO: unregister from service discovery
	// TODO: stop frontends gracefully
}

func main() {
	rpcAddr := flag.String("rpcaddr", ":1115", "rpc listen address")
	httpAddr := flag.String("httpaddr", ":8080", "http frontend listen address")
	flag.Parse()

	// Will use DISCOVERD environment variable
	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	// Read etcd address from ETCD
	etcdAddr := strings.Split(os.Getenv("ETCD"), ",")
	if len(etcdAddr) == 1 && etcdAddr[0] == "" {
		etcdAddr = nil
	}

	var s Server
	s.HTTPFrontend = NewHTTPFrontend(*httpAddr, etcd.NewClient(etcdAddr), d)
	rpc.Register(&Router{s})
	rpc.HandleHTTP()
	go http.ListenAndServe(*rpcAddr, nil)

	if err = d.Register("flynn-strowger-rpc", *rpcAddr); err != nil {
		log.Fatal(err)
	}

	s.ListenAndServe(nil)
}
<|endoftext|>


<commit_before>package main

import (
  _ "database/sql"
  "encoding/json"
  "fmt"
  "github.com/codegangsta/negroni"
  "github.com/gorilla/mux"
  "github.com/jinzhu/gorm"
  "github.com/joho/godotenv"
  _ "github.com/lib/pq"
  "github.com/unrolled/render"
  "log"
  "net/http"
  "os"
  "io/ioutil"
)

type Api struct {
  DB gorm.DB
}

type Hacker struct {
  Id    int64
  Name  string `sql:"not null;unique"`
  Today bool
}

func main() {
  InitEnv()

  api := Api{}
  api.InitDB()
  api.InitSchema()

  // classic provides Recovery, Logging, Static default middleware
  n := negroni.Classic()
  // for easy template rendering
  r := render.New(render.Options{
    Directory:  "app/templates",
    Layout:     "layout",
    Extensions: []string{".tmpl", ".html"},
  })

  router := mux.NewRouter()

  router.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    // Assumes you have a template in ./app/templates called "index.html"
    r.HTML(w, http.StatusOK, "index", nil)
  })

  // GET /hackers/chase
  router.HandleFunc("/hackers/{github_username}", api.HackerHandler).Methods("GET")

  // POST /hackers
  router.HandleFunc("/hackers", api.CreateHackerHandler).Methods("POST")

  // router goes last
  n.UseHandler(router)
  n.Run(":3000")
}

// learned from: http://www.alexedwards.net/blog/golang-response-snippets#json
func (api *Api) HackerHandler(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r) // from the request
  // need to figure out how to recall a db record from params/Vars
  // return/display JSON dump of saved object
  // my_little_json := Hacker{1, params["github_username"], today("github_username")}
  hacker := Hacker{}
  if err := api.DB.Where("name = ?", params["github_username"]).First(&hacker).Error; err != nil {
    // This really should redirect to a Not Found route. Or return a not found JSON
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  js, err := json.Marshal(&hacker)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.Header().Set("Content-Type", "application/json")
  w.Write(js)
}

func (api *Api) CreateHackerHandler(w http.ResponseWriter, r *http.Request) {
  err := r.ParseForm()
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // save data
  hacker := Hacker{Name: r.Form.Get("name")}
  if err := api.DB.Where(Hacker{Name: r.Form.Get("name")}).FirstOrCreate(&hacker).Error; err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // make JSON
  js, err := json.Marshal(&hacker)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // return JSON
  w.Header().Set("Content-Type", "application/json")
  w.Write(js)
}

func today(h string) bool{
  url := fmt.Sprintf("https://api.github.com/users/%s/events", h)

  response, err := http.Get(url)

  if err != nil {
    log.Fatal(err.Error())
  }

  body, err := ioutil.RealAll(res.Body)

  if err != nil {
    log.Fatal(err.Error())
  }

  // do something with the body
}

func InitEnv() {
  env := godotenv.Load()
  if env != nil {
    log.Fatal("Error loading .env file")
  }
}

func (api *Api) InitDB() {
  var err error
  db_user := os.Getenv("DATABASE_USER")
  db_pass := os.Getenv("DATABASE_PASS")
  db_host := os.Getenv("DATABASE_HOST")
  db_name := os.Getenv("DATABASE_NAME")
  logger := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  logger.Println("got db_user: ", db_user)

  api.DB, err = gorm.Open("postgres", fmt.Sprintf("user=%s dbname=%s password=%s host=%s sslmode=disable", db_user, db_name, db_pass, db_host))
  if err != nil {
    log.Fatal("database connection error: ", err)
  }
  api.DB.LogMode(true)
}

func (api *Api) InitSchema() {
  api.DB.AutoMigrate(&Hacker{})
}
<commit_msg>fooling around with json<commit_after>package main

import (
  _ "database/sql"
  "encoding/json"
  "fmt"
  "github.com/codegangsta/negroni"
  "github.com/gorilla/mux"
  "github.com/jinzhu/gorm"
  "github.com/joho/godotenv"
  _ "github.com/lib/pq"
  "github.com/unrolled/render"
  "log"
  "net/http"
  "os"
  "io/ioutil"
)

type Api struct {
  DB gorm.DB
}

type Hacker struct {
  Id    int64
  Name  string `sql:"not null;unique"`
  Today bool
}

func main() {
  InitEnv()

  api := Api{}
  api.InitDB()
  api.InitSchema()

  // classic provides Recovery, Logging, Static default middleware
  n := negroni.Classic()
  // for easy template rendering
  r := render.New(render.Options{
    Directory:  "app/templates",
    Layout:     "layout",
    Extensions: []string{".tmpl", ".html"},
  })

  router := mux.NewRouter()

  router.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    // Assumes you have a template in ./app/templates called "index.html"
    r.HTML(w, http.StatusOK, "index", nil)
  })

  // GET /hackers/chase
  router.HandleFunc("/hackers/{github_username}", api.HackerHandler).Methods("GET")

  // POST /hackers
  router.HandleFunc("/hackers", api.CreateHackerHandler).Methods("POST")

  // router goes last
  n.UseHandler(router)
  n.Run(":3000")
}

// learned from: http://www.alexedwards.net/blog/golang-response-snippets#json
func (api *Api) HackerHandler(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r) // from the request
  // need to figure out how to recall a db record from params/Vars
  // return/display JSON dump of saved object
  // my_little_json := Hacker{1, params["github_username"], today("github_username")}
  hacker := Hacker{}
  if err := api.DB.Where("name = ?", params["github_username"]).First(&hacker).Error; err != nil {
    // This really should redirect to a Not Found route. Or return a not found JSON
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  js, err := json.Marshal(&hacker)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.Header().Set("Content-Type", "application/json")
  w.Write(js)
}

func (api *Api) CreateHackerHandler(w http.ResponseWriter, r *http.Request) {
  err := r.ParseForm()
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // save data
  hacker := Hacker{Name: r.Form.Get("name")}
  if err := api.DB.Where(Hacker{Name: r.Form.Get("name")}).FirstOrCreate(&hacker).Error; err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // make JSON
  js, err := json.Marshal(&hacker)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  // return JSON
  w.Header().Set("Content-Type", "application/json")
  w.Write(js)
}

func today(h string) string {

  var i *[]interface{}

  personal_url := fmt.Sprintf("https://api.github.com/users/%s/events", h)

  body := read_github_events(personal_url)

  err := json.Unmarshal(body, &i)

  if err != nil {
    log.Fatal(err.Error())
  }

  return fmt.Sprintf("%v", i)
}

func read_github_events(url string) []byte {
  response, err := http.Get(url)

  if err != nil {
    log.Fatal(err.Error())
  }

  body, err := ioutil.ReadAll(response.Body)

  if err != nil {
    log.Fatal(err.Error())
  }

  return body
}

func InitEnv() {
  env := godotenv.Load()
  if env != nil {
    log.Fatal("Error loading .env file")
  }
}

func (api *Api) InitDB() {
  var err error
  db_user := os.Getenv("DATABASE_USER")
  db_pass := os.Getenv("DATABASE_PASS")
  db_host := os.Getenv("DATABASE_HOST")
  db_name := os.Getenv("DATABASE_NAME")
  logger := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)
  logger.Println("got db_user: ", db_user)

  api.DB, err = gorm.Open("postgres", fmt.Sprintf("user=%s dbname=%s password=%s host=%s sslmode=disable", db_user, db_name, db_pass, db_host))
  if err != nil {
    log.Fatal("database connection error: ", err)
  }
  api.DB.LogMode(true)
}

func (api *Api) InitSchema() {
  api.DB.AutoMigrate(&Hacker{})
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/wjessop/go-piglow"

	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"
)

// from go-piglow
var colorToLEDs = map[string][3]int8{
	"white":  [3]int8{12, 9, 10},
	"blue":   [3]int8{14, 4, 11},
	"green":  [3]int8{3, 5, 13},
	"yellow": [3]int8{2, 8, 15},
	"orange": [3]int8{1, 7, 16},
	"red":    [3]int8{0, 6, 17},
}

var colorOrder = [6]string{
	"white",
	"blue",
	"green",
	"yellow",
	"orange",
	"red",
}

type Blinky struct {
	p    *piglow.Piglow
	quit chan bool
	done chan bool
}

func main() {
	var webqueue string
	if webqueue = os.Getenv("WEBQUEUE"); len(webqueue) == 0 {
		log.Fatal("Set queue with WEBQUEUE env")
	}

	var commandChan = make(chan string)

	// start up command dispatcher
	go dispatcher(commandChan)

	log.Println("Starting queue poll on", webqueue)
	for {
		log.Println("Poll...")
		res, err := http.Get(webqueue)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		body, err := ioutil.ReadAll(res.Body)
		res.Body.Close()
		if err != nil {
			log.Fatal(err)
		}

		if res.StatusCode == 200 {
			// send command over to dispatcher
			commandChan <- strings.TrimSpace(string(body))
		}
	}
}

func dispatcher(in chan string) {
	var p *piglow.Piglow
	var err error

	var quit = make(chan bool)
	var done = make(chan bool)
	var running = false

	// Create a new Piglow
	p, err = piglow.NewPiglow()
	if err != nil {
		log.Fatal("Couldn't create a Piglow: ", err)
	}

	var blinky = &Blinky{p, quit, done}

	// clear the LEDs
	p.SetAll(0)
	err = p.Apply()
	if err != nil { // Apply the changes
		log.Fatal("Couldn't apply changes: ", err)
	}

	for {
		command := <-in

		log.Println("processing command:", command)

		// if animation is already running, stop it
		// and wait for it to finish
		if running {
			quit <- true
			<-done
		}

		// clear all LEDs
		p.SetAll(0)
		err = p.Apply()

		// dispatch command to sub-goroutines
		switch {
		case command == "shimmer":
			go shimmer(blinky)
		case command == "pulse":
			go pulse(blinky)
		case command == "bounce":
			go bounce(blinky, false)
		case command == "bounce2":
			go bounce(blinky, true)
		case command == "cycle":
			go cycle(blinky)
		case command == "arms":
			go arms(blinky, false)
		case command == "arms2":
			go arms(blinky, true)
		case strings.HasSuffix(command, "spin"):
			go spin(blinky, strings.TrimSuffix(command, "spin"), false)
		case strings.HasSuffix(command, "spin2"):
			go spin(blinky, strings.TrimSuffix(command, "spin2"), true)
		default:
			go solid(blinky, command)
		}
		running = true
	}
}

// animate each arm on and then each arm off
func arms(blinky *Blinky, reset bool) {

	var tentacle = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if tentacle == 3 {
			tentacle = 0

			if !reset {
				if value == 4 {
					value = 0
				} else {
					value = 4
				}
			}
		}

		if reset {
			p.SetAll(0)
			p.Apply()
		}
		p.SetTentacle(tentacle, uint8(value))
		p.Apply()

		// next tentacle
		tentacle += 1
	})
}

// spin through a particular color
func spin(blinky *Blinky, color string, reset bool) {

	leds := colorToLEDs[color]
	var index = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if index == 3 {
			index = 0

			if !reset {
				if value == 4 {
					value = 0
				} else {
					value = 4
				}
			}
		}

		if reset {
			p.SetAll(0)
			p.Apply()
		}
		p.SetLED(int8(leds[index]), uint8(value))
		p.Apply()

		// next index
		index += 1
	})
}

// cycle leds from the center
func cycle(blinky *Blinky) {

	var index = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if index == len(colorOrder) {
			index = 0

			if value == 4 {
				value = 0
			} else {
				value = 4
			}
		}

		for _, led := range colorToLEDs[colorOrder[index]] {
			p.SetLED(led, uint8(value))
		}
		p.Apply()

		// next index
		index += 1
	})
}

// pulse all LEDs
func pulse(blinky *Blinky) {

	var step = 2
	var max = 30
	var value = 2
	var brighten = true

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {

		if value == max {
			brighten = false
		}
		if value == 2 {
			brighten = true
		}

		p.SetAll(uint8(value))
		p.Apply()

		if brighten {
			value += step
		} else {
			value -= step
		}
	})
}

// shimmer all LEDs
func shimmer(blinky *Blinky) {

	var min = 2
	var max = 10

	blinky.p.SetAll(uint8(min))
	blinky.p.Apply()

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		p.SetLED(int8(rand.Intn(18)), uint8(rand.Intn(max-min)+min))
		p.Apply()
	})
}

// bounce a single led along the arm(s)
func bounce(blinky *Blinky, singleArm bool) {

	var index = 0
	var value = 4
	var arm = 0
	var outward = true

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {

		if index == (len(colorOrder) - 1) {
			outward = false
		}
		if index == 0 {
			outward = true

			// advance arm if in single arm mode
			if singleArm {
				arm += 1
				if arm == 3 {
					arm = 0
				}
			}
		}

		p.SetAll(0)
		p.Apply()
		for i, led := range colorToLEDs[colorOrder[index]] {
			if !singleArm || arm == i {
				p.SetLED(led, uint8(value))
			}
		}
		p.Apply()

		// next index
		if outward {
			index += 1
		} else {
			index -= 1
		}
	})
}

// This function handles the common case of a simple animation with no cleanup
func animate(blinky *Blinky, timeout time.Duration, callback func(*piglow.Piglow)) {
	for {
		select {
		case <-blinky.quit:
			blinky.done <- true
			return
		default:
			callback(blinky.p)
			time.Sleep(timeout)
		}
	}
}

// turn on all LEDs of a certain color
func solid(blinky *Blinky, color string) {

	log.Println("setting to ", color)
	switch color {
	case "green":
		blinky.p.SetGreen(8)
	case "blue":
		blinky.p.SetBlue(8)
	case "white":
		blinky.p.SetWhite(8)
	case "yellow":
		blinky.p.SetYellow(8)
	case "orange":
		blinky.p.SetOrange(8)
	case "red":
		blinky.p.SetRed(8)
	case "clear":
	case "all":
		blinky.p.SetAll(8)
	default:
		blinky.p.SetLED(int8(len(color)%17), 8)
	}
	blinky.p.Apply()

	// wait for the end, aka no animation
	animate(blinky, time.Second/10, func(p *piglow.Piglow) {})
}
<commit_msg>added animateWithInit and refactored<commit_after>package main

import (
	"github.com/wjessop/go-piglow"

	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
	"time"
)

// from go-piglow
var colorToLEDs = map[string][3]int8{
	"white":  [3]int8{12, 9, 10},
	"blue":   [3]int8{14, 4, 11},
	"green":  [3]int8{3, 5, 13},
	"yellow": [3]int8{2, 8, 15},
	"orange": [3]int8{1, 7, 16},
	"red":    [3]int8{0, 6, 17},
}

var colorOrder = [6]string{
	"white",
	"blue",
	"green",
	"yellow",
	"orange",
	"red",
}

type Blinky struct {
	p    *piglow.Piglow
	quit chan bool
	done chan bool
}

func main() {
	var webqueue string
	if webqueue = os.Getenv("WEBQUEUE"); len(webqueue) == 0 {
		log.Fatal("Set queue with WEBQUEUE env")
	}

	var commandChan = make(chan string)

	// start up command dispatcher
	go dispatcher(commandChan)

	log.Println("Starting queue poll on", webqueue)
	for {
		log.Println("Poll...")
		res, err := http.Get(webqueue)
		if err != nil {
			log.Fatalln("Error:", err)
		}

		body, err := ioutil.ReadAll(res.Body)
		res.Body.Close()
		if err != nil {
			log.Fatal(err)
		}

		if res.StatusCode == 200 {
			// send command over to dispatcher
			commandChan <- strings.TrimSpace(string(body))
		}
	}
}

func dispatcher(in chan string) {
	var p *piglow.Piglow
	var err error

	var quit = make(chan bool)
	var done = make(chan bool)
	var running = false

	// Create a new Piglow
	p, err = piglow.NewPiglow()
	if err != nil {
		log.Fatal("Couldn't create a Piglow: ", err)
	}

	var blinky = &Blinky{p, quit, done}

	// clear the LEDs
	p.SetAll(0)
	err = p.Apply()
	if err != nil { // Apply the changes
		log.Fatal("Couldn't apply changes: ", err)
	}

	for {
		command := <-in

		log.Println("processing command:", command)

		// if animation is already running, stop it
		// and wait for it to finish
		if running {
			quit <- true
			<-done
		}

		// clear all LEDs
		p.SetAll(0)
		err = p.Apply()

		// dispatch command to sub-goroutines
		switch {
		case command == "shimmer":
			go shimmer(blinky)
		case command == "pulse":
			go pulse(blinky)
		case command == "bounce":
			go bounce(blinky, false)
		case command == "bounce2":
			go bounce(blinky, true)
		case command == "cycle":
			go cycle(blinky)
		case command == "arms":
			go arms(blinky, false)
		case command == "arms2":
			go arms(blinky, true)
		case strings.HasSuffix(command, "spin"):
			go spin(blinky, strings.TrimSuffix(command, "spin"), false)
		case strings.HasSuffix(command, "spin2"):
			go spin(blinky, strings.TrimSuffix(command, "spin2"), true)
		default:
			go solid(blinky, command)
		}
		running = true
	}
}

// animate each arm on and then each arm off
func arms(blinky *Blinky, reset bool) {

	var tentacle = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if tentacle == 3 {
			tentacle = 0

			if !reset {
				if value == 4 {
					value = 0
				} else {
					value = 4
				}
			}
		}

		if reset {
			p.SetAll(0)
			p.Apply()
		}
		p.SetTentacle(tentacle, uint8(value))
		p.Apply()

		// next tentacle
		tentacle += 1
	})
}

// spin through a particular color
func spin(blinky *Blinky, color string, reset bool) {

	leds := colorToLEDs[color]
	var index = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if index == 3 {
			index = 0

			if !reset {
				if value == 4 {
					value = 0
				} else {
					value = 4
				}
			}
		}

		if reset {
			p.SetAll(0)
			p.Apply()
		}
		p.SetLED(int8(leds[index]), uint8(value))
		p.Apply()

		// next index
		index += 1
	})
}

// cycle leds from the center
func cycle(blinky *Blinky) {

	var index = 0
	var value = 4

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {
		if index == len(colorOrder) {
			index = 0

			if value == 4 {
				value = 0
			} else {
				value = 4
			}
		}

		for _, led := range colorToLEDs[colorOrder[index]] {
			p.SetLED(led, uint8(value))
		}
		p.Apply()

		// next index
		index += 1
	})
}

// pulse all LEDs
func pulse(blinky *Blinky) {

	var step = 2
	var max = 30
	var value = 2
	var brighten = true

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {

		if value == max {
			brighten = false
		}
		if value == 2 {
			brighten = true
		}

		p.SetAll(uint8(value))
		p.Apply()

		if brighten {
			value += step
		} else {
			value -= step
		}
	})
}

// shimmer all LEDs
func shimmer(blinky *Blinky) {

	var min = 2
	var max = 10

	var init = func(p *piglow.Piglow) {
		p.SetAll(uint8(min))
		p.Apply()
	}

	var animate = func(p *piglow.Piglow) {
		p.SetLED(int8(rand.Intn(18)), uint8(rand.Intn(max-min)+min))
		p.Apply()
	}

	animateWithInit(blinky, time.Second/10, init, animate)
}

// bounce a single led along the arm(s)
func bounce(blinky *Blinky, singleArm bool) {

	var index = 0
	var value = 4
	var arm = 0
	var outward = true

	animate(blinky, time.Second/10, func(p *piglow.Piglow) {

		if index == (len(colorOrder) - 1) {
			outward = false
		}
		if index == 0 {
			outward = true

			// advance arm if in single arm mode
			if singleArm {
				arm += 1
				if arm == 3 {
					arm = 0
				}
			}
		}

		p.SetAll(0)
		p.Apply()
		for i, led := range colorToLEDs[colorOrder[index]] {
			if !singleArm || arm == i {
				p.SetLED(led, uint8(value))
			}
		}
		p.Apply()

		// next index
		if outward {
			index += 1
		} else {
			index -= 1
		}
	})
}

// This function handles the common case of a simple animation with no cleanup
func animate(blinky *Blinky, timeout time.Duration, callback func(*piglow.Piglow)) {
	for {
		select {
		case <-blinky.quit:
			blinky.done <- true
			return
		default:
			callback(blinky.p)
			time.Sleep(timeout)
		}
	}
}

// animateWithInit is for animations that need initialization
func animateWithInit(blinky *Blinky, timeout time.Duration, init func(*piglow.Piglow), animation func(*piglow.Piglow)) {

	init(blinky.p)

	animate(blinky, timeout, animation)
}

// turn on all LEDs of a certain color
func solid(blinky *Blinky, color string) {

	var init = func(p *piglow.Piglow) {
		switch color {
		case "green":
			p.SetGreen(8)
		case "blue":
			p.SetBlue(8)
		case "white":
			p.SetWhite(8)
		case "yellow":
			p.SetYellow(8)
		case "orange":
			p.SetOrange(8)
		case "red":
			p.SetRed(8)
		case "clear":
		case "all":
			p.SetAll(8)
		default:
			p.SetLED(int8(len(color)%17), 8)
		}
		p.Apply()
	}

	// wait for the end, aka no animation
	animateWithInit(blinky, time.Second/10, init, func(p *piglow.Piglow) {})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

type ResponseData struct {
	StatusCode  int      `json:"-"`
	Key         string   `json:"key"`
	IsNamespace bool     `json:"namespace"`
	Value       string   `json:"value"`
	Keys        []string `json:"keys,omitempty"`  // need better decision here
	Error       string   `json:"error,omitempty"` // need better decision here
}

var validKey = regexp.MustCompile(`^[a-zA-Z0-9_\-/]+$`)

func handler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	var responseData ResponseData
	key := r.URL.Path[1:]
	if validKey.MatchString(key) {
		key_path := expandPath(key)
		value := r.PostForm.Get("value")
		var keys []string
		var err error

		switch r.Method {
		case "GET":
			var values []string
			values, err = readKey(key_path)
			if len(values) == 1 {
				value = values[0]
			} else {
				keys = values
			}
		case "DELETE":
			err = deleteKey(key_path)
		case "PUT", "POST":
			err = putKey(key_path, value)
		}

		if err == nil {
			responseData = ResponseData{StatusCode: http.StatusOK, Key: key, Value: value, Keys: keys}
			if keys == nil {
				responseData.IsNamespace = false
			} else {
				responseData.IsNamespace = true
			}
		} else {
			responseData = ResponseData{StatusCode: http.StatusNotFound, Key: key, Error: err.Error()}
		}
	} else {
		responseData = ResponseData{StatusCode: http.StatusBadRequest, Key: key, Error: "Invalid key. Only " + validKey.String() + " allowed!"}
	}

	content, err := json.Marshal(responseData)
	if err == nil && responseData.StatusCode != 0 {
		callHooks(key, r.Method)
		w.WriteHeader(responseData.StatusCode)
		w.Header().Set("Content-Type", "application/json")
		w.Write(append(content, '\n'))
	} else {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
		fmt.Println(err)
	}
}

func readKey(path string) ([]string, error) {
	var result []string
	var err error

	var fileInfo os.FileInfo
	fileInfo, err = os.Stat(path)
	if err == nil {
		if fileInfo.IsDir() {
			var files []os.FileInfo
			if files, err = ioutil.ReadDir(path); err == nil {
				for _, f := range files {
					result = append(result, f.Name())
				}
			}
		} else {
			var content []byte
			if content, err = ioutil.ReadFile(path); err == nil {
				result = append(result, string(content))
			}
		}
	}
	return result, err
}

func putKey(path string, value string) error {
	os.MkdirAll(filepath.Dir(path), os.ModePerm)
	return ioutil.WriteFile(path, []byte(value), os.ModePerm)
}

func deleteKey(path string) error {
	return os.Remove(path)
}

func expandPath(key string) string {
	return filepath.Join(opts.DataPath, key)
}

// Return nil if File exists, else non-nil value
func fileExists(filename string) error {
	_, err := os.Stat(filename)
	return err
}

// Return nil if filename is a directory, else non-nil value
func isDirectory(filename string) error {
	stat, err := os.Stat(filename)
	if err == nil && !stat.IsDir() {
		return errors.New("'" + filename + "' is not a directory!")
	}
	return nil
}

func callHooks(key, action string) {
	keyparts := strings.Split(key, "/")
	tmpkey := keyparts[0]
	callHook(tmpkey, action)
	for _, keypart := range keyparts[1:] {
		tmpkey = tmpkey + "/" + keypart
		callHook(tmpkey, action)
	}
}

// ignore errors, just print them and continue
func callHook(key, action string) {
	for _, hookUrl := range opts.WebHookUrls {
		if hookUrl[:4] != "http" {
			hookUrl = "http://" + hookUrl
		}
		go func(hookUrl string, hookData url.Values) {
			if _, err := http.PostForm(hookUrl, hookData); err != nil {
				fmt.Printf("WebHook Post failed: %s", err)
			}
		}(hookUrl, url.Values{"key": {key}, "action": {action}})
	}
}

var opts struct {
	DataPath    string   `short:"d" long:"data-path" default:"./data" description:"Directory where files will be stored."`
	Port        int      `short:"p" long:"port" default:"8080" description:"Port where server is listening for requests."`
	WebHookUrls []string `short:"w" long:"webhook-url" description:"WebHook-Urls."`
}

func main() {
	flags.Parse(&opts)
	opts.DataPath, _ = filepath.Abs(opts.DataPath)
	fmt.Println("DATA_PATH:", opts.DataPath)
	fmt.Println("PORT:", opts.Port)

	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+strconv.Itoa(opts.Port), nil)
}
<commit_msg>explicit set namespace and don't guess it..<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

type ResponseData struct {
	StatusCode  int      `json:"-"`
	Key         string   `json:"key"`
	IsNamespace bool     `json:"namespace"`
	Value       string   `json:"value"`
	Keys        []string `json:"keys,omitempty"`  // need better decision here
	Error       string   `json:"error,omitempty"` // need better decision here
}

var validKey = regexp.MustCompile(`^[a-zA-Z0-9_\-/]+$`)

func handler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	var responseData ResponseData
	key := r.URL.Path[1:]
	if validKey.MatchString(key) {
		key_path := expandPath(key)
		value := r.PostForm.Get("value")
		var keys []string
		var err error

		switch r.Method {
		case "GET":
			var values []string
			var isNamespace bool
			values, isNamespace, err = readKey(key_path)
			if isNamespace {
				keys = values
			} else {
				value = values[0]
			}
		case "DELETE":
			err = deleteKey(key_path)
		case "PUT", "POST":
			err = putKey(key_path, value)
		}

		if err == nil {
			responseData = ResponseData{StatusCode: http.StatusOK, Key: key, Value: value, Keys: keys}
			if keys == nil {
				responseData.IsNamespace = false
			} else {
				responseData.IsNamespace = true
			}
		} else {
			responseData = ResponseData{StatusCode: http.StatusNotFound, Key: key, Error: err.Error()}
		}
	} else {
		responseData = ResponseData{StatusCode: http.StatusBadRequest, Key: key, Error: "Invalid key. Only " + validKey.String() + " allowed!"}
	}

	content, err := json.Marshal(responseData)
	if err == nil && responseData.StatusCode != 0 {
		callHooks(key, r.Method)
		w.WriteHeader(responseData.StatusCode)
		w.Header().Set("Content-Type", "application/json")
		w.Write(append(content, '\n'))
	} else {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(http.StatusText(http.StatusInternalServerError)))
		fmt.Println(err)
	}
}

func readKey(path string) ([]string, bool, error) {
	var result []string
	var err error

	var fileInfo os.FileInfo
	fileInfo, err = os.Stat(path)
	isNamespace := false
	if err == nil {
		if fileInfo.IsDir() {
			isNamespace = true
			var files []os.FileInfo
			if files, err = ioutil.ReadDir(path); err == nil {
				for _, f := range files {
					result = append(result, f.Name())
				}
			}
		} else {
			var content []byte
			if content, err = ioutil.ReadFile(path); err == nil {
				result = append(result, string(content))
			}
		}
	}
	return result, isNamespace, err
}

func putKey(path string, value string) error {
	os.MkdirAll(filepath.Dir(path), os.ModePerm)
	return ioutil.WriteFile(path, []byte(value), os.ModePerm)
}

func deleteKey(path string) error {
	return os.Remove(path)
}

func expandPath(key string) string {
	return filepath.Join(opts.DataPath, key)
}

// Return nil if File exists, else non-nil value
func fileExists(filename string) error {
	_, err := os.Stat(filename)
	return err
}

// Return nil if filename is a directory, else non-nil value
func isDirectory(filename string) error {
	stat, err := os.Stat(filename)
	if err == nil && !stat.IsDir() {
		return errors.New("'" + filename + "' is not a directory!")
	}
	return nil
}

func callHooks(key, action string) {
	keyparts := strings.Split(key, "/")
	tmpkey := keyparts[0]
	callHook(tmpkey, action)
	for _, keypart := range keyparts[1:] {
		tmpkey = tmpkey + "/" + keypart
		callHook(tmpkey, action)
	}
}

// ignore errors, just print them and continue
func callHook(key, action string) {
	for _, hookUrl := range opts.WebHookUrls {
		if hookUrl[:4] != "http" {
			hookUrl = "http://" + hookUrl
		}
		go func(hookUrl string, hookData url.Values) {
			if _, err := http.PostForm(hookUrl, hookData); err != nil {
				fmt.Printf("WebHook Post failed: %s", err)
			}
		}(hookUrl, url.Values{"key": {key}, "action": {action}})
	}
}

var opts struct {
	DataPath    string   `short:"d" long:"data-path" default:"./data" description:"Directory where files will be stored."`
	Port        int      `short:"p" long:"port" default:"8080" description:"Port where server is listening for requests."`
	WebHookUrls []string `short:"w" long:"webhook-url" description:"WebHook-Urls."`
}

func main() {
	flags.Parse(&opts)
	opts.DataPath, _ = filepath.Abs(opts.DataPath)
	fmt.Println("DATA_PATH:", opts.DataPath)
	fmt.Println("PORT:", opts.Port)

	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+strconv.Itoa(opts.Port), nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"mime"
	"net/http"
	"path/filepath"
	"text/template"
	"time"
)

// ResponseBody is structure
type ResponseBody struct {
	ID string
}

// This method handles all requests.
func handle(w http.ResponseWriter, r *http.Request) {
	log.Print("[INFO] " + fmt.Sprintf("%#v", r))

	var proto Protocol
	c := Config()

	if c.Delay > 0 {
		time.Sleep(time.Duration(c.Delay) * time.Second)
	}

	for k, v := range c.Header {
		w.Header().Set(k, v)
	}

	switch c.Protocol {
	case "JSON-RPC":
		proto = &JSONRPC{}
	case "REST":
		proto = &REST{}
	default:
		panic(fmt.Sprintf("Error known protocol: %s", c.Protocol))
	}

	file, id := proto.ResponseFile(w, r)

	ext := filepath.Ext(file)
	if ext != "" {
		contentType := mime.TypeByExtension(ext)
		w.Header().Set("Content-Type", contentType)
	}

	if id != "" && IsFileExist(file) {
		tpl := template.Must(template.ParseFiles(file))
		tpl.Execute(w, ResponseBody{ID: id})
	} else {
		http.ServeFile(w, r, file)
	}
}

// Run server
func Run() {
	c := Config()

	s := &http.Server{
		Addr:           c.Addr,
		Handler:        http.HandlerFunc(handle),
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	s.ListenAndServe()
}
<commit_msg>to clean log<commit_after>package main

import (
	"fmt"
	"log"
	"mime"
	"net/http"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

// ResponseBody is structure
type ResponseBody struct {
	ID string
}

// This method handles all requests.
func handle(w http.ResponseWriter, r *http.Request) {
	var proto Protocol
	c := Config()

	log.Print("[INFO] " + fmt.Sprintf("%s - \"%s %s %s\" - \"%s\"",
		r.RemoteAddr, r.Method, r.RequestURI, r.Proto, strings.Join(r.Header["User-Agent"], ",")))

	if c.Delay > 0 {
		time.Sleep(time.Duration(c.Delay) * time.Second)
	}

	switch c.Protocol {
	case "JSON-RPC":
		proto = &JSONRPC{}
	case "REST":
		proto = &REST{}
	default:
		panic(fmt.Sprintf("Error known protocol: %s", c.Protocol))
	}

	file, id := proto.ResponseFile(w, r)

	ext := filepath.Ext(file)
	t := "Content-Type"

	for k, v := range c.Header {
		if k == t && ext != "" {
			w.Header().Set(t, mime.TypeByExtension(ext))
		} else {
			w.Header().Set(k, v)
		}
	}

	if id != "" && IsFileExist(file) {
		tpl := template.Must(template.ParseFiles(file))
		tpl.Execute(w, ResponseBody{ID: id})
	} else {
		http.ServeFile(w, r, file)
	}
}

// Run server
func Run() {
	c := Config()

	s := &http.Server{
		Addr:           c.Addr,
		Handler:        http.HandlerFunc(handle),
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	s.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/garyburd/redigo/redis"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"log"
	"net/http"
	"strings"
)

var (
	pool *redis.Pool
)

type PageData struct {
	CurrentUrl *Url
	Stats      SiteStats
	Message    string
}

func GetNewPageData() PageData {
	k := PageData{}
	k.Stats = GetSiteStats()
	return k
}

func main() {
	err := MakeConfig()
	if err != nil {
		log.Fatal(err.Error())
	}
	pool = newPool()
	m := martini.Classic()
	m.Use(render.Renderer(render.Options{
		Directory:  "templates",
		Extensions: []string{".tmpl", ".html"},
	}))
	m.Get("/", IndexHandler)
	m.Get("/api/add/**", ApiAddURLHandler)
	m.Get("/add", WebAddHandler)
	m.Get("/view/:id", ViewHandler)
	m.Get("/:id", GetURLAndRedirect)
	log.Println("Listening on " + config.ListenAt)
	if config.RunJobs {
		log.Print("Running jobs every: ", config.GetJobInvertal())
		go RunJobs()
	}
	log.Fatal(http.ListenAndServe(config.ListenAt, m))
}

func IndexHandler(r render.Render) {
	pd := GetNewPageData()
	r.HTML(http.StatusOK, "index", pd)
}

func ViewHandler(m martini.Params, w http.ResponseWriter, r *http.Request, r2 render.Render) {
	k, err := GetUrlById(m["id"])
	if err != nil {
		pd := GetNewPageData()
		pd.Message = err.Error()
		r2.HTML(http.StatusInternalServerError, "error", pd)
		return
	}
	if k != nil {
		pd := GetNewPageData()
		pd.CurrentUrl = k
		r2.HTML(http.StatusOK, "view", pd)
		return
	} else {
		pd := GetNewPageData()
		pd.Message = "404 Not Found"
		r2.HTML(http.StatusNotFound, "error", pd)
		return
	}
}

func WebAddHandler(w http.ResponseWriter, r *http.Request, r2 render.Render) {
	if len(r.URL.Query()["url"]) < 1 {
		pd := GetNewPageData()
		pd.Message = "No arguments specified."
		r2.HTML(500, "error", pd)
		return
	}
	k := r.URL.Query()["url"][0]
	if k == "" {
		http.Redirect(w, r, "/", http.StatusMovedPermanently)
	} else {
		k = UrlPreprocessor(k)
		new, err := GetNewUrl(k)
		if err != nil {
			pd := GetNewPageData()
			pd.Message = err.Error()
			r2.HTML(500, "error", pd)
		} else {
			http.Redirect(w, r, "/view/"+new.id, http.StatusMovedPermanently)
		}
	}
}

func GetURLAndRedirect(params martini.Params, w http.ResponseWriter, r *http.Request, r2 render.Render) {
	k, err := GetUrlById(params["id"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if k != nil {
		if strings.Contains(k.Link, config.BaseURL) || strings.Split(k.Link, ":")[0] == "/"+k.id {
			k.Link = config.BaseURL
		}
		http.Redirect(w, r, k.Link, http.StatusMovedPermanently)
	} else {
		pd := GetNewPageData()
		pd.Message = "404 Not Found"
		r2.HTML(http.StatusNotFound, "error", pd)
	}
}

func ApiAddURLHandler(params martini.Params, w http.ResponseWriter, r *http.Request) {
	a := UrlPreprocessor(params["_1"])
	k, err := GetNewUrl(a)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		w.Write([]byte(config.BaseURL + k.id))
	}
}

func UrlPreprocessor(url string) string {
	if !strings.HasPrefix(url, "http:/") && !strings.HasPrefix(url, "https:/") {
		url = "http://" + url
	}
	return url
}
<commit_msg>rework api: new syntax is /api/add?url=<url_here><commit_after>package main

import (
	"github.com/garyburd/redigo/redis"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"log"
	"net/http"
	"strings"
)

var (
	pool *redis.Pool
)

type PageData struct {
	CurrentUrl *Url
	Stats      SiteStats
	Message    string
}

func GetNewPageData() PageData {
	k := PageData{}
	k.Stats = GetSiteStats()
	return k
}

func main() {
	err := MakeConfig()
	if err != nil {
		log.Fatal(err.Error())
	}
	pool = newPool()
	m := martini.Classic()
	m.Use(render.Renderer(render.Options{
		Directory:  "templates",
		Extensions: []string{".tmpl", ".html"},
	}))
	m.Get("/", IndexHandler)
	m.Get("/api/add", ApiAddURLHandler)
	m.Get("/add", WebAddHandler)
	m.Get("/view/:id", ViewHandler)
	m.Get("/:id", GetURLAndRedirect)
	log.Println("Listening on " + config.ListenAt)
	if config.RunJobs {
		log.Print("Running jobs every: ", config.GetJobInvertal())
		go RunJobs()
	}
	log.Fatal(http.ListenAndServe(config.ListenAt, m))
}

func IndexHandler(r render.Render) {
	pd := GetNewPageData()
	r.HTML(http.StatusOK, "index", pd)
}

func ViewHandler(m martini.Params, w http.ResponseWriter, r *http.Request, r2 render.Render) {
	k, err := GetUrlById(m["id"])
	if err != nil {
		pd := GetNewPageData()
		pd.Message = err.Error()
		r2.HTML(http.StatusInternalServerError, "error", pd)
		return
	}
	if k != nil {
		pd := GetNewPageData()
		pd.CurrentUrl = k
		r2.HTML(http.StatusOK, "view", pd)
		return
	} else {
		pd := GetNewPageData()
		pd.Message = "404 Not Found"
		r2.HTML(http.StatusNotFound, "error", pd)
		return
	}
}

func WebAddHandler(w http.ResponseWriter, r *http.Request, r2 render.Render) {
	if len(r.URL.Query()["url"]) < 1 {
		pd := GetNewPageData()
		pd.Message = "No arguments specified."
		r2.HTML(500, "error", pd)
		return
	}
	k := r.URL.Query()["url"][0]
	if k == "" {
		http.Redirect(w, r, "/", http.StatusMovedPermanently)
	} else {
		k = UrlPreprocessor(k)
		new, err := GetNewUrl(k)
		if err != nil {
			pd := GetNewPageData()
			pd.Message = err.Error()
			r2.HTML(500, "error", pd)
		} else {
			http.Redirect(w, r, "/view/"+new.id, http.StatusMovedPermanently)
		}
	}
}

func ApiAddURLHandler(r *http.Request) string {
	if len(r.URL.Query()["url"]) < 1 {
		return "Error, no arguments specified"
	}
	k := r.URL.Query()["url"][0]
	if k == "" {
		return "Error, no url specified"
	} else {
		k := UrlPreprocessor(k)
		new, err := GetNewUrl(k)
		if err != nil {
			return err.Error()
		} else {
			return config.BaseURL + new.id
		}
	}
}

func GetURLAndRedirect(params martini.Params, w http.ResponseWriter, r *http.Request, r2 render.Render) {
	k, err := GetUrlById(params["id"])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if k != nil {
		if strings.Contains(k.Link, config.BaseURL) || strings.Split(k.Link, ":")[0] == "/"+k.id {
			k.Link = config.BaseURL
		}
		http.Redirect(w, r, k.Link, http.StatusMovedPermanently)
	} else {
		pd := GetNewPageData()
		pd.Message = "404 Not Found"
		r2.HTML(http.StatusNotFound, "error", pd)
	}
}

func UrlPreprocessor(url string) string {
	if !strings.HasPrefix(url, "http:/") && !strings.HasPrefix(url, "https:/") {
		url = "http://" + url
	}
	return url
}
<|endoftext|>


<commit_before>// Package httpterm provides closable http.Server with extended read timeouts.
package httpterm

import (
	"errors"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

// Server traps http.Server, exposes additional fuctionality
type Server struct {
	// HeadReadTimeout defines timeout for reading request headers.
	HeadReadTimeout time.Duration

	// BodyReadTimeout defines timeout for reading request body.
	// This timeout is being applied just before calling the request handler.
	BodyReadTimeout time.Duration

	// IdleTimeout defines for how long connection can be idle between requests.
	IdleTimeout time.Duration

	// NewAsActive controls whether new connection can be idle before issuing
	// a request. By default, new connections will have IdleTimeout allowing for
	// idle period before issuing a request. However, if this flag is set, new
	// connections will be treated as immediately expecting the request, thus
	// HeadReadTimeout will be applied.
	NewAsActive bool

	// CloseOnSignal enables server shutdown on SIGTERM/SIGNINT.
	// Signal handler is registered in Serve() method.
	CloseOnSignal bool

	server   *http.Server // wrapped http server
	listener *rtListener

	lock    sync.Mutex
	closing bool

	// conns is a map of connections which indicates whether connection is active,
	// i.e. there a request being processed (including header handling)
	conns map[net.Conn]bool
}

// NewServer wraps http.Server, which should be already configured.
func NewServer(server *http.Server) *Server {
	return &Server{server: server, conns: make(map[net.Conn]bool)}
}

// Serve behaves as http.Server.Serve on the wrapped server instance
func (s *Server) Serve(l net.Listener) (pending <-chan bool, err error) {
	oldConnState := s.server.ConnState
	newConnState := func(c net.Conn, state http.ConnState) {
		s.updateConnState(c, state)
		// Pass to original handler
		if oldConnState != nil {
			oldConnState(c, state)
		}
	}

	s.server.ConnState = newConnState

	// Wrap with custom listener
	s.listener = &rtListener{
		Listener:    l,
		newAsActive: s.NewAsActive,
		callback:    func(c net.Conn) { newConnState(c, StateData) },
	}

	// Register signal handling for shutdown if requested
	if s.CloseOnSignal {
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
		go func() {
			<-c
			s.Close()
		}()
	}

	// Serve loop
	err = s.server.Serve(s.listener)
	if err == errListenerClosed {
		err = nil
	}

	// Wait for pending requests
	waiter := make(chan bool)
	pending = waiter
	go func() {
		s.listener.wg.Wait()
		close(waiter)
	}()

	return
}

// ListenAndServe listens on the TCP network address from passed http.Server.Addr
// and calls Serve(). Returned channel can be used to wait for pending requests
// and will be closed once everything is handled.
func (s *Server) ListenAndServe() (pending <-chan bool, err error) {
	addr := s.server.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return nil, err
	}
	return s.Serve(l)
}

// ErrClosing indicating that operation is not allowed as server is closing
var ErrClosing = errors.New("server closing")

// Close server
func (s *Server) Close() error {
	s.lock.Lock()
	defer s.lock.Unlock()

	if s.closing {
		return ErrClosing
	}

	if err := s.listener.Close(); err != nil {
		return err
	}

	s.server.SetKeepAlivesEnabled(false)
	s.closing = true

	// Set a 100ms deadline for all inactive connections (new or idle).
	// If during this period state changes to active, request will be processed
	// with regular request timeout, otherwise connection will be closed.
	deadline := time.Now().Add(100 * time.Millisecond)
	for c, active := range s.conns {
		if !active {
			c.SetReadDeadline(deadline)
		}
	}

	return nil
}

func (s *Server) getTimeout(state http.ConnState) (timeout time.Duration) {
	// Update state for new connection according to policy
	if state == http.StateNew {
		if s.NewAsActive {
			state = StateData
		} else {
			state = http.StateIdle
		}
	}

	switch state {
	case http.StateIdle:
		timeout = s.IdleTimeout

	case StateData:
		timeout = s.HeadReadTimeout

	case http.StateActive:
		timeout = s.BodyReadTimeout
	}

	return
}

func (s *Server) updateConnState(c net.Conn, state http.ConnState) {
	s.lock.Lock()
	defer s.lock.Unlock()

	// Update connection map
	switch state {
	case http.StateNew, http.StateIdle:
		s.conns[c] = false
	case http.StateClosed, http.StateHijacked:
		delete(s.conns, c)
		s.listener.wg.Done()
	case StateData:
		s.conns[c] = true
	}

	if state == http.StateIdle {
		if c, ok := c.(*rtConn); ok {
			c.idle()
		}
	}

	// Update timeout if not closing or new request
	if !s.closing || state == StateData || state == http.StateActive {
		if t := s.getTimeout(state); t != 0 {
			c.SetReadDeadline(time.Now().Add(t))
		}
	}
}

type rtListener struct {
	net.Listener

	newAsActive bool             // set new connections as active
	callback    func(c net.Conn) // data callback

	wg     sync.WaitGroup
	mx     sync.Mutex
	closed bool
}

// This error will be proagated to Serve when we delibaretely close the listener
var errListenerClosed = errors.New("listener closed")

func (l *rtListener) Accept() (c net.Conn, err error) {
	l.wg.Add(1)
	defer func() {
		if c == nil {
			l.wg.Done()
		}
	}()

	c, err = l.Listener.Accept()
	if c != nil {
		c = &rtConn{c, l.newAsActive, l.callback}
	}
	if err != nil {
		l.mx.Lock()
		if l.closed {
			err = errListenerClosed
		}
		l.mx.Unlock()
	}
	return
}

func (l *rtListener) Close() (err error) {
	l.mx.Lock()
	l.closed = true
	l.mx.Unlock()
	return l.Listener.Close()
}

const (
	// StateData tells when initial request data (header) was received.
	// This varies from http.StateActive, as the latter is issued after headers
	// are parsed.
	StateData http.ConnState = 100 + iota
)

// rtConn is a net.Conn that sets read deadlines for idle and active state.
// It automatically detects requests as first bytes are read after idle state.
type rtConn struct {
	net.Conn

	active   bool             // are we currently processing a request?
	callback func(c net.Conn) // data callback
}

func (c *rtConn) Read(b []byte) (n int, err error) {
	n, err = c.Conn.Read(b)
	if n > 0 && !c.active {
		c.callback(c)
	}
	return
}

func (c *rtConn) idle() {
	c.active = false
}
<commit_msg>Use ErrClosing internally<commit_after>// Package httpterm provides closable http.Server with extended read timeouts.
package httpterm

import (
	"errors"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

// ErrClosing indicating that operation is not allowed as server is closing
var ErrClosing = errors.New("server closing")

// Server traps http.Server, exposes additional fuctionality
type Server struct {
	// HeadReadTimeout defines timeout for reading request headers.
	HeadReadTimeout time.Duration

	// BodyReadTimeout defines timeout for reading request body.
	// This timeout is being applied just before calling the request handler.
	BodyReadTimeout time.Duration

	// IdleTimeout defines for how long connection can be idle between requests.
	IdleTimeout time.Duration

	// NewAsActive controls whether new connection can be idle before issuing
	// a request. By default, new connections will have IdleTimeout allowing for
	// idle period before issuing a request. However, if this flag is set, new
	// connections will be treated as immediately expecting the request, thus
	// HeadReadTimeout will be applied.
	NewAsActive bool

	// CloseOnSignal enables server shutdown on SIGTERM/SIGNINT.
	// Signal handler is registered in Serve() method.
	CloseOnSignal bool

	server   *http.Server // wrapped http server
	listener *rtListener

	lock    sync.Mutex
	closing bool

	// conns is a map of connections which indicates whether connection is active,
	// i.e. there a request being processed (including header handling)
	conns map[net.Conn]bool
}

// NewServer wraps http.Server, which should be already configured.
func NewServer(server *http.Server) *Server {
	return &Server{server: server, conns: make(map[net.Conn]bool)}
}

// Serve behaves as http.Server.Serve on the wrapped server instance
func (s *Server) Serve(l net.Listener) (pending <-chan bool, err error) {
	oldConnState := s.server.ConnState
	newConnState := func(c net.Conn, state http.ConnState) {
		s.updateConnState(c, state)
		// Pass to original handler
		if oldConnState != nil {
			oldConnState(c, state)
		}
	}

	s.server.ConnState = newConnState

	// Wrap with custom listener
	s.listener = &rtListener{
		Listener:    l,
		newAsActive: s.NewAsActive,
		callback:    func(c net.Conn) { newConnState(c, StateData) },
	}

	// Register signal handling for shutdown if requested
	if s.CloseOnSignal {
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
		go func() {
			<-c
			s.Close()
		}()
	}

	// Serve loop
	err = s.server.Serve(s.listener)
	// Clear error if server deliberately closed
	if err == ErrClosing {
		err = nil
	}

	// Wait for pending requests
	waiter := make(chan bool)
	pending = waiter
	go func() {
		s.listener.wg.Wait()
		close(waiter)
	}()

	return
}

// ListenAndServe listens on the TCP network address from passed http.Server.Addr
// and calls Serve(). Returned channel can be used to wait for pending requests
// and will be closed once everything is handled.
func (s *Server) ListenAndServe() (pending <-chan bool, err error) {
	addr := s.server.Addr
	if addr == "" {
		addr = ":http"
	}
	l, err := net.Listen("tcp", addr)
	if err != nil {
		return nil, err
	}
	return s.Serve(l)
}

// Close server
func (s *Server) Close() error {
	s.lock.Lock()
	defer s.lock.Unlock()

	if s.closing {
		return ErrClosing
	}

	if err := s.listener.Close(); err != nil {
		return err
	}

	s.server.SetKeepAlivesEnabled(false)
	s.closing = true

	// Set a 100ms deadline for all inactive connections (new or idle).
	// If during this period state changes to active, request will be processed
	// with regular request timeout, otherwise connection will be closed.
	deadline := time.Now().Add(100 * time.Millisecond)
	for c, active := range s.conns {
		if !active {
			c.SetReadDeadline(deadline)
		}
	}

	return nil
}

func (s *Server) getTimeout(state http.ConnState) (timeout time.Duration) {
	// Update state for new connection according to policy
	if state == http.StateNew {
		if s.NewAsActive {
			state = StateData
		} else {
			state = http.StateIdle
		}
	}

	switch state {
	case http.StateIdle:
		timeout = s.IdleTimeout

	case StateData:
		timeout = s.HeadReadTimeout

	case http.StateActive:
		timeout = s.BodyReadTimeout
	}

	return
}

func (s *Server) updateConnState(c net.Conn, state http.ConnState) {
	s.lock.Lock()
	defer s.lock.Unlock()

	// Update connection map
	switch state {
	case http.StateNew, http.StateIdle:
		s.conns[c] = false
	case http.StateClosed, http.StateHijacked:
		delete(s.conns, c)
		s.listener.wg.Done()
	case StateData:
		s.conns[c] = true
	}

	if state == http.StateIdle {
		if c, ok := c.(*rtConn); ok {
			c.idle()
		}
	}

	// Update timeout if not closing or new request
	if !s.closing || state == StateData || state == http.StateActive {
		if t := s.getTimeout(state); t != 0 {
			c.SetReadDeadline(time.Now().Add(t))
		}
	}
}

type rtListener struct {
	net.Listener

	newAsActive bool             // set new connections as active
	callback    func(c net.Conn) // data callback

	wg     sync.WaitGroup
	mx     sync.Mutex
	closed bool
}

func (l *rtListener) Accept() (c net.Conn, err error) {
	l.wg.Add(1)
	defer func() {
		if c == nil {
			l.wg.Done()
		}
	}()

	c, err = l.Listener.Accept()
	if c != nil {
		c = &rtConn{c, l.newAsActive, l.callback}
	}
	if err != nil {
		l.mx.Lock()
		if l.closed {
			err = ErrClosing
		}
		l.mx.Unlock()
	}
	return
}

func (l *rtListener) Close() (err error) {
	l.mx.Lock()
	l.closed = true
	l.mx.Unlock()
	return l.Listener.Close()
}

const (
	// StateData tells when initial request data (header) was received.
	// This varies from http.StateActive, as the latter is issued after headers
	// are parsed.
	StateData http.ConnState = 100 + iota
)

// rtConn is a net.Conn that sets read deadlines for idle and active state.
// It automatically detects requests as first bytes are read after idle state.
type rtConn struct {
	net.Conn

	active   bool             // are we currently processing a request?
	callback func(c net.Conn) // data callback
}

func (c *rtConn) Read(b []byte) (n int, err error) {
	n, err = c.Conn.Read(b)
	if n > 0 && !c.active {
		c.callback(c)
	}
	return
}

func (c *rtConn) idle() {
	c.active = false
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	redirectC := controllers.NewRedirectController(c)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)

	// End routes

	s.UseHandler(router)

	return &s, nil

}
<commit_msg>Redirect URYplayer to On Tap<commit_after>package main

import (
	"net/http"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	redirectC := controllers.NewRedirectController(c)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	getRouter.HandleFunc("/uryplayer/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/ontap/", 301)
	})

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)

	// End routes

	s.UseHandler(router)

	return &s, nil

}
<|endoftext|>